From 7fcbb869e164d59e724977d73c07ca48b6d8db51 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Wed, 1 Mar 2023 21:21:08 +0200 Subject: [PATCH] Kernel: Initialize GDT in kernel code We dont use the boot GDT only while booting --- kernel/arch/i386/GDT.cpp | 142 +++++++++++++++++++++++++++++++++ kernel/arch/i386/boot.S | 74 +++++++---------- kernel/arch/i386/make.config | 1 + kernel/arch/x86_64/GDT.cpp | 122 ++++++++++++++++++++++++++++ kernel/arch/x86_64/boot.S | 6 +- kernel/arch/x86_64/make.config | 1 + kernel/include/kernel/GDT.h | 38 +-------- kernel/kernel/kernel.cpp | 4 + 8 files changed, 306 insertions(+), 82 deletions(-) create mode 100644 kernel/arch/i386/GDT.cpp create mode 100644 kernel/arch/x86_64/GDT.cpp diff --git a/kernel/arch/i386/GDT.cpp b/kernel/arch/i386/GDT.cpp new file mode 100644 index 0000000000..d8f6008483 --- /dev/null +++ b/kernel/arch/i386/GDT.cpp @@ -0,0 +1,142 @@ +#include +#include + +#include + +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); + } + +} \ No newline at end of file diff --git a/kernel/arch/i386/boot.S b/kernel/arch/i386/boot.S index 29fc471af0..0dab850da2 100644 --- a/kernel/arch/i386/boot.S +++ b/kernel/arch/i386/boot.S @@ -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 diff --git a/kernel/arch/i386/make.config b/kernel/arch/i386/make.config index f50633b446..7535445dc1 100644 --- a/kernel/arch/i386/make.config +++ b/kernel/arch/i386/make.config @@ -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 \ diff --git a/kernel/arch/x86_64/GDT.cpp b/kernel/arch/x86_64/GDT.cpp new file mode 100644 index 0000000000..22f4aaf067 --- /dev/null +++ b/kernel/arch/x86_64/GDT.cpp @@ -0,0 +1,122 @@ +#include +#include + +#include + +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); + } + +} \ No newline at end of file diff --git a/kernel/arch/x86_64/boot.S b/kernel/arch/x86_64/boot.S index ce61894338..ed810323e0 100644 --- a/kernel/arch/x86_64/boot.S +++ b/kernel/arch/x86_64/boot.S @@ -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 diff --git a/kernel/arch/x86_64/make.config b/kernel/arch/x86_64/make.config index a5d2ceecc4..225d0cfd08 100644 --- a/kernel/arch/x86_64/make.config +++ b/kernel/arch/x86_64/make.config @@ -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 \ diff --git a/kernel/include/kernel/GDT.h b/kernel/include/kernel/GDT.h index c28ccc717c..51f59966d9 100644 --- a/kernel/include/kernel/GDT.h +++ b/kernel/include/kernel/GDT.h @@ -2,43 +2,9 @@ #include -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(); } \ No newline at end of file diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index fd8fe2683f..da01928cd7 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -76,6 +77,9 @@ extern "C" void kernel_main() kmalloc_initialize(); dprintln("kmalloc initialized"); + GDT::initialize(); + dprintln("GDT initialized"); + IDT::initialize(); dprintln("IDT initialized");