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.
This commit is contained in:
Alex Smith
2012-07-05 13:55:59 +01:00
parent 2f36ef5afe
commit 0da10c8b51
3 changed files with 36 additions and 16 deletions
+5 -8
View File
@@ -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");
}
+3 -2
View File
@@ -9,8 +9,9 @@
#include <SupportDefs.h>
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();
+28 -6
View File
@@ -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