diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..41ae717 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.o +kernel + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7a27d49 --- /dev/null +++ b/Makefile @@ -0,0 +1,26 @@ + +CFLAGS += -ffreestanding + +SRCS := head.asm kernel.c +OBJS := $(foreach src,$(SRCS),$(basename $(src)).o) + +LINK_SCRIPT := link.ld + +KERN_BIN := kernel + +all: $(KERN_BIN) + +clean: + rm $(KERN_BIN) + rm $(OBJS) + +$(KERN_BIN): $(OBJS) + ld -m elf_i386 -T $(LINK_SCRIPT) -o $@ $(OBJS) + +# Rule for compiling nasm assembly +%.o: %.asm + nasm -f elf32 $< -o $@ + +# Rule for compiling C +%.o: %.c + gcc -m32 $(CFLAGS) -c $< -o $@ diff --git a/README.md b/README.md index 5bcf17f..3498fab 100644 --- a/README.md +++ b/README.md @@ -14,13 +14,7 @@ Kernel 201 - Let’s write a Kernel with keyboard and screen support ####Build commands#### ``` -nasm -f elf32 kernel.asm -o kasm.o -``` -``` -gcc -m32 -c kernel.c -o kc.o -``` -``` -ld -m elf_i386 -T link.ld -o kernel kasm.o kc.o +make ``` ####Test on emulator#### diff --git a/kernel.asm b/head.asm similarity index 84% rename from kernel.asm rename to head.asm index 1c2fee7..53bcc7a 100644 --- a/kernel.asm +++ b/head.asm @@ -14,6 +14,7 @@ global keyboard_handler global read_port global write_port global load_idt +global load_gdt extern kmain ;this is defined in the c file extern keyboard_handler_main @@ -36,15 +37,34 @@ load_idt: sti ;turn on interrupts ret +load_gdt: + mov edx, [esp + 4] + lgdt [edx] + ret + keyboard_handler: + push ds + push es + push fs + push gs + pushad + call keyboard_handler_main + + popad + pop ds + pop es + pop fs + pop gs iretd start: - cli ;block interrupts mov esp, stack_space call kmain + cli +.loop: hlt ;halt the CPU + jmp .loop section .bss resb 8192; 8KB for stack diff --git a/kernel.c b/kernel.c index 352a5c4..5758d43 100644 --- a/kernel.c +++ b/kernel.c @@ -2,7 +2,6 @@ * Copyright (C) 2014 Arjun Sreedharan * License: GPL version 2 or higher http://www.gnu.org/licenses/gpl.html */ -#include #include "keyboard_map.h" /* there are 25 lines each of 80 columns; each element takes 2 bytes */ @@ -15,7 +14,30 @@ #define KEYBOARD_STATUS_PORT 0x64 #define IDT_SIZE 256 #define INTERRUPT_GATE 0x8e -#define KERNEL_CODE_SEGMENT_OFFSET 0x08 +#define KERNEL_CODE_SEGMENT_OFFSET KERNEL_CS + +#define GDT_SIZE 3 +#define GDT_MEM_LOW 0 +#define GDT_MEM_LEN 0xFFFFFFFF + +#define GDT_EXE 0x8 +#define GDT_READ 0x2 +#define GDT_WRITE 0x2 + +/* Kernel code always runs in ring 0 */ +#define DPL_KERNEL 0 + +/* GDT entry numbers */ +enum { + _GDT_NULL, + _KERNEL_CS, + _KERNEL_DS +}; + +/* GDT entry offsets */ +#define GDT_NULL (_GDT_NULL << 3) +#define KERNEL_CS (_KERNEL_CS << 3) +#define KERNEL_DS (_KERNEL_DS << 3) #define ENTER_KEY_CODE 0x1C @@ -23,20 +45,91 @@ extern unsigned char keyboard_map[128]; extern void keyboard_handler(void); extern char read_port(unsigned short port); extern void write_port(unsigned short port, unsigned char data); -extern void load_idt(unsigned long *idt_ptr); /* current cursor location */ unsigned int current_loc = 0; /* video memory begins at address 0xb8000 */ char *vidptr = (char*)0xb8000; +struct GDT_entry { + /* Low 8 bits of the "limit", or length of memory this descriptor refers to. */ + unsigned short limit_low; + unsigned short base_low; /* 'Low' 16-bits of the base */ + unsigned char base_middle; /* 'middle' 8 bits of the base */ + + unsigned char type :4; /* Flags for type of memory this descriptor describes */ + unsigned char one :1; + unsigned char dpl :2; /* Descriptor privilege level - Ring level */ + unsigned char present :1; /* 1 for any valid GDT entry */ + + unsigned char limit :4; /* Top 4 bytes of 'limit' */ + unsigned char avilable :1; + unsigned char zero :1; + unsigned char op_size :1; /* Selects between 16-bit and 32-bit */ + unsigned char gran :1; /* If this bit is set, then 'limit' is a count of 4K blocks, not bytes */ + + unsigned char base_high; /* High 8 bits of the base */ +} __attribute__((packed)); + +struct gdt_ptr { + unsigned short limit; + unsigned long base; +} __attribute__((packed)); + +extern void load_gdt(struct gdt_ptr *gdt_ptr); + +#define GDT_ENTRY(gdt_type, gdt_base, gdt_limit, gdt_dpl) \ + { \ + .limit_low = (((gdt_limit) >> 12) & 0xFFFF), \ + .base_low = ((gdt_base) & 0xFFFF), \ + .base_middle = (((gdt_base) >> 16) & 0xFF), \ + .type = gdt_type, \ + .one = 1, \ + .dpl = gdt_dpl, \ + .present = 1, \ + .limit = ((gdt_limit) >> 28), \ + .avilable = 0, \ + .zero = 0, \ + .op_size = 1, \ + .gran = 1, \ + .base_high = (((gdt_base) >> 24) & 0xFF), \ + } + +/* Define our GDT that we'll use - We know everything upfront, so we just + * initalize it with the correct settings. + * + * This sets up the NULL, entry, and then the kernel's CS and DS segments, + * which just span all 4GB of memory. */ +struct GDT_entry GDT[GDT_SIZE] = { + [_GDT_NULL] = { 0 /* NULL GDT entry - Required */ }, + [_KERNEL_CS] = GDT_ENTRY(GDT_EXE | GDT_READ, 0, 0xFFFFFFFF, DPL_KERNEL), + [_KERNEL_DS] = GDT_ENTRY(GDT_WRITE, 0, 0xFFFFFFFF, DPL_KERNEL) +}; + +void gdt_init(void) +{ + struct gdt_ptr gdt_ptr; + + gdt_ptr.base = (unsigned long)GDT; + gdt_ptr.limit = sizeof(GDT); + load_gdt(&gdt_ptr); +} + + struct IDT_entry{ unsigned short int offset_lowerbits; unsigned short int selector; unsigned char zero; unsigned char type_attr; unsigned short int offset_higherbits; -}; +} __attribute__((packed)); + +struct idt_ptr { + unsigned short limit; + unsigned long base; +} __attribute__((packed)); + +extern void load_idt(struct idt_ptr *idt_ptr); struct IDT_entry IDT[IDT_SIZE]; @@ -44,8 +137,7 @@ struct IDT_entry IDT[IDT_SIZE]; void idt_init(void) { unsigned long keyboard_address; - unsigned long idt_address; - unsigned long idt_ptr[2]; + struct idt_ptr idt_ptr; /* populate IDT entry of keyboard's interrupt */ keyboard_address = (unsigned long)keyboard_handler; @@ -87,11 +179,10 @@ void idt_init(void) write_port(0xA1 , 0xff); /* fill the IDT descriptor */ - idt_address = (unsigned long)IDT ; - idt_ptr[0] = (sizeof (struct IDT_entry) * IDT_SIZE) + ((idt_address & 0xffff) << 16); - idt_ptr[1] = idt_address >> 16 ; + idt_ptr.limit = sizeof(IDT); + idt_ptr.base = (unsigned long)IDT; - load_idt(idt_ptr); + load_idt(&idt_ptr); } void kb_init(void) @@ -156,9 +247,11 @@ void kmain(void) kprint_newline(); kprint_newline(); + gdt_init(); idt_init(); kb_init(); - while(1); + while(1) + asm volatile ("hlt"); }