#include #include #include #include #define NUM_ENTRIES 3 struct SegmentDescriptor { uint32_t limit; uint32_t base; uint8_t access_byte; uint8_t flags; }; struct GDT { uint16_t size; uint64_t* base; } __attribute__((packed)); static uint64_t entries[NUM_ENTRIES]; static size_t current_entry = 0; struct GDT gdt; static void encodeGdtEntry(uint8_t *target, struct SegmentDescriptor source) { // Check the limit to make sure that it can be encoded if (source.limit > 0xFFFFF) { terminal_writestring("WARNING: GDT entry has a limit ("); print_hex_bytes(&source.limit, 4); terminal_writestring(") that is larger than accepted."); return; } // Encode the limit target[0] = source.limit & 0xFF; target[1] = (source.limit >> 8) & 0xFF; target[6] = (source.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; // Encode the access byte target[5] = source.access_byte; // Encode the flags target[6] |= (source.flags << 4); print_hex_bytes(target, 8); } static void add_entry(struct SegmentDescriptor entry) { if (current_entry == NUM_ENTRIES) { terminal_writestring("WARNING: More GDT entries than NUM_ENTRIES.\n"); return; } uint64_t descriptor = 0; encodeGdtEntry((uint8_t*) &descriptor, entry); entries[current_entry] = descriptor; current_entry++; } static void load_gdt() { gdt.size = NUM_ENTRIES * 8 - 1; gdt.base = entries; for (int i = 0; i < NUM_ENTRIES; i++) { print_hex_bytes(gdt.base + i, 8); terminal_putchar('\n'); } asm ( "lgdt %0" : : "m"(gdt) ); } void gdt_init() { terminal_initialize(); struct SegmentDescriptor null; null.limit = 0; null.base = 0; null.access_byte = 0; null.flags = 0; terminal_writestring("Kernel Null: "); add_entry(null); terminal_putchar('\n'); struct SegmentDescriptor kernel_code; kernel_code.limit = 0x000003FF; kernel_code.base = 0x00000000; kernel_code.access_byte = 0b10011010; kernel_code.flags = 0b1100; terminal_writestring("Kernel Code: "); add_entry(kernel_code); terminal_putchar('\n'); struct SegmentDescriptor kernel_data; kernel_code.limit = 0x000003FF; kernel_data.base = 0x00400000; kernel_data.access_byte = 0b10010010; kernel_data.flags = 0b1100; terminal_writestring("Kernel Data: "); add_entry(kernel_data); terminal_putchar('\n'); load_gdt(); }