diff --git a/TODO.org b/TODO.org index 9163544..da103ff 100644 --- a/TODO.org +++ b/TODO.org @@ -10,10 +10,11 @@ ** TODO Improve Build * [ ] Add arguments ** TODO Global Constructors Table - * [ ] Init GDT in early kernel + * [X] Init GDT in early kernel * [ ] Add LDT (Local Descriptor Table) ** TODO Serial * [ ] Print debuging messages to Serial + * [ ] Add more arguments to serial_printf function * [ ] Add input from Serial ** TODO Interrupt Description Table * [ ] Init IDT in early kernel diff --git a/kernel/Makefile b/kernel/Makefile index fb9fa63..7abeb79 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -29,6 +29,7 @@ LIBS:=$(LIBS) $(KERNEL_ARCH_LIBS) KERNEL_OBJS=\ $(KERNEL_ARCH_OBJS) \ +kernel/early_kernel.o \ kernel/kernel.o \ OBJS=\ diff --git a/kernel/arch/i386/boot.S b/kernel/arch/i386/boot.S index 24883c7..057b527 100644 --- a/kernel/arch/i386/boot.S +++ b/kernel/arch/i386/boot.S @@ -29,6 +29,9 @@ _start: # Call the global constructors. call _init + # Call early kernel (init GDT, IDT and other) + call kernel_early_main + # Transfer control to the main kernel. call kernel_main @@ -37,3 +40,19 @@ _start: 1: hlt jmp 1b .size _start, . - _start + +.global gdt_flush +gdt_flush: + cli + mov 0x4(%esp),%eax + sgdtl (%eax) + mov $0x10,%ax + mov %eax,%ds + mov %eax,%es + mov %eax,%fs + mov %eax,%gs + mov %eax,%ss + ljmp $0x8,$.flush +.flush: + ret + diff --git a/kernel/kernel/early_kernel.c b/kernel/kernel/early_kernel.c new file mode 100644 index 0000000..5777188 --- /dev/null +++ b/kernel/kernel/early_kernel.c @@ -0,0 +1,12 @@ +#include + +#include +#include "serial.h" +#include "gdt.c" + +void kernel_early_main(void) { + gdt_init(); + terminal_initialize(); + init_serial(); + serial_printf("gdt initialized!\n"); +} diff --git a/kernel/kernel/gdt.c b/kernel/kernel/gdt.c new file mode 100644 index 0000000..01e5b4b --- /dev/null +++ b/kernel/kernel/gdt.c @@ -0,0 +1,108 @@ + +// Used for creating GDT segment descriptors in 64-bit integer form. + +#include +#include + +// Each define here is for a specific flag in the descriptor. +// Refer to the intel documentation for a description of what each one does. +#define SEG_DESCTYPE(x) ((x) << 0x04) // Descriptor type (0 for system, 1 for code/data) +#define SEG_PRES(x) ((x) << 0x07) // Present +#define SEG_SAVL(x) ((x) << 0x0C) // Available for system use +#define SEG_LONG(x) ((x) << 0x0D) // Long mode +#define SEG_SIZE(x) ((x) << 0x0E) // Size (0 for 16-bit, 1 for 32) +#define SEG_GRAN(x) ((x) << 0x0F) // Granularity (0 for 1B - 1MB, 1 for 4KB - 4GB) +#define SEG_PRIV(x) (((x) & 0x03) << 0x05) // Set privilege level (0 - 3) + +#define SEG_DATA_RD 0x00 // Read-Only +#define SEG_DATA_RDA 0x01 // Read-Only, accessed +#define SEG_DATA_RDWR 0x02 // Read/Write +#define SEG_DATA_RDWRA 0x03 // Read/Write, accessed +#define SEG_DATA_RDEXPD 0x04 // Read-Only, expand-down +#define SEG_DATA_RDEXPDA 0x05 // Read-Only, expand-down, accessed +#define SEG_DATA_RDWREXPD 0x06 // Read/Write, expand-down +#define SEG_DATA_RDWREXPDA 0x07 // Read/Write, expand-down, accessed +#define SEG_CODE_EX 0x08 // Execute-Only +#define SEG_CODE_EXA 0x09 // Execute-Only, accessed +#define SEG_CODE_EXRD 0x0A // Execute/Read +#define SEG_CODE_EXRDA 0x0B // Execute/Read, accessed +#define SEG_CODE_EXC 0x0C // Execute-Only, conforming +#define SEG_CODE_EXCA 0x0D // Execute-Only, conforming, accessed +#define SEG_CODE_EXRDC 0x0E // Execute/Read, conforming +#define SEG_CODE_EXRDCA 0x0F // Execute/Read, conforming, accessed + +#define GDT_CODE_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \ + SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ + SEG_PRIV(0) | SEG_CODE_EXRD + +#define GDT_DATA_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \ + SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ + SEG_PRIV(0) | SEG_DATA_RDWR + +#define GDT_CODE_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \ + SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ + SEG_PRIV(3) | SEG_CODE_EXRD + +#define GDT_DATA_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \ + SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ + SEG_PRIV(3) | SEG_DATA_RDWR +#define GDT_MAX_DESCRIPTORS 3 + +struct gdt_entry { + uint16_t limit_low; + uint16_t base_low; + uint8_t base_middle; + uint8_t access; + uint8_t granularity; + uint8_t base_high; +}__attribute__((packed)); + +struct gdt_ptr { + uint16_t limit; + uint32_t base; +}__attribute__((packed)); + +struct gdt_entry gdt[GDT_MAX_DESCRIPTORS]; +struct gdt_ptr gp; + +extern void gdt_flush(struct gdt_ptr* gdt_ptr_addr); + +void +create_descriptor(uint32_t base, uint32_t limit, uint16_t flag) +{ + uint64_t descriptor; + + // Create the high 32 bit segment + descriptor = limit & 0x000F0000; // set limit bits 19:16 + descriptor |= (flag << 8) & 0x00F0FF00; // set type, p, dpl, s, g, d/b, l and avl fields + descriptor |= (base >> 16) & 0x000000FF; // set base bits 23:16 + descriptor |= base & 0xFF000000; // set base bits 31:24 + + // Shift by 32 to allow for low part of segment + descriptor <<= 32; + + // Create the low 32 bit segment + descriptor |= base << 16; // set base bits 15:0 + descriptor |= limit & 0x0000FFFF; // set limit bits 15:0 + + printf("0x%.16llX\n", descriptor); +} + +void gdt_init() { + gp.limit = (sizeof(struct gdt_entry) * GDT_MAX_DESCRIPTORS) - 1; + gp.base = (uint32_t) &gdt; + + create_descriptor(0, 0, 0); + create_descriptor(0, 0x000FFFFF, (GDT_CODE_PL0)); + create_descriptor(0, 0x000FFFFF, (GDT_DATA_PL0)); + create_descriptor(0, 0x000FFFFF, (GDT_CODE_PL3)); + create_descriptor(0, 0x000FFFFF, (GDT_DATA_PL3)); + + /* + gdt_set_gate(0, 0, 0, 0, 0); + gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); + gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); + */ + + gdt_flush(&gp); +} diff --git a/kernel/kernel/kernel.c b/kernel/kernel/kernel.c index f454fbd..711670d 100644 --- a/kernel/kernel/kernel.c +++ b/kernel/kernel/kernel.c @@ -1,13 +1,6 @@ -#define PORT 0x3f8 - #include -#include -#include "serial.h" - void kernel_main(void) { - terminal_initialize(); - init_serial(); printf("Hello from OrionOS!\n"); printf("Testing serial\n"); serial_printf("Test is success!\n");