1/* 2 * Copyright 2012, Alex Smith, alex@alex-smith.me.uk. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7#include <asm_defs.h> 8 9#define __x86_64__ 10#include <arch/x86/descriptors.h> 11#undef __x86_64__ 12 13 14#define GDT_LIMIT 0x800 15 16 17.code32 18 19 20/*! void long_enter_kernel(int currentCPU, uint64 stackTop); */ 21FUNCTION(long_enter_kernel): 22 // Preserve the arguments. We may no longer be able to use the stack once 23 // paging is disabled. 24 movl 4(%esp), %ebx 25 movl 8(%esp), %edi 26 movl 12(%esp), %esi 27 28 // We're about to disable paging, so we need to load the the physical 29 // address of our GDT. 30 lgdtl long_phys_gdtr 31 32 // Currently running with 32-bit paging tables at an identity mapped 33 // address. To switch to 64-bit paging we must first disable 32-bit paging, 34 // otherwise loading the new CR3 will fault. 35 movl %cr0, %eax 36 andl $~(1 << 31), %eax 37 movl %eax, %cr0 38 39 // Enable PAE and PGE 40 movl %cr4, %eax 41 orl $(1 << 5) | (1 << 7), %eax 42 movl %eax, %cr4 43 44 // Point CR3 to the kernel's PML4. 45 movl gLongPhysicalPML4, %eax 46 movl %eax, %cr3 47 48 // Enable long mode by setting EFER.LME. 49 movl $0xc0000080, %ecx 50 rdmsr 51 orl $(1 << 8), %eax 52 wrmsr 53 54 // Re-enable paging, which will put us in compatibility mode as we are 55 // currently in a 32-bit code segment. 56 movl %cr0, %ecx 57 orl $(1 << 31), %ecx 58 movl %ecx, %cr0 59 60 // Jump into the 64-bit code segment. 61 ljmp $KERNEL_CODE_SELECTOR, $.Llmode 62.align 8 63.code64 64.Llmode: 65 // Set data segments. 66 mov $KERNEL_DATA_SELECTOR, %ax 67 mov %ax, %ss 68 xor %ax, %ax 69 mov %ax, %ds 70 mov %ax, %es 71 mov %ax, %fs 72 mov %ax, %gs 73 74 // Load the virtual address of the GDT. 75 lgdtq long_virt_gdtr(%rip) 76 77 // Set the stack pointer. 78 movl %edi, %esp 79 shl $32, %rsi 80 orq %rsi, %rsp 81 82 // Clear the stack frame/RFLAGS. 83 xorq %rbp, %rbp 84 push $0 85 popf 86 87 // Get arguments and call the kernel entry point. 88 leaq gKernelArgs(%rip), %rdi 89 movl %ebx, %esi 90 movq gLongKernelEntry(%rip), %rax 91 call *%rax 92 93 94.data 95 96 97long_phys_gdtr: 98 .word GDT_LIMIT - 1 99SYMBOL(gLongPhysicalGDT): 100 .long 0 101 102long_virt_gdtr: 103 .word GDT_LIMIT - 1 104SYMBOL(gLongVirtualGDT): 105 .quad 0 106 107SYMBOL(gLongPhysicalPML4): 108 .long 0 109 110SYMBOL(gLongKernelEntry): 111 .quad 0 112