From 03fe4d8c2ea7a42d2165ac7d2cf26670c86ed063 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 17 May 2023 21:41:08 -0700 Subject: [PATCH] Load our own GDT. Replace the GDT from limine with our own. --- init-dbg.sh | 2 +- zion/CMakeLists.txt | 14 +++---- zion/common/gdt.cpp | 92 ++++++++++++++++++++++++++++++++++++++++++ zion/common/gdt.h | 3 ++ zion/common/load_gdt.s | 15 +++++++ zion/zion.cpp | 3 ++ 6 files changed, 119 insertions(+), 10 deletions(-) create mode 100644 zion/common/gdt.cpp create mode 100644 zion/common/gdt.h create mode 100644 zion/common/load_gdt.s diff --git a/init-dbg.sh b/init-dbg.sh index 2fc9230..ce23937 100755 --- a/init-dbg.sh +++ b/init-dbg.sh @@ -1,2 +1,2 @@ #! /bin/bash -cmake -B builddbg/ -G Ninja -D CMAKE_CXX_COMPILER=x86_64-elf-gcc -D CMAKE_ASM-ATT_COMPILER=x86_64-elf-as -D CMAKE_BUILD_TYPE=Debug +cmake -B builddbg/ -G Ninja -D CMAKE_CXX_COMPILER=x86_64-elf-gcc -D CMAKE_ASM-ATT_COMPILER=x86_64-elf-gcc -D CMAKE_BUILD_TYPE=Debug diff --git a/zion/CMakeLists.txt b/zion/CMakeLists.txt index eb74bc5..3c0c5da 100644 --- a/zion/CMakeLists.txt +++ b/zion/CMakeLists.txt @@ -1,4 +1,6 @@ add_executable(zion + common/gdt.cpp + common/load_gdt.s debug/debug.cpp zion.cpp) @@ -7,20 +9,14 @@ target_include_directories(zion ${CMAKE_CURRENT_SOURCE_DIR} ) -# -c -- Don't run the linker. +# -c -- Don't run the linker (only necessary for the assembler) +# -ffreestanding # -nostdlib -- Don't include the standard library. # -mabi=sysv -- Explicitly specify the ABI since we will rely on it. # -mno-red-zone -- Don't put data below the stack pointer (clobbered by interrupts). # -mcmodel=kernel -- Assume the kernel code is running in the higher half. # -mgeneral-regs-only -- Prevent GCC from using a whole host of nonsense registers (that we have to enable). -# Hopefully preceded by -mgeneral-regs-only -# -mno-80387 -# -mno-mmx -# -mno-3dnow -# -mno-sse -mno-sse2 -# -MMD -- Something with the preprocessor? -set(_Z_COMPILE_FLAGS "${CMAKE_CXX_FLAGS} -ffreestanding -nostdlib -mabi=sysv -mno-red-zone -mcmodel=kernel -mgeneral-regs-only") -# -mno-80387 -mno-mmx -mno-3dnow -mno-sse -mno-sse2 -MMD +set(_Z_COMPILE_FLAGS "${CMAKE_CXX_FLAGS} -c -ffreestanding -nostdlib -mabi=sysv -mno-red-zone -mcmodel=kernel -mgeneral-regs-only") set(_Z_LINK_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/linker.ld") diff --git a/zion/common/gdt.cpp b/zion/common/gdt.cpp new file mode 100644 index 0000000..a280d3a --- /dev/null +++ b/zion/common/gdt.cpp @@ -0,0 +1,92 @@ +#include "common/gdt.h" + +#include + +#define GDT_ACCESSED 1 +#define GDT_READ_WRITE (1 << 1) +#define GDT_EXECUTABLE (1 << 3) +#define GDT_SEGMENT (1 << 4) +#define GDT_RING3 (3 << 5) +#define GDT_PRESENT (1 << 7) + +#define GDT_FLAGS (1 << 7) | (1 << 5) // 4K granularity | long mode + +struct TaskStateSegment { + uint32_t reserved = 0; + uint64_t rsp0 = 0; + uint64_t rsp1 = 0; + uint64_t rsp2 = 0; + uint64_t reserved2 = 0; + uint64_t ist1 = 0; + uint64_t ist2 = 0; + uint64_t ist3 = 0; + uint64_t ist4 = 0; + uint64_t ist5 = 0; + uint64_t ist6 = 0; + uint64_t ist7 = 0; + uint64_t reserved3 = 0; + uint16_t reserved4 = 0; + uint16_t iomap_base = 0; +} __attribute__((packed)); + +struct GdtPointer { + uint16_t size; + uint64_t base; +} __attribute__((packed)); + +static uint64_t gGdtSegments[7]; +static TaskStateSegment gTaskStateSegment; + +// Defined in load_gdt.s +extern "C" void ReloadSegments(); + +uint64_t CreateSegment(uint64_t access, uint64_t flags) { + uint64_t base = 0; + access &= 0xFF; + flags &= 0xF0; + flags |= 0xF; // For the highest 4 bits of the limit. + // Lowest bits are the limit (always set to max); + return (0xFFFF) | (access << 40) | (flags << 48); +} + +uint64_t CreateTssSegment(TaskStateSegment* tss) { + uint64_t base = reinterpret_cast(tss); + uint64_t limit = sizeof(TaskStateSegment); + uint64_t access = GDT_ACCESSED | GDT_PRESENT | GDT_EXECUTABLE; + return limit | ((base & 0xFFFF) << 16) | ((base >> 16 & 0xFF) << 32) | + (access << 40) | (((base >> 24) & 0xFF) << 56); +} + +void InitGdt() { + gGdtSegments[0] = CreateSegment(0, 0); + uint64_t default_bits = GDT_PRESENT | GDT_SEGMENT | GDT_READ_WRITE; + + // Kernel CS + gGdtSegments[1] = CreateSegment(default_bits | GDT_EXECUTABLE, GDT_FLAGS); + + // Kernel DS + gGdtSegments[2] = CreateSegment(default_bits, GDT_FLAGS); + + // User CS + gGdtSegments[3] = + CreateSegment(default_bits | GDT_RING3 | GDT_EXECUTABLE, GDT_FLAGS); + + // User DS + gGdtSegments[4] = CreateSegment(default_bits | GDT_RING3, GDT_FLAGS); + + gTaskStateSegment.iomap_base = sizeof(TaskStateSegment); + gGdtSegments[5] = CreateTssSegment(&gTaskStateSegment); + gGdtSegments[6] = reinterpret_cast(&gTaskStateSegment) >> 32; + + GdtPointer gdtp{ + .size = sizeof(gGdtSegments) - 1, + .base = reinterpret_cast(&gGdtSegments), + }; + + asm volatile("lgdt %0" ::"m"(gdtp)); + ReloadSegments(); + asm volatile( + "mov $0x28, %%ax;" + "ltr %%ax;" :: + : "rax"); +} diff --git a/zion/common/gdt.h b/zion/common/gdt.h new file mode 100644 index 0000000..df0b364 --- /dev/null +++ b/zion/common/gdt.h @@ -0,0 +1,3 @@ +#pragma once + +void InitGdt(); diff --git a/zion/common/load_gdt.s b/zion/common/load_gdt.s new file mode 100644 index 0000000..b5974cd --- /dev/null +++ b/zion/common/load_gdt.s @@ -0,0 +1,15 @@ +.global ReloadSegments +ReloadSegments: + push $0x08 + lea ._reload_cs, %rax + push %rax + retfq + +._reload_cs: + mov $0x10, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + ret diff --git a/zion/zion.cpp b/zion/zion.cpp index c4d5aab..37cb331 100644 --- a/zion/zion.cpp +++ b/zion/zion.cpp @@ -1,9 +1,12 @@ #include +#include "common/gdt.h" #include "debug/debug.h" extern "C" void zion() { dbgln("Hello World!"); + InitGdt(); + dbgln("New GDT Loaded!"); while (1) ;