Add some "kernel" code written in C
Draw few message on VGA Setup Interruption Description Table Setup IRQ
This commit is contained in:
parent
523bff7fce
commit
f1341d3d72
6
Makefile
6
Makefile
@ -1,8 +1,8 @@
|
||||
AS=nasm
|
||||
ASFLAGS += -f elf32
|
||||
LDFLAGS += -m32 -nostdlib -static -fno-common -fno-use-cxa-atexit -fno-exceptions -fno-non-call-exceptions -fno-weak -fno-rtti
|
||||
CFLAGS += -m32 -Wall -Wextra -Werror -ffreestanding -fno-exceptions
|
||||
CXXFLAGS += -m32 -Wall -Wextra -Werror -ffreestanding -fno-exceptions -fno-rtti
|
||||
LDFLAGS += -m32 -nostdlib -static -fno-common -fno-use-cxa-atexit -fno-exceptions -fno-non-call-exceptions -fno-weak -fno-rtti -fno-stack-protector
|
||||
CFLAGS += -m32 -Wall -Wextra -Werror -ffreestanding -fno-exceptions -fno-pie -fno-stack-protector
|
||||
CXXFLAGS += -m32 -Wall -Wextra -Werror -ffreestanding -fno-exceptions -fno-rtti -fno-pie
|
||||
|
||||
|
||||
asmsrc=$(wildcard *.asm)
|
||||
|
44
idt.c
Normal file
44
idt.c
Normal file
@ -0,0 +1,44 @@
|
||||
#include "idt.h"
|
||||
static struct idtEntry idt[IDT_NUM];
|
||||
|
||||
|
||||
int idtSetup()
|
||||
{
|
||||
struct idtRegister idtr;
|
||||
|
||||
for (int i = 0; i < IDT_NUM; i++) {
|
||||
struct idtEntry *idte = idt + i;
|
||||
|
||||
/* Setup an empty IDTE interrupt gate, see figure 5-2 in Intel
|
||||
x86 doc, vol 3 */
|
||||
idte->seg_sel = BUILD_SEGMENT_SELECTOR(RING_0, 0, SEGMENT_IDX_CODE);
|
||||
idte->reserved = 0;
|
||||
idte->flags = 0;
|
||||
idte->type = 0x6; /* Interrupt gate (110b) */
|
||||
idte->op_size = 1; /* 32bits instructions */
|
||||
|
||||
/* Disabled it for now */
|
||||
idte->zero = 0;
|
||||
idte->offset_low = 0;
|
||||
idte->offset_high = 0;
|
||||
idte->dpl = 0;
|
||||
idte->present = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup the IDT register, see Intel x86 doc vol 3, section 5.8.
|
||||
*/
|
||||
|
||||
/* Address of the IDT */
|
||||
idtr.base_addr = (uint32_t) idt;
|
||||
|
||||
/* The limit is the maximum offset in bytes from the base address of
|
||||
the IDT */
|
||||
idtr.limit = sizeof(idt) - 1;
|
||||
|
||||
/* Commit the IDT into the CPU */
|
||||
asm volatile ("lidt %0\n"::"m"(idtr):"memory");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
44
idt.h
Normal file
44
idt.h
Normal file
@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
#define IDT_NUM 256
|
||||
|
||||
#define RING_0 0
|
||||
#define RING_1 1
|
||||
#define RING_2 2
|
||||
#define RING_3 3
|
||||
|
||||
#define SEGMENT_IDX_NULL 0
|
||||
#define SEGMENT_IDX_CODE 1
|
||||
#define SEGMENT_IDX_DATA 2
|
||||
|
||||
struct idtEntry {
|
||||
uint16_t offset_low;
|
||||
uint16_t seg_sel;
|
||||
uint8_t reserved : 5;
|
||||
uint8_t flags : 3;
|
||||
uint8_t type : 3;
|
||||
uint8_t op_size : 1;
|
||||
uint8_t zero : 1;
|
||||
uint8_t dpl : 2;
|
||||
uint8_t present : 1;
|
||||
uint16_t offset_high;
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* The IDT register, which stores the address and size of the
|
||||
* IDT.
|
||||
*
|
||||
* @see Intel x86 doc vol 3, section 2.4, figure 2-4
|
||||
*/
|
||||
struct idtRegister {
|
||||
uint16_t limit;
|
||||
uint32_t base_addr;
|
||||
} __attribute__((packed, aligned(8)));
|
||||
|
||||
/* Build segment http://wiki.osdev.org/Selector*/
|
||||
#define BUILD_SEGMENT_SELECTOR(desc_privilege, in_ldt, index) \
|
||||
((((desc_privilege)&0x3) << 0) | (((in_ldt) ? 1 : 0) << 2) | \
|
||||
((index) << 3))
|
||||
|
||||
int idtSetup();
|
21
io.h
Normal file
21
io.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
// NIH http://wiki.osdev.org/Inline_Assembly/Examples#I.2FO_access
|
||||
static inline void outb(uint16_t port, uint8_t val)
|
||||
{
|
||||
asm volatile ( "outb %0, %1" : : "a"(val), "Nd"(port) );
|
||||
/* There's an outb %al, $imm8 encoding, for compile-time constant port numbers that fit in 8b. (N constraint).
|
||||
* Wider immediate constants would be truncated at assemble-time (e.g. "i" constraint).
|
||||
* The outb %al, %dx encoding is the only option for all other cases.
|
||||
* %1 expands to %dx because port is a uint16_t. %w1 could be used if we had the port number a wider C type */
|
||||
}
|
||||
|
||||
static inline uint8_t inb(uint16_t port)
|
||||
{
|
||||
uint8_t ret;
|
||||
asm volatile ( "inb %1, %0"
|
||||
: "=a"(ret)
|
||||
: "Nd"(port) );
|
||||
return ret;
|
||||
}
|
8
irq.c
Normal file
8
irq.c
Normal file
@ -0,0 +1,8 @@
|
||||
#include "irq.h"
|
||||
#include "pic.h"
|
||||
|
||||
int irqSetup()
|
||||
{
|
||||
initPic();
|
||||
return 0;
|
||||
}
|
21
irq.h
Normal file
21
irq.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#define IRQ_TIMER 0 // MASTER IRQ
|
||||
#define IRQ_KEYBOARD 1
|
||||
#define IRQ_SLAVE_PIC 2
|
||||
#define IRQ_COM2 3
|
||||
#define IRQ_COM1 4
|
||||
#define IRQ_LPT2 5
|
||||
#define IRQ_FLOPPY 6
|
||||
#define IRQ_LPT1 7
|
||||
#define IRQ_8_NOT_DEFINED 8 // SLAVE
|
||||
#define IRQ_RESERVED_1 9 // SLAVE IRQ
|
||||
#define IRQ_RESERVED_2 10
|
||||
#define IRQ_RESERVED_3 11
|
||||
#define IRQ_RESERVED_4 12
|
||||
#define IRQ_COPROCESSOR 13
|
||||
#define IRQ_HARDDISK 14
|
||||
#define IRQ_RESERVED_5 15
|
||||
|
||||
typedef void (*irq_handler)(int irq);
|
||||
int irqSetup();
|
37
main.c
Normal file
37
main.c
Normal file
@ -0,0 +1,37 @@
|
||||
#include "idt.h"
|
||||
#include "io.h"
|
||||
#include "irq.h"
|
||||
#include "types.h"
|
||||
#include "vga.h"
|
||||
|
||||
char getScancode()
|
||||
{
|
||||
char c = 0;
|
||||
do {
|
||||
if (inb(0x60) != c) {
|
||||
c = inb(0x60);
|
||||
if (c > 0)
|
||||
return c;
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
|
||||
void cpuid(int code, uint32_t *a, uint32_t *d)
|
||||
{
|
||||
asm volatile("cpuid" : "=a"(*a), "=d"(*d) : "0"(code) : "ebx", "ecx");
|
||||
}
|
||||
|
||||
void kmain()
|
||||
{
|
||||
const short color = GREEN;
|
||||
clearScreen(BLACK);
|
||||
printString("Setting up IDT", color, BLACK, 0, 0);
|
||||
idtSetup();
|
||||
printString("Setting up IRQ", color, BLACK, 0, 1);
|
||||
irqSetup();
|
||||
|
||||
while (1) {
|
||||
char c = getScancode();
|
||||
printChar(c, color, BLACK, 0, 5);
|
||||
}
|
||||
}
|
8
mbr.asm
8
mbr.asm
@ -152,6 +152,14 @@ boot2:
|
||||
add ebx,2
|
||||
jmp .loop32
|
||||
halt:
|
||||
mov esp,kernel_stack_top
|
||||
extern kmain
|
||||
call kmain
|
||||
cli
|
||||
hlt
|
||||
hello32: db "Hello 32 bits world!",0
|
||||
section .bss
|
||||
align 4
|
||||
kernel_stack_bottom: equ $
|
||||
resb 16384 ; 16 KB
|
||||
kernel_stack_top:
|
||||
|
64
pic.c
Normal file
64
pic.c
Normal file
@ -0,0 +1,64 @@
|
||||
#include "pic.h"
|
||||
#include "io.h"
|
||||
|
||||
#define ICW1_ICW4 0x01 /* ICW4 (not) needed */
|
||||
#define ICW1_SINGLE 0x02 /* Single (cascade) mode */
|
||||
#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */
|
||||
#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */
|
||||
#define ICW1_INIT 0x10 /* Initialization - required! */
|
||||
|
||||
#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */
|
||||
#define ICW4_AUTO 0x02 /* Auto (normal) EOI */
|
||||
#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */
|
||||
#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */
|
||||
#define ICW4_SFNM 0x10 /* Special fully nested (not) */
|
||||
|
||||
void initPic(void)
|
||||
{
|
||||
/* Send CMD: Init + senquence in 4 DATA */
|
||||
outb(ICW1_INIT + ICW1_ICW4, PIC_MASTER_CMD);
|
||||
outb(ICW1_INIT + ICW1_ICW4, PIC_SLAVE_CMD);
|
||||
|
||||
/* Send ICW2: ctrl base address. Remap IRQ from interupt range 0x0-0xF to 0x20-0x2F as
|
||||
* intel
|
||||
* reserve interupt 0x0-0x1F in protected mode (e.g. 0-7 are CPU exception) */
|
||||
outb(0x20, PIC_MASTER_DATA);
|
||||
outb(0x28, PIC_SLAVE_DATA);
|
||||
|
||||
/* Send ICW3 master: mask where slaves are connected */
|
||||
outb(0x4, PIC_MASTER_DATA);
|
||||
/* Send ICW3 slave: index where the slave is connected on master */
|
||||
outb(0x2, PIC_SLAVE_DATA);
|
||||
|
||||
/* Send ICW4: 8086 mode, fully nested, not buffered, no implicit EOI */
|
||||
outb(ICW4_8086, PIC_MASTER_DATA);
|
||||
outb(ICW4_8086, PIC_SLAVE_DATA);
|
||||
|
||||
/* Send OCW1:
|
||||
* Closing all IRQs : waiting for a correct handler The only IRQ
|
||||
* enabled is the cascade (that's why we use 0xFB for the master) */
|
||||
outb(0xFB, PIC_MASTER_DATA);
|
||||
outb(0xFF, PIC_SLAVE_DATA);
|
||||
}
|
||||
|
||||
void enableIrq(int irq)
|
||||
{
|
||||
if (irq < 8) {
|
||||
uint8_t status = inb(PIC_MASTER_DATA);
|
||||
outb((status | (1 << irq)), PIC_MASTER_DATA);
|
||||
} else {
|
||||
uint8_t status = inb(PIC_SLAVE_DATA);
|
||||
outb((status | (1 << irq)), PIC_SLAVE_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
void disableIrq(int irq)
|
||||
{
|
||||
if (irq < 8) {
|
||||
uint8_t status = inb(PIC_MASTER_DATA);
|
||||
outb((status & ~(1 << irq)), PIC_MASTER_DATA);
|
||||
} else {
|
||||
uint8_t status = inb(PIC_SLAVE_DATA);
|
||||
outb((status & ~(1 << irq)), PIC_SLAVE_DATA);
|
||||
}
|
||||
}
|
18
pic.h
Normal file
18
pic.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
//2 PIC 8259 are available on x86
|
||||
//
|
||||
// Master - command: 0x20, data: 0x21
|
||||
// Slave - command: 0xA0, data: 0xA1
|
||||
//
|
||||
// http://www.jamesmolloy.co.uk/tutorial_html/5.-IRQs%20and%20the%20PIT.html
|
||||
// SimpleOS art2
|
||||
// http://wiki.osdev.org/PIC
|
||||
|
||||
#define PIC_MASTER_CMD 0x20
|
||||
#define PIC_SLAVE_CMD 0xa0
|
||||
#define PIC_MASTER_DATA 0x21
|
||||
#define PIC_SLAVE_DATA 0xa0
|
||||
|
||||
void initPic(void);
|
||||
void enableIrq(int irq);
|
||||
void disableIrq(int irq);
|
36
types.h
Normal file
36
types.h
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
typedef __signed__ char __s8;
|
||||
typedef unsigned char __u8;
|
||||
|
||||
typedef __signed__ short __s16;
|
||||
typedef unsigned short __u16;
|
||||
|
||||
typedef __signed__ int __s32;
|
||||
typedef unsigned int __u32;
|
||||
|
||||
#ifdef __GNUC__
|
||||
__extension__ typedef __signed__ long long __s64;
|
||||
__extension__ typedef unsigned long long __u64;
|
||||
#else
|
||||
typedef __signed__ long long __s64;
|
||||
typedef unsigned long long __u64;
|
||||
#endif
|
||||
|
||||
/* sysv */
|
||||
typedef unsigned char unchar;
|
||||
typedef unsigned short ushort;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
|
||||
typedef __s8 int8_t;
|
||||
typedef __s16 int16_t;
|
||||
typedef __s32 int32_t;
|
||||
|
||||
typedef __u8 uint8_t;
|
||||
typedef __u16 uint16_t;
|
||||
typedef __u32 uint32_t;
|
||||
|
||||
typedef __u64 uint64_t;
|
||||
typedef __u64 u_int64_t;
|
||||
typedef __s64 int64_t;
|
30
vga.c
Normal file
30
vga.c
Normal file
@ -0,0 +1,30 @@
|
||||
#include "vga.h"
|
||||
|
||||
void clearScreen(int bgColor)
|
||||
{
|
||||
volatile short *vga = (short *)VGA_ADDR;
|
||||
long int colorAttr = bgColor << 12;
|
||||
for (int i = 0; i < VGA_WIDTH * VGA_HEIGHT; i++) {
|
||||
vga[i] = colorAttr;
|
||||
}
|
||||
}
|
||||
|
||||
void printChar(const char str, int color, int bgColor, int startX, int startY)
|
||||
{
|
||||
volatile short *vga = (short *)VGA_ADDR;
|
||||
long int colorAttr = (bgColor << 4 | (color & 0x0f)) << 8;
|
||||
vga[80 * startY + startX] = colorAttr | str;
|
||||
}
|
||||
|
||||
void printString(const char *str, int color, int bgColor, int startX,
|
||||
int startY)
|
||||
{
|
||||
volatile short *vga = (short *)VGA_ADDR;
|
||||
int i = 0;
|
||||
long int colorAttr = (bgColor << 4 | (color & 0x0f)) << 8;
|
||||
while (*str) {
|
||||
vga[80 * startY + startX + i] = colorAttr | *str;
|
||||
str++;
|
||||
i++;
|
||||
}
|
||||
}
|
19
vga.h
Normal file
19
vga.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#define BLACK 0x00
|
||||
#define BLUE 0x01
|
||||
#define GREEN 0x02
|
||||
#define CYAN 0x03
|
||||
#define RED 0x04
|
||||
#define MAGENTA 0x05
|
||||
#define BROWN 0x06
|
||||
#define GREY 0x07
|
||||
#define WHITE 0x0F
|
||||
|
||||
#define VGA_ADDR 0xB8000
|
||||
#define VGA_WIDTH 80
|
||||
#define VGA_HEIGHT 15
|
||||
|
||||
void clearScreen(int bgColor);
|
||||
void printChar(const char str, int color, int bgColor, int startX, int startY);
|
||||
void printString(const char *str, int color, int bgColor, int startX, int startY);
|
Loading…
Reference in New Issue
Block a user