1/** 2 * \file 3 * \brief Initializes the APs to long mode. 4 * This file starts an AP in real-mode, sets up the needed GDT, switches to 5 * protected-mode, enables paging and the long-mode and switches to long-mode. 6 * After that, it jumps to the entry point of the kernel. 7 */ 8 9/* 10 * Copyright (c) 2007, 2008, 2010, ETH Zurich. 11 * All rights reserved. 12 * 13 * This file is distributed under the terms in the attached LICENSE file. 14 * If you do not find this file, copies can be found by writing to: 15 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 16 */ 17 18#include <target/x86_32/offsets_target.h> 19#include <init.h> 20#include <x86.h> 21 22#define PROT_MODE_ENABLE 1 23#define PAGING_ENABLE 31 24#define PROT_CS 8 25#define PROT_DS 16 26#define PAE 0x20 27#define LME 8 28#define BOOT_AP_KERNEL_SIZE 4096 29 30/** 31 * Get doxygen to ignore the rest of this file, as it is very confused otherwise 32 * \cond 33 */ 34 35 .text 36 .align 4096 37 .code16 38 .org X86_32_REAL_MODE_OFFSET 39 40 41//start the 16bit real-mode code here 42 43 .global x86_32_start_ap 44x86_32_start_ap: 45 cli 46 mov $X86_32_REAL_MODE_SEGMENT,%ax 47 mov %ax,%ds 48 mov $(x86_32_init_ap_lock - x86_32_start_ap),%si 49start_ap_spin: 50 xor %ax,%ax 51 lock bts %ax,(%si) 52 jc start_ap_spin 53 mov $(gdt_ptr - x86_32_start_ap),%esi 54 lgdt (%esi) 55 mov %cr0,%eax 56 or $PROT_MODE_ENABLE,%al 57 mov %eax,%cr0 58// jmp PROT_CS:start_ap_pm 59 .byte 0x66 60 .byte 0xea 61 .long start_ap_pm - x86_32_start_ap + X86_32_REAL_MODE_LINEAR_OFFSET 62 .word PROT_CS 63 64//start the 32bit protected-mode code here 65 66 .code32 67start_ap_pm: 68 // set up stack 69 mov $PROT_DS,%eax 70 mov %eax,%ss 71 mov %eax,%ds 72 mov %eax,%es 73 mov %eax,%fs 74 mov %eax,%gs 75 mov $(start_ap_stack - x86_32_start_ap + X86_32_REAL_MODE_LINEAR_OFFSET),%esp 76 77 // jmp to the first C initialization function in the kernel 78 // the address is copied here to this code by start_aps_startall 79 // the jmp is a jmp to an absolute address. it is difficult to compute 80 // it here, because it is IP-relative and the IP here is 81 // REAL_MODE_LINEAR_OFFSET + some offset for _every_ AP to be started, 82 // independently of the final kernel location 83 mov x86_32_init_ap_global - x86_32_start_ap + X86_32_REAL_MODE_LINEAR_OFFSET,%ebx 84 mov $KERNEL_BOOT_MAGIC,%eax 85 mov x86_32_init_ap_absolute_entry - x86_32_start_ap + X86_32_REAL_MODE_LINEAR_OFFSET,%ecx 86 87//we should not return here after the call, but for any case, use a call 88//instead of a jmp... 89 call *%ecx 90 91//we should never reach this location... 92loop_ap: 93 hlt 94 jmp loop_ap 95 96 97//stack for 64bit mode 98 99 .align 16 100 .fill BOOT_AP_KERNEL_SIZE,1,0 101start_ap_stack: 102 103 104 .align 16 105gdt: 106 .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 107 .byte 0xff,0xff,0x00,0x00,0x00,0x9a,0xcf,0x00 // 32bit code segment for protected-mode 108 .byte 0xff,0xff,0x00,0x00,0x00,0x93,0xcf,0x00 // 32bit data segment for protected-mode 109 110gdt_ptr: 111 .word gdt_ptr - gdt 112 .long gdt - x86_32_start_ap + X86_32_REAL_MODE_LINEAR_OFFSET 113 .long 0 114 115 // the absolute destination address to the first C function in the kernel. 116 // The address is copied to this variable by start_aps_startall. 117 .global x86_32_init_ap_absolute_entry 118x86_32_init_ap_absolute_entry: 119 .long 0 120 .long 0 121 122 .global x86_32_init_ap_global 123x86_32_init_ap_global: 124 .long 0 125 .long 0 126 127 128 .global x86_32_init_ap_wait 129x86_32_init_ap_wait: 130 .long 0 131 132 .global x86_32_init_ap_apic_id 133x86_32_init_ap_apic_id: 134 .byte 0 135 136 .global x86_32_init_ap_lock 137x86_32_init_ap_lock: 138 .byte 0 139 140 141 .global x86_32_start_ap_end 142x86_32_start_ap_end: 143 144/** 145 * \endcond 146 */ 147