added 2 changesets to branch 'refs/remotes/xyzzy-github/x86_64' old head: 78d482e3b8a7b67ed37a7479fddeb735897f282d new head: 0da10c8b51f9ec443a53873b37d07fab30a5734e ---------------------------------------------------------------------------- 2f36ef5: Fixed the x86_64 setjmp implementation. * typedef for jmp_buf was using int where it should be long. * setjmp was clearing the buffer pointer rather than the signal mask before calling sigsetjmp. * KDL now works without crashing on x86_64. 0da10c8: 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. [ Alex Smith <alex@xxxxxxxxxxxxxxxx> ] ---------------------------------------------------------------------------- 5 files changed, 38 insertions(+), 18 deletions(-) headers/posix/arch/x86_64/arch_setjmp.h | 2 +- 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 ++++++++++++++---- src/system/libroot/posix/arch/x86_64/sigsetjmp.S | 2 +- ############################################################################ Commit: 2f36ef5afe5aae9b150597d6281826a1c3ed2f3a Author: Alex Smith <alex@xxxxxxxxxxxxxxxx> Date: Thu Jul 5 12:52:36 2012 UTC Fixed the x86_64 setjmp implementation. * typedef for jmp_buf was using int where it should be long. * setjmp was clearing the buffer pointer rather than the signal mask before calling sigsetjmp. * KDL now works without crashing on x86_64. ---------------------------------------------------------------------------- diff --git a/headers/posix/arch/x86_64/arch_setjmp.h b/headers/posix/arch/x86_64/arch_setjmp.h index 2d8f39e..e1043da 100644 --- a/headers/posix/arch/x86_64/arch_setjmp.h +++ b/headers/posix/arch/x86_64/arch_setjmp.h @@ -6,6 +6,6 @@ #define _ARCH_SETJMP_H_ -typedef int __jmp_buf[8]; +typedef unsigned long __jmp_buf[8]; #endif /* _ARCH_SETJMP_H_ */ diff --git a/src/system/libroot/posix/arch/x86_64/sigsetjmp.S b/src/system/libroot/posix/arch/x86_64/sigsetjmp.S index 25bef80..0e7b5af 100644 --- a/src/system/libroot/posix/arch/x86_64/sigsetjmp.S +++ b/src/system/libroot/posix/arch/x86_64/sigsetjmp.S @@ -31,7 +31,7 @@ FUNCTION_END(setjmp) /* int setjmp(jmp_buf buffer) */ FUNCTION(setjmp): // Jump to sigsetjmp with a zero saveMask. - xorl %edi, %edi + xorl %esi, %esi jmp sigsetjmp FUNCTION_END(setjmp) ############################################################################ Commit: 0da10c8b51f9ec443a53873b37d07fab30a5734e Author: Alex Smith <alex@xxxxxxxxxxxxxxxx> Date: Thu Jul 5 12:55:59 2012 UTC 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. ---------------------------------------------------------------------------- diff --git a/src/system/boot/platform/bios_ia32/long.cpp b/src/system/boot/platform/bios_ia32/long.cpp index 60bcdcf..2a942df 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 de2a039..084b5b3 100644 --- a/src/system/boot/platform/bios_ia32/long.h +++ b/src/system/boot/platform/bios_ia32/long.h @@ -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(); diff --git a/src/system/boot/platform/bios_ia32/long_asm.S b/src/system/boot/platform/bios_ia32/long_asm.S index 43be6af..30bfd2b 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