#include #include #include extern "C" uintptr_t g_boot_stack_top[0]; namespace Kernel::GDT { struct TaskStateSegment { uint32_t reserved1; uint64_t rsp0; uint64_t rsp1; uint64_t rsp2; uint64_t reserved2; uint64_t ist1; uint64_t ist2; uint64_t ist3; uint64_t ist4; uint64_t ist5; uint64_t ist6; uint64_t ist7; uint64_t reserved3; uint16_t reserved4; uint16_t iopb; } __attribute__((packed)); union SegmentDescriptor { struct { uint16_t limit1; uint16_t base1; uint8_t base2; uint8_t access; uint8_t limit2 : 4; uint8_t flags : 4; uint8_t base3; } __attribute__((packed)); struct { uint32_t low; uint32_t high; } __attribute__((packed)); } __attribute__((packed)); struct GDTR { uint16_t size; uint64_t address; } __attribute__((packed)); static constexpr uint16_t s_tss_offset = 0x28; static TaskStateSegment s_tss; static BAN::Array s_gdt; // null, kernel code, kernel data, user code, user data, tss low, tss high static GDTR s_gdtr; static void write_entry(uint8_t offset, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags) { ASSERT(offset % sizeof(SegmentDescriptor) == 0); SegmentDescriptor& desc = s_gdt[offset / sizeof(SegmentDescriptor)]; desc.base1 = (base >> 0) & 0xFFFF; desc.base2 = (base >> 16) & 0xFF; desc.base3 = (base >> 24) & 0xFF; desc.limit1 = (limit >> 0) & 0xFFFF; desc.limit2 = (limit >> 16) & 0x0F; desc.access = access & 0xFF; desc.flags = flags & 0x0F; } static void write_tss() { memset(&s_tss, 0x00, sizeof(TaskStateSegment)); s_tss.iopb = sizeof(TaskStateSegment); uint64_t base = (uint64_t)&s_tss; write_entry(s_tss_offset, (uint32_t)base, sizeof(TaskStateSegment), 0x89, 0x0); SegmentDescriptor& desc = s_gdt[s_tss_offset / sizeof(SegmentDescriptor) + 1]; desc.low = base >> 32; desc.high = 0; } void set_tss_stack(uintptr_t rsp) { s_tss.rsp0 = rsp; } static void flush_gdt() { asm volatile("lgdt %0" :: "m"(s_gdtr)); } static void flush_tss() { asm volatile("ltr %0" :: "m"(s_tss_offset)); } void initialize() { s_gdtr.address = (uint64_t)&s_gdt; s_gdtr.size = s_gdt.size() * sizeof(SegmentDescriptor) - 1; write_entry(0x00, 0x00000000, 0x00000, 0x00, 0x0); // null write_entry(0x08, 0x00000000, 0xFFFFF, 0x9A, 0xA); // kernel code write_entry(0x10, 0x00000000, 0xFFFFF, 0x92, 0xC); // kernel data write_entry(0x18, 0x00000000, 0xFFFFF, 0xFA, 0xA); // user code write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, 0xC); // user data write_tss(); flush_gdt(); flush_tss(); } }