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 // Currently running with 32-bit paging tables at an identity mapped 31 // address. To switch to 64-bit paging we must first disable 32-bit paging, 32 // otherwise loading the new CR3 will fault. 33 movl %cr0, %eax 34 andl $~(1 << 31), %eax 35 movl %eax, %cr0 36 37 // Enable PAE and PGE 38 movl %cr4, %eax 39 orl $(1 << 5) | (1 << 7), %eax 40 movl %eax, %cr4 41 42 // Point CR3 to the kernel's PML4. 43 movl gLongPhysicalPML4, %eax 44 movl %eax, %cr3 45 46 // Enable long mode by setting EFER.LME. 47 movl $0xc0000080, %ecx 48 rdmsr 49 orl $(1 << 8), %eax 50 wrmsr 51 52 // Re-enable paging, which will put us in compatibility mode as we are 53 // currently in a 32-bit code segment. 54 movl %cr0, %ecx 55 orl $(1 << 31), %ecx 56 movl %ecx, %cr0 57 58 // Load 64-bit enabled GDT 59 lgdtl long_gdtr 60 61 // Jump into the 64-bit code segment. 62 ljmp $KERNEL_CODE_SELECTOR, $.Llmode 63.align 8 64.code64 65.Llmode: 66 // Set data segments. 67 mov $KERNEL_DATA_SELECTOR, %ax 68 mov %ax, %ss 69 xor %ax, %ax 70 mov %ax, %ds 71 mov %ax, %es 72 mov %ax, %fs 73 mov %ax, %gs 74 75 // Set the stack pointer. 76 movl %edi, %esp 77 shl $32, %rsi 78 orq %rsi, %rsp 79 80 // Clear the stack frame/RFLAGS. 81 xorq %rbp, %rbp 82 push $0 83 popf 84 85 // Get arguments and call the kernel entry point. 86 leaq gKernelArgs(%rip), %rdi 87 movl %ebx, %esi 88 movq gLongKernelEntry(%rip), %rax 89 call *%rax 90 91 92.data 93 94 95long_gdtr: 96 .word BOOT_GDT_SEGMENT_COUNT * 8 - 1 97SYMBOL(gLongGDT): 98 .long 0 99 100SYMBOL(gLongPhysicalPML4): 101 .long 0 102 103SYMBOL(gLongKernelEntry): 104 .quad 0 105