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

142
kernel/arch/i386/GDT.cpp Normal file
View File

@ -0,0 +1,142 @@
#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
{
uint16_t link;
uint16_t reserved1;
uint32_t esp0;
uint16_t ss0;
uint16_t reserved2;
uint32_t esp1;
uint16_t ss1;
uint16_t reserved3;
uint32_t esp2;
uint16_t ss2;
uint16_t reserved4;
uint32_t cr3;
uint32_t eip;
uint32_t eflags;
uint32_t eax;
uint32_t ecx;
uint32_t edx;
uint32_t ebx;
uint32_t esp;
uint32_t ebp;
uint32_t esi;
uint32_t edi;
uint16_t es;
uint16_t reserved5;
uint16_t cs;
uint16_t reserved6;
uint16_t ss;
uint16_t reserved7;
uint16_t ds;
uint16_t reserved8;
uint16_t fs;
uint16_t reserved9;
uint16_t gs;
uint16_t reserved10;
uint16_t ldtr;
uint16_t reserved11;
uint16_t reserved12;
uint16_t iopb;
uint32_t ssp;
} __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;
uint32_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->ss0 = 0x10;
s_tss->esp0 = (uintptr_t)g_boot_stack_top;
write_entry(offset, (uint32_t)s_tss, sizeof(TaskStateSegment), 0x89, 0x0);
}
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;
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, 0xC); // kernel code
write_entry(0x10, 0x00000000, 0xFFFFF, 0x92, 0xC); // kernel data
write_entry(0x18, 0x00000000, 0xFFFFF, 0xFA, 0xC); // user code
write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, 0xC); // user data
write_tss(0x28);
flush_gdt();
flush_tss(0x28);
}
}

View File

@ -20,37 +20,27 @@
.long 32
.section .bss, "aw", @nobits
# Create stack
stack_bottom:
.skip 16384
stack_top:
.global g_kernel_cmdline
g_kernel_cmdline:
.skip 4096
# Create stack
.global g_boot_stack_bottom
g_boot_stack_bottom:
.skip 16384
.global g_boot_stack_top
g_boot_stack_top:
.global g_gdtr
g_gdtr:
.skip 2 + 4
.global g_gdt
g_gdt:
.skip 5 * 8
# 0 MiB -> 1 MiB: bootloader stuff
# 1 MiB -> 2 MiB: kernel
# 2 MiB -> 3 MiB: kmalloc
# 3 MiB -> 4 Mib: kmalloc_fixed
.align 32
boot_page_directory_pointer_table:
.skip 4 * 8
.align 4096
boot_page_directory1:
.skip 512 * 8
# Reserve memory for paging structures,
# we will identity map first 4 MiB
# 0 MiB -> 1 MiB: bootloader stuff
# 1 MiB -> 2 MiB: kernel
# 2 MiB -> 3 MiB: kmalloc
# 3 MiB -> 4 Mib: kmalloc_eternal
.align 32
boot_page_directory_pointer_table:
.skip 4 * 8
.align 4096
boot_page_directory1:
.skip 512 * 8
.section .text, "a"
.global g_kernel_cmdline
g_kernel_cmdline:
.skip 4096
.global g_multiboot_info
g_multiboot_info:
@ -59,6 +49,16 @@ g_multiboot_info:
g_multiboot_magic:
.skip 4
.section .text, "a"
boot_gdt:
.quad 0x0000000000000000 # null
.quad 0x00CF9A000000FFFF # kernel code
.quad 0x00CF92000000FFFF # kernel data
boot_gdtr:
.short . - boot_gdt - 1
.long boot_gdt
has_cpuid:
pushfl
pushfl
@ -140,18 +140,7 @@ initialize_paging:
ret
initialize_gdt:
# setup gdt
movw $(5 * 8 - 1), g_gdtr
movl $(g_gdt), g_gdtr + 2
movl $(0x0000FFFF), g_gdt + 0x08
movl $(0x00CF9A00), g_gdt + 0x08 + 4
movl $(0x0000FFFF), g_gdt + 0x10
movl $(0x00CF9200), g_gdt + 0x10 + 4
movl $(0x0000FFFF), g_gdt + 0x18
movl $(0x00CFFA00), g_gdt + 0x18 + 4
movl $(0x0000FFFF), g_gdt + 0x20
movl $(0x00CFF200), g_gdt + 0x20 + 4
lgdt g_gdtr
lgdt boot_gdtr
# flush gdt
movw $0x10, %ax
@ -164,12 +153,11 @@ initialize_gdt:
flush:
ret
.global _start
.type _start, @function
_start:
# Initialize stack and multiboot info
movl $stack_top, %esp
movl $g_boot_stack_top, %esp
movl %eax, g_multiboot_magic
movl %ebx, g_multiboot_info

View File

@ -7,6 +7,7 @@ ELF_FORMAT=elf32-i386
KERNEL_ARCH_OBJS= \
$(ARCHDIR)/boot.o \
$(ARCHDIR)/GDT.o \
$(ARCHDIR)/IDT.o \
$(ARCHDIR)/MMU.o \
$(ARCHDIR)/SpinLock.o \

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 \

View File

@ -2,43 +2,9 @@
#include <stdint.h>
namespace GDT
namespace Kernel::GDT
{
union SegmentDesriptor
{
struct
{
uint16_t limit_lo;
uint16_t base_lo;
uint8_t base_hi1;
uint8_t type : 4;
uint8_t system : 1;
uint8_t DPL : 2;
uint8_t present : 1;
uint8_t limit_hi : 4;
uint8_t flags : 4;
uint8_t base_hi2;
} __attribute__((packed));
struct
{
uint32_t low;
uint32_t high;
} __attribute__((packed));
} __attribute__((packed));
struct GDTR
{
uint16_t size;
void* address;
} __attribute__((packed));
extern "C" GDTR g_gdtr[];
extern "C" SegmentDesriptor g_gdt[];
void initialize();
}

View File

@ -1,5 +1,6 @@
#include <kernel/Debug.h>
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/GDT.h>
#include <kernel/IDT.h>
#include <kernel/Input.h>
#include <kernel/InterruptController.h>
@ -76,6 +77,9 @@ extern "C" void kernel_main()
kmalloc_initialize();
dprintln("kmalloc initialized");
GDT::initialize();
dprintln("GDT initialized");
IDT::initialize();
dprintln("IDT initialized");