From b5aad1c81d1c11f506d5c0e71cc1f9c57642b6a4 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Mon, 28 Jun 2021 17:03:08 +0200 Subject: [PATCH] Kernel: Fix GDT and segment selectors to make userland work on x86_64 Userland faulted on the very first instruction before because the PML4T/PDPT/etc. weren't marked as user-accessible. For some reason x86 doesn't care about that. Also, we need to provide an appropriate userspace stack segment selector to iretq. --- Kernel/Arch/x86/DescriptorTable.h | 5 +++-- Kernel/Arch/x86/common/Processor.cpp | 1 + Kernel/Arch/x86/x86_64/Processor.cpp | 9 +++++++-- Kernel/VM/PageDirectory.cpp | 10 +++++----- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/Kernel/Arch/x86/DescriptorTable.h b/Kernel/Arch/x86/DescriptorTable.h index 51585279a36..907dd5f998d 100644 --- a/Kernel/Arch/x86/DescriptorTable.h +++ b/Kernel/Arch/x86/DescriptorTable.h @@ -28,8 +28,9 @@ static_assert(GDT_SELECTOR_CODE0 + 24 == GDT_SELECTOR_DATA3); // SS3 = CS0 + 32 #else # define GDT_SELECTOR_CODE0 0x08 # define GDT_SELECTOR_CODE3 0x10 -# define GDT_SELECTOR_TSS 0x18 -# define GDT_SELECTOR_TSS_PART2 0x20 +# define GDT_SELECTOR_DATA3 0x18 +# define GDT_SELECTOR_TSS 0x20 +# define GDT_SELECTOR_TSS_PART2 0x28 #endif namespace Kernel { diff --git a/Kernel/Arch/x86/common/Processor.cpp b/Kernel/Arch/x86/common/Processor.cpp index 48b9bbef7bf..f608713c784 100644 --- a/Kernel/Arch/x86/common/Processor.cpp +++ b/Kernel/Arch/x86/common/Processor.cpp @@ -1070,6 +1070,7 @@ UNMAP_AFTER_INIT void Processor::gdt_init() #else write_raw_gdt_entry(GDT_SELECTOR_CODE0, 0x0000ffff, 0x00af9a00); // code0 write_raw_gdt_entry(GDT_SELECTOR_CODE3, 0x0000ffff, 0x00affa00); // code3 + write_raw_gdt_entry(GDT_SELECTOR_DATA3, 0x0000ffff, 0x008ff200); // data3 #endif #if ARCH(I386) diff --git a/Kernel/Arch/x86/x86_64/Processor.cpp b/Kernel/Arch/x86/x86_64/Processor.cpp index 104202cb954..00fd7a25eb9 100644 --- a/Kernel/Arch/x86/x86_64/Processor.cpp +++ b/Kernel/Arch/x86/x86_64/Processor.cpp @@ -115,8 +115,13 @@ u32 Processor::init_context(Thread& thread, bool leave_crit) iretframe.rflags = regs.rflags; iretframe.rip = regs.rip; iretframe.cs = regs.cs; - iretframe.userspace_rsp = kernel_stack_top; - iretframe.userspace_ss = 0; + if (return_to_user) { + iretframe.userspace_rsp = regs.rsp; + iretframe.userspace_ss = GDT_SELECTOR_DATA3 | 3; + } else { + iretframe.userspace_rsp = kernel_stack_top; + iretframe.userspace_ss = 0; + } // make space for a trap frame stack_top -= sizeof(TrapFrame); diff --git a/Kernel/VM/PageDirectory.cpp b/Kernel/VM/PageDirectory.cpp index e4b8cd5d456..5bc2da0f6db 100644 --- a/Kernel/VM/PageDirectory.cpp +++ b/Kernel/VM/PageDirectory.cpp @@ -95,7 +95,7 @@ PageDirectory::PageDirectory(const RangeAllocator* parent_range_allocator) #if ARCH(X86_64) { auto& table = *(PageDirectoryPointerTable*)MM.quickmap_page(*m_pml4t); - table.raw[0] = (FlatPtr)m_directory_table->paddr().as_ptr() | 3; + table.raw[0] = (FlatPtr)m_directory_table->paddr().as_ptr() | 7; MM.unquickmap_page(); } #endif @@ -108,10 +108,10 @@ PageDirectory::PageDirectory(const RangeAllocator* parent_range_allocator) table.raw[2] = (FlatPtr)m_directory_pages[2]->paddr().as_ptr() | 1; table.raw[3] = (FlatPtr)m_directory_pages[3]->paddr().as_ptr() | 1; #else - table.raw[0] = (FlatPtr)m_directory_pages[0]->paddr().as_ptr() | 3; - table.raw[1] = (FlatPtr)m_directory_pages[1]->paddr().as_ptr() | 3; - table.raw[2] = (FlatPtr)m_directory_pages[2]->paddr().as_ptr() | 3; - table.raw[3] = (FlatPtr)m_directory_pages[3]->paddr().as_ptr() | 3; + table.raw[0] = (FlatPtr)m_directory_pages[0]->paddr().as_ptr() | 7; + table.raw[1] = (FlatPtr)m_directory_pages[1]->paddr().as_ptr() | 7; + table.raw[2] = (FlatPtr)m_directory_pages[2]->paddr().as_ptr() | 7; + table.raw[3] = (FlatPtr)m_directory_pages[3]->paddr().as_ptr() | 7; #endif // 2 ** MAXPHYADDR - 1