Kernel: Store current processor pointer in IA32_GS_BASE
This allows easier access to processors fields
This commit is contained in:
parent
efed67cbd0
commit
29fd682672
|
@ -18,9 +18,6 @@ namespace Kernel
|
||||||
gdt->write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, 0xC); // user data
|
gdt->write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, 0xC); // user data
|
||||||
gdt->write_tss();
|
gdt->write_tss();
|
||||||
|
|
||||||
gdt->flush_gdt();
|
|
||||||
gdt->flush_tss();
|
|
||||||
|
|
||||||
return gdt;
|
return gdt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -356,7 +356,7 @@ done:
|
||||||
|
|
||||||
extern "C" void syscall_asm();
|
extern "C" void syscall_asm();
|
||||||
|
|
||||||
IDT* IDT::create()
|
IDT* IDT::create(bool is_bsb)
|
||||||
{
|
{
|
||||||
auto* idt = new IDT();
|
auto* idt = new IDT();
|
||||||
ASSERT(idt);
|
ASSERT(idt);
|
||||||
|
@ -369,7 +369,7 @@ done:
|
||||||
|
|
||||||
// FIXME: distribute IRQs more evenly?
|
// FIXME: distribute IRQs more evenly?
|
||||||
#define X(num) idt->register_interrupt_handler(IRQ_VECTOR_BASE + num, irq ## num);
|
#define X(num) idt->register_interrupt_handler(IRQ_VECTOR_BASE + num, irq ## num);
|
||||||
if (Processor::current_is_bsb())
|
if (is_bsb)
|
||||||
{
|
{
|
||||||
IRQ_LIST_X
|
IRQ_LIST_X
|
||||||
}
|
}
|
||||||
|
@ -377,18 +377,15 @@ done:
|
||||||
|
|
||||||
idt->register_syscall_handler(0x80, syscall_asm);
|
idt->register_syscall_handler(0x80, syscall_asm);
|
||||||
|
|
||||||
idt->flush();
|
|
||||||
|
|
||||||
return idt;
|
return idt;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[noreturn]] void IDT::force_triple_fault()
|
[[noreturn]] void IDT::force_triple_fault()
|
||||||
{
|
{
|
||||||
// load 0 sized IDT and trigger an interrupt to 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.set_interrupt_state(InterruptState::Disabled);
|
Processor::idt().m_idtr.size = 0;
|
||||||
processor.idt().m_idtr.size = 0;
|
Processor::idt().load();
|
||||||
processor.idt().flush();
|
|
||||||
asm volatile("int $0x00");
|
asm volatile("int $0x00");
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
|
@ -312,7 +312,7 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
asm volatile("movq %0, %%cr3" :: "r"(m_highest_paging_struct));
|
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)
|
void PageTable::invalidate(vaddr_t vaddr)
|
||||||
|
|
|
@ -158,13 +158,6 @@ enable_sse:
|
||||||
movl %eax, %cr4
|
movl %eax, %cr4
|
||||||
ret
|
ret
|
||||||
|
|
||||||
initialize_lapic_id:
|
|
||||||
movl $1, %eax
|
|
||||||
cpuid
|
|
||||||
shrl $24, %ebx
|
|
||||||
movw %bx, %gs
|
|
||||||
ret
|
|
||||||
|
|
||||||
initialize_paging:
|
initialize_paging:
|
||||||
# enable PAE
|
# enable PAE
|
||||||
movl %cr4, %ecx
|
movl %cr4, %ecx
|
||||||
|
@ -198,7 +191,6 @@ _start:
|
||||||
movl %ebx, V2P(bootloader_info)
|
movl %ebx, V2P(bootloader_info)
|
||||||
|
|
||||||
movl $V2P(boot_stack_top), %esp
|
movl $V2P(boot_stack_top), %esp
|
||||||
call initialize_lapic_id
|
|
||||||
|
|
||||||
call check_requirements
|
call check_requirements
|
||||||
call enable_sse
|
call enable_sse
|
||||||
|
@ -278,7 +270,6 @@ ap_protected_mode:
|
||||||
|
|
||||||
movl ap_stack_ptr, %esp
|
movl ap_stack_ptr, %esp
|
||||||
movb $1, V2P(g_ap_stack_loaded)
|
movb $1, V2P(g_ap_stack_loaded)
|
||||||
call V2P(initialize_lapic_id)
|
|
||||||
|
|
||||||
call V2P(enable_sse)
|
call V2P(enable_sse)
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,7 @@ namespace Kernel
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static GDT* create();
|
static GDT* create();
|
||||||
|
void load() { flush_gdt(); flush_tss(); }
|
||||||
|
|
||||||
static constexpr inline bool is_user_segment(uint8_t segment)
|
static constexpr inline bool is_user_segment(uint8_t segment)
|
||||||
{
|
{
|
||||||
|
|
|
@ -34,23 +34,23 @@ namespace Kernel
|
||||||
BAN_NON_MOVABLE(IDT);
|
BAN_NON_MOVABLE(IDT);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static IDT* create();
|
static IDT* create(bool is_bsb);
|
||||||
|
|
||||||
[[noreturn]] static void force_triple_fault();
|
[[noreturn]] static void force_triple_fault();
|
||||||
|
|
||||||
void register_irq_handler(uint8_t irq, Interruptable* interruptable);
|
void register_irq_handler(uint8_t irq, Interruptable* interruptable);
|
||||||
|
|
||||||
|
void load()
|
||||||
|
{
|
||||||
|
asm volatile("lidt %0" :: "m"(m_idtr) : "memory");
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IDT() = default;
|
IDT() = default;
|
||||||
|
|
||||||
void register_interrupt_handler(uint8_t index, void (*handler)());
|
void register_interrupt_handler(uint8_t index, void (*handler)());
|
||||||
void register_syscall_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:
|
private:
|
||||||
BAN::Array<GateDescriptor, 0x100> m_idt;
|
BAN::Array<GateDescriptor, 0x100> m_idt;
|
||||||
IDTR m_idtr {
|
IDTR m_idtr {
|
||||||
|
|
|
@ -40,7 +40,7 @@ namespace Kernel
|
||||||
static void initialize();
|
static void initialize();
|
||||||
|
|
||||||
static PageTable& kernel();
|
static PageTable& kernel();
|
||||||
static PageTable& current() { return *reinterpret_cast<PageTable*>(Processor::current().m_current_page_table); }
|
static PageTable& current() { return *reinterpret_cast<PageTable*>(Processor::get_current_page_table()); }
|
||||||
|
|
||||||
static constexpr vaddr_t fast_page() { return KERNEL_OFFSET; }
|
static constexpr vaddr_t fast_page() { return KERNEL_OFFSET; }
|
||||||
|
|
||||||
|
|
|
@ -22,18 +22,13 @@ namespace Kernel
|
||||||
class Processor
|
class Processor
|
||||||
{
|
{
|
||||||
BAN_NON_COPYABLE(Processor);
|
BAN_NON_COPYABLE(Processor);
|
||||||
|
BAN_NON_MOVABLE(Processor);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static Processor& create(ProcessorID id);
|
static Processor& create(ProcessorID id);
|
||||||
|
static Processor& initialize();
|
||||||
|
|
||||||
static ProcessorID current_id()
|
static ProcessorID current_id() { return read_gs_sized<ProcessorID>(offsetof(Processor, m_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 bsb_id() { return s_bsb_id; }
|
static ProcessorID bsb_id() { return s_bsb_id; }
|
||||||
static bool current_is_bsb() { return current_id() == bsb_id(); }
|
static bool current_is_bsb() { return current_id() == bsb_id(); }
|
||||||
|
@ -55,42 +50,71 @@ namespace Kernel
|
||||||
return InterruptState::Disabled;
|
return InterruptState::Disabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static uintptr_t current_stack_bottom() { return reinterpret_cast<uintptr_t>(read_gs_ptr(offsetof(Processor, m_stack))); }
|
||||||
|
static uintptr_t current_stack_top() { return current_stack_bottom() + s_stack_size; }
|
||||||
|
|
||||||
uintptr_t stack_bottom() const { return reinterpret_cast<uintptr_t>(m_stack); }
|
uintptr_t stack_bottom() const { return reinterpret_cast<uintptr_t>(m_stack); }
|
||||||
uintptr_t stack_top() const { return stack_bottom() + m_stack_size; }
|
uintptr_t stack_top() const { return stack_bottom() + s_stack_size; }
|
||||||
|
|
||||||
void initialize();
|
static GDT& gdt() { return *reinterpret_cast<GDT*>(read_gs_ptr(offsetof(Processor, m_gdt))); }
|
||||||
|
static IDT& idt() { return *reinterpret_cast<IDT*>(read_gs_ptr(offsetof(Processor, m_idt))); }
|
||||||
|
|
||||||
GDT& gdt() { ASSERT(m_gdt); return *m_gdt; }
|
static void* get_current_page_table() { return read_gs_ptr(offsetof(Processor, m_current_page_table)); }
|
||||||
IDT& idt() { ASSERT(m_idt); return *m_idt; }
|
static void set_current_page_table(void* page_table) { write_gs_ptr(offsetof(Processor, m_current_page_table), page_table); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Processor() = default;
|
Processor() = default;
|
||||||
Processor(Processor&& other)
|
~Processor() { ASSERT_NOT_REACHED(); }
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static T read_gs_sized(uintptr_t offset) requires(sizeof(T) <= 8)
|
||||||
{
|
{
|
||||||
m_stack = other.m_stack;
|
#define __ASM_INPUT(operation) operation " %%gs:(%[offset]), %[result]" : [result]"=rm"(result) : [offset]"rm"(offset)
|
||||||
other.m_stack = nullptr;
|
T result;
|
||||||
|
if constexpr(sizeof(T) == 8)
|
||||||
m_gdt = other.m_gdt;
|
asm volatile(__ASM_INPUT("movq"));
|
||||||
other.m_gdt = nullptr;
|
if constexpr(sizeof(T) == 4)
|
||||||
|
asm volatile(__ASM_INPUT("movl"));
|
||||||
m_idt = other.m_idt;
|
if constexpr(sizeof(T) == 2)
|
||||||
other.m_idt = nullptr;
|
asm volatile(__ASM_INPUT("movw"));
|
||||||
|
if constexpr(sizeof(T) == 1)
|
||||||
|
asm volatile(__ASM_INPUT("movb"));
|
||||||
|
return result;
|
||||||
|
#undef __ASM_INPUT
|
||||||
}
|
}
|
||||||
~Processor();
|
|
||||||
|
template<typename T>
|
||||||
|
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<void*>(offset); }
|
||||||
|
static void write_gs_ptr(uintptr_t offset, void* value) { write_gs_sized<void*>(offset, value); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static ProcessorID s_bsb_id;
|
static ProcessorID s_bsb_id;
|
||||||
|
|
||||||
|
ProcessorID m_id { PROCESSOR_NONE };
|
||||||
|
|
||||||
|
static constexpr size_t s_stack_size { 4096 };
|
||||||
void* m_stack { nullptr };
|
void* m_stack { nullptr };
|
||||||
static constexpr size_t m_stack_size { 4096 };
|
|
||||||
|
|
||||||
GDT* m_gdt { nullptr };
|
GDT* m_gdt { nullptr };
|
||||||
IDT* m_idt { nullptr };
|
IDT* m_idt { nullptr };
|
||||||
|
|
||||||
void* m_current_page_table { nullptr };
|
void* m_current_page_table { nullptr };
|
||||||
|
|
||||||
friend class BAN::Vector<Processor>;
|
friend class BAN::Array<Processor, 0xFF>;
|
||||||
friend class PageTable;
|
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
#error
|
#error
|
||||||
|
|
|
@ -232,10 +232,9 @@ namespace Kernel
|
||||||
|
|
||||||
dprintln("Trying to enable processor (lapic id {})", processor.apic_id);
|
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::with_fast_page((paddr_t)g_ap_init_addr, [&] {
|
||||||
PageTable::fast_page_as_sized<uint32_t>(2) = V2P(Kernel::Processor::get(processor.processor_id).stack_top());
|
PageTable::fast_page_as_sized<uint32_t>(2) = V2P(proc.stack_top());
|
||||||
});
|
});
|
||||||
*g_ap_stack_loaded = 0;
|
*g_ap_stack_loaded = 0;
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,10 @@ namespace Kernel
|
||||||
|
|
||||||
void Interruptable::set_irq(int irq)
|
void Interruptable::set_irq(int irq)
|
||||||
{
|
{
|
||||||
auto& processor = Processor::current();
|
|
||||||
if (m_irq != -1)
|
if (m_irq != -1)
|
||||||
processor.idt().register_irq_handler(m_irq, nullptr);
|
Processor::idt().register_irq_handler(m_irq, nullptr);
|
||||||
m_irq = irq;
|
m_irq = irq;
|
||||||
processor.idt().register_irq_handler(irq, this);
|
Processor::idt().register_irq_handler(irq, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interruptable::enable_interrupt()
|
void Interruptable::enable_interrupt()
|
||||||
|
|
|
@ -1,57 +1,70 @@
|
||||||
#include <BAN/Vector.h>
|
#include <kernel/Memory/kmalloc.h>
|
||||||
#include <kernel/Processor.h>
|
#include <kernel/Processor.h>
|
||||||
|
|
||||||
|
#include <kernel/Debug.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
|
static constexpr uint32_t MSR_IA32_GS_BASE = 0xC0000101;
|
||||||
|
|
||||||
ProcessorID Processor::s_bsb_id { PROCESSOR_NONE };
|
ProcessorID Processor::s_bsb_id { PROCESSOR_NONE };
|
||||||
|
|
||||||
static BAN::Vector<Processor> s_processors;
|
static BAN::Array<Processor, 0xFF> 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)
|
Processor& Processor::create(ProcessorID id)
|
||||||
{
|
{
|
||||||
// bsb is the first processor
|
// bsb is the first processor
|
||||||
if (s_bsb_id == PROCESSOR_NONE)
|
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];
|
auto& processor = s_processors[id];
|
||||||
if (processor.m_stack == nullptr)
|
|
||||||
{
|
ASSERT(processor.m_id == PROCESSOR_NONE);
|
||||||
processor.m_stack = kmalloc(m_stack_size, 4096, true);
|
processor.m_id = id;
|
||||||
|
|
||||||
|
processor.m_stack = kmalloc(s_stack_size, 4096, true);
|
||||||
ASSERT(processor.m_stack);
|
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;
|
return processor;
|
||||||
}
|
}
|
||||||
|
|
||||||
Processor::~Processor()
|
Processor& Processor::initialize()
|
||||||
{
|
{
|
||||||
if (m_stack)
|
auto id = read_processor_id();
|
||||||
kfree(m_stack);
|
auto& processor = s_processors[id];
|
||||||
m_stack = nullptr;
|
|
||||||
|
|
||||||
if (m_gdt)
|
// set gs base to pointer to this processor
|
||||||
delete m_gdt;
|
uint64_t ptr = reinterpret_cast<uint64_t>(&processor);
|
||||||
m_gdt = nullptr;
|
asm volatile("wrmsr" :: "d"(ptr >> 32), "a"(ptr), "c"(MSR_IA32_GS_BASE));
|
||||||
}
|
|
||||||
|
|
||||||
Processor& Processor::get(ProcessorID id)
|
ASSERT(processor.m_gdt);
|
||||||
{
|
processor.gdt().load();
|
||||||
return s_processors[id];
|
|
||||||
}
|
|
||||||
|
|
||||||
void Processor::initialize()
|
ASSERT(processor.m_idt);
|
||||||
{
|
processor.idt().load();
|
||||||
ASSERT(this == &Processor::current());
|
|
||||||
|
|
||||||
ASSERT(m_gdt == nullptr);
|
return processor;
|
||||||
m_gdt = GDT::create();
|
|
||||||
ASSERT(m_gdt);
|
|
||||||
|
|
||||||
ASSERT(m_idt == nullptr);
|
|
||||||
m_idt = IDT::create();
|
|
||||||
ASSERT(m_idt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace Kernel
|
||||||
|
|
||||||
ALWAYS_INLINE static void load_temp_stack()
|
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<void> Scheduler::initialize()
|
BAN::ErrorOr<void> Scheduler::initialize()
|
||||||
|
@ -223,7 +223,7 @@ namespace Kernel
|
||||||
#if SCHEDULER_VERIFY_STACK
|
#if SCHEDULER_VERIFY_STACK
|
||||||
vaddr_t rsp;
|
vaddr_t rsp;
|
||||||
read_rsp(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());
|
ASSERT(&PageTable::current() == &PageTable::kernel());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -256,7 +256,7 @@ namespace Kernel
|
||||||
if (current->has_process())
|
if (current->has_process())
|
||||||
{
|
{
|
||||||
current->process().page_table().load();
|
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
|
else
|
||||||
PageTable::kernel().load();
|
PageTable::kernel().load();
|
||||||
|
|
|
@ -102,8 +102,8 @@ extern "C" void kernel_main(uint32_t boot_magic, uint32_t boot_info)
|
||||||
parse_boot_info(boot_magic, boot_info);
|
parse_boot_info(boot_magic, boot_info);
|
||||||
dprintln("boot info parsed");
|
dprintln("boot info parsed");
|
||||||
|
|
||||||
Processor::create(Processor::current_id());
|
Processor::create(0);
|
||||||
Processor::current().initialize();
|
Processor::initialize();
|
||||||
dprintln("BSP initialized");
|
dprintln("BSP initialized");
|
||||||
|
|
||||||
PageTable::initialize();
|
PageTable::initialize();
|
||||||
|
@ -211,7 +211,7 @@ extern "C" void ap_main()
|
||||||
{
|
{
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
Processor::current().initialize();
|
Processor::initialize();
|
||||||
PageTable::kernel().initial_load();
|
PageTable::kernel().initial_load();
|
||||||
|
|
||||||
dprintln("ap{} initialized", Processor::current_id());
|
dprintln("ap{} initialized", Processor::current_id());
|
||||||
|
|
Loading…
Reference in New Issue