]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/CpuDxe/ApStartup.c
UefiCpuPkg/CpuDxe: Move SetMtrrsFromBuffer() location.
[mirror_edk2.git] / UefiCpuPkg / CpuDxe / ApStartup.c
CommitLineData
533263ee
JJ
1/** @file\r
2 CPU DXE AP Startup\r
3\r
21d0e750 4 Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>\r
533263ee
JJ
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
21d0e750
SZ
21typedef struct {\r
22 UINT8 MoveIa32EferMsrToEcx[5];\r
23 UINT8 ReadIa32EferMsr[2];\r
24 UINT8 SetExecuteDisableBitEnableBit[4];\r
25 UINT8 WriteIa32EferMsr[2];\r
26\r
27#if defined (MDE_CPU_IA32)\r
28 UINT8 MovEaxCr3;\r
29 UINT32 Cr3Value;\r
30 UINT8 MovCr3Eax[3];\r
31\r
32 UINT8 MoveCr4ToEax[3];\r
33 UINT8 SetCr4Bit5[4];\r
34 UINT8 MoveEaxToCr4[3];\r
35\r
36 UINT8 MoveCr0ToEax[3];\r
37 UINT8 SetCr0PagingBit[4];\r
38 UINT8 MoveEaxToCr0[3];\r
39#endif\r
40} ENABLE_EXECUTE_DISABLE_CODE;\r
41\r
42ENABLE_EXECUTE_DISABLE_CODE mEnableExecuteDisableCodeTemplate = {\r
43 { 0xB9, 0x80, 0x00, 0x00, 0xC0 }, // mov ecx, 0xc0000080\r
44 { 0x0F, 0x32 }, // rdmsr\r
45 { 0x0F, 0xBA, 0xE8, 0x0B }, // bts eax, 11\r
46 { 0x0F, 0x30 }, // wrmsr\r
47\r
48#if defined (MDE_CPU_IA32)\r
49 0xB8, 0x00000000, // mov eax, cr3 value\r
50 { 0x0F, 0x22, 0xd8 }, // mov cr3, eax\r
51\r
52 { 0x0F, 0x20, 0xE0 }, // mov eax, cr4\r
53 { 0x0F, 0xBA, 0xE8, 0x05 }, // bts eax, 5\r
54 { 0x0F, 0x22, 0xE0 }, // mov cr4, eax\r
55\r
56 { 0x0F, 0x20, 0xC0 }, // mov eax, cr0\r
57 { 0x0F, 0xBA, 0xE8, 0x1F }, // bts eax, 31\r
58 { 0x0F, 0x22, 0xC0 }, // mov cr0, eax\r
59#endif\r
60};\r
61\r
533263ee
JJ
62typedef struct {\r
63 UINT8 JmpToCli[2];\r
64\r
65 UINT16 GdtLimit;\r
66 UINT32 GdtBase;\r
67\r
68 UINT8 Cli;\r
69\r
70 UINT8 MovAxRealSegment; UINT16 RealSegment;\r
71 UINT8 MovDsAx[2];\r
72\r
73 UINT8 MovBxGdtr[3];\r
74 UINT8 LoadGdt[5];\r
75\r
76 UINT8 MovEaxCr0[2];\r
77 UINT32 MovEaxCr0Value;\r
78 UINT8 MovCr0Eax[3];\r
79\r
80 UINT8 FarJmp32Flat[2]; UINT32 FlatJmpOffset; UINT16 FlatJmpSelector;\r
81\r
82 //\r
83 // Now in IA32\r
84 //\r
85 UINT8 MovEaxCr4;\r
86 UINT32 MovEaxCr4Value;\r
87 UINT8 MovCr4Eax[3];\r
88\r
89 UINT8 MoveDataSelectorIntoAx[2]; UINT16 FlatDataSelector;\r
90 UINT8 MoveFlatDataSelectorFromAxToDs[2];\r
91 UINT8 MoveFlatDataSelectorFromAxToEs[2];\r
92 UINT8 MoveFlatDataSelectorFromAxToFs[2];\r
93 UINT8 MoveFlatDataSelectorFromAxToGs[2];\r
94 UINT8 MoveFlatDataSelectorFromAxToSs[2];\r
95\r
21d0e750
SZ
96 //\r
97 // Code placeholder to enable PAE Execute Disable for IA32\r
98 // and enable Execute Disable Bit for X64\r
99 //\r
100 ENABLE_EXECUTE_DISABLE_CODE EnableExecuteDisable;\r
101\r
533263ee
JJ
102#if defined (MDE_CPU_X64)\r
103 //\r
104 // Transition to X64\r
105 //\r
106 UINT8 MovEaxCr3;\r
107 UINT32 Cr3Value;\r
108 UINT8 MovCr3Eax[3];\r
109\r
110 UINT8 MoveCr4ToEax[3];\r
111 UINT8 SetCr4Bit5[4];\r
112 UINT8 MoveEaxToCr4[3];\r
113\r
114 UINT8 MoveLongModeEnableMsrToEcx[5];\r
115 UINT8 ReadLmeMsr[2];\r
116 UINT8 SetLongModeEnableBit[4];\r
117 UINT8 WriteLmeMsr[2];\r
118\r
119 UINT8 MoveCr0ToEax[3];\r
120 UINT8 SetCr0PagingBit[4];\r
121 UINT8 MoveEaxToCr0[3];\r
122 //UINT8 DeadLoop[2];\r
123\r
124 UINT8 FarJmp32LongMode; UINT32 LongJmpOffset; UINT16 LongJmpSelector;\r
125#endif // defined (MDE_CPU_X64)\r
126\r
127#if defined (MDE_CPU_X64)\r
128 UINT8 MovEaxOrRaxCpuDxeEntry[2]; UINTN CpuDxeEntryValue;\r
129#else\r
130 UINT8 MovEaxOrRaxCpuDxeEntry; UINTN CpuDxeEntryValue;\r
131#endif\r
132 UINT8 JmpToCpuDxeEntry[2];\r
133\r
134} STARTUP_CODE;\r
135\r
136#pragma pack()\r
137\r
138/**\r
139 This .asm code used for translating processor from 16 bit real mode into\r
140 64 bit long mode. which help to create the mStartupCodeTemplate value.\r
141\r
142 To assemble:\r
143 * nasm -o ApStartup ApStartup.asm\r
144 Then disassemble:\r
145 * ndisasm -b 16 ApStartup\r
146 * ndisasm -b 16 -e 6 ApStartup\r
147 * ndisasm -b 32 -e 32 ApStartup (This -e offset may need adjustment)\r
148 * ndisasm -b 64 -e 0x83 ApStartup (This -e offset may need adjustment)\r
149\r
150 %define DEFAULT_CR0 0x00000023\r
151 %define DEFAULT_CR4 0x640\r
152\r
153 BITS 16\r
154\r
155 jmp short TransitionFromReal16To32BitFlat\r
156\r
157 ALIGN 2\r
158\r
159 Gdtr:\r
160 dw 0x5a5a\r
161 dd 0x5a5a5a5a\r
162\r
163 ;\r
164 ; Modified: EAX, EBX\r
165 ;\r
166 TransitionFromReal16To32BitFlat:\r
167\r
168 cli\r
169 mov ax, 0x5a5a\r
170 mov ds, ax\r
171\r
172 mov bx, Gdtr\r
173 o32 lgdt [ds:bx]\r
174\r
175 mov eax, cr4\r
176 btc eax, 5\r
177 mov cr4, eax\r
178\r
179 mov eax, DEFAULT_CR0\r
180 mov cr0, eax\r
181\r
182 jmp 0x5a5a:dword jumpTo32BitAndLandHere\r
183 BITS 32\r
184 jumpTo32BitAndLandHere:\r
185\r
186 mov eax, DEFAULT_CR4\r
187 mov cr4, eax\r
188\r
189 mov ax, 0x5a5a\r
190 mov ds, ax\r
191 mov es, ax\r
192 mov fs, ax\r
193 mov gs, ax\r
194 mov ss, ax\r
195\r
196 ;\r
197 ; Jump to CpuDxe for IA32\r
198 ;\r
199 mov eax, 0x5a5a5a5a\r
200 or eax, eax\r
201 jz Transition32FlatTo64Flat\r
202 jmp eax\r
203\r
204 ;\r
205 ; Transition to X64\r
206 ;\r
207 Transition32FlatTo64Flat:\r
208 mov eax, 0x5a5a5a5a\r
209 mov cr3, eax\r
210\r
211 mov eax, cr4\r
212 bts eax, 5 ; enable PAE\r
213 mov cr4, eax\r
214\r
215 mov ecx, 0xc0000080\r
216 rdmsr\r
217 bts eax, 8 ; set LME\r
218 wrmsr\r
219\r
220 mov eax, cr0\r
221 bts eax, 31 ; set PG\r
222 mov cr0, eax ; enable paging\r
223\r
224 ;\r
225 ; Jump to CpuDxe for X64\r
226 ;\r
227 jmp 0x5a5a:jumpTo64BitAndLandHere\r
228 BITS 64\r
229 jumpTo64BitAndLandHere:\r
230 mov rax, 0xcdcdcdcdcdcdcdcd\r
231 jmp rax\r
232**/\r
233STARTUP_CODE mStartupCodeTemplate = {\r
234 { 0xeb, 0x06 }, // Jump to cli\r
235 0, // GDT Limit\r
236 0, // GDT Base\r
237 0xfa, // cli (Clear Interrupts)\r
238 0xb8, 0x0000, // mov ax, RealSegment\r
239 { 0x8e, 0xd8 }, // mov ds, ax\r
240 { 0xBB, 0x02, 0x00 }, // mov bx, Gdtr\r
241 { 0x3e, 0x66, 0x0f, 0x01, 0x17 }, // lgdt [ds:bx]\r
242 { 0x66, 0xB8 }, 0x00000023, // mov eax, cr0 value\r
243 { 0x0F, 0x22, 0xC0 }, // mov cr0, eax\r
244 { 0x66, 0xEA }, // far jmp to 32-bit flat\r
245 OFFSET_OF(STARTUP_CODE, MovEaxCr4),\r
246 LINEAR_CODE_SEL,\r
247 0xB8, 0x00000640, // mov eax, cr4 value\r
248 { 0x0F, 0x22, 0xe0 }, // mov cr4, eax\r
249 { 0x66, 0xb8 }, CPU_DATA_SEL, // mov ax, FlatDataSelector\r
250 { 0x8e, 0xd8 }, // mov ds, ax\r
251 { 0x8e, 0xc0 }, // mov es, ax\r
252 { 0x8e, 0xe0 }, // mov fs, ax\r
253 { 0x8e, 0xe8 }, // mov gs, ax\r
254 { 0x8e, 0xd0 }, // mov ss, ax\r
255\r
256#if defined (MDE_CPU_X64)\r
21d0e750
SZ
257 //\r
258 // Code placeholder to enable Execute Disable Bit for X64\r
259 // Default is all NOP - No Operation\r
260 //\r
261 {\r
262 { 0x90, 0x90, 0x90, 0x90, 0x90 },\r
263 { 0x90, 0x90 },\r
264 { 0x90, 0x90, 0x90, 0x90 },\r
265 { 0x90, 0x90 },\r
266 },\r
267\r
533263ee
JJ
268 0xB8, 0x00000000, // mov eax, cr3 value\r
269 { 0x0F, 0x22, 0xd8 }, // mov cr3, eax\r
270\r
271 { 0x0F, 0x20, 0xE0 }, // mov eax, cr4\r
272 { 0x0F, 0xBA, 0xE8, 0x05 }, // bts eax, 5\r
273 { 0x0F, 0x22, 0xE0 }, // mov cr4, eax\r
274\r
275 { 0xB9, 0x80, 0x00, 0x00, 0xC0 }, // mov ecx, 0xc0000080\r
276 { 0x0F, 0x32 }, // rdmsr\r
277 { 0x0F, 0xBA, 0xE8, 0x08 }, // bts eax, 8\r
278 { 0x0F, 0x30 }, // wrmsr\r
279\r
280 { 0x0F, 0x20, 0xC0 }, // mov eax, cr0\r
281 { 0x0F, 0xBA, 0xE8, 0x1F }, // bts eax, 31\r
282 { 0x0F, 0x22, 0xC0 }, // mov cr0, eax\r
283\r
284 0xEA, // FarJmp32LongMode\r
285 OFFSET_OF(STARTUP_CODE, MovEaxOrRaxCpuDxeEntry),\r
286 LINEAR_CODE64_SEL,\r
21d0e750
SZ
287#else\r
288 //\r
289 // Code placeholder to enable PAE Execute Disable for IA32\r
290 // Default is all NOP - No Operation\r
291 //\r
292 {\r
293 { 0x90, 0x90, 0x90, 0x90, 0x90 },\r
294 { 0x90, 0x90 },\r
295 { 0x90, 0x90, 0x90, 0x90 },\r
296 { 0x90, 0x90 },\r
297\r
298 0x90, 0x90909090,\r
299 { 0x90, 0x90, 0x90 },\r
300\r
301 { 0x90, 0x90, 0x90 },\r
302 { 0x90, 0x90, 0x90, 0x90 },\r
303 { 0x90, 0x90, 0x90 },\r
304\r
305 { 0x90, 0x90, 0x90 },\r
306 { 0x90, 0x90, 0x90, 0x90 },\r
307 { 0x90, 0x90, 0x90 },\r
308 },\r
309#endif\r
533263ee
JJ
310\r
311 //0xeb, 0xfe, // jmp $\r
312#if defined (MDE_CPU_X64)\r
313 { 0x48, 0xb8 }, 0x0, // mov rax, X64 CpuDxe MP Entry Point\r
314#else\r
315 0xB8, 0x0, // mov eax, IA32 CpuDxe MP Entry Point\r
316#endif\r
317 { 0xff, 0xe0 }, // jmp to eax/rax (CpuDxe MP Entry Point)\r
318\r
319};\r
320\r
fe078dd5 321volatile STARTUP_CODE *StartupCode = NULL;\r
533263ee 322\r
21d0e750
SZ
323/**\r
324 The function will check if BSP Execute Disable is enabled.\r
325 DxeIpl may have enabled Execute Disable for BSP,\r
326 APs need to get the status and sync up the settings.\r
327\r
328 @retval TRUE BSP Execute Disable is enabled.\r
329 @retval FALSE BSP Execute Disable is not enabled.\r
330\r
331**/\r
332BOOLEAN\r
333IsBspExecuteDisableEnabled (\r
334 VOID\r
335 )\r
336{\r
337 UINT32 RegEax;\r
338 UINT32 RegEdx;\r
339 UINT64 MsrRegisters;\r
340 BOOLEAN Enabled;\r
341\r
342 Enabled = FALSE;\r
343 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
344 if (RegEax >= 0x80000001) {\r
345 AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);\r
346 //\r
347 // Cpuid 0x80000001\r
348 // Bit 20: Execute Disable Bit available.\r
349 //\r
350 if ((RegEdx & BIT20) != 0) {\r
351 MsrRegisters = AsmReadMsr64 (0xC0000080);\r
352 //\r
353 // Msr 0xC0000080\r
354 // Bit 11: Execute Disable Bit enable.\r
355 //\r
356 if ((MsrRegisters & BIT11) != 0) {\r
357 Enabled = TRUE;\r
358 }\r
359 }\r
360 }\r
361\r
362 return Enabled;\r
363}\r
364\r
533263ee 365/**\r
fe078dd5
CF
366 Prepares Startup Code for APs.\r
367 This function prepares Startup Code for APs.\r
533263ee
JJ
368\r
369 @retval EFI_SUCCESS The APs were started\r
370 @retval EFI_OUT_OF_RESOURCES Cannot allocate memory to start APs\r
371\r
372**/\r
373EFI_STATUS\r
fe078dd5
CF
374PrepareAPStartupCode (\r
375 VOID\r
533263ee
JJ
376 )\r
377{\r
378 EFI_STATUS Status;\r
533263ee
JJ
379 IA32_DESCRIPTOR Gdtr;\r
380 EFI_PHYSICAL_ADDRESS StartAddress;\r
381\r
382 StartAddress = BASE_1MB;\r
383 Status = gBS->AllocatePages (\r
384 AllocateMaxAddress,\r
385 EfiACPIMemoryNVS,\r
386 EFI_SIZE_TO_PAGES (sizeof (*StartupCode)),\r
387 &StartAddress\r
388 );\r
389 if (EFI_ERROR (Status)) {\r
390 return Status;\r
391 }\r
392\r
393 StartupCode = (STARTUP_CODE*)(VOID*)(UINTN) StartAddress;\r
394 CopyMem ((VOID*) StartupCode, &mStartupCodeTemplate, sizeof (*StartupCode));\r
395 StartupCode->RealSegment = (UINT16) (((UINTN) StartAddress) >> 4);\r
396\r
397 AsmReadGdtr (&Gdtr);\r
398 StartupCode->GdtLimit = Gdtr.Limit;\r
399 StartupCode->GdtBase = (UINT32) Gdtr.Base;\r
400\r
fe078dd5 401 StartupCode->CpuDxeEntryValue = (UINTN) AsmApEntryPoint;\r
533263ee
JJ
402\r
403 StartupCode->FlatJmpOffset += (UINT32) StartAddress;\r
404\r
21d0e750
SZ
405 if (IsBspExecuteDisableEnabled ()) {\r
406 CopyMem (\r
407 (VOID*) &StartupCode->EnableExecuteDisable,\r
408 &mEnableExecuteDisableCodeTemplate,\r
409 sizeof (ENABLE_EXECUTE_DISABLE_CODE)\r
410 );\r
411 }\r
533263ee
JJ
412#if defined (MDE_CPU_X64)\r
413 StartupCode->Cr3Value = (UINT32) AsmReadCr3 ();\r
414 StartupCode->LongJmpOffset += (UINT32) StartAddress;\r
21d0e750
SZ
415#else\r
416 StartupCode->EnableExecuteDisable.Cr3Value = (UINT32) AsmReadCr3 ();\r
533263ee
JJ
417#endif\r
418\r
fe078dd5
CF
419 return EFI_SUCCESS;\r
420}\r
421\r
422/**\r
423 Free the code buffer of startup AP.\r
424\r
425**/\r
426VOID\r
427FreeApStartupCode (\r
428 VOID\r
429 )\r
430{\r
431 if (StartupCode != NULL) {\r
432 gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)(VOID*) StartupCode,\r
433 EFI_SIZE_TO_PAGES (sizeof (*StartupCode)));\r
434 }\r
435}\r
533263ee 436\r
fe078dd5
CF
437\r
438/**\r
439 Starts the Application Processors and directs them to jump to the\r
440 specified routine.\r
441\r
442 The processor jumps to this code in flat mode, but the processor's\r
443 stack is not initialized.\r
444\r
445 @retval EFI_SUCCESS The APs were started\r
446\r
447**/\r
448EFI_STATUS\r
449StartApsStackless (\r
450 VOID\r
451 )\r
452{\r
453 SendInitSipiSipiAllExcludingSelf ((UINT32)(UINTN)(VOID*) StartupCode);\r
533263ee 454 //\r
1e410ead 455 // Wait for APs to arrive at the ApEntryPoint routine\r
533263ee 456 //\r
1e410ead 457 MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds));\r
533263ee 458\r
533263ee
JJ
459 return EFI_SUCCESS;\r
460}\r
461\r
ac9dbb3b
CF
462/**\r
463 Resets the Application Processor and directs it to jump to the\r
464 specified routine.\r
465\r
466 The processor jumps to this code in flat mode, but the processor's\r
467 stack is not initialized.\r
468\r
469 @param ProcessorId the AP of ProcessorId was reset\r
470**/\r
471VOID\r
472ResetApStackless (\r
473 IN UINT32 ProcessorId\r
474 )\r
475{\r
476 SendInitSipiSipi (ProcessorId,\r
477 (UINT32)(UINTN)(VOID*) StartupCode);\r
478}\r