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