]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/CpuDxe/ApStartup.c
UefiCpuPkg/CpuDxe: split out StartupCode from StartApsStackless()
[mirror_edk2.git] / UefiCpuPkg / CpuDxe / ApStartup.c
CommitLineData
533263ee
JJ
1/** @file\r
2 CPU DXE AP Startup\r
3\r
4 Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "CpuDxe.h"\r
16#include "CpuGdt.h"\r
17#include "CpuMp.h"\r
18\r
19#pragma pack(1)\r
20\r
21typedef struct {\r
22 UINT8 JmpToCli[2];\r
23\r
24 UINT16 GdtLimit;\r
25 UINT32 GdtBase;\r
26\r
27 UINT8 Cli;\r
28\r
29 UINT8 MovAxRealSegment; UINT16 RealSegment;\r
30 UINT8 MovDsAx[2];\r
31\r
32 UINT8 MovBxGdtr[3];\r
33 UINT8 LoadGdt[5];\r
34\r
35 UINT8 MovEaxCr0[2];\r
36 UINT32 MovEaxCr0Value;\r
37 UINT8 MovCr0Eax[3];\r
38\r
39 UINT8 FarJmp32Flat[2]; UINT32 FlatJmpOffset; UINT16 FlatJmpSelector;\r
40\r
41 //\r
42 // Now in IA32\r
43 //\r
44 UINT8 MovEaxCr4;\r
45 UINT32 MovEaxCr4Value;\r
46 UINT8 MovCr4Eax[3];\r
47\r
48 UINT8 MoveDataSelectorIntoAx[2]; UINT16 FlatDataSelector;\r
49 UINT8 MoveFlatDataSelectorFromAxToDs[2];\r
50 UINT8 MoveFlatDataSelectorFromAxToEs[2];\r
51 UINT8 MoveFlatDataSelectorFromAxToFs[2];\r
52 UINT8 MoveFlatDataSelectorFromAxToGs[2];\r
53 UINT8 MoveFlatDataSelectorFromAxToSs[2];\r
54\r
55#if defined (MDE_CPU_X64)\r
56 //\r
57 // Transition to X64\r
58 //\r
59 UINT8 MovEaxCr3;\r
60 UINT32 Cr3Value;\r
61 UINT8 MovCr3Eax[3];\r
62\r
63 UINT8 MoveCr4ToEax[3];\r
64 UINT8 SetCr4Bit5[4];\r
65 UINT8 MoveEaxToCr4[3];\r
66\r
67 UINT8 MoveLongModeEnableMsrToEcx[5];\r
68 UINT8 ReadLmeMsr[2];\r
69 UINT8 SetLongModeEnableBit[4];\r
70 UINT8 WriteLmeMsr[2];\r
71\r
72 UINT8 MoveCr0ToEax[3];\r
73 UINT8 SetCr0PagingBit[4];\r
74 UINT8 MoveEaxToCr0[3];\r
75 //UINT8 DeadLoop[2];\r
76\r
77 UINT8 FarJmp32LongMode; UINT32 LongJmpOffset; UINT16 LongJmpSelector;\r
78#endif // defined (MDE_CPU_X64)\r
79\r
80#if defined (MDE_CPU_X64)\r
81 UINT8 MovEaxOrRaxCpuDxeEntry[2]; UINTN CpuDxeEntryValue;\r
82#else\r
83 UINT8 MovEaxOrRaxCpuDxeEntry; UINTN CpuDxeEntryValue;\r
84#endif\r
85 UINT8 JmpToCpuDxeEntry[2];\r
86\r
87} STARTUP_CODE;\r
88\r
89#pragma pack()\r
90\r
91/**\r
92 This .asm code used for translating processor from 16 bit real mode into\r
93 64 bit long mode. which help to create the mStartupCodeTemplate value.\r
94\r
95 To assemble:\r
96 * nasm -o ApStartup ApStartup.asm\r
97 Then disassemble:\r
98 * ndisasm -b 16 ApStartup\r
99 * ndisasm -b 16 -e 6 ApStartup\r
100 * ndisasm -b 32 -e 32 ApStartup (This -e offset may need adjustment)\r
101 * ndisasm -b 64 -e 0x83 ApStartup (This -e offset may need adjustment)\r
102\r
103 %define DEFAULT_CR0 0x00000023\r
104 %define DEFAULT_CR4 0x640\r
105\r
106 BITS 16\r
107\r
108 jmp short TransitionFromReal16To32BitFlat\r
109\r
110 ALIGN 2\r
111\r
112 Gdtr:\r
113 dw 0x5a5a\r
114 dd 0x5a5a5a5a\r
115\r
116 ;\r
117 ; Modified: EAX, EBX\r
118 ;\r
119 TransitionFromReal16To32BitFlat:\r
120\r
121 cli\r
122 mov ax, 0x5a5a\r
123 mov ds, ax\r
124\r
125 mov bx, Gdtr\r
126 o32 lgdt [ds:bx]\r
127\r
128 mov eax, cr4\r
129 btc eax, 5\r
130 mov cr4, eax\r
131\r
132 mov eax, DEFAULT_CR0\r
133 mov cr0, eax\r
134\r
135 jmp 0x5a5a:dword jumpTo32BitAndLandHere\r
136 BITS 32\r
137 jumpTo32BitAndLandHere:\r
138\r
139 mov eax, DEFAULT_CR4\r
140 mov cr4, eax\r
141\r
142 mov ax, 0x5a5a\r
143 mov ds, ax\r
144 mov es, ax\r
145 mov fs, ax\r
146 mov gs, ax\r
147 mov ss, ax\r
148\r
149 ;\r
150 ; Jump to CpuDxe for IA32\r
151 ;\r
152 mov eax, 0x5a5a5a5a\r
153 or eax, eax\r
154 jz Transition32FlatTo64Flat\r
155 jmp eax\r
156\r
157 ;\r
158 ; Transition to X64\r
159 ;\r
160 Transition32FlatTo64Flat:\r
161 mov eax, 0x5a5a5a5a\r
162 mov cr3, eax\r
163\r
164 mov eax, cr4\r
165 bts eax, 5 ; enable PAE\r
166 mov cr4, eax\r
167\r
168 mov ecx, 0xc0000080\r
169 rdmsr\r
170 bts eax, 8 ; set LME\r
171 wrmsr\r
172\r
173 mov eax, cr0\r
174 bts eax, 31 ; set PG\r
175 mov cr0, eax ; enable paging\r
176\r
177 ;\r
178 ; Jump to CpuDxe for X64\r
179 ;\r
180 jmp 0x5a5a:jumpTo64BitAndLandHere\r
181 BITS 64\r
182 jumpTo64BitAndLandHere:\r
183 mov rax, 0xcdcdcdcdcdcdcdcd\r
184 jmp rax\r
185**/\r
186STARTUP_CODE mStartupCodeTemplate = {\r
187 { 0xeb, 0x06 }, // Jump to cli\r
188 0, // GDT Limit\r
189 0, // GDT Base\r
190 0xfa, // cli (Clear Interrupts)\r
191 0xb8, 0x0000, // mov ax, RealSegment\r
192 { 0x8e, 0xd8 }, // mov ds, ax\r
193 { 0xBB, 0x02, 0x00 }, // mov bx, Gdtr\r
194 { 0x3e, 0x66, 0x0f, 0x01, 0x17 }, // lgdt [ds:bx]\r
195 { 0x66, 0xB8 }, 0x00000023, // mov eax, cr0 value\r
196 { 0x0F, 0x22, 0xC0 }, // mov cr0, eax\r
197 { 0x66, 0xEA }, // far jmp to 32-bit flat\r
198 OFFSET_OF(STARTUP_CODE, MovEaxCr4),\r
199 LINEAR_CODE_SEL,\r
200 0xB8, 0x00000640, // mov eax, cr4 value\r
201 { 0x0F, 0x22, 0xe0 }, // mov cr4, eax\r
202 { 0x66, 0xb8 }, CPU_DATA_SEL, // mov ax, FlatDataSelector\r
203 { 0x8e, 0xd8 }, // mov ds, ax\r
204 { 0x8e, 0xc0 }, // mov es, ax\r
205 { 0x8e, 0xe0 }, // mov fs, ax\r
206 { 0x8e, 0xe8 }, // mov gs, ax\r
207 { 0x8e, 0xd0 }, // mov ss, ax\r
208\r
209#if defined (MDE_CPU_X64)\r
210 0xB8, 0x00000000, // mov eax, cr3 value\r
211 { 0x0F, 0x22, 0xd8 }, // mov cr3, eax\r
212\r
213 { 0x0F, 0x20, 0xE0 }, // mov eax, cr4\r
214 { 0x0F, 0xBA, 0xE8, 0x05 }, // bts eax, 5\r
215 { 0x0F, 0x22, 0xE0 }, // mov cr4, eax\r
216\r
217 { 0xB9, 0x80, 0x00, 0x00, 0xC0 }, // mov ecx, 0xc0000080\r
218 { 0x0F, 0x32 }, // rdmsr\r
219 { 0x0F, 0xBA, 0xE8, 0x08 }, // bts eax, 8\r
220 { 0x0F, 0x30 }, // wrmsr\r
221\r
222 { 0x0F, 0x20, 0xC0 }, // mov eax, cr0\r
223 { 0x0F, 0xBA, 0xE8, 0x1F }, // bts eax, 31\r
224 { 0x0F, 0x22, 0xC0 }, // mov cr0, eax\r
225\r
226 0xEA, // FarJmp32LongMode\r
227 OFFSET_OF(STARTUP_CODE, MovEaxOrRaxCpuDxeEntry),\r
228 LINEAR_CODE64_SEL,\r
229#endif // defined (MDE_CPU_X64)\r
230\r
231 //0xeb, 0xfe, // jmp $\r
232#if defined (MDE_CPU_X64)\r
233 { 0x48, 0xb8 }, 0x0, // mov rax, X64 CpuDxe MP Entry Point\r
234#else\r
235 0xB8, 0x0, // mov eax, IA32 CpuDxe MP Entry Point\r
236#endif\r
237 { 0xff, 0xe0 }, // jmp to eax/rax (CpuDxe MP Entry Point)\r
238\r
239};\r
240\r
fe078dd5 241volatile STARTUP_CODE *StartupCode = NULL;\r
533263ee
JJ
242\r
243/**\r
fe078dd5
CF
244 Prepares Startup Code for APs.\r
245 This function prepares Startup Code for APs.\r
533263ee
JJ
246\r
247 @retval EFI_SUCCESS The APs were started\r
248 @retval EFI_OUT_OF_RESOURCES Cannot allocate memory to start APs\r
249\r
250**/\r
251EFI_STATUS\r
fe078dd5
CF
252PrepareAPStartupCode (\r
253 VOID\r
533263ee
JJ
254 )\r
255{\r
256 EFI_STATUS Status;\r
533263ee
JJ
257 IA32_DESCRIPTOR Gdtr;\r
258 EFI_PHYSICAL_ADDRESS StartAddress;\r
259\r
260 StartAddress = BASE_1MB;\r
261 Status = gBS->AllocatePages (\r
262 AllocateMaxAddress,\r
263 EfiACPIMemoryNVS,\r
264 EFI_SIZE_TO_PAGES (sizeof (*StartupCode)),\r
265 &StartAddress\r
266 );\r
267 if (EFI_ERROR (Status)) {\r
268 return Status;\r
269 }\r
270\r
271 StartupCode = (STARTUP_CODE*)(VOID*)(UINTN) StartAddress;\r
272 CopyMem ((VOID*) StartupCode, &mStartupCodeTemplate, sizeof (*StartupCode));\r
273 StartupCode->RealSegment = (UINT16) (((UINTN) StartAddress) >> 4);\r
274\r
275 AsmReadGdtr (&Gdtr);\r
276 StartupCode->GdtLimit = Gdtr.Limit;\r
277 StartupCode->GdtBase = (UINT32) Gdtr.Base;\r
278\r
fe078dd5 279 StartupCode->CpuDxeEntryValue = (UINTN) AsmApEntryPoint;\r
533263ee
JJ
280\r
281 StartupCode->FlatJmpOffset += (UINT32) StartAddress;\r
282\r
283#if defined (MDE_CPU_X64)\r
284 StartupCode->Cr3Value = (UINT32) AsmReadCr3 ();\r
285 StartupCode->LongJmpOffset += (UINT32) StartAddress;\r
286#endif\r
287\r
fe078dd5
CF
288 return EFI_SUCCESS;\r
289}\r
290\r
291/**\r
292 Free the code buffer of startup AP.\r
293\r
294**/\r
295VOID\r
296FreeApStartupCode (\r
297 VOID\r
298 )\r
299{\r
300 if (StartupCode != NULL) {\r
301 gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)(VOID*) StartupCode,\r
302 EFI_SIZE_TO_PAGES (sizeof (*StartupCode)));\r
303 }\r
304}\r
533263ee 305\r
fe078dd5
CF
306\r
307/**\r
308 Starts the Application Processors and directs them to jump to the\r
309 specified routine.\r
310\r
311 The processor jumps to this code in flat mode, but the processor's\r
312 stack is not initialized.\r
313\r
314 @retval EFI_SUCCESS The APs were started\r
315\r
316**/\r
317EFI_STATUS\r
318StartApsStackless (\r
319 VOID\r
320 )\r
321{\r
322 SendInitSipiSipiAllExcludingSelf ((UINT32)(UINTN)(VOID*) StartupCode);\r
533263ee
JJ
323 //\r
324 // Wait 100 milliseconds for APs to arrive at the ApEntryPoint routine\r
325 //\r
326 MicroSecondDelay (100 * 1000);\r
327\r
533263ee
JJ
328 return EFI_SUCCESS;\r
329}\r
330\r