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:
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user