Kernel: Initialize GDT in kernel code

We dont use the boot GDT only while booting
This commit is contained in:
Bananymous
2023-03-01 21:21:08 +02:00
parent 7f8cad83b1
commit 7fcbb869e1
8 changed files with 306 additions and 82 deletions

122
kernel/arch/x86_64/GDT.cpp Normal file
View File

@@ -0,0 +1,122 @@
#include <BAN/Assert.h>
#include <kernel/GDT.h>
#include <string.h>
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 TaskStateSegment* s_tss = nullptr;
static SegmentDescriptor* s_gdt = nullptr;
static GDTR s_gdtr;
static void write_entry(uint8_t offset, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags)
{
SegmentDescriptor& desc = *(SegmentDescriptor*)((uintptr_t)s_gdt + offset);
desc.base1 = base;
desc.base2 = base >> 16;
desc.base3 = base >> 24;
desc.limit1 = limit;
desc.limit2 = limit >> 16;
desc.access = access;
desc.flags = flags;
}
static void write_tss(uint8_t offset)
{
s_tss = new TaskStateSegment();
ASSERT(s_tss);
memset(s_tss, 0x00, sizeof(TaskStateSegment));
s_tss->rsp0 = (uintptr_t)g_boot_stack_top;
uintptr_t base = (uintptr_t)s_tss;
write_entry(offset, (uint32_t)base, sizeof(TaskStateSegment), 0x89, 0x0);
SegmentDescriptor& desc = *(SegmentDescriptor*)((uintptr_t)s_gdt + offset + 0x08);
desc.low = base >> 32;
desc.high = 0;
}
static void flush_gdt()
{
asm volatile("lgdt %0" :: "m"(s_gdtr));
}
extern "C" void flush_tss(uint16_t offset)
{
asm volatile("ltr %0" :: "m"(offset));
}
void initialize()
{
constexpr uint32_t descriptor_count = 6 + 1; // tss takes 2
s_gdt = new SegmentDescriptor[descriptor_count];
ASSERT(s_gdt);
s_gdtr.address = (uint64_t)s_gdt;
s_gdtr.size = descriptor_count * 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(0x28);
flush_gdt();
flush_tss(0x28);
}
}

View File

@@ -43,7 +43,7 @@
# 0 MiB -> 1 MiB: bootloader stuff
# 1 MiB -> 2 MiB: kernel
# 2 MiB -> 3 MiB: kmalloc
# 3 MiB -> 4 MiB: kmalloc_eternal
# 3 MiB -> 4 MiB: kmalloc_fixed
.align 4096
boot_pml4:
.skip 512 * 8
@@ -52,8 +52,6 @@
boot_pd1:
.skip 512 * 8
.section .text, "a"
.global g_multiboot_info
g_multiboot_info:
.skip 8
@@ -61,6 +59,8 @@ g_multiboot_info:
g_multiboot_magic:
.skip 8
.section .text, "a"
boot_gdt:
.quad 0x0000000000000000 # null descriptor
.quad 0x00AF9A000000FFFF # kernel code

View File

@@ -7,6 +7,7 @@ ELF_FORMAT=elf64-x86-64
KERNEL_ARCH_OBJS= \
$(ARCHDIR)/boot.o \
$(ARCHDIR)/GDT.o \
$(ARCHDIR)/IDT.o \
$(ARCHDIR)/interrupts.o \
$(ARCHDIR)/MMU.o \