xref: /plan9-contrib/sys/src/9k/k10/l64sipi.s (revision 9ef1f84b659abcb917c5c090acbce0772e494f21)
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