diff --git a/kernel/arch/x86_64/GDT.cpp b/kernel/arch/x86_64/GDT.cpp index 1baeb33416..c477b2387d 100644 --- a/kernel/arch/x86_64/GDT.cpp +++ b/kernel/arch/x86_64/GDT.cpp @@ -1,68 +1,35 @@ -#include #include +#include #include -namespace Kernel::GDT +namespace Kernel { - struct TaskStateSegment + GDT* GDT::create() { - 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)); + auto* gdt = new GDT(); + ASSERT(gdt); - 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)); + gdt->write_entry(0x00, 0x00000000, 0x00000, 0x00, 0x0); // null + gdt->write_entry(0x08, 0x00000000, 0xFFFFF, 0x9A, 0xA); // kernel code + gdt->write_entry(0x10, 0x00000000, 0xFFFFF, 0x92, 0xC); // kernel data + gdt->write_entry(0x18, 0x00000000, 0xFFFFF, 0xFA, 0xA); // user code + gdt->write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, 0xC); // user data + gdt->write_tss(); - struct - { - uint32_t low; - uint32_t high; - } __attribute__((packed)); + gdt->flush_gdt(); + gdt->flush_tss(); - } __attribute__((packed)); + return gdt; + } - 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) + void GDT::write_entry(uint8_t offset, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags) { ASSERT(offset % sizeof(SegmentDescriptor) == 0); + uint8_t idx = offset / sizeof(SegmentDescriptor); - SegmentDescriptor& desc = s_gdt[offset / sizeof(SegmentDescriptor)]; + auto& desc = m_gdt[idx]; desc.base1 = (base >> 0) & 0xFFFF; desc.base2 = (base >> 16) & 0xFF; desc.base3 = (base >> 24) & 0xFF; @@ -75,49 +42,18 @@ namespace Kernel::GDT desc.flags = flags & 0x0F; } - static void write_tss() + void GDT::write_tss() { - memset(&s_tss, 0x00, sizeof(TaskStateSegment)); - s_tss.iopb = sizeof(TaskStateSegment); + memset(&m_tss, 0x00, sizeof(TaskStateSegment)); + m_tss.iopb = sizeof(TaskStateSegment); - uint64_t base = (uint64_t)&s_tss; + uint64_t base = reinterpret_cast(&m_tss); - write_entry(s_tss_offset, (uint32_t)base, sizeof(TaskStateSegment), 0x89, 0x0); + write_entry(0x28, (uint32_t)base, sizeof(TaskStateSegment), 0x89, 0x0); - SegmentDescriptor& desc = s_gdt[s_tss_offset / sizeof(SegmentDescriptor) + 1]; + auto& desc = m_gdt[0x30 / sizeof(SegmentDescriptor)]; 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(); - } - } diff --git a/kernel/include/kernel/GDT.h b/kernel/include/kernel/GDT.h index a8245d5e02..20e16ab381 100644 --- a/kernel/include/kernel/GDT.h +++ b/kernel/include/kernel/GDT.h @@ -1,16 +1,100 @@ #pragma once +#include +#include + #include -namespace Kernel::GDT +namespace Kernel { - static constexpr inline bool is_user_segment(uint8_t segment) + struct TaskStateSegment { - return (segment & 3) == 3; - } + 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)); - void initialize(); - void set_tss_stack(uintptr_t); + 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)); + + class GDT + { + BAN_NON_COPYABLE(GDT); + BAN_NON_MOVABLE(GDT); + + public: + static GDT* create(); + + static constexpr inline bool is_user_segment(uint8_t segment) + { + return (segment & 3) == 3; + } + + void set_tss_stack(uintptr_t rsp) + { + m_tss.rsp0 = rsp; + } + + private: + GDT() = default; + + void write_entry(uint8_t offset, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags); + void write_tss(); + + void flush_gdt() + { + asm volatile("lgdt %0" :: "m"(m_gdtr) : "memory"); + } + + void flush_tss() + { + asm volatile("ltr %0" :: "rm"((uint16_t)0x28) : "memory"); + } + + private: + BAN::Array m_gdt; // null, kernel code, kernel data, user code, user data, tss low, tss high + TaskStateSegment m_tss; + const GDTR m_gdtr { + .size = m_gdt.size() * sizeof(SegmentDescriptor) - 1, + .address = reinterpret_cast(m_gdt.data()) + }; + }; } diff --git a/kernel/include/kernel/Processor.h b/kernel/include/kernel/Processor.h index d3f78d7710..afa5f836bb 100644 --- a/kernel/include/kernel/Processor.h +++ b/kernel/include/kernel/Processor.h @@ -1,7 +1,9 @@ #pragma once #include + #include +#include namespace Kernel { @@ -54,12 +56,19 @@ namespace Kernel uintptr_t stack_bottom() const { return reinterpret_cast(m_stack); } uintptr_t stack_top() const { return stack_bottom() + m_stack_size; } + void initialize(); + + GDT& gdt() { ASSERT(m_gdt); return *m_gdt; } + private: Processor() = default; Processor(Processor&& other) { m_stack = other.m_stack; other.m_stack = nullptr; + + m_gdt = other.m_gdt; + other.m_gdt = nullptr; } ~Processor(); @@ -67,6 +76,8 @@ namespace Kernel void* m_stack { nullptr }; static constexpr size_t m_stack_size { 4096 }; + GDT* m_gdt { nullptr }; + friend class BAN::Vector; }; #else diff --git a/kernel/kernel/Processor.cpp b/kernel/kernel/Processor.cpp index 2ff0678331..5016edc360 100644 --- a/kernel/kernel/Processor.cpp +++ b/kernel/kernel/Processor.cpp @@ -24,6 +24,10 @@ namespace Kernel if (m_stack) kfree(m_stack); m_stack = nullptr; + + if (m_gdt) + delete m_gdt; + m_gdt = nullptr; } Processor& Processor::get(ProcessorID id) @@ -31,4 +35,13 @@ namespace Kernel return s_processors[id]; } + void Processor::initialize() + { + ASSERT(this == &Processor::current()); + + ASSERT(m_gdt == nullptr); + m_gdt = GDT::create(); + ASSERT(m_gdt); + } + } diff --git a/kernel/kernel/Scheduler.cpp b/kernel/kernel/Scheduler.cpp index a9d5a5ef39..f12b1fcfa4 100644 --- a/kernel/kernel/Scheduler.cpp +++ b/kernel/kernel/Scheduler.cpp @@ -256,7 +256,7 @@ namespace Kernel if (current->has_process()) { current->process().page_table().load(); - GDT::set_tss_stack(current->interrupt_stack_base() + current->interrupt_stack_size()); + Processor::current().gdt().set_tss_stack(current->interrupt_stack_base() + current->interrupt_stack_size()); } else PageTable::kernel().load(); diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index 7821769691..b6de2132ed 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -103,11 +103,9 @@ extern "C" void kernel_main(uint32_t boot_magic, uint32_t boot_info) dprintln("boot info parsed"); Processor::create(Processor::current_id()); + Processor::current().initialize(); dprintln("BSP initialized"); - GDT::initialize(); - dprintln("GDT initialized"); - IDT::initialize(); dprintln("IDT initialized"); @@ -215,7 +213,8 @@ extern "C" void ap_main() { using namespace Kernel; - dprintln("hello from processor {}", Processor::current_id()); + Processor::current().initialize(); + dprintln("ap{} initialized", Processor::current_id()); for (;;) asm volatile("");