From 0da10c8b51f9ec443a53873b37d07fab30a5734e Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Thu, 5 Jul 2012 13:55:59 +0100 Subject: [PATCH] Some fixes to the long mode switch code. * Wasn't storing the fixed virtual address of the PML4 in kernel_args. * After switching to long mode, reload GDTR with the virtual address of the GDT. This was working fine until now because the physical address was identity mapped, but broke as soon as I removed the identity mapping. --- src/system/boot/platform/bios_ia32/long.cpp | 13 +++---- src/system/boot/platform/bios_ia32/long.h | 5 +-- src/system/boot/platform/bios_ia32/long_asm.S | 34 +++++++++++++++---- 3 files changed, 36 insertions(+), 16 deletions(-) diff --git a/src/system/boot/platform/bios_ia32/long.cpp b/src/system/boot/platform/bios_ia32/long.cpp index 60bcdcf744..2a942df653 100644 --- a/src/system/boot/platform/bios_ia32/long.cpp +++ b/src/system/boot/platform/bios_ia32/long.cpp @@ -104,7 +104,7 @@ long_mmu_init() // Allocate the top level PML4. pml4 = (uint64*)mmu_allocate_page(&gKernelArgs.arch_args.phys_pgdir); memset(pml4, 0, B_PAGE_SIZE); - gKernelArgs.arch_args.vir_pgdir = (uint64)(addr_t)pml4; + gKernelArgs.arch_args.vir_pgdir = fix_address((uint64)(addr_t)pml4); // Find the highest physical memory address. We map all physical memory // into the kernel address space, so we want to make sure we map everything @@ -319,14 +319,11 @@ long_start_kernel() // We're about to enter the kernel -- disable console output. stdout = NULL; - // Load the new GDT. The physical address is used because long_enter_kernel - // disables 32-bit paging. - gdt_idt_descr gdtr = { GDT_LIMIT - 1, gKernelArgs.arch_args.phys_gdt }; - asm volatile("lgdt %0" :: "m"(gdtr)); - // Enter the kernel! - long_enter_kernel(gKernelArgs.arch_args.phys_pgdir, entry, stackTop, - kernelArgs, 0); + long_enter_kernel(gKernelArgs.arch_args.phys_pgdir, + gKernelArgs.arch_args.phys_gdt, gKernelArgs.arch_args.vir_gdt, + entry, stackTop, kernelArgs, 0); + panic("Shouldn't get here"); } diff --git a/src/system/boot/platform/bios_ia32/long.h b/src/system/boot/platform/bios_ia32/long.h index de2a0392c7..084b5b36e8 100644 --- a/src/system/boot/platform/bios_ia32/long.h +++ b/src/system/boot/platform/bios_ia32/long.h @@ -9,8 +9,9 @@ #include -extern "C" void long_enter_kernel(uint32 pml4, uint64 entry, uint64 stackTop, - uint64 kernelArgs, int currentCPU); +extern "C" void long_enter_kernel(uint32 physPML4, uint32 physGDT, + uint64 virtGDT, uint64 entry, uint64 stackTop, uint64 kernelArgs, + int currentCPU); extern void long_start_kernel(); diff --git a/src/system/boot/platform/bios_ia32/long_asm.S b/src/system/boot/platform/bios_ia32/long_asm.S index 43be6af4cd..30bfd2be02 100644 --- a/src/system/boot/platform/bios_ia32/long_asm.S +++ b/src/system/boot/platform/bios_ia32/long_asm.S @@ -11,13 +11,22 @@ #undef __x86_64__ +#define GDT_LIMIT 0x800 + + .code32 -/*! void long_enter_kernel(uint32 pml4, uint64 entry, uint64 stackTop, - uint64 kernelArgs, int currentCPU); +/*! void long_enter_kernel(uint32 physPML4, uint32 physGDT, uint64 virtGDT, + uint64 entry, uint64 stackTop, uint64 kernelArgs, int currentCPU); */ FUNCTION(long_enter_kernel): + // We're about to disable paging, so we need to load the the physical + // address of our GDT. + movl 8(%esp), %eax + movl %eax, (long_gdtr + 2) + lgdtl (long_gdtr) + // Currently running with 32-bit paging tables at an identity mapped // address. To switch to 64-bit paging we must first disable 32-bit paging, // otherwise loading the new CR3 will fault. @@ -62,11 +71,16 @@ FUNCTION(long_enter_kernel): // Clear the high 32 bits of RSP. movl %esp, %esp + // Load the virtual address of the GDT. + movq 12(%rsp), %rax + movq %rax, long_gdtr + 2(%rip) + lgdtq long_gdtr(%rip) + // Get the entry point address, arguments and new stack pointer. - movq 8(%rsp), %rax - movq 24(%rsp), %rdi - movl 32(%rsp), %esi - movq 16(%rsp), %rsp + movq 20(%rsp), %rax + movq 36(%rsp), %rdi + movl 44(%rsp), %esi + movq 28(%rsp), %rsp // Clear the stack frame/RFLAGS. xorq %rbp, %rbp @@ -75,3 +89,11 @@ FUNCTION(long_enter_kernel): // Call the kernel entry point. call *%rax + + +.data + + +long_gdtr: + .word GDT_LIMIT - 1 + .quad 0