From 29fd68267200875e0ad6d1369e8c08e7d571b07c Mon Sep 17 00:00:00 2001 From: Bananymous Date: Thu, 7 Mar 2024 16:05:29 +0200 Subject: [PATCH] Kernel: Store current processor pointer in IA32_GS_BASE This allows easier access to processors fields --- kernel/arch/x86_64/GDT.cpp | 3 - kernel/arch/x86_64/IDT.cpp | 13 ++-- kernel/arch/x86_64/PageTable.cpp | 2 +- kernel/arch/x86_64/boot.S | 9 --- kernel/include/kernel/GDT.h | 1 + kernel/include/kernel/IDT.h | 12 ++-- kernel/include/kernel/Memory/PageTable.h | 2 +- kernel/include/kernel/Processor.h | 76 +++++++++++++++-------- kernel/kernel/APIC.cpp | 5 +- kernel/kernel/Interruptable.cpp | 5 +- kernel/kernel/Processor.cpp | 77 ++++++++++++++---------- kernel/kernel/Scheduler.cpp | 6 +- kernel/kernel/kernel.cpp | 6 +- 13 files changed, 119 insertions(+), 98 deletions(-) diff --git a/kernel/arch/x86_64/GDT.cpp b/kernel/arch/x86_64/GDT.cpp index c477b2387d..18f0b61ac2 100644 --- a/kernel/arch/x86_64/GDT.cpp +++ b/kernel/arch/x86_64/GDT.cpp @@ -18,9 +18,6 @@ namespace Kernel gdt->write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, 0xC); // user data gdt->write_tss(); - gdt->flush_gdt(); - gdt->flush_tss(); - return gdt; } diff --git a/kernel/arch/x86_64/IDT.cpp b/kernel/arch/x86_64/IDT.cpp index 7489c9c33b..5b7187cd6e 100644 --- a/kernel/arch/x86_64/IDT.cpp +++ b/kernel/arch/x86_64/IDT.cpp @@ -356,7 +356,7 @@ done: extern "C" void syscall_asm(); - IDT* IDT::create() + IDT* IDT::create(bool is_bsb) { auto* idt = new IDT(); ASSERT(idt); @@ -369,7 +369,7 @@ done: // FIXME: distribute IRQs more evenly? #define X(num) idt->register_interrupt_handler(IRQ_VECTOR_BASE + num, irq ## num); - if (Processor::current_is_bsb()) + if (is_bsb) { IRQ_LIST_X } @@ -377,18 +377,15 @@ done: idt->register_syscall_handler(0x80, syscall_asm); - idt->flush(); - return idt; } [[noreturn]] void IDT::force_triple_fault() { // load 0 sized IDT and trigger an interrupt to force triple fault - auto& processor = Processor::current(); - processor.set_interrupt_state(InterruptState::Disabled); - processor.idt().m_idtr.size = 0; - processor.idt().flush(); + Processor::set_interrupt_state(InterruptState::Disabled); + Processor::idt().m_idtr.size = 0; + Processor::idt().load(); asm volatile("int $0x00"); ASSERT_NOT_REACHED(); } diff --git a/kernel/arch/x86_64/PageTable.cpp b/kernel/arch/x86_64/PageTable.cpp index 5d728cc5f1..80607f6398 100644 --- a/kernel/arch/x86_64/PageTable.cpp +++ b/kernel/arch/x86_64/PageTable.cpp @@ -312,7 +312,7 @@ namespace Kernel { SpinLockGuard _(m_lock); asm volatile("movq %0, %%cr3" :: "r"(m_highest_paging_struct)); - Processor::current().m_current_page_table = this; + Processor::set_current_page_table(this); } void PageTable::invalidate(vaddr_t vaddr) diff --git a/kernel/arch/x86_64/boot.S b/kernel/arch/x86_64/boot.S index 253c9fc2a8..4d4d1d00f9 100644 --- a/kernel/arch/x86_64/boot.S +++ b/kernel/arch/x86_64/boot.S @@ -158,13 +158,6 @@ enable_sse: movl %eax, %cr4 ret -initialize_lapic_id: - movl $1, %eax - cpuid - shrl $24, %ebx - movw %bx, %gs - ret - initialize_paging: # enable PAE movl %cr4, %ecx @@ -198,7 +191,6 @@ _start: movl %ebx, V2P(bootloader_info) movl $V2P(boot_stack_top), %esp - call initialize_lapic_id call check_requirements call enable_sse @@ -278,7 +270,6 @@ ap_protected_mode: movl ap_stack_ptr, %esp movb $1, V2P(g_ap_stack_loaded) - call V2P(initialize_lapic_id) call V2P(enable_sse) diff --git a/kernel/include/kernel/GDT.h b/kernel/include/kernel/GDT.h index 20e16ab381..a4bb623e00 100644 --- a/kernel/include/kernel/GDT.h +++ b/kernel/include/kernel/GDT.h @@ -61,6 +61,7 @@ namespace Kernel public: static GDT* create(); + void load() { flush_gdt(); flush_tss(); } static constexpr inline bool is_user_segment(uint8_t segment) { diff --git a/kernel/include/kernel/IDT.h b/kernel/include/kernel/IDT.h index 2857efd834..fc8c096c61 100644 --- a/kernel/include/kernel/IDT.h +++ b/kernel/include/kernel/IDT.h @@ -34,23 +34,23 @@ namespace Kernel BAN_NON_MOVABLE(IDT); public: - static IDT* create(); + static IDT* create(bool is_bsb); [[noreturn]] static void force_triple_fault(); void register_irq_handler(uint8_t irq, Interruptable* interruptable); + void load() + { + asm volatile("lidt %0" :: "m"(m_idtr) : "memory"); + } + private: IDT() = default; void register_interrupt_handler(uint8_t index, void (*handler)()); void register_syscall_handler(uint8_t index, void (*handler)()); - void flush() - { - asm volatile("lidt %0" :: "m"(m_idtr) : "memory"); - } - private: BAN::Array m_idt; IDTR m_idtr { diff --git a/kernel/include/kernel/Memory/PageTable.h b/kernel/include/kernel/Memory/PageTable.h index 0855b80e96..a23f5f91c9 100644 --- a/kernel/include/kernel/Memory/PageTable.h +++ b/kernel/include/kernel/Memory/PageTable.h @@ -40,7 +40,7 @@ namespace Kernel static void initialize(); static PageTable& kernel(); - static PageTable& current() { return *reinterpret_cast(Processor::current().m_current_page_table); } + static PageTable& current() { return *reinterpret_cast(Processor::get_current_page_table()); } static constexpr vaddr_t fast_page() { return KERNEL_OFFSET; } diff --git a/kernel/include/kernel/Processor.h b/kernel/include/kernel/Processor.h index 3adf5be3d7..ce1aaad85e 100644 --- a/kernel/include/kernel/Processor.h +++ b/kernel/include/kernel/Processor.h @@ -22,18 +22,13 @@ namespace Kernel class Processor { BAN_NON_COPYABLE(Processor); + BAN_NON_MOVABLE(Processor); public: static Processor& create(ProcessorID id); + static Processor& initialize(); - static ProcessorID current_id() - { - uint16_t id; - asm volatile("movw %%gs, %0" : "=rm"(id)); - return id; - } - static Processor& get(ProcessorID); - static Processor& current() { return get(current_id()); } + static ProcessorID current_id() { return read_gs_sized(offsetof(Processor, m_id)); } static ProcessorID bsb_id() { return s_bsb_id; } static bool current_is_bsb() { return current_id() == bsb_id(); } @@ -55,42 +50,71 @@ namespace Kernel return InterruptState::Disabled; }; - uintptr_t stack_bottom() const { return reinterpret_cast(m_stack); } - uintptr_t stack_top() const { return stack_bottom() + m_stack_size; } + static uintptr_t current_stack_bottom() { return reinterpret_cast(read_gs_ptr(offsetof(Processor, m_stack))); } + static uintptr_t current_stack_top() { return current_stack_bottom() + s_stack_size; } - void initialize(); + uintptr_t stack_bottom() const { return reinterpret_cast(m_stack); } + uintptr_t stack_top() const { return stack_bottom() + s_stack_size; } - GDT& gdt() { ASSERT(m_gdt); return *m_gdt; } - IDT& idt() { ASSERT(m_idt); return *m_idt; } + static GDT& gdt() { return *reinterpret_cast(read_gs_ptr(offsetof(Processor, m_gdt))); } + static IDT& idt() { return *reinterpret_cast(read_gs_ptr(offsetof(Processor, m_idt))); } + + static void* get_current_page_table() { return read_gs_ptr(offsetof(Processor, m_current_page_table)); } + static void set_current_page_table(void* page_table) { write_gs_ptr(offsetof(Processor, m_current_page_table), page_table); } private: Processor() = default; - Processor(Processor&& other) + ~Processor() { ASSERT_NOT_REACHED(); } + + template + static T read_gs_sized(uintptr_t offset) requires(sizeof(T) <= 8) { - m_stack = other.m_stack; - other.m_stack = nullptr; - - m_gdt = other.m_gdt; - other.m_gdt = nullptr; - - m_idt = other.m_idt; - other.m_idt = nullptr; +#define __ASM_INPUT(operation) operation " %%gs:(%[offset]), %[result]" : [result]"=rm"(result) : [offset]"rm"(offset) + T result; + if constexpr(sizeof(T) == 8) + asm volatile(__ASM_INPUT("movq")); + if constexpr(sizeof(T) == 4) + asm volatile(__ASM_INPUT("movl")); + if constexpr(sizeof(T) == 2) + asm volatile(__ASM_INPUT("movw")); + if constexpr(sizeof(T) == 1) + asm volatile(__ASM_INPUT("movb")); + return result; +#undef __ASM_INPUT } - ~Processor(); + + template + static void write_gs_sized(uintptr_t offset, T value) requires(sizeof(T) <= 8) + { +#define __ASM_INPUT(operation) operation " %[value], %%gs:(%[offset])" :: [value]"rm"(value), [offset]"rm"(offset) : "memory" + if constexpr(sizeof(T) == 8) + asm volatile(__ASM_INPUT("movq")); + if constexpr(sizeof(T) == 4) + asm volatile(__ASM_INPUT("movl")); + if constexpr(sizeof(T) == 2) + asm volatile(__ASM_INPUT("movw")); + if constexpr(sizeof(T) == 1) + asm volatile(__ASM_INPUT("movb")); +#undef __ASM_INPUT + } + + static void* read_gs_ptr(uintptr_t offset) { return read_gs_sized(offset); } + static void write_gs_ptr(uintptr_t offset, void* value) { write_gs_sized(offset, value); } private: static ProcessorID s_bsb_id; + ProcessorID m_id { PROCESSOR_NONE }; + + static constexpr size_t s_stack_size { 4096 }; void* m_stack { nullptr }; - static constexpr size_t m_stack_size { 4096 }; GDT* m_gdt { nullptr }; IDT* m_idt { nullptr }; void* m_current_page_table { nullptr }; - friend class BAN::Vector; - friend class PageTable; + friend class BAN::Array; }; #else #error diff --git a/kernel/kernel/APIC.cpp b/kernel/kernel/APIC.cpp index 503cf6514a..ef0b6072cc 100644 --- a/kernel/kernel/APIC.cpp +++ b/kernel/kernel/APIC.cpp @@ -232,10 +232,9 @@ namespace Kernel dprintln("Trying to enable processor (lapic id {})", processor.apic_id); - Kernel::Processor::create(processor.processor_id); - + auto& proc = Kernel::Processor::create(processor.processor_id); PageTable::with_fast_page((paddr_t)g_ap_init_addr, [&] { - PageTable::fast_page_as_sized(2) = V2P(Kernel::Processor::get(processor.processor_id).stack_top()); + PageTable::fast_page_as_sized(2) = V2P(proc.stack_top()); }); *g_ap_stack_loaded = 0; diff --git a/kernel/kernel/Interruptable.cpp b/kernel/kernel/Interruptable.cpp index 450ac8b51f..502c4b33b6 100644 --- a/kernel/kernel/Interruptable.cpp +++ b/kernel/kernel/Interruptable.cpp @@ -8,11 +8,10 @@ namespace Kernel void Interruptable::set_irq(int irq) { - auto& processor = Processor::current(); if (m_irq != -1) - processor.idt().register_irq_handler(m_irq, nullptr); + Processor::idt().register_irq_handler(m_irq, nullptr); m_irq = irq; - processor.idt().register_irq_handler(irq, this); + Processor::idt().register_irq_handler(irq, this); } void Interruptable::enable_interrupt() diff --git a/kernel/kernel/Processor.cpp b/kernel/kernel/Processor.cpp index 4c38b90cfa..886bf07d60 100644 --- a/kernel/kernel/Processor.cpp +++ b/kernel/kernel/Processor.cpp @@ -1,57 +1,70 @@ -#include +#include #include +#include + namespace Kernel { + static constexpr uint32_t MSR_IA32_GS_BASE = 0xC0000101; + ProcessorID Processor::s_bsb_id { PROCESSOR_NONE }; - static BAN::Vector s_processors; + static BAN::Array s_processors; + + static ProcessorID read_processor_id() + { + uint8_t id; + asm volatile( + "movl $1, %%eax;" + "cpuid;" + "shrl $24, %%ebx;" + "movb %%bl, %0;" + : "=rm"(id) + :: "eax", "ebx", "ecx", "edx" + ); + return id; + } Processor& Processor::create(ProcessorID id) { // bsb is the first processor if (s_bsb_id == PROCESSOR_NONE) - s_bsb_id = id; + s_bsb_id = id = read_processor_id(); - while (s_processors.size() <= id) - MUST(s_processors.emplace_back()); auto& processor = s_processors[id]; - if (processor.m_stack == nullptr) - { - processor.m_stack = kmalloc(m_stack_size, 4096, true); - ASSERT(processor.m_stack); - } + + ASSERT(processor.m_id == PROCESSOR_NONE); + processor.m_id = id; + + processor.m_stack = kmalloc(s_stack_size, 4096, true); + ASSERT(processor.m_stack); + + processor.m_gdt = GDT::create(); + ASSERT(processor.m_gdt); + + processor.m_idt = IDT::create(id == s_bsb_id); + ASSERT(processor.m_idt); + return processor; } - Processor::~Processor() + Processor& Processor::initialize() { - if (m_stack) - kfree(m_stack); - m_stack = nullptr; + auto id = read_processor_id(); + auto& processor = s_processors[id]; - if (m_gdt) - delete m_gdt; - m_gdt = nullptr; - } + // set gs base to pointer to this processor + uint64_t ptr = reinterpret_cast(&processor); + asm volatile("wrmsr" :: "d"(ptr >> 32), "a"(ptr), "c"(MSR_IA32_GS_BASE)); - Processor& Processor::get(ProcessorID id) - { - return s_processors[id]; - } + ASSERT(processor.m_gdt); + processor.gdt().load(); - void Processor::initialize() - { - ASSERT(this == &Processor::current()); + ASSERT(processor.m_idt); + processor.idt().load(); - ASSERT(m_gdt == nullptr); - m_gdt = GDT::create(); - ASSERT(m_gdt); - - ASSERT(m_idt == nullptr); - m_idt = IDT::create(); - ASSERT(m_idt); + return processor; } } diff --git a/kernel/kernel/Scheduler.cpp b/kernel/kernel/Scheduler.cpp index f12b1fcfa4..90c1a4080e 100644 --- a/kernel/kernel/Scheduler.cpp +++ b/kernel/kernel/Scheduler.cpp @@ -18,7 +18,7 @@ namespace Kernel ALWAYS_INLINE static void load_temp_stack() { - asm volatile("movq %0, %%rsp" :: "rm"(Processor::current().stack_top())); + asm volatile("movq %0, %%rsp" :: "rm"(Processor::current_stack_top())); } BAN::ErrorOr Scheduler::initialize() @@ -223,7 +223,7 @@ namespace Kernel #if SCHEDULER_VERIFY_STACK vaddr_t rsp; read_rsp(rsp); - ASSERT(Processor::current().stack_bottom() <= rsp && rsp <= Processor::current().stack_top()); + ASSERT(Processor::current_stack_bottom() <= rsp && rsp <= Processor::current_stack_top()); ASSERT(&PageTable::current() == &PageTable::kernel()); #endif @@ -256,7 +256,7 @@ namespace Kernel if (current->has_process()) { current->process().page_table().load(); - Processor::current().gdt().set_tss_stack(current->interrupt_stack_base() + current->interrupt_stack_size()); + Processor::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 0291fbd7de..500f785e27 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -102,8 +102,8 @@ extern "C" void kernel_main(uint32_t boot_magic, uint32_t boot_info) parse_boot_info(boot_magic, boot_info); dprintln("boot info parsed"); - Processor::create(Processor::current_id()); - Processor::current().initialize(); + Processor::create(0); + Processor::initialize(); dprintln("BSP initialized"); PageTable::initialize(); @@ -211,7 +211,7 @@ extern "C" void ap_main() { using namespace Kernel; - Processor::current().initialize(); + Processor::initialize(); PageTable::kernel().initial_load(); dprintln("ap{} initialized", Processor::current_id());