From d711938821faa8edb5a609eac4c4b2a8621c19e7 Mon Sep 17 00:00:00 2001 From: Patrick Wuttke Date: Fri, 19 Jan 2024 09:42:58 +0100 Subject: [PATCH] Added TSS and code to enter user mode (kind of). --- targets/_any/src/app/main.cpp | 2 + targets/x86_64/src/kernel/boot.s | 29 ++++++++++++ targets/x86_64/src/kernel/startup.cpp | 25 ++++++++--- targets/x86_64/src/kernel/x86_64.hpp | 64 +++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 7 deletions(-) diff --git a/targets/_any/src/app/main.cpp b/targets/_any/src/app/main.cpp index 231fbc3..a925b44 100644 --- a/targets/_any/src/app/main.cpp +++ b/targets/_any/src/app/main.cpp @@ -1,4 +1,6 @@ extern "C" void main() { + // __asm__ __volatile__("cli"); + while(true); } diff --git a/targets/x86_64/src/kernel/boot.s b/targets/x86_64/src/kernel/boot.s index 8e4fea6..248d6a6 100644 --- a/targets/x86_64/src/kernel/boot.s +++ b/targets/x86_64/src/kernel/boot.s @@ -85,6 +85,35 @@ __reloadSegments: movw %ax, %ss ret +.global __flushTSS +.type __flushTSS @function +// void __flushTSS(uint16_t segment [%di]) +__flushTSS: + ltr %di + ret + +.global __enterUsermode +.type __enterUsermode @function +// void __enterUsermode(uint16_t codeSegment [%di], uint16_t dataSegment [%si], void* rsp [%rdx], void* function [%rcx]) +__enterUsermode: + orw $0x3, %di // we are switching to ring 3, therefore set the bottom 2 bits to 3 + orw $0x3, %si // same for the data segment + movw %si, %ds + movw %si, %es + movw %si, %fs + movw %si, %gs + + movq %rsp, (%rdx) + movq %rsp, %rax + pushq %rsi // data segment + pushq %rax + pushf // flags + pushq %rdi // code segment + pushq %rcx + iretq + + + /* Set the size of the _start symbol to the current location '.' minus its start. This is useful when debugging or when you implement call tracing. diff --git a/targets/x86_64/src/kernel/startup.cpp b/targets/x86_64/src/kernel/startup.cpp index 4219e56..f8887f6 100644 --- a/targets/x86_64/src/kernel/startup.cpp +++ b/targets/x86_64/src/kernel/startup.cpp @@ -46,15 +46,24 @@ inline constexpr std::uint8_t INTERRUPT_VIRTUALIZATION_EXCEPTION = 0x14; inline constexpr std::uint8_t INTERRUPT_CONTROL_PROTECTION_EXCEPTION = 0x15; inline constexpr std::uint8_t INTERRUPT_KEYBOARD = irqToInterrupt(1); +TaskStateSegment tss alignas(16); + constinit std::array GDT alignas(16) = { SEGMENT_NULL, SEGMENT_KERNEL_CODE, SEGMENT_KERNEL_DATA, SEGMENT_USER_CODE, SEGMENT_USER_DATA, - SEGMENT_NULL + SEGMENT_NULL, // TSS lower + SEGMENT_NULL // TSS higher }; +inline constexpr std::uint16_t SEGIDX_KERNEL_CODE = 1 << 3; +inline constexpr std::uint16_t SEGIDX_KERNEL_DATA = 2 << 3; +inline constexpr std::uint16_t SEGIDX_USER_CODE = 3 << 3; +inline constexpr std::uint16_t SEGIDX_USER_DATA = 4 << 3; +inline constexpr std::uint16_t SEGIDX_TSS = 5 << 3; + constinit std::array IDT alignas(16); void initHeapFromEfiMemoryMap(const EfiMemoryMap& memoryMap) noexcept @@ -133,6 +142,8 @@ void initGlobals() extern "C" void __setGDT(uint16_t limit, void* base); extern "C" void __setIDT(uint16_t limit, void* base); extern "C" void __reloadSegments(uint64_t code, uint64_t data); +extern "C" void __flushTSS(uint16_t segment); +extern "C" void __enterUsermode(uint16_t codeSegment, uint16_t dataSegment, void* rsp, void (*function)()); template void setupInterrupt(std::uint8_t index, THandler handler) noexcept @@ -180,9 +191,11 @@ void kernel_main() setupInterrupt(INTERRUPT_CONTROL_PROTECTION_EXCEPTION, &baos::isrControlProtectionException); setupInterrupt(INTERRUPT_KEYBOARD, &ps2::isrKeyboard); + makeTSSSegment(&tss, &GDT[5]); __setGDT(sizeof(GDT), &GDT); __setIDT(sizeof(IDT), &IDT); - __reloadSegments(0x08, 0x10); + __reloadSegments(SEGIDX_KERNEL_CODE, SEGIDX_KERNEL_DATA); + __flushTSS(SEGIDX_TSS); const bool picsInited = initPICs(MASTER_PIC_OFFSET, SLAVE_PIC_OFFSET); unmaskIRQ(1); @@ -229,6 +242,8 @@ void kernel_main() } std::puts("This is BadAppleOS and everything is fine!\n"); + + __enterUsermode(SEGIDX_USER_CODE, SEGIDX_USER_DATA, &tss.rsp0, &main); while (true) { ps2::KeyEvent event; @@ -240,12 +255,8 @@ void kernel_main() event.down ? "true" : "false", event.repeat ? "true" : "false" ); - if (event.down && event.scancode == ps2::Scancode::ESCAPE) - { - int x = 1 / 0; - } } - main(); + } } // extern "C" diff --git a/targets/x86_64/src/kernel/x86_64.hpp b/targets/x86_64/src/kernel/x86_64.hpp index 5ab9ad5..6ca274e 100644 --- a/targets/x86_64/src/kernel/x86_64.hpp +++ b/targets/x86_64/src/kernel/x86_64.hpp @@ -5,6 +5,7 @@ #define BAD_APPLE_OS_X86_64_HPP_INCLUDED #include +#include // --- Segments --- // @@ -78,6 +79,30 @@ struct SegmentDescriptor /* 56 */ unsigned baseHigh : 8 = 0; } __attribute__((packed)); +enum class SystemSegmentDescriptorType +{ + TSS = 0, + LDT = 1 +}; + +struct SystemSegmentDescriptor +{ + /* 0 */ unsigned limitLow : 16 = 0; + /* 16 */ unsigned baseLow : 24 = 0; + /* 40 */ unsigned type : 4 = 0; + /* 44 */ SystemSegmentDescriptorType descType : 1 = SystemSegmentDescriptorType::TSS; + /* 45 */ unsigned privilegeLevel : 2 = 0; + /* 47 */ bool present : 1 = false; + /* 48 */ unsigned limitHigh : 4 = 0; + /* 52 */ bool available : 1 = 0; + /* 53 */ bool long_ : 1 = 0; + /* 54 */ bool big : 1 = 0; + /* 55 */ SegmentGranularity granularity : 1 = SegmentGranularity::BYTE; + /* 56 */ unsigned long baseHigh : 40 = 0; + /* 96 */ unsigned reserved : 32 = 0; +} __attribute__((packed)); +static_assert(2 * sizeof(SegmentDescriptor) == sizeof(SystemSegmentDescriptor)); + inline constexpr const SegmentDescriptor SEGMENT_NULL = {}; inline constexpr const SegmentDescriptor SEGMENT_KERNEL_CODE = { @@ -175,4 +200,43 @@ struct InterruptDescriptor /* 96 */ unsigned reserved2_ : 32 = 0; } __attribute__((packed)); +struct TaskStateSegment +{ + /* 0 */ std::uint32_t reserved0 = 0; + /* 32 */ std::uint64_t rsp0 = 0; + /* 96 */ std::uint64_t rsp1 = 0; + /* 160 */ std::uint64_t rsp2 = 0; + /* 224 */ std::uint64_t reserved1 = 0; + /* 288 */ std::uint64_t ist1 = 0; + /* 352 */ std::uint64_t ist2 = 0; + /* 416 */ std::uint64_t ist3 = 0; + /* 480 */ std::uint64_t ist4 = 0; + /* 544 */ std::uint64_t ist5 = 0; + /* 608 */ std::uint64_t ist6 = 0; + /* 672 */ std::uint64_t ist7 = 0; + /* 736 */ std::uint64_t reserved2 = 0; + /* 800 */ std::uint16_t reserved3 = 0; + /* 816 */ std::uint16_t iobpOffset = 0; +} __attribute__((packed)); + +inline void makeTSSSegment(TaskStateSegment* tssEntry, SegmentDescriptor* outSegments) noexcept +{ + const std::uint64_t base = std::bit_cast(tssEntry); + SystemSegmentDescriptor descriptor { + .limitLow = sizeof(TaskStateSegment), + .baseLow = static_cast(base) & 0xFFFFFF, + .type = static_cast(SystemSegmentType::TSS_32_AVAILABLE), + .descType = SystemSegmentDescriptorType::TSS, + .privilegeLevel = 0, + .present = true, + .limitHigh = 0, + .available = false, + .long_ = false, + .big = false, + .granularity = SegmentGranularity::BYTE, + .baseHigh = (base & 0xFFFFFFFFFF000000) >> 24 + }; + std::memcpy(outSegments, &descriptor, 2 * sizeof(SegmentDescriptor)); +} + #endif // !defined(BAD_APPLE_OS_X86_64_HPP_INCLUDED)