Преглед изворни кода

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.
Gunnar Beutner пре 4 година
родитељ
комит
b5aad1c81d

+ 3 - 2
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 {

+ 1 - 0
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)

+ 7 - 2
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);

+ 5 - 5
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