1/* 2 * Start-up request IPI handler. 3 * 4 * This code is executed on an application processor in response to receiving 5 * a Start-up IPI (SIPI) from another processor. 6 * This must be placed on a 4KiB boundary 7 * somewhere in the 1st MiB of conventional memory. However, 8 * due to some shortcuts below it's restricted further to within the 1st 64KiB. 9 * The AP starts in real-mode, with 10 * CS selector set to the startup memory address/16; 11 * CS base set to startup memory address; 12 * CS limit set to 64KiB; 13 * CPL and IP set to 0. 14 * Parameters are passed to this code via a vector in low memory 15 * indexed by the APIC number of the processor. The layout, size, 16 * and location have to be kept in sync with the setup in sipi.s. 17 */ 18#include "mem.h" 19#include "amd64l.h" 20 21/* 22 * Some machine instructions not handled well by [68][al]. 23 * This is a messy piece of code, requiring instructions in real mode, 24 * protected mode (+long mode on amd64). The MODE pseudo-op of 6[al] handles 25 * the latter two OK, but 'MODE $16' is incomplete, e.g. it does 26 * not truncate operands appropriately, hence the ugly 'rMOVAX' macro. 27 * Fortunately, the only other instruction executed in real mode that 28 * could cause a problem (ORL) is encoded such that it will work OK. 29 */ 30#define DELAY BYTE $0xeb; /* JMP .+2 */ \ 31 BYTE $0x00 32#define NOP BYTE $0x90 /* NOP */ 33 34#define pFARJMP32(s, o) BYTE $0xea; /* far jmp ptr32:16 */ \ 35 LONG $o; WORD $s 36 37#define rFARJMP16(s, o) BYTE $0xea; /* far jump ptr16:16 */ \ 38 WORD $o; WORD $s; 39#define rFARJMP32(s, o) BYTE $0x66; /* far jump ptr32:16 */ \ 40 pFARJMP32(s, o) 41#define rLGDT(gdtptr) BYTE $0x0f; /* LGDT */ \ 42 BYTE $0x01; BYTE $0x16; \ 43 WORD $gdtptr 44#define rMOVAX(i) BYTE $0xb8; /* i -> AX */ \ 45 WORD $i; 46 47/* 48 * Real mode. Welcome to 1978. 49 * Load a basic GDT, turn on protected mode and make 50 * inter-segment jump to the protected mode code. 51 */ 52MODE $16 53 54TEXT _real<>(SB), 1, $-4 55 rFARJMP16(0, _endofheader<>-KZERO(SB)) /* */ 56 57_startofheader: 58 NOP; NOP; NOP 59 QUAD $0xa5a5a5a5a5a5a5a5 60 61TEXT _gdt32p<>(SB), 1, $-4 62 QUAD $0x0000000000000000 /* NULL descriptor */ 63 QUAD $0x00cf9a000000ffff /* CS */ 64 QUAD $0x00cf92000000ffff /* DS */ 65 QUAD $0x0020980000000000 /* Long mode CS */ 66 67TEXT _gdtptr32p<>(SB), 1, $-4 68 WORD $(4*8-1) /* includes long mode */ 69 LONG $_gdt32p<>-KZERO(SB) 70 71TEXT _gdt64<>(SB), 1, $-4 72 QUAD $0x0000000000000000 /* NULL descriptor */ 73 QUAD $0x0020980000000000 /* CS */ 74 QUAD $0x0000800000000000 /* DS */ 75 76TEXT _gdtptr64v<>(SB), 1, $-4 77 WORD $(3*8-1) 78 QUAD $_gdt64<>(SB) 79 80TEXT _endofheader<>(SB), 1, $-4 81 MOVW CS, AX 82 MOVW AX, DS /* initialise DS */ 83 84 rLGDT(_gdtptr32p<>-KZERO(SB)) /* load a basic gdt */ 85 86 MOVL CR0, AX 87 ORL $Pe, AX 88 MOVL AX, CR0 /* turn on protected mode */ 89 DELAY /* JMP .+2 */ 90 91 rMOVAX (SSEL(SiDS, SsTIGDT|SsRPL0)) /* */ 92 MOVW AX, DS 93 MOVW AX, ES 94 MOVW AX, FS 95 MOVW AX, GS 96 MOVW AX, SS 97 98 rFARJMP32(SSEL(SiCS, SsTIGDT|SsRPL0), _protected<>-KZERO(SB)) 99 100/* 101 * Protected mode. Welcome to 1982. 102 * Get the local APIC ID from the memory mapped APIC 103 * and use it to locate the index to the parameter vector; 104 * load the PDB with the page table address from the 105 * information vector; 106 * make an identity map for the inter-segment jump below, 107 * using the stack space to hold a temporary PDP and PD; 108 * enable and activate long mode; 109 * make an inter-segment jump to the long mode code. 110 */ 111MODE $32 112 113/* 114 * Macros for accessing page table entries; must turn 115 * the C-style array-index macros into a page table byte 116 * offset. 117 */ 118#define PML4O(v) ((PTLX((v), 3))<<3) 119#define PDPO(v) ((PTLX((v), 2))<<3) 120#define PDO(v) ((PTLX((v), 1))<<3) 121#define PTO(v) ((PTLX((v), 0))<<3) 122 123TEXT _protected<>(SB), 1, $-4 124 MOVL $0xfee00000, BP /* apicbase */ 125 MOVL 0x20(BP), BP /* Id */ 126 SHRL $24, BP /* becomes RARG later */ 127 128 MOVL BP, AX /* apicno */ 129 IMULL $32, AX /* [apicno] */ 130 MOVL $_real<>-KZERO(SB), BX 131 ADDL $4096, BX /* sipi */ 132 ADDL AX, BX /* sipi[apicno] */ 133 134 MOVL 0(BX), SI /* sipi[apicno].pml4 */ 135 136 MOVL SI, AX 137 MOVL AX, CR3 /* load the mmu */ 138 139 MOVL AX, DX 140 SUBL $MACHSTKSZ, DX /* PDP for identity map */ 141 ADDL $(PteRW|PteP), DX 142 MOVL DX, PML4O(0)(AX) /* PML4E for identity map */ 143 144 SUBL $MACHSTKSZ, AX /* PDP for identity map */ 145 ADDL $PTSZ, DX 146 MOVL DX, PDPO(0)(AX) /* PDPE for identity map */ 147 MOVL $(PtePS|PteRW|PteP), DX 148 ADDL $PTSZ, AX /* PD for identity map */ 149 MOVL DX, PDO(0)(AX) /* PDE for identity 0-[24]MiB */ 150 151 152/* 153 * Enable and activate Long Mode. From the manual: 154 * make sure Page Size Extentions are off, and Page Global 155 * Extensions and Physical Address Extensions are on in CR4; 156 * set Long Mode Enable in the Extended Feature Enable MSR; 157 * set Paging Enable in CR0; 158 * make an inter-segment jump to the Long Mode code. 159 * It's all in 32-bit mode until the jump is made. 160 */ 161TEXT _lme<>(SB), 1, $-4 162 MOVL CR4, AX 163 ANDL $~Pse, AX /* Page Size */ 164 ORL $(Pge|Pae), AX /* Page Global, Phys. Address */ 165 MOVL AX, CR4 166 167 MOVL $Efer, CX /* Extended Feature Enable */ 168 RDMSR 169 ORL $Lme, AX /* Long Mode Enable */ 170 WRMSR 171 172 MOVL CR0, DX 173 ANDL $~(Cd|Nw|Ts|Mp), DX 174 ORL $(Pg|Wp), DX /* Paging Enable */ 175 MOVL DX, CR0 176 177 pFARJMP32(SSEL(3, SsTIGDT|SsRPL0), _identity<>-KZERO(SB)) 178 179/* 180 * Long mode. Welcome to 2003. 181 * Jump out of the identity map space; 182 * load a proper long mode GDT; 183 * zap the identity map; 184 * initialise the stack, RMACH, RUSER, 185 * and call the C startup code. 186 */ 187MODE $64 188 189TEXT _identity<>(SB), 1, $-4 190 MOVQ $_start64v<>(SB), AX 191 JMP* AX 192 193TEXT _start64v<>(SB), 1, $-4 194 MOVQ $_gdtptr64v<>(SB), AX 195 MOVL (AX), GDTR 196 197 XORQ DX, DX /* DX is 0 from here on */ 198 MOVW DX, DS /* not used in long mode */ 199 MOVW DX, ES /* not used in long mode */ 200 MOVW DX, FS 201 MOVW DX, GS 202 MOVW DX, SS /* not used in long mode */ 203 204 MOVLQZX SI, SI /* sipi[apicno].pml4 */ 205 MOVQ SI, AX 206 ADDQ $KZERO, AX /* PML4 */ 207 MOVQ DX, PML4O(0)(AX) /* zap identity map */ 208 MOVQ SI, CR3 /* flush TLB */ 209 210 ADDQ $KZERO, BX /* &sipi[apicno] */ 211 212 MOVQ 8(BX), SP /* sipi[apicno].stack */ 213 214 PUSHQ DX /* clear flags */ 215 POPFQ 216 MOVLQZX RARG, RARG /* APIC ID */ 217 PUSHQ RARG /* apicno */ 218 219 MOVQ 16(BX), RMACH /* sipi[apicno].mach */ 220 MOVQ DX, RUSER 221 MOVQ 24(BX), AX /* sipi[apicno].pc */ 222 CALL* AX /* (*sipi[apicno].pc)(apicno) */ 223 224_ndnr: 225 JMP _ndnr 226