Kernel: Move GDT to Processor
This commit is contained in:
parent
8670364f44
commit
58aca68726
|
@ -1,68 +1,35 @@
|
||||||
#include <BAN/Array.h>
|
|
||||||
#include <kernel/GDT.h>
|
#include <kernel/GDT.h>
|
||||||
|
#include <kernel/Debug.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
namespace Kernel::GDT
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
struct TaskStateSegment
|
GDT* GDT::create()
|
||||||
{
|
{
|
||||||
uint32_t reserved1;
|
auto* gdt = new GDT();
|
||||||
uint64_t rsp0;
|
ASSERT(gdt);
|
||||||
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
|
gdt->write_entry(0x00, 0x00000000, 0x00000, 0x00, 0x0); // null
|
||||||
{
|
gdt->write_entry(0x08, 0x00000000, 0xFFFFF, 0x9A, 0xA); // kernel code
|
||||||
struct
|
gdt->write_entry(0x10, 0x00000000, 0xFFFFF, 0x92, 0xC); // kernel data
|
||||||
{
|
gdt->write_entry(0x18, 0x00000000, 0xFFFFF, 0xFA, 0xA); // user code
|
||||||
uint16_t limit1;
|
gdt->write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, 0xC); // user data
|
||||||
uint16_t base1;
|
gdt->write_tss();
|
||||||
uint8_t base2;
|
|
||||||
uint8_t access;
|
|
||||||
uint8_t limit2 : 4;
|
|
||||||
uint8_t flags : 4;
|
|
||||||
uint8_t base3;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct
|
gdt->flush_gdt();
|
||||||
{
|
gdt->flush_tss();
|
||||||
uint32_t low;
|
|
||||||
uint32_t high;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
} __attribute__((packed));
|
return gdt;
|
||||||
|
}
|
||||||
|
|
||||||
struct GDTR
|
void GDT::write_entry(uint8_t offset, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags)
|
||||||
{
|
|
||||||
uint16_t size;
|
|
||||||
uint64_t address;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
static constexpr uint16_t s_tss_offset = 0x28;
|
|
||||||
|
|
||||||
static TaskStateSegment s_tss;
|
|
||||||
static BAN::Array<SegmentDescriptor, 7> 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);
|
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.base1 = (base >> 0) & 0xFFFF;
|
||||||
desc.base2 = (base >> 16) & 0xFF;
|
desc.base2 = (base >> 16) & 0xFF;
|
||||||
desc.base3 = (base >> 24) & 0xFF;
|
desc.base3 = (base >> 24) & 0xFF;
|
||||||
|
@ -75,49 +42,18 @@ namespace Kernel::GDT
|
||||||
desc.flags = flags & 0x0F;
|
desc.flags = flags & 0x0F;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_tss()
|
void GDT::write_tss()
|
||||||
{
|
{
|
||||||
memset(&s_tss, 0x00, sizeof(TaskStateSegment));
|
memset(&m_tss, 0x00, sizeof(TaskStateSegment));
|
||||||
s_tss.iopb = sizeof(TaskStateSegment);
|
m_tss.iopb = sizeof(TaskStateSegment);
|
||||||
|
|
||||||
uint64_t base = (uint64_t)&s_tss;
|
uint64_t base = reinterpret_cast<uint64_t>(&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.low = base >> 32;
|
||||||
desc.high = 0;
|
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,100 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Array.h>
|
||||||
|
#include <BAN/NoCopyMove.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
namespace Kernel::GDT
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
class GDT
|
||||||
|
{
|
||||||
|
BAN_NON_COPYABLE(GDT);
|
||||||
|
BAN_NON_MOVABLE(GDT);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static GDT* create();
|
||||||
|
|
||||||
static constexpr inline bool is_user_segment(uint8_t segment)
|
static constexpr inline bool is_user_segment(uint8_t segment)
|
||||||
{
|
{
|
||||||
return (segment & 3) == 3;
|
return (segment & 3) == 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initialize();
|
void set_tss_stack(uintptr_t rsp)
|
||||||
void set_tss_stack(uintptr_t);
|
{
|
||||||
|
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<SegmentDescriptor, 7> 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<uint64_t>(m_gdt.data())
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/ForwardList.h>
|
#include <BAN/ForwardList.h>
|
||||||
|
|
||||||
#include <kernel/Arch.h>
|
#include <kernel/Arch.h>
|
||||||
|
#include <kernel/GDT.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
@ -54,12 +56,19 @@ namespace Kernel
|
||||||
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() + m_stack_size; }
|
||||||
|
|
||||||
|
void initialize();
|
||||||
|
|
||||||
|
GDT& gdt() { ASSERT(m_gdt); return *m_gdt; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Processor() = default;
|
Processor() = default;
|
||||||
Processor(Processor&& other)
|
Processor(Processor&& other)
|
||||||
{
|
{
|
||||||
m_stack = other.m_stack;
|
m_stack = other.m_stack;
|
||||||
other.m_stack = nullptr;
|
other.m_stack = nullptr;
|
||||||
|
|
||||||
|
m_gdt = other.m_gdt;
|
||||||
|
other.m_gdt = nullptr;
|
||||||
}
|
}
|
||||||
~Processor();
|
~Processor();
|
||||||
|
|
||||||
|
@ -67,6 +76,8 @@ namespace Kernel
|
||||||
void* m_stack { nullptr };
|
void* m_stack { nullptr };
|
||||||
static constexpr size_t m_stack_size { 4096 };
|
static constexpr size_t m_stack_size { 4096 };
|
||||||
|
|
||||||
|
GDT* m_gdt { nullptr };
|
||||||
|
|
||||||
friend class BAN::Vector<Processor>;
|
friend class BAN::Vector<Processor>;
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -24,6 +24,10 @@ namespace Kernel
|
||||||
if (m_stack)
|
if (m_stack)
|
||||||
kfree(m_stack);
|
kfree(m_stack);
|
||||||
m_stack = nullptr;
|
m_stack = nullptr;
|
||||||
|
|
||||||
|
if (m_gdt)
|
||||||
|
delete m_gdt;
|
||||||
|
m_gdt = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Processor& Processor::get(ProcessorID id)
|
Processor& Processor::get(ProcessorID id)
|
||||||
|
@ -31,4 +35,13 @@ namespace Kernel
|
||||||
return s_processors[id];
|
return s_processors[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Processor::initialize()
|
||||||
|
{
|
||||||
|
ASSERT(this == &Processor::current());
|
||||||
|
|
||||||
|
ASSERT(m_gdt == nullptr);
|
||||||
|
m_gdt = GDT::create();
|
||||||
|
ASSERT(m_gdt);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -256,7 +256,7 @@ namespace Kernel
|
||||||
if (current->has_process())
|
if (current->has_process())
|
||||||
{
|
{
|
||||||
current->process().page_table().load();
|
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
|
else
|
||||||
PageTable::kernel().load();
|
PageTable::kernel().load();
|
||||||
|
|
|
@ -103,11 +103,9 @@ extern "C" void kernel_main(uint32_t boot_magic, uint32_t boot_info)
|
||||||
dprintln("boot info parsed");
|
dprintln("boot info parsed");
|
||||||
|
|
||||||
Processor::create(Processor::current_id());
|
Processor::create(Processor::current_id());
|
||||||
|
Processor::current().initialize();
|
||||||
dprintln("BSP initialized");
|
dprintln("BSP initialized");
|
||||||
|
|
||||||
GDT::initialize();
|
|
||||||
dprintln("GDT initialized");
|
|
||||||
|
|
||||||
IDT::initialize();
|
IDT::initialize();
|
||||||
dprintln("IDT initialized");
|
dprintln("IDT initialized");
|
||||||
|
|
||||||
|
@ -215,7 +213,8 @@ extern "C" void ap_main()
|
||||||
{
|
{
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
dprintln("hello from processor {}", Processor::current_id());
|
Processor::current().initialize();
|
||||||
|
dprintln("ap{} initialized", Processor::current_id());
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
asm volatile("");
|
asm volatile("");
|
||||||
|
|
Loading…
Reference in New Issue