]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
OvmfPkg: Move the GHCB allocations into reserved memory
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / DxeMpLib.c
CommitLineData
3e8ad6bd
JF
1/** @file\r
2 MP initialize support functions for DXE phase.\r
3\r
c788c2b1 4 Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.<BR>\r
0acd8697 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
3e8ad6bd
JF
6\r
7**/\r
8\r
9#include "MpLib.h"\r
96378861
JF
10\r
11#include <Library/UefiLib.h>\r
12#include <Library/UefiBootServicesTableLib.h>\r
43c9fdcc 13#include <Library/DebugAgentLib.h>\r
15720a6c 14#include <Library/DxeServicesTableLib.h>\r
7b7508ad
TL
15#include <Register/Amd/Fam17Msr.h>\r
16#include <Register/Amd/Ghcb.h>\r
96378861 17\r
b6e45716
JF
18#include <Protocol/Timer.h>\r
19\r
bf2786dc 20#define AP_SAFE_STACK_SIZE 128\r
96378861 21\r
93ca4c0f 22CPU_MP_DATA *mCpuMpData = NULL;\r
96378861 23EFI_EVENT mCheckAllApsEvent = NULL;\r
4d3314f6 24EFI_EVENT mMpInitExitBootServicesEvent = NULL;\r
8677a56a 25EFI_EVENT mLegacyBootEvent = NULL;\r
96378861 26volatile BOOLEAN mStopCheckAllApsStatus = TRUE;\r
5183fb37 27VOID *mReservedApLoopFunc = NULL;\r
bf2786dc 28UINTN mReservedTopOfApStack;\r
9f91cb01 29volatile UINT32 mNumberToFinish = 0;\r
93ca4c0f 30\r
43c9fdcc
JF
31/**\r
32 Enable Debug Agent to support source debugging on AP function.\r
33\r
34**/\r
35VOID\r
36EnableDebugAgent (\r
37 VOID\r
38 )\r
39{\r
40 //\r
41 // Initialize Debug Agent to support source level debug in DXE phase\r
42 //\r
43 InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_AP, NULL, NULL);\r
44}\r
45\r
93ca4c0f
JF
46/**\r
47 Get the pointer to CPU MP Data structure.\r
48\r
49 @return The pointer to CPU MP Data structure.\r
50**/\r
51CPU_MP_DATA *\r
52GetCpuMpData (\r
53 VOID\r
54 )\r
55{\r
56 ASSERT (mCpuMpData != NULL);\r
57 return mCpuMpData;\r
58}\r
59\r
60/**\r
61 Save the pointer to CPU MP Data structure.\r
62\r
63 @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.\r
64**/\r
65VOID\r
66SaveCpuMpData (\r
67 IN CPU_MP_DATA *CpuMpData\r
68 )\r
69{\r
70 mCpuMpData = CpuMpData;\r
71}\r
72\r
96378861 73/**\r
e4ff6349 74 Get available system memory below 0x88000 by specified size.\r
ed66e0e3 75\r
a6b3d753 76 @param[in] WakeupBufferSize Wakeup buffer size required\r
3ed4e502 77\r
a6b3d753
SZ
78 @retval other Return wakeup buffer address below 1MB.\r
79 @retval -1 Cannot find free memory below 1MB.\r
ed66e0e3 80**/\r
a6b3d753
SZ
81UINTN\r
82GetWakeupBuffer (\r
83 IN UINTN WakeupBufferSize\r
ed66e0e3
JF
84 )\r
85{\r
a6b3d753
SZ
86 EFI_STATUS Status;\r
87 EFI_PHYSICAL_ADDRESS StartAddress;\r
88\r
e4ff6349
ED
89 //\r
90 // Try to allocate buffer below 1M for waking vector.\r
91 // LegacyBios driver only reports warning when page allocation in range\r
92 // [0x60000, 0x88000) fails.\r
93 // This library is consumed by CpuDxe driver to produce CPU Arch protocol.\r
94 // LagacyBios driver depends on CPU Arch protocol which guarantees below\r
95 // allocation runs earlier than LegacyBios driver.\r
96 //\r
97 StartAddress = 0x88000;\r
a6b3d753
SZ
98 Status = gBS->AllocatePages (\r
99 AllocateMaxAddress,\r
100 EfiBootServicesData,\r
101 EFI_SIZE_TO_PAGES (WakeupBufferSize),\r
102 &StartAddress\r
103 );\r
104 ASSERT_EFI_ERROR (Status);\r
e4ff6349 105 if (EFI_ERROR (Status)) {\r
a6b3d753 106 StartAddress = (EFI_PHYSICAL_ADDRESS) -1;\r
3ed4e502 107 }\r
e4ff6349
ED
108\r
109 DEBUG ((DEBUG_INFO, "WakeupBufferStart = %x, WakeupBufferSize = %x\n",\r
110 (UINTN) StartAddress, WakeupBufferSize));\r
111\r
a6b3d753 112 return (UINTN) StartAddress;\r
ed66e0e3
JF
113}\r
114\r
f32bfe6d
JW
115/**\r
116 Get available EfiBootServicesCode memory below 4GB by specified size.\r
117\r
118 This buffer is required to safely transfer AP from real address mode to\r
119 protected mode or long mode, due to the fact that the buffer returned by\r
120 GetWakeupBuffer() may be marked as non-executable.\r
121\r
122 @param[in] BufferSize Wakeup transition buffer size.\r
123\r
124 @retval other Return wakeup transition buffer address below 4GB.\r
125 @retval 0 Cannot find free memory below 4GB.\r
126**/\r
127UINTN\r
128GetModeTransitionBuffer (\r
129 IN UINTN BufferSize\r
130 )\r
131{\r
132 EFI_STATUS Status;\r
133 EFI_PHYSICAL_ADDRESS StartAddress;\r
134\r
135 StartAddress = BASE_4GB - 1;\r
136 Status = gBS->AllocatePages (\r
137 AllocateMaxAddress,\r
138 EfiBootServicesCode,\r
139 EFI_SIZE_TO_PAGES (BufferSize),\r
140 &StartAddress\r
141 );\r
142 if (EFI_ERROR (Status)) {\r
143 StartAddress = 0;\r
144 }\r
145\r
146 return (UINTN)StartAddress;\r
147}\r
148\r
7b7508ad
TL
149/**\r
150 Return the address of the SEV-ES AP jump table.\r
151\r
152 This buffer is required in order for an SEV-ES guest to transition from\r
153 UEFI into an OS.\r
154\r
155 @return Return SEV-ES AP jump table buffer\r
156**/\r
157UINTN\r
158GetSevEsAPMemory (\r
159 VOID\r
160 )\r
161{\r
162 EFI_STATUS Status;\r
163 EFI_PHYSICAL_ADDRESS StartAddress;\r
164\r
165 //\r
166 // Allocate 1 page for AP jump table page\r
167 //\r
168 StartAddress = BASE_4GB - 1;\r
169 Status = gBS->AllocatePages (\r
170 AllocateMaxAddress,\r
171 EfiReservedMemoryType,\r
172 1,\r
173 &StartAddress\r
174 );\r
175 ASSERT_EFI_ERROR (Status);\r
176\r
177 DEBUG ((DEBUG_INFO, "Dxe: SevEsAPMemory = %lx\n", (UINTN) StartAddress));\r
178\r
179 return (UINTN) StartAddress;\r
180}\r
181\r
96378861
JF
182/**\r
183 Checks APs status and updates APs status if needed.\r
184\r
185**/\r
186VOID\r
187CheckAndUpdateApsStatus (\r
188 VOID\r
189 )\r
190{\r
08085f08
JF
191 UINTN ProcessorNumber;\r
192 EFI_STATUS Status;\r
193 CPU_MP_DATA *CpuMpData;\r
194\r
195 CpuMpData = GetCpuMpData ();\r
196\r
197 //\r
198 // First, check whether pending StartupAllAPs() exists.\r
199 //\r
200 if (CpuMpData->WaitEvent != NULL) {\r
201\r
202 Status = CheckAllAPs ();\r
203 //\r
204 // If all APs finish for StartupAllAPs(), signal the WaitEvent for it.\r
205 //\r
206 if (Status != EFI_NOT_READY) {\r
207 Status = gBS->SignalEvent (CpuMpData->WaitEvent);\r
208 CpuMpData->WaitEvent = NULL;\r
209 }\r
210 }\r
211\r
212 //\r
213 // Second, check whether pending StartupThisAPs() callings exist.\r
214 //\r
215 for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {\r
216\r
217 if (CpuMpData->CpuData[ProcessorNumber].WaitEvent == NULL) {\r
218 continue;\r
219 }\r
220\r
221 Status = CheckThisAP (ProcessorNumber);\r
222\r
223 if (Status != EFI_NOT_READY) {\r
224 gBS->SignalEvent (CpuMpData->CpuData[ProcessorNumber].WaitEvent);\r
225 CpuMpData->CpuData[ProcessorNumber].WaitEvent = NULL;\r
226 }\r
227 }\r
96378861
JF
228}\r
229\r
230/**\r
231 Checks APs' status periodically.\r
232\r
438f1766 233 This function is triggered by timer periodically to check the\r
96378861
JF
234 state of APs for StartupAllAPs() and StartupThisAP() executed\r
235 in non-blocking mode.\r
236\r
237 @param[in] Event Event triggered.\r
238 @param[in] Context Parameter passed with the event.\r
239\r
240**/\r
241VOID\r
242EFIAPI\r
243CheckApsStatus (\r
244 IN EFI_EVENT Event,\r
245 IN VOID *Context\r
246 )\r
247{\r
248 //\r
249 // If CheckApsStatus() is not stopped, otherwise return immediately.\r
250 //\r
251 if (!mStopCheckAllApsStatus) {\r
252 CheckAndUpdateApsStatus ();\r
253 }\r
254}\r
ed66e0e3 255\r
7b7508ad
TL
256/**\r
257 Get Protected mode code segment with 16-bit default addressing\r
258 from current GDT table.\r
259\r
260 @return Protected mode 16-bit code segment value.\r
261**/\r
262UINT16\r
263GetProtectedMode16CS (\r
264 VOID\r
265 )\r
266{\r
267 IA32_DESCRIPTOR GdtrDesc;\r
268 IA32_SEGMENT_DESCRIPTOR *GdtEntry;\r
269 UINTN GdtEntryCount;\r
270 UINT16 Index;\r
271\r
272 Index = (UINT16) -1;\r
273 AsmReadGdtr (&GdtrDesc);\r
274 GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);\r
275 GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base;\r
276 for (Index = 0; Index < GdtEntryCount; Index++) {\r
277 if (GdtEntry->Bits.L == 0) {\r
278 if (GdtEntry->Bits.Type > 8 && GdtEntry->Bits.DB == 0) {\r
279 break;\r
280 }\r
281 }\r
282 GdtEntry++;\r
283 }\r
284 ASSERT (Index != GdtEntryCount);\r
285 return Index * 8;\r
286}\r
287\r
4d3314f6
JF
288/**\r
289 Get Protected mode code segment from current GDT table.\r
290\r
b31c1ad1 291 @return Protected mode code segment value.\r
4d3314f6
JF
292**/\r
293UINT16\r
294GetProtectedModeCS (\r
295 VOID\r
296 )\r
297{\r
298 IA32_DESCRIPTOR GdtrDesc;\r
299 IA32_SEGMENT_DESCRIPTOR *GdtEntry;\r
300 UINTN GdtEntryCount;\r
301 UINT16 Index;\r
302\r
4d3314f6
JF
303 AsmReadGdtr (&GdtrDesc);\r
304 GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);\r
305 GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base;\r
306 for (Index = 0; Index < GdtEntryCount; Index++) {\r
307 if (GdtEntry->Bits.L == 0) {\r
7b7508ad 308 if (GdtEntry->Bits.Type > 8 && GdtEntry->Bits.DB == 1) {\r
4d3314f6
JF
309 break;\r
310 }\r
311 }\r
312 GdtEntry++;\r
313 }\r
37fba7c2 314 ASSERT (Index != GdtEntryCount);\r
4d3314f6
JF
315 return Index * 8;\r
316}\r
317\r
318/**\r
319 Do sync on APs.\r
320\r
321 @param[in, out] Buffer Pointer to private data buffer.\r
322**/\r
323VOID\r
324EFIAPI\r
325RelocateApLoop (\r
326 IN OUT VOID *Buffer\r
327 )\r
328{\r
329 CPU_MP_DATA *CpuMpData;\r
330 BOOLEAN MwaitSupport;\r
331 ASM_RELOCATE_AP_LOOP AsmRelocateApLoopFunc;\r
bf2786dc 332 UINTN ProcessorNumber;\r
4d3314f6 333\r
7367cc6c 334 MpInitLibWhoAmI (&ProcessorNumber);\r
4d3314f6
JF
335 CpuMpData = GetCpuMpData ();\r
336 MwaitSupport = IsMwaitSupport ();\r
081f6416 337 AsmRelocateApLoopFunc = (ASM_RELOCATE_AP_LOOP) (UINTN) mReservedApLoopFunc;\r
bf2786dc
JF
338 AsmRelocateApLoopFunc (\r
339 MwaitSupport,\r
340 CpuMpData->ApTargetCState,\r
341 CpuMpData->PmCodeSegment,\r
9f91cb01
JF
342 mReservedTopOfApStack - ProcessorNumber * AP_SAFE_STACK_SIZE,\r
343 (UINTN) &mNumberToFinish\r
bf2786dc 344 );\r
4d3314f6
JF
345 //\r
346 // It should never reach here\r
347 //\r
348 ASSERT (FALSE);\r
349}\r
350\r
351/**\r
352 Callback function for ExitBootServices.\r
353\r
354 @param[in] Event Event whose notification function is being invoked.\r
355 @param[in] Context The pointer to the notification function's context,\r
356 which is implementation-dependent.\r
357\r
358**/\r
359VOID\r
360EFIAPI\r
86af2eb8 361MpInitChangeApLoopCallback (\r
4d3314f6
JF
362 IN EFI_EVENT Event,\r
363 IN VOID *Context\r
364 )\r
365{\r
366 CPU_MP_DATA *CpuMpData;\r
5183fb37 367\r
4d3314f6
JF
368 CpuMpData = GetCpuMpData ();\r
369 CpuMpData->PmCodeSegment = GetProtectedModeCS ();\r
7b7508ad 370 CpuMpData->Pm16CodeSegment = GetProtectedMode16CS ();\r
4d3314f6 371 CpuMpData->ApLoopMode = PcdGet8 (PcdCpuApLoopMode);\r
9f91cb01 372 mNumberToFinish = CpuMpData->CpuCount - 1;\r
cf4e79e4 373 WakeUpAP (CpuMpData, TRUE, 0, RelocateApLoop, NULL, TRUE);\r
9f91cb01
JF
374 while (mNumberToFinish > 0) {\r
375 CpuPause ();\r
376 }\r
86af2eb8 377 DEBUG ((DEBUG_INFO, "%a() done!\n", __FUNCTION__));\r
4d3314f6
JF
378}\r
379\r
93ca4c0f
JF
380/**\r
381 Initialize global data for MP support.\r
382\r
383 @param[in] CpuMpData The pointer to CPU MP Data structure.\r
384**/\r
385VOID\r
386InitMpGlobalData (\r
387 IN CPU_MP_DATA *CpuMpData\r
388 )\r
389{\r
15720a6c
JW
390 EFI_STATUS Status;\r
391 EFI_PHYSICAL_ADDRESS Address;\r
392 UINTN ApSafeBufferSize;\r
393 UINTN Index;\r
394 EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc;\r
395 UINTN StackBase;\r
52315261 396 CPU_INFO_IN_HOB *CpuInfoInHob;\r
96378861 397\r
93ca4c0f
JF
398 SaveCpuMpData (CpuMpData);\r
399\r
14e8137c
JF
400 if (CpuMpData->CpuCount == 1) {\r
401 //\r
402 // If only BSP exists, return\r
403 //\r
404 return;\r
405 }\r
406\r
15720a6c
JW
407 if (PcdGetBool (PcdCpuStackGuard)) {\r
408 //\r
409 // One extra page at the bottom of the stack is needed for Guard page.\r
410 //\r
411 if (CpuMpData->CpuApStackSize <= EFI_PAGE_SIZE) {\r
412 DEBUG ((DEBUG_ERROR, "PcdCpuApStackSize is not big enough for Stack Guard!\n"));\r
413 ASSERT (FALSE);\r
414 }\r
415\r
52315261
JW
416 //\r
417 // DXE will reuse stack allocated for APs at PEI phase if it's available.\r
418 // Let's check it here.\r
419 //\r
420 // Note: BSP's stack guard is set at DxeIpl phase. But for the sake of\r
421 // BSP/AP exchange, stack guard for ApTopOfStack of cpu 0 will still be\r
422 // set here.\r
423 //\r
424 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;\r
15720a6c 425 for (Index = 0; Index < CpuMpData->CpuCount; ++Index) {\r
52315261 426 if (CpuInfoInHob != NULL && CpuInfoInHob[Index].ApTopOfStack != 0) {\r
20737c2f 427 StackBase = (UINTN)CpuInfoInHob[Index].ApTopOfStack - CpuMpData->CpuApStackSize;\r
52315261
JW
428 } else {\r
429 StackBase = CpuMpData->Buffer + Index * CpuMpData->CpuApStackSize;\r
430 }\r
15720a6c
JW
431\r
432 Status = gDS->GetMemorySpaceDescriptor (StackBase, &MemDesc);\r
433 ASSERT_EFI_ERROR (Status);\r
434\r
435 Status = gDS->SetMemorySpaceAttributes (\r
436 StackBase,\r
437 EFI_PAGES_TO_SIZE (1),\r
438 MemDesc.Attributes | EFI_MEMORY_RP\r
439 );\r
440 ASSERT_EFI_ERROR (Status);\r
52315261
JW
441\r
442 DEBUG ((DEBUG_INFO, "Stack Guard set at %lx [cpu%lu]!\n",\r
443 (UINT64)StackBase, (UINT64)Index));\r
15720a6c
JW
444 }\r
445 }\r
446\r
5183fb37 447 //\r
ffd6b0b1
JF
448 // Avoid APs access invalid buffer data which allocated by BootServices,\r
449 // so we will allocate reserved data for AP loop code. We also need to\r
450 // allocate this buffer below 4GB due to APs may be transferred to 32bit\r
451 // protected mode on long mode DXE.\r
5183fb37
JF
452 // Allocating it in advance since memory services are not available in\r
453 // Exit Boot Services callback function.\r
454 //\r
bc2288f5
JW
455 ApSafeBufferSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (\r
456 CpuMpData->AddressMap.RelocateApLoopFuncSize\r
457 ));\r
ffd6b0b1
JF
458 Address = BASE_4GB - 1;\r
459 Status = gBS->AllocatePages (\r
460 AllocateMaxAddress,\r
461 EfiReservedMemoryType,\r
bf2786dc 462 EFI_SIZE_TO_PAGES (ApSafeBufferSize),\r
ffd6b0b1
JF
463 &Address\r
464 );\r
465 ASSERT_EFI_ERROR (Status);\r
bc2288f5 466\r
ffd6b0b1 467 mReservedApLoopFunc = (VOID *) (UINTN) Address;\r
5183fb37 468 ASSERT (mReservedApLoopFunc != NULL);\r
bc2288f5
JW
469\r
470 //\r
471 // Make sure that the buffer memory is executable if NX protection is enabled\r
472 // for EfiReservedMemoryType.\r
7367cc6c 473 //\r
bc2288f5
JW
474 // TODO: Check EFI_MEMORY_XP bit set or not once it's available in DXE GCD\r
475 // service.\r
476 //\r
477 Status = gDS->GetMemorySpaceDescriptor (Address, &MemDesc);\r
478 if (!EFI_ERROR (Status)) {\r
479 gDS->SetMemorySpaceAttributes (\r
480 Address,\r
481 ApSafeBufferSize,\r
482 MemDesc.Attributes & (~EFI_MEMORY_XP)\r
483 );\r
484 }\r
485\r
486 ApSafeBufferSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (\r
487 CpuMpData->CpuCount * AP_SAFE_STACK_SIZE\r
488 ));\r
489 Address = BASE_4GB - 1;\r
490 Status = gBS->AllocatePages (\r
491 AllocateMaxAddress,\r
492 EfiReservedMemoryType,\r
493 EFI_SIZE_TO_PAGES (ApSafeBufferSize),\r
494 &Address\r
495 );\r
496 ASSERT_EFI_ERROR (Status);\r
497\r
498 mReservedTopOfApStack = (UINTN) Address + ApSafeBufferSize;\r
bf2786dc 499 ASSERT ((mReservedTopOfApStack & (UINTN)(CPU_STACK_ALIGNMENT - 1)) == 0);\r
ffd6b0b1
JF
500 CopyMem (\r
501 mReservedApLoopFunc,\r
502 CpuMpData->AddressMap.RelocateApLoopFuncAddress,\r
503 CpuMpData->AddressMap.RelocateApLoopFuncSize\r
504 );\r
5183fb37 505\r
96378861
JF
506 Status = gBS->CreateEvent (\r
507 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
508 TPL_NOTIFY,\r
509 CheckApsStatus,\r
510 NULL,\r
511 &mCheckAllApsEvent\r
512 );\r
513 ASSERT_EFI_ERROR (Status);\r
514\r
515 //\r
516 // Set timer to check all APs status.\r
517 //\r
518 Status = gBS->SetTimer (\r
519 mCheckAllApsEvent,\r
520 TimerPeriodic,\r
a1c35ff3
HW
521 EFI_TIMER_PERIOD_MICROSECONDS (\r
522 PcdGet32 (PcdCpuApStatusCheckIntervalInMicroSeconds)\r
523 )\r
96378861
JF
524 );\r
525 ASSERT_EFI_ERROR (Status);\r
8677a56a 526\r
4d3314f6
JF
527 Status = gBS->CreateEvent (\r
528 EVT_SIGNAL_EXIT_BOOT_SERVICES,\r
529 TPL_CALLBACK,\r
86af2eb8 530 MpInitChangeApLoopCallback,\r
4d3314f6
JF
531 NULL,\r
532 &mMpInitExitBootServicesEvent\r
533 );\r
534 ASSERT_EFI_ERROR (Status);\r
8677a56a
JF
535\r
536 Status = gBS->CreateEventEx (\r
537 EVT_NOTIFY_SIGNAL,\r
538 TPL_CALLBACK,\r
539 MpInitChangeApLoopCallback,\r
540 NULL,\r
541 &gEfiEventLegacyBootGuid,\r
542 &mLegacyBootEvent\r
543 );\r
544 ASSERT_EFI_ERROR (Status);\r
93ca4c0f 545}\r
3e8ad6bd
JF
546\r
547/**\r
548 This service executes a caller provided function on all enabled APs.\r
549\r
550 @param[in] Procedure A pointer to the function to be run on\r
551 enabled APs of the system. See type\r
552 EFI_AP_PROCEDURE.\r
553 @param[in] SingleThread If TRUE, then all the enabled APs execute\r
554 the function specified by Procedure one by\r
555 one, in ascending order of processor handle\r
556 number. If FALSE, then all the enabled APs\r
557 execute the function specified by Procedure\r
558 simultaneously.\r
559 @param[in] WaitEvent The event created by the caller with CreateEvent()\r
560 service. If it is NULL, then execute in\r
561 blocking mode. BSP waits until all APs finish\r
562 or TimeoutInMicroSeconds expires. If it's\r
563 not NULL, then execute in non-blocking mode.\r
564 BSP requests the function specified by\r
565 Procedure to be started on all the enabled\r
566 APs, and go on executing immediately. If\r
567 all return from Procedure, or TimeoutInMicroSeconds\r
568 expires, this event is signaled. The BSP\r
569 can use the CheckEvent() or WaitForEvent()\r
570 services to check the state of event. Type\r
571 EFI_EVENT is defined in CreateEvent() in\r
572 the Unified Extensible Firmware Interface\r
573 Specification.\r
367284e7 574 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for\r
3e8ad6bd
JF
575 APs to return from Procedure, either for\r
576 blocking or non-blocking mode. Zero means\r
577 infinity. If the timeout expires before\r
578 all APs return from Procedure, then Procedure\r
579 on the failed APs is terminated. All enabled\r
580 APs are available for next function assigned\r
581 by MpInitLibStartupAllAPs() or\r
582 MPInitLibStartupThisAP().\r
583 If the timeout expires in blocking mode,\r
584 BSP returns EFI_TIMEOUT. If the timeout\r
585 expires in non-blocking mode, WaitEvent\r
586 is signaled with SignalEvent().\r
587 @param[in] ProcedureArgument The parameter passed into Procedure for\r
588 all APs.\r
589 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,\r
590 if all APs finish successfully, then its\r
591 content is set to NULL. If not all APs\r
592 finish before timeout expires, then its\r
593 content is set to address of the buffer\r
594 holding handle numbers of the failed APs.\r
595 The buffer is allocated by MP Initialization\r
596 library, and it's the caller's responsibility to\r
597 free the buffer with FreePool() service.\r
598 In blocking mode, it is ready for consumption\r
599 when the call returns. In non-blocking mode,\r
600 it is ready when WaitEvent is signaled. The\r
601 list of failed CPU is terminated by\r
602 END_OF_CPU_LIST.\r
603\r
604 @retval EFI_SUCCESS In blocking mode, all APs have finished before\r
605 the timeout expired.\r
606 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched\r
607 to all enabled APs.\r
608 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the\r
609 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was\r
610 signaled.\r
611 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not\r
612 supported.\r
613 @retval EFI_DEVICE_ERROR Caller processor is AP.\r
614 @retval EFI_NOT_STARTED No enabled APs exist in the system.\r
615 @retval EFI_NOT_READY Any enabled APs are busy.\r
616 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
617 @retval EFI_TIMEOUT In blocking mode, the timeout expired before\r
618 all enabled APs have finished.\r
619 @retval EFI_INVALID_PARAMETER Procedure is NULL.\r
620\r
621**/\r
622EFI_STATUS\r
623EFIAPI\r
624MpInitLibStartupAllAPs (\r
625 IN EFI_AP_PROCEDURE Procedure,\r
626 IN BOOLEAN SingleThread,\r
627 IN EFI_EVENT WaitEvent OPTIONAL,\r
628 IN UINTN TimeoutInMicroseconds,\r
629 IN VOID *ProcedureArgument OPTIONAL,\r
630 OUT UINTN **FailedCpuList OPTIONAL\r
631 )\r
632{\r
86efe976
JF
633 EFI_STATUS Status;\r
634\r
635 //\r
636 // Temporarily stop checkAllApsStatus for avoid resource dead-lock.\r
637 //\r
638 mStopCheckAllApsStatus = TRUE;\r
639\r
ee0c39fa 640 Status = StartupAllCPUsWorker (\r
86efe976
JF
641 Procedure,\r
642 SingleThread,\r
ee0c39fa 643 TRUE,\r
86efe976
JF
644 WaitEvent,\r
645 TimeoutInMicroseconds,\r
646 ProcedureArgument,\r
647 FailedCpuList\r
648 );\r
649\r
650 //\r
651 // Start checkAllApsStatus\r
652 //\r
653 mStopCheckAllApsStatus = FALSE;\r
654\r
655 return Status;\r
3e8ad6bd
JF
656}\r
657\r
658/**\r
659 This service lets the caller get one enabled AP to execute a caller-provided\r
660 function.\r
661\r
662 @param[in] Procedure A pointer to the function to be run on the\r
663 designated AP of the system. See type\r
664 EFI_AP_PROCEDURE.\r
665 @param[in] ProcessorNumber The handle number of the AP. The range is\r
666 from 0 to the total number of logical\r
667 processors minus 1. The total number of\r
668 logical processors can be retrieved by\r
669 MpInitLibGetNumberOfProcessors().\r
670 @param[in] WaitEvent The event created by the caller with CreateEvent()\r
671 service. If it is NULL, then execute in\r
672 blocking mode. BSP waits until this AP finish\r
673 or TimeoutInMicroSeconds expires. If it's\r
674 not NULL, then execute in non-blocking mode.\r
675 BSP requests the function specified by\r
676 Procedure to be started on this AP,\r
677 and go on executing immediately. If this AP\r
678 return from Procedure or TimeoutInMicroSeconds\r
679 expires, this event is signaled. The BSP\r
680 can use the CheckEvent() or WaitForEvent()\r
681 services to check the state of event. Type\r
682 EFI_EVENT is defined in CreateEvent() in\r
683 the Unified Extensible Firmware Interface\r
684 Specification.\r
367284e7 685 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for\r
3e8ad6bd
JF
686 this AP to finish this Procedure, either for\r
687 blocking or non-blocking mode. Zero means\r
688 infinity. If the timeout expires before\r
689 this AP returns from Procedure, then Procedure\r
690 on the AP is terminated. The\r
691 AP is available for next function assigned\r
692 by MpInitLibStartupAllAPs() or\r
693 MpInitLibStartupThisAP().\r
694 If the timeout expires in blocking mode,\r
695 BSP returns EFI_TIMEOUT. If the timeout\r
696 expires in non-blocking mode, WaitEvent\r
697 is signaled with SignalEvent().\r
698 @param[in] ProcedureArgument The parameter passed into Procedure on the\r
699 specified AP.\r
700 @param[out] Finished If NULL, this parameter is ignored. In\r
701 blocking mode, this parameter is ignored.\r
702 In non-blocking mode, if AP returns from\r
703 Procedure before the timeout expires, its\r
704 content is set to TRUE. Otherwise, the\r
705 value is set to FALSE. The caller can\r
706 determine if the AP returned from Procedure\r
707 by evaluating this value.\r
708\r
709 @retval EFI_SUCCESS In blocking mode, specified AP finished before\r
710 the timeout expires.\r
711 @retval EFI_SUCCESS In non-blocking mode, the function has been\r
712 dispatched to specified AP.\r
713 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the\r
714 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was\r
715 signaled.\r
716 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not\r
717 supported.\r
718 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
719 @retval EFI_TIMEOUT In blocking mode, the timeout expired before\r
720 the specified AP has finished.\r
721 @retval EFI_NOT_READY The specified AP is busy.\r
722 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
723 @retval EFI_NOT_FOUND The processor with the handle specified by\r
724 ProcessorNumber does not exist.\r
725 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.\r
726 @retval EFI_INVALID_PARAMETER Procedure is NULL.\r
727\r
728**/\r
729EFI_STATUS\r
730EFIAPI\r
731MpInitLibStartupThisAP (\r
732 IN EFI_AP_PROCEDURE Procedure,\r
733 IN UINTN ProcessorNumber,\r
734 IN EFI_EVENT WaitEvent OPTIONAL,\r
735 IN UINTN TimeoutInMicroseconds,\r
736 IN VOID *ProcedureArgument OPTIONAL,\r
737 OUT BOOLEAN *Finished OPTIONAL\r
738 )\r
739{\r
20ae5774
JF
740 EFI_STATUS Status;\r
741\r
742 //\r
743 // temporarily stop checkAllApsStatus for avoid resource dead-lock.\r
744 //\r
745 mStopCheckAllApsStatus = TRUE;\r
746\r
747 Status = StartupThisAPWorker (\r
748 Procedure,\r
749 ProcessorNumber,\r
750 WaitEvent,\r
751 TimeoutInMicroseconds,\r
752 ProcedureArgument,\r
753 Finished\r
754 );\r
755\r
756 mStopCheckAllApsStatus = FALSE;\r
757\r
758 return Status;\r
3e8ad6bd
JF
759}\r
760\r
761/**\r
762 This service switches the requested AP to be the BSP from that point onward.\r
763 This service changes the BSP for all purposes. This call can only be performed\r
764 by the current BSP.\r
765\r
766 @param[in] ProcessorNumber The handle number of AP that is to become the new\r
767 BSP. The range is from 0 to the total number of\r
768 logical processors minus 1. The total number of\r
769 logical processors can be retrieved by\r
770 MpInitLibGetNumberOfProcessors().\r
771 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an\r
772 enabled AP. Otherwise, it will be disabled.\r
773\r
774 @retval EFI_SUCCESS BSP successfully switched.\r
775 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to\r
776 this service returning.\r
777 @retval EFI_UNSUPPORTED Switching the BSP is not supported.\r
778 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
779 @retval EFI_NOT_FOUND The processor with the handle specified by\r
780 ProcessorNumber does not exist.\r
781 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or\r
782 a disabled AP.\r
783 @retval EFI_NOT_READY The specified AP is busy.\r
784 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
785\r
786**/\r
787EFI_STATUS\r
788EFIAPI\r
789MpInitLibSwitchBSP (\r
790 IN UINTN ProcessorNumber,\r
791 IN BOOLEAN EnableOldBSP\r
792 )\r
793{\r
b6e45716
JF
794 EFI_STATUS Status;\r
795 EFI_TIMER_ARCH_PROTOCOL *Timer;\r
796 UINT64 TimerPeriod;\r
41be0da5 797\r
8ad05bd2 798 TimerPeriod = 0;\r
b6e45716
JF
799 //\r
800 // Locate Timer Arch Protocol\r
801 //\r
802 Status = gBS->LocateProtocol (&gEfiTimerArchProtocolGuid, NULL, (VOID **) &Timer);\r
803 if (EFI_ERROR (Status)) {\r
804 Timer = NULL;\r
805 }\r
806\r
807 if (Timer != NULL) {\r
808 //\r
809 // Save current rate of DXE Timer\r
810 //\r
811 Timer->GetTimerPeriod (Timer, &TimerPeriod);\r
812 //\r
813 // Disable DXE Timer and drain pending interrupts\r
814 //\r
815 Timer->SetTimerPeriod (Timer, 0);\r
816 }\r
41be0da5
JF
817\r
818 Status = SwitchBSPWorker (ProcessorNumber, EnableOldBSP);\r
819\r
b6e45716
JF
820 if (Timer != NULL) {\r
821 //\r
822 // Enable and restore rate of DXE Timer\r
823 //\r
824 Timer->SetTimerPeriod (Timer, TimerPeriod);\r
825 }\r
826\r
41be0da5 827 return Status;\r
3e8ad6bd
JF
828}\r
829\r
830/**\r
831 This service lets the caller enable or disable an AP from this point onward.\r
832 This service may only be called from the BSP.\r
833\r
834 @param[in] ProcessorNumber The handle number of AP.\r
835 The range is from 0 to the total number of\r
836 logical processors minus 1. The total number of\r
837 logical processors can be retrieved by\r
838 MpInitLibGetNumberOfProcessors().\r
839 @param[in] EnableAP Specifies the new state for the processor for\r
840 enabled, FALSE for disabled.\r
841 @param[in] HealthFlag If not NULL, a pointer to a value that specifies\r
842 the new health status of the AP. This flag\r
843 corresponds to StatusFlag defined in\r
844 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only\r
845 the PROCESSOR_HEALTH_STATUS_BIT is used. All other\r
846 bits are ignored. If it is NULL, this parameter\r
847 is ignored.\r
848\r
849 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.\r
850 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed\r
851 prior to this service returning.\r
852 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.\r
853 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
854 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber\r
855 does not exist.\r
856 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.\r
857 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
858\r
859**/\r
860EFI_STATUS\r
861EFIAPI\r
862MpInitLibEnableDisableAP (\r
863 IN UINTN ProcessorNumber,\r
864 IN BOOLEAN EnableAP,\r
865 IN UINT32 *HealthFlag OPTIONAL\r
866 )\r
867{\r
e37109bc
JF
868 EFI_STATUS Status;\r
869 BOOLEAN TempStopCheckState;\r
870\r
871 TempStopCheckState = FALSE;\r
872 //\r
873 // temporarily stop checkAllAPsStatus for initialize parameters.\r
874 //\r
875 if (!mStopCheckAllApsStatus) {\r
876 mStopCheckAllApsStatus = TRUE;\r
877 TempStopCheckState = TRUE;\r
878 }\r
879\r
880 Status = EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag);\r
881\r
882 if (TempStopCheckState) {\r
883 mStopCheckAllApsStatus = FALSE;\r
884 }\r
885\r
886 return Status;\r
3e8ad6bd 887}\r
c788c2b1
SF
888\r
889/**\r
890 This funtion will try to invoke platform specific microcode shadow logic to\r
891 relocate microcode update patches into memory.\r
892\r
4ac82ea1 893 @param[in, out] CpuMpData The pointer to CPU MP Data structure.\r
c788c2b1
SF
894\r
895 @retval EFI_SUCCESS Shadow microcode success.\r
896 @retval EFI_OUT_OF_RESOURCES No enough resource to complete the operation.\r
897 @retval EFI_UNSUPPORTED Can't find platform specific microcode shadow\r
898 PPI/Protocol.\r
899**/\r
900EFI_STATUS\r
901PlatformShadowMicrocode (\r
902 IN OUT CPU_MP_DATA *CpuMpData\r
903 )\r
904{\r
905 //\r
906 // There is no DXE version of platform shadow microcode protocol so far.\r
907 // A platform which only uses DxeMpInitLib instance could only supports\r
908 // the PCD based microcode shadowing.\r
909 //\r
910 return EFI_UNSUPPORTED;\r
911}\r