#include #include "gdt.h" #include "kprintf.h" extern void set_gdt(uint32_t gdt_ptr); struct tss TSS; 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) { if (limit > 0xFFFFF) { kprintf(KERN_ERR "GDT cannot encode limits larger than 0xFFFFF"); } // Encode the limit target[0] = limit & 0xFF; target[1] = (limit >> 8) & 0xFF; target[6] = (limit >> 16) & 0x0F; // Encode the base 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] = access; // Encode the flags target[6] |= (granularity << 4); } void init_gdt(void) { gdtr->size = 8 * GDT_SIZE - 1; gdtr->base = (uint32_t)&gdt_entries[0]; set_gdt_entry_value(gdt_entries + 0x00, 0, 0, 0, 0); // Null segment set_gdt_entry_value( gdt_entries + GDT_OFFSET_KERNEL_CODE, 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 + GDT_OFFSET_KERNEL_DATA, 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 + GDT_OFFSET_KERNEL_STACK, 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_CONFORM | GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA | GDT_ACCESS_A_ACCESSED, GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // Kernel stack set_gdt_entry_value( gdt_entries + GDT_OFFSET_USER_CODE, 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 + GDT_OFFSET_USER_DATA, 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 + GDT_OFFSET_USER_STACK, 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 // TSS set_gdt_entry_value(gdt_entries + GDT_OFFSET_TSS, (uint32_t)&TSS, sizeof(struct tss) - 1, 0x89, 0); set_gdt(((uint32_t)gdtr)); }