1/* 2** Copyright 2001, Travis Geiselbrecht. All rights reserved. 3** Copyright 2012, Alex Smith, alex@alex-smith.me.uk. 4** Distributed under the terms of the NewOS License. 5*/ 6 7// Relocatable. Before calling, long_smp_trampoline_args should point 8// to a struct long_trampoline_args (see smp.cpp). This pointer should 9// be 16-byte aligned, below 1MB and identity-mapped. 10.globl long_smp_trampoline 11.globl long_smp_trampoline_end 12.globl long_smp_trampoline_args 13 14#include <asm_defs.h> 15 16#include <arch/x86/descriptors.h> 17#include "mmu.h" 18 19.code16 20long_smp_trampoline: 21 cli 22 23// movl 0xdeadbeef, esi 24 .byte 0x66 25 .byte 0xbe 26long_smp_trampoline_args: 27 .long 0xdeadbeef 28 29 // Load the trampoline args into ss. 30 movl %esi, %eax 31 shrl $4, %eax 32 movw %ax, %ss 33 xorw %sp, %sp 34 35 // Switch to protected mode. 36 popl %ebx 37 popl %edx 38 lgdt (%edx) 39 40 movl %cr0,%eax 41 orl $0x01,%eax 42 movl %eax,%cr0 43 44 pushl $8 45 leal (long_trampoline_32 - long_smp_trampoline)(%ebx), %eax 46 pushl %eax 47 .byte 0x66 48.code32 49 lret 50 51long_trampoline_32: 52 mov $0x10, %ax 53 mov %ax, %ds 54 mov %ax, %es 55 mov %ax, %fs 56 mov %ax, %gs 57 mov %ax, %ss 58 // Put the trampoline args on the stack. 59 movl %esi, %esp 60 addl $8, %esp 61 62 // Enable PAE and PGE 63 movl %cr4, %eax 64 orl $(1 << 5) | (1 << 7), %eax 65 movl %eax, %cr4 66 67 // Point CR3 to the kernel's PML4. 68 popl %eax 69 movl %eax, %cr3 70 71 // Enable long mode by setting EFER.LME. 72 movl $0xc0000080, %ecx 73 rdmsr 74 orl $(1 << 8), %eax 75 wrmsr 76 77 // Re-enable paging, which will put us in compatibility mode as we are 78 // currently in a 32-bit code segment. 79 movl %cr0, %ecx 80 orl $(1 << 31), %ecx 81 movl %ecx, %cr0 82 83 // Load 64-bit enabled GDT 84 popl %eax 85 lgdtl (%eax) 86 87 // Jump into the 64-bit code segment. 88 pushl $KERNEL_CODE_SELECTOR 89 leal (.Llmode - long_smp_trampoline)(%ebx), %eax 90 pushl %eax 91 lret 92.align 8 93.code64 94.Llmode: 95 // Set data segments. 96 mov $KERNEL_DATA_SELECTOR, %ax 97 mov %ax, %ss 98 xor %ax, %ax 99 mov %ax, %ds 100 mov %ax, %es 101 mov %ax, %fs 102 mov %ax, %gs 103 104 // Initialisation that comes from long_smp_start_kernel. 105 movq %cr0, %rax 106 orq $0x10000, %rax 107 andq $(~6), %rax 108 movq %rax, %cr0 109 fninit 110 movq %cr4, %rax 111 orq $0x600, %rax 112 movq %rax, %cr4 113 114 // Get kernel arguments. 115 popq %rax 116 popq %rdi 117 popq %rsi 118 119 // Set the stack pointer, write to the sentinel and clear the stack frame/RFLAGS. 120 popq %rbp 121 movq $0, (%rsp) 122 movq %rbp, %rsp 123 xorq %rbp, %rbp 124 push $0 125 popf 126 127 // Call the entry point. 128 call *%rax 129long_smp_trampoline_end: 130