diff --git a/headers/gdt.h b/headers/gdt.h index 9cc0aa1..490393e 100644 --- a/headers/gdt.h +++ b/headers/gdt.h @@ -2,16 +2,19 @@ #include -#define GDT_BASE 0x00000800 -// sizeof(Segment Descriptor) * nb(Segment Descriptor) -#define GDT_SIZE 8 * 7 +#define GDT_ADDRESS 0x00000800 +#define GDT_SIZE 7 -struct gdt_entry { - uint32_t limit; - uint32_t base; - uint8_t access_byte; - uint8_t flags; -}; +// https://wiki.osdev.org/Global_Descriptor_Table#Segment_Descriptor +struct gdt_entry +{ + uint16_t limit_low; + uint16_t base_low; + uint8_t base_middle; + uint8_t access; + uint8_t limit_high_and_flags; + uint8_t base_high; +} __attribute__((packed)) ; // https://wiki.osdev.org/Global_Descriptor_Table#GDTR struct gdt_descriptor { @@ -19,4 +22,22 @@ struct gdt_descriptor { uint32_t base; } __attribute__((packed)); -void initGdt(); \ No newline at end of file +void initGdt(); + +#define GDT_FLAG_64BIT_MODE 0b0010 +#define GDT_FLAG_32BIT_MODE 0b0100 +#define GDT_FLAG_PAGE_MODE 0b1000 +#define GDT_FLAG_BYTE_MODE 0b1000 + +#define GDT_ACCESS_P_VALID 0b10000000 +#define GDT_ACCESS_DPL_KERNEL_MODE 0b00000000 +#define GDT_ACCESS_DPL_USER_MODE 0b01100000 +#define GDT_ACCESS_S_CODE_OR_DATA 0b00010000 +#define GDT_ACCESS_S_SYSTEM_SEGMENT 0b00010000 +#define GDT_ACCESS_E_EXECUTABLE 0b00001000 +#define GDT_ACCESS_E_NOT_EXECUTABLE 0b00000000 +#define GDT_ACCESS_DC_CONFORM 0b00000100 // TODO UNDERSTAND THIS BIT +#define GDT_ACCESS_DC_NOT_CONFORM 0b00000000 +#define GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA 0b00000010 +#define GDT_ACCESS_A_ACCESSED 0b00000001 +#define GDT_ACCESS_A_NOT_ACCESSED 0b00000000 \ No newline at end of file diff --git a/src/gdt/gdt.c b/src/gdt/gdt.c index e31dc79..9268238 100644 --- a/src/gdt/gdt.c +++ b/src/gdt/gdt.c @@ -1,86 +1,52 @@ +#include + #include "gdt.h" #include "kprintf.h" #include "string.h" -extern void setGdt(void *); +extern void set_gdt(uint32_t gdt_ptr); -void encodeGdtEntry(uint8_t *target, struct gdt_entry source) +uint8_t gdt_entries[GDT_SIZE * 8]; +struct gdt_descriptor *gdtr = (struct gdt_descriptor *) GDT_ADDRESS; + +static void set_gdt_entry_value(uint8_t *target, uint32_t base, uint32_t limit, uint8_t access, uint8_t granularity) { - // Check the limit to make sure that it can be encoded - if (source.limit > 0xFFFFF) { - kprintf(KERN_ERR, - "GDT cannot encode limits larger than 0xFFFFF"); + if (limit > 0xFFFFF) { + kprintf(KERN_ERR, "GDT cannot encode limits larger than 0xFFFFF"); } // Encode the limit - target[0] = source.limit & 0xFF; - target[1] = (source.limit >> 8) & 0xFF; - target[6] = (source.limit >> 16) & 0x0F; + target[0] = limit & 0xFF; + target[1] = (limit >> 8) & 0xFF; + target[6] = (limit >> 16) & 0x0F; // Encode the base - target[2] = source.base & 0xFF; - target[3] = (source.base >> 8) & 0xFF; - target[4] = (source.base >> 16) & 0xFF; - target[7] = (source.base >> 24) & 0xFF; + target[2] = base & 0xFF; + target[3] = (base >> 8) & 0xFF; + target[4] = (base >> 16) & 0xFF; + target[7] = (base >> 24) & 0xFF; // Encode the access byte - target[5] = source.access_byte; + target[5] = access; // Encode the flags - target[6] |= (source.flags << 4); + target[6] |= (granularity << 4); } -uint8_t gdt_entries[8][7]; -struct gdt_descriptor gdtr; - void initGdt() { - gdtr.size = GDT_SIZE - 1; - gdtr.base = GDT_BASE; + gdtr->size = 8 * GDT_SIZE - 1; + gdtr->base = (uint32_t) &gdt_entries; - struct gdt_entry gdt_entry_null_descriptor = { - .base = 0, .limit = 0x00000000, .access_byte = 0x00, .flags = 0x0}; - encodeGdtEntry(gdt_entries[0], gdt_entry_null_descriptor); + set_gdt_entry_value(gdt_entries + 0x00, 0, 0, 0, 0); // Null segment - struct gdt_entry gdt_entry_kernel_mode_code_segment = { - .base = 0, .limit = 0xFFFFF, .access_byte = 0x9A, .flags = 0xC}; - encodeGdtEntry(gdt_entries[1], gdt_entry_kernel_mode_code_segment); + set_gdt_entry_value(gdt_entries + 0x08, 0, 0xFFFFF, GDT_ACCESS_P_VALID | GDT_ACCESS_DPL_KERNEL_MODE | GDT_ACCESS_S_CODE_OR_DATA | GDT_ACCESS_E_EXECUTABLE | GDT_ACCESS_DC_NOT_CONFORM | GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA | GDT_ACCESS_A_ACCESSED, GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // Kernel code + set_gdt_entry_value(gdt_entries + 0x10, 0, 0xFFFFF, GDT_ACCESS_P_VALID | GDT_ACCESS_DPL_KERNEL_MODE | GDT_ACCESS_S_CODE_OR_DATA | GDT_ACCESS_E_NOT_EXECUTABLE | GDT_ACCESS_DC_NOT_CONFORM | GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA | GDT_ACCESS_A_ACCESSED, GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // Kernel data + set_gdt_entry_value(gdt_entries + 0x18, 0, 0x0, GDT_ACCESS_P_VALID | GDT_ACCESS_DPL_KERNEL_MODE | GDT_ACCESS_S_CODE_OR_DATA | GDT_ACCESS_E_NOT_EXECUTABLE | GDT_ACCESS_DC_CONFORM |GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA | GDT_ACCESS_A_ACCESSED, GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // Kernel stack - struct gdt_entry gdt_entry_kernel_mode_data_segment = { - .base = 0, .limit = 0xFFFFF, .access_byte = 0x92, .flags = 0xC}; - encodeGdtEntry(gdt_entries[2], gdt_entry_kernel_mode_data_segment); + set_gdt_entry_value(gdt_entries + 0x20, 0, 0xFFFFF, GDT_ACCESS_P_VALID | GDT_ACCESS_DPL_USER_MODE | GDT_ACCESS_S_CODE_OR_DATA | GDT_ACCESS_E_EXECUTABLE | GDT_ACCESS_DC_CONFORM | GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA | GDT_ACCESS_A_ACCESSED, GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // User code + set_gdt_entry_value(gdt_entries + 0x28, 0, 0xFFFFF, GDT_ACCESS_P_VALID | GDT_ACCESS_DPL_USER_MODE | GDT_ACCESS_S_CODE_OR_DATA | GDT_ACCESS_E_NOT_EXECUTABLE | GDT_ACCESS_DC_NOT_CONFORM | GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA | GDT_ACCESS_A_ACCESSED, GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // User data + set_gdt_entry_value(gdt_entries + 0x30, 0, 0xFFFFF, GDT_ACCESS_P_VALID | GDT_ACCESS_DPL_USER_MODE | GDT_ACCESS_S_CODE_OR_DATA | GDT_ACCESS_E_NOT_EXECUTABLE | GDT_ACCESS_DC_CONFORM | GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA | GDT_ACCESS_A_ACCESSED, GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // User stack - struct gdt_entry gdt_entry_kernel_mode_stack_segment = { .base = 0x0, - .limit = 0x0, - .access_byte = 0x97, - .flags = 0x0D }; - encodeGdtEntry(gdt_entries[3], gdt_entry_kernel_mode_stack_segment); - - struct gdt_entry gdt_entry_user_mode_code_segment = { - .base = 0, .limit = 0xFFFFF, .access_byte = 0xFA, .flags = 0xC}; - encodeGdtEntry(gdt_entries[4], gdt_entry_user_mode_code_segment); - - struct gdt_entry gdt_entry_user_mode_data_segment = { - .base = 0, .limit = 0xFFFFF, .access_byte = 0xF2, .flags = 0xC}; - encodeGdtEntry(gdt_entries[5], gdt_entry_user_mode_data_segment); - - struct gdt_entry gdt_entry_user_mode_stack_segment = { .base = 0x0, - .limit = 0x0, - .access_byte = 0xF7, - .flags = 0x0D }; - encodeGdtEntry(gdt_entries[6], gdt_entry_user_mode_stack_segment); - - memcpy((void *)gdtr.base, (void *)gdt_entries, (size_t)GDT_SIZE); - - /* load the gdtr registry */ - asm("lgdtl (gdtr)"); - - /* initiliaz the segments */ - asm(" movw $0x10, %ax \n \ - movw %ax, %ds \n \ - movw %ax, %es \n \ - movw %ax, %fs \n \ - movw %ax, %gs \n \ - ljmp $0x08, $next \n \ - next: \n"); + set_gdt(((uint32_t) gdtr)); } diff --git a/src/gdt/set_gdt.s b/src/gdt/set_gdt.s new file mode 100644 index 0000000..8783dda --- /dev/null +++ b/src/gdt/set_gdt.s @@ -0,0 +1,18 @@ +.intel_syntax noprefix + +.section .text + .global set_gdt + + set_gdt: + mov eax, [esp+4] // 1st parameter : pointer to the IDT + lgdt [eax] + mov ax, 0x10 // 0x10 is the offset in the GDT to our data segment + mov ds, ax // Load all data segment selectors + mov fs, ax + mov gs, ax + mov es, ax + mov ax, 0x18 // 0x18 is the offset in the GDT to our kernel stack + mov ss, ax + jmp 0x08:.flush // 0x08 is the offset to our code segment: far jump on it + .flush: + ret \ No newline at end of file diff --git a/src/kernel.c b/src/kernel.c index 1ddc371..827682c 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -1,6 +1,8 @@ #include "gdt.h" #include "shell.h" #include "terminal.h" +#include "power.h" +#include "gdt.h" #include #include @@ -22,6 +24,6 @@ void kernel_main(void) /* Initialize terminal interface */ terminal_initialize(); - /* initGdt(); */ + initGdt(); shell_init(); }