]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
MpInitLib: Allocate code buffer for PEI phase
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / PeiMpLib.c
CommitLineData
3e8ad6bd
JF
1/** @file\r
2 MP initialize support functions for PEI phase.\r
3\r
348a34d9 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
58942277
ED
10#include <Library/PeiServicesLib.h>\r
11#include <Guid/S3SmmInitDone.h>\r
c788c2b1 12#include <Ppi/ShadowMicrocode.h>\r
58942277 13\r
053e878b 14STATIC UINT64 mSevEsPeiWakeupBuffer = BASE_1MB;\r
dbc22a17 15\r
58942277
ED
16/**\r
17 S3 SMM Init Done notification function.\r
18\r
19 @param PeiServices Indirect reference to the PEI Services Table.\r
20 @param NotifyDesc Address of the notification descriptor data structure.\r
21 @param InvokePpi Address of the PPI that was invoked.\r
22\r
23 @retval EFI_SUCCESS The function completes successfully.\r
24\r
25**/\r
26EFI_STATUS\r
27EFIAPI\r
28NotifyOnS3SmmInitDonePpi (\r
053e878b
MK
29 IN EFI_PEI_SERVICES **PeiServices,\r
30 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,\r
31 IN VOID *InvokePpi\r
58942277
ED
32 );\r
33\r
58942277
ED
34//\r
35// Global function\r
36//\r
053e878b 37EFI_PEI_NOTIFY_DESCRIPTOR mS3SmmInitDoneNotifyDesc = {\r
58942277
ED
38 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
39 &gEdkiiS3SmmInitDoneGuid,\r
40 NotifyOnS3SmmInitDonePpi\r
41};\r
42\r
58942277
ED
43/**\r
44 S3 SMM Init Done notification function.\r
45\r
46 @param PeiServices Indirect reference to the PEI Services Table.\r
47 @param NotifyDesc Address of the notification descriptor data structure.\r
48 @param InvokePpi Address of the PPI that was invoked.\r
49\r
50 @retval EFI_SUCCESS The function completes successfully.\r
51\r
52**/\r
53EFI_STATUS\r
54EFIAPI\r
55NotifyOnS3SmmInitDonePpi (\r
053e878b
MK
56 IN EFI_PEI_SERVICES **PeiServices,\r
57 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,\r
58 IN VOID *InvokePpi\r
58942277
ED
59 )\r
60{\r
053e878b 61 CPU_MP_DATA *CpuMpData;\r
58942277
ED
62\r
63 CpuMpData = GetCpuMpData ();\r
64\r
65 //\r
66 // PiSmmCpuDxeSmm driver hardcode change the loop mode to HLT mode.\r
67 // So in this notify function, code need to check the current loop\r
68 // mode, if it is not HLT mode, code need to change loop mode back\r
69 // to the original mode.\r
70 //\r
71 if (CpuMpData->ApLoopMode != ApInHltLoop) {\r
72 CpuMpData->WakeUpByInitSipiSipi = TRUE;\r
73 }\r
74\r
75 return EFI_SUCCESS;\r
76}\r
77\r
43c9fdcc
JF
78/**\r
79 Enable Debug Agent to support source debugging on AP function.\r
80\r
81**/\r
82VOID\r
83EnableDebugAgent (\r
84 VOID\r
85 )\r
86{\r
87}\r
88\r
93ca4c0f
JF
89/**\r
90 Get pointer to CPU MP Data structure.\r
c563077a
RN
91 For BSP, the pointer is retrieved from HOB.\r
92 For AP, the structure is just after IDT.\r
93ca4c0f
JF
93\r
94 @return The pointer to CPU MP Data structure.\r
95**/\r
96CPU_MP_DATA *\r
97GetCpuMpData (\r
98 VOID\r
99 )\r
100{\r
c563077a
RN
101 CPU_MP_DATA *CpuMpData;\r
102 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;\r
103 IA32_DESCRIPTOR Idtr;\r
93ca4c0f 104\r
c563077a
RN
105 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);\r
106 if (ApicBaseMsr.Bits.BSP == 1) {\r
107 CpuMpData = GetCpuMpDataFromGuidedHob ();\r
108 ASSERT (CpuMpData != NULL);\r
109 } else {\r
110 AsmReadIdtr (&Idtr);\r
053e878b 111 CpuMpData = (CPU_MP_DATA *)(Idtr.Base + Idtr.Limit + 1);\r
c563077a 112 }\r
053e878b 113\r
93ca4c0f
JF
114 return CpuMpData;\r
115}\r
116\r
117/**\r
118 Save the pointer to CPU MP Data structure.\r
119\r
120 @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.\r
121**/\r
122VOID\r
123SaveCpuMpData (\r
053e878b 124 IN CPU_MP_DATA *CpuMpData\r
93ca4c0f
JF
125 )\r
126{\r
053e878b
MK
127 UINT64 Data64;\r
128\r
93ca4c0f
JF
129 //\r
130 // Build location of CPU MP DATA buffer in HOB\r
131 //\r
053e878b 132 Data64 = (UINT64)(UINTN)CpuMpData;\r
93ca4c0f
JF
133 BuildGuidDataHob (\r
134 &mCpuInitMpLibHobGuid,\r
053e878b 135 (VOID *)&Data64,\r
93ca4c0f
JF
136 sizeof (UINT64)\r
137 );\r
138}\r
139\r
ed66e0e3
JF
140/**\r
141 Check if AP wakeup buffer is overlapped with existing allocated buffer.\r
142\r
143 @param[in] WakeupBufferStart AP wakeup buffer start address.\r
144 @param[in] WakeupBufferEnd AP wakeup buffer end address.\r
145\r
146 @retval TRUE There is overlap.\r
147 @retval FALSE There is no overlap.\r
148**/\r
149BOOLEAN\r
150CheckOverlapWithAllocatedBuffer (\r
053e878b
MK
151 IN UINT64 WakeupBufferStart,\r
152 IN UINT64 WakeupBufferEnd\r
ed66e0e3
JF
153 )\r
154{\r
053e878b
MK
155 EFI_PEI_HOB_POINTERS Hob;\r
156 EFI_HOB_MEMORY_ALLOCATION *MemoryHob;\r
157 BOOLEAN Overlapped;\r
158 UINT64 MemoryStart;\r
159 UINT64 MemoryEnd;\r
ed66e0e3
JF
160\r
161 Overlapped = FALSE;\r
162 //\r
163 // Get the HOB list for processing\r
164 //\r
165 Hob.Raw = GetHobList ();\r
166 //\r
167 // Collect memory ranges\r
168 //\r
169 while (!END_OF_HOB_LIST (Hob)) {\r
170 if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {\r
171 MemoryHob = Hob.MemoryAllocation;\r
5986cf38
RN
172 MemoryStart = MemoryHob->AllocDescriptor.MemoryBaseAddress;\r
173 MemoryEnd = MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength;\r
ed66e0e3
JF
174 if (!((WakeupBufferStart >= MemoryEnd) || (WakeupBufferEnd <= MemoryStart))) {\r
175 Overlapped = TRUE;\r
176 break;\r
177 }\r
178 }\r
053e878b 179\r
ed66e0e3
JF
180 Hob.Raw = GET_NEXT_HOB (Hob);\r
181 }\r
053e878b 182\r
ed66e0e3
JF
183 return Overlapped;\r
184}\r
185\r
186/**\r
187 Get available system memory below 1MB by specified size.\r
188\r
189 @param[in] WakeupBufferSize Wakeup buffer size required\r
190\r
191 @retval other Return wakeup buffer address below 1MB.\r
192 @retval -1 Cannot find free memory below 1MB.\r
193**/\r
194UINTN\r
195GetWakeupBuffer (\r
053e878b 196 IN UINTN WakeupBufferSize\r
ed66e0e3
JF
197 )\r
198{\r
053e878b
MK
199 EFI_PEI_HOB_POINTERS Hob;\r
200 UINT64 WakeupBufferStart;\r
201 UINT64 WakeupBufferEnd;\r
ed66e0e3
JF
202\r
203 WakeupBufferSize = (WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1);\r
204\r
205 //\r
206 // Get the HOB list for processing\r
207 //\r
208 Hob.Raw = GetHobList ();\r
209\r
210 //\r
211 // Collect memory ranges\r
212 //\r
213 while (!END_OF_HOB_LIST (Hob)) {\r
214 if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
215 if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) &&\r
216 (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&\r
217 ((Hob.ResourceDescriptor->ResourceAttribute &\r
218 (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |\r
219 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |\r
220 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED\r
053e878b
MK
221 )) == 0)\r
222 )\r
223 {\r
ed66e0e3
JF
224 //\r
225 // Need memory under 1MB to be collected here\r
226 //\r
5986cf38 227 WakeupBufferEnd = Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength;\r
b95908e0 228 if (ConfidentialComputingGuestHas (CCAttrAmdSevEs) &&\r
053e878b
MK
229 (WakeupBufferEnd > mSevEsPeiWakeupBuffer))\r
230 {\r
dbc22a17
TL
231 //\r
232 // SEV-ES Wakeup buffer should be under 1MB and under any previous one\r
233 //\r
234 WakeupBufferEnd = mSevEsPeiWakeupBuffer;\r
235 } else if (WakeupBufferEnd > BASE_1MB) {\r
ed66e0e3
JF
236 //\r
237 // Wakeup buffer should be under 1MB\r
238 //\r
239 WakeupBufferEnd = BASE_1MB;\r
240 }\r
053e878b 241\r
ed66e0e3
JF
242 while (WakeupBufferEnd > WakeupBufferSize) {\r
243 //\r
244 // Wakeup buffer should be aligned on 4KB\r
245 //\r
246 WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1);\r
247 if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) {\r
248 break;\r
249 }\r
053e878b 250\r
ed66e0e3
JF
251 if (CheckOverlapWithAllocatedBuffer (WakeupBufferStart, WakeupBufferEnd)) {\r
252 //\r
253 // If this range is overlapped with existing allocated buffer, skip it\r
254 // and find the next range\r
255 //\r
256 WakeupBufferEnd -= WakeupBufferSize;\r
257 continue;\r
258 }\r
053e878b
MK
259\r
260 DEBUG ((\r
261 DEBUG_INFO,\r
262 "WakeupBufferStart = %x, WakeupBufferSize = %x\n",\r
263 WakeupBufferStart,\r
264 WakeupBufferSize\r
265 ));\r
dbc22a17 266\r
b95908e0 267 if (ConfidentialComputingGuestHas (CCAttrAmdSevEs)) {\r
dbc22a17
TL
268 //\r
269 // Next SEV-ES wakeup buffer allocation must be below this\r
270 // allocation\r
271 //\r
272 mSevEsPeiWakeupBuffer = WakeupBufferStart;\r
273 }\r
274\r
5986cf38 275 return (UINTN)WakeupBufferStart;\r
ed66e0e3
JF
276 }\r
277 }\r
278 }\r
053e878b 279\r
ed66e0e3
JF
280 //\r
281 // Find the next HOB\r
282 //\r
283 Hob.Raw = GET_NEXT_HOB (Hob);\r
284 }\r
285\r
053e878b 286 return (UINTN)-1;\r
ed66e0e3
JF
287}\r
288\r
f32bfe6d
JW
289/**\r
290 Get available EfiBootServicesCode memory below 4GB by specified size.\r
291\r
292 This buffer is required to safely transfer AP from real address mode to\r
293 protected mode or long mode, due to the fact that the buffer returned by\r
294 GetWakeupBuffer() may be marked as non-executable.\r
295\r
296 @param[in] BufferSize Wakeup transition buffer size.\r
297\r
298 @retval other Return wakeup transition buffer address below 4GB.\r
299 @retval 0 Cannot find free memory below 4GB.\r
300**/\r
301UINTN\r
54aeed7e 302AllocateCodeBuffer (\r
053e878b 303 IN UINTN BufferSize\r
f32bfe6d
JW
304 )\r
305{\r
54aeed7e
RN
306 EFI_STATUS Status;\r
307 EFI_PHYSICAL_ADDRESS Address;\r
308\r
309 Status = PeiServicesAllocatePages (EfiBootServicesCode, EFI_SIZE_TO_PAGES (BufferSize), &Address);\r
310 if (EFI_ERROR (Status)) {\r
311 Address = 0;\r
312 }\r
313\r
314 return (UINTN)Address;\r
f32bfe6d
JW
315}\r
316\r
7b7508ad
TL
317/**\r
318 Return the address of the SEV-ES AP jump table.\r
319\r
320 This buffer is required in order for an SEV-ES guest to transition from\r
321 UEFI into an OS.\r
322\r
323 @return Return SEV-ES AP jump table buffer\r
324**/\r
325UINTN\r
326GetSevEsAPMemory (\r
327 VOID\r
328 )\r
329{\r
330 //\r
331 // PEI phase doesn't need to do such transition. So simply return 0.\r
332 //\r
333 return 0;\r
334}\r
335\r
08085f08
JF
336/**\r
337 Checks APs status and updates APs status if needed.\r
338\r
339**/\r
340VOID\r
341CheckAndUpdateApsStatus (\r
342 VOID\r
343 )\r
344{\r
345}\r
346\r
e1ed5573
HW
347/**\r
348 Build the microcode patch HOB that contains the base address and size of the\r
349 microcode patch stored in the memory.\r
350\r
351 @param[in] CpuMpData Pointer to the CPU_MP_DATA structure.\r
352\r
353**/\r
354VOID\r
355BuildMicrocodeCacheHob (\r
053e878b 356 IN CPU_MP_DATA *CpuMpData\r
e1ed5573
HW
357 )\r
358{\r
053e878b
MK
359 EDKII_MICROCODE_PATCH_HOB *MicrocodeHob;\r
360 UINTN HobDataLength;\r
361 UINT32 Index;\r
e1ed5573
HW
362\r
363 HobDataLength = sizeof (EDKII_MICROCODE_PATCH_HOB) +\r
364 sizeof (UINT64) * CpuMpData->CpuCount;\r
365\r
053e878b 366 MicrocodeHob = AllocatePool (HobDataLength);\r
e1ed5573
HW
367 if (MicrocodeHob == NULL) {\r
368 ASSERT (FALSE);\r
369 return;\r
370 }\r
371\r
372 //\r
373 // Store the information of the memory region that holds the microcode patches.\r
374 //\r
375 MicrocodeHob->MicrocodePatchAddress = CpuMpData->MicrocodePatchAddress;\r
376 MicrocodeHob->MicrocodePatchRegionSize = CpuMpData->MicrocodePatchRegionSize;\r
377\r
378 //\r
379 // Store the detected microcode patch for each processor as well.\r
380 //\r
381 MicrocodeHob->ProcessorCount = CpuMpData->CpuCount;\r
382 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
383 if (CpuMpData->CpuData[Index].MicrocodeEntryAddr != 0) {\r
384 MicrocodeHob->ProcessorSpecificPatchOffset[Index] =\r
385 CpuMpData->CpuData[Index].MicrocodeEntryAddr - CpuMpData->MicrocodePatchAddress;\r
386 } else {\r
387 MicrocodeHob->ProcessorSpecificPatchOffset[Index] = MAX_UINT64;\r
388 }\r
389 }\r
390\r
391 BuildGuidDataHob (\r
392 &gEdkiiMicrocodePatchHobGuid,\r
393 MicrocodeHob,\r
394 HobDataLength\r
395 );\r
396\r
397 return;\r
398}\r
399\r
93ca4c0f
JF
400/**\r
401 Initialize global data for MP support.\r
402\r
403 @param[in] CpuMpData The pointer to CPU MP Data structure.\r
404**/\r
405VOID\r
406InitMpGlobalData (\r
053e878b 407 IN CPU_MP_DATA *CpuMpData\r
93ca4c0f
JF
408 )\r
409{\r
58942277
ED
410 EFI_STATUS Status;\r
411\r
e1ed5573 412 BuildMicrocodeCacheHob (CpuMpData);\r
93ca4c0f 413 SaveCpuMpData (CpuMpData);\r
58942277
ED
414\r
415 ///\r
416 /// Install Notify\r
417 ///\r
418 Status = PeiServicesNotifyPpi (&mS3SmmInitDoneNotifyDesc);\r
419 ASSERT_EFI_ERROR (Status);\r
93ca4c0f
JF
420}\r
421\r
3e8ad6bd
JF
422/**\r
423 This service executes a caller provided function on all enabled APs.\r
424\r
425 @param[in] Procedure A pointer to the function to be run on\r
426 enabled APs of the system. See type\r
427 EFI_AP_PROCEDURE.\r
428 @param[in] SingleThread If TRUE, then all the enabled APs execute\r
429 the function specified by Procedure one by\r
430 one, in ascending order of processor handle\r
431 number. If FALSE, then all the enabled APs\r
432 execute the function specified by Procedure\r
433 simultaneously.\r
434 @param[in] WaitEvent The event created by the caller with CreateEvent()\r
435 service. If it is NULL, then execute in\r
436 blocking mode. BSP waits until all APs finish\r
437 or TimeoutInMicroSeconds expires. If it's\r
438 not NULL, then execute in non-blocking mode.\r
439 BSP requests the function specified by\r
440 Procedure to be started on all the enabled\r
441 APs, and go on executing immediately. If\r
442 all return from Procedure, or TimeoutInMicroSeconds\r
443 expires, this event is signaled. The BSP\r
444 can use the CheckEvent() or WaitForEvent()\r
445 services to check the state of event. Type\r
446 EFI_EVENT is defined in CreateEvent() in\r
447 the Unified Extensible Firmware Interface\r
448 Specification.\r
367284e7 449 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for\r
3e8ad6bd
JF
450 APs to return from Procedure, either for\r
451 blocking or non-blocking mode. Zero means\r
452 infinity. If the timeout expires before\r
453 all APs return from Procedure, then Procedure\r
454 on the failed APs is terminated. All enabled\r
455 APs are available for next function assigned\r
456 by MpInitLibStartupAllAPs() or\r
457 MPInitLibStartupThisAP().\r
458 If the timeout expires in blocking mode,\r
459 BSP returns EFI_TIMEOUT. If the timeout\r
460 expires in non-blocking mode, WaitEvent\r
461 is signaled with SignalEvent().\r
462 @param[in] ProcedureArgument The parameter passed into Procedure for\r
463 all APs.\r
464 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,\r
465 if all APs finish successfully, then its\r
466 content is set to NULL. If not all APs\r
467 finish before timeout expires, then its\r
468 content is set to address of the buffer\r
469 holding handle numbers of the failed APs.\r
470 The buffer is allocated by MP Initialization\r
471 library, and it's the caller's responsibility to\r
472 free the buffer with FreePool() service.\r
473 In blocking mode, it is ready for consumption\r
474 when the call returns. In non-blocking mode,\r
475 it is ready when WaitEvent is signaled. The\r
476 list of failed CPU is terminated by\r
477 END_OF_CPU_LIST.\r
478\r
479 @retval EFI_SUCCESS In blocking mode, all APs have finished before\r
480 the timeout expired.\r
481 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched\r
482 to all enabled APs.\r
483 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the\r
484 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was\r
485 signaled.\r
486 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not\r
487 supported.\r
488 @retval EFI_DEVICE_ERROR Caller processor is AP.\r
489 @retval EFI_NOT_STARTED No enabled APs exist in the system.\r
490 @retval EFI_NOT_READY Any enabled APs are busy.\r
491 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
492 @retval EFI_TIMEOUT In blocking mode, the timeout expired before\r
493 all enabled APs have finished.\r
494 @retval EFI_INVALID_PARAMETER Procedure is NULL.\r
495\r
496**/\r
497EFI_STATUS\r
498EFIAPI\r
499MpInitLibStartupAllAPs (\r
053e878b
MK
500 IN EFI_AP_PROCEDURE Procedure,\r
501 IN BOOLEAN SingleThread,\r
502 IN EFI_EVENT WaitEvent OPTIONAL,\r
503 IN UINTN TimeoutInMicroseconds,\r
504 IN VOID *ProcedureArgument OPTIONAL,\r
505 OUT UINTN **FailedCpuList OPTIONAL\r
3e8ad6bd
JF
506 )\r
507{\r
86efe976
JF
508 if (WaitEvent != NULL) {\r
509 return EFI_UNSUPPORTED;\r
510 }\r
511\r
ee0c39fa 512 return StartupAllCPUsWorker (\r
86efe976
JF
513 Procedure,\r
514 SingleThread,\r
ee0c39fa 515 TRUE,\r
86efe976
JF
516 NULL,\r
517 TimeoutInMicroseconds,\r
518 ProcedureArgument,\r
519 FailedCpuList\r
520 );\r
3e8ad6bd
JF
521}\r
522\r
523/**\r
524 This service lets the caller get one enabled AP to execute a caller-provided\r
525 function.\r
526\r
527 @param[in] Procedure A pointer to the function to be run on the\r
528 designated AP of the system. See type\r
529 EFI_AP_PROCEDURE.\r
530 @param[in] ProcessorNumber The handle number of the AP. The range is\r
531 from 0 to the total number of logical\r
532 processors minus 1. The total number of\r
533 logical processors can be retrieved by\r
534 MpInitLibGetNumberOfProcessors().\r
535 @param[in] WaitEvent The event created by the caller with CreateEvent()\r
536 service. If it is NULL, then execute in\r
537 blocking mode. BSP waits until this AP finish\r
538 or TimeoutInMicroSeconds expires. If it's\r
539 not NULL, then execute in non-blocking mode.\r
540 BSP requests the function specified by\r
541 Procedure to be started on this AP,\r
542 and go on executing immediately. If this AP\r
543 return from Procedure or TimeoutInMicroSeconds\r
544 expires, this event is signaled. The BSP\r
545 can use the CheckEvent() or WaitForEvent()\r
546 services to check the state of event. Type\r
547 EFI_EVENT is defined in CreateEvent() in\r
548 the Unified Extensible Firmware Interface\r
549 Specification.\r
367284e7 550 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for\r
3e8ad6bd
JF
551 this AP to finish this Procedure, either for\r
552 blocking or non-blocking mode. Zero means\r
553 infinity. If the timeout expires before\r
554 this AP returns from Procedure, then Procedure\r
555 on the AP is terminated. The\r
556 AP is available for next function assigned\r
557 by MpInitLibStartupAllAPs() or\r
558 MpInitLibStartupThisAP().\r
559 If the timeout expires in blocking mode,\r
560 BSP returns EFI_TIMEOUT. If the timeout\r
561 expires in non-blocking mode, WaitEvent\r
562 is signaled with SignalEvent().\r
563 @param[in] ProcedureArgument The parameter passed into Procedure on the\r
564 specified AP.\r
565 @param[out] Finished If NULL, this parameter is ignored. In\r
566 blocking mode, this parameter is ignored.\r
567 In non-blocking mode, if AP returns from\r
568 Procedure before the timeout expires, its\r
569 content is set to TRUE. Otherwise, the\r
570 value is set to FALSE. The caller can\r
571 determine if the AP returned from Procedure\r
572 by evaluating this value.\r
573\r
574 @retval EFI_SUCCESS In blocking mode, specified AP finished before\r
575 the timeout expires.\r
576 @retval EFI_SUCCESS In non-blocking mode, the function has been\r
577 dispatched to specified AP.\r
578 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the\r
579 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was\r
580 signaled.\r
581 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not\r
582 supported.\r
583 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
584 @retval EFI_TIMEOUT In blocking mode, the timeout expired before\r
585 the specified AP has finished.\r
586 @retval EFI_NOT_READY The specified AP is busy.\r
587 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
588 @retval EFI_NOT_FOUND The processor with the handle specified by\r
589 ProcessorNumber does not exist.\r
590 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.\r
591 @retval EFI_INVALID_PARAMETER Procedure is NULL.\r
592\r
593**/\r
594EFI_STATUS\r
595EFIAPI\r
596MpInitLibStartupThisAP (\r
053e878b
MK
597 IN EFI_AP_PROCEDURE Procedure,\r
598 IN UINTN ProcessorNumber,\r
599 IN EFI_EVENT WaitEvent OPTIONAL,\r
600 IN UINTN TimeoutInMicroseconds,\r
601 IN VOID *ProcedureArgument OPTIONAL,\r
602 OUT BOOLEAN *Finished OPTIONAL\r
3e8ad6bd
JF
603 )\r
604{\r
20ae5774
JF
605 if (WaitEvent != NULL) {\r
606 return EFI_UNSUPPORTED;\r
607 }\r
608\r
609 return StartupThisAPWorker (\r
610 Procedure,\r
611 ProcessorNumber,\r
612 NULL,\r
613 TimeoutInMicroseconds,\r
614 ProcedureArgument,\r
615 Finished\r
616 );\r
3e8ad6bd
JF
617}\r
618\r
619/**\r
620 This service switches the requested AP to be the BSP from that point onward.\r
621 This service changes the BSP for all purposes. This call can only be performed\r
622 by the current BSP.\r
623\r
624 @param[in] ProcessorNumber The handle number of AP that is to become the new\r
625 BSP. The range is from 0 to the total number of\r
626 logical processors minus 1. The total number of\r
627 logical processors can be retrieved by\r
628 MpInitLibGetNumberOfProcessors().\r
629 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an\r
630 enabled AP. Otherwise, it will be disabled.\r
631\r
632 @retval EFI_SUCCESS BSP successfully switched.\r
633 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to\r
634 this service returning.\r
635 @retval EFI_UNSUPPORTED Switching the BSP is not supported.\r
636 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
637 @retval EFI_NOT_FOUND The processor with the handle specified by\r
638 ProcessorNumber does not exist.\r
639 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or\r
640 a disabled AP.\r
641 @retval EFI_NOT_READY The specified AP is busy.\r
642 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
643\r
644**/\r
645EFI_STATUS\r
646EFIAPI\r
647MpInitLibSwitchBSP (\r
053e878b
MK
648 IN UINTN ProcessorNumber,\r
649 IN BOOLEAN EnableOldBSP\r
3e8ad6bd
JF
650 )\r
651{\r
41be0da5 652 return SwitchBSPWorker (ProcessorNumber, EnableOldBSP);\r
3e8ad6bd
JF
653}\r
654\r
655/**\r
656 This service lets the caller enable or disable an AP from this point onward.\r
657 This service may only be called from the BSP.\r
658\r
659 @param[in] ProcessorNumber The handle number of AP.\r
660 The range is from 0 to the total number of\r
661 logical processors minus 1. The total number of\r
662 logical processors can be retrieved by\r
663 MpInitLibGetNumberOfProcessors().\r
664 @param[in] EnableAP Specifies the new state for the processor for\r
665 enabled, FALSE for disabled.\r
666 @param[in] HealthFlag If not NULL, a pointer to a value that specifies\r
667 the new health status of the AP. This flag\r
668 corresponds to StatusFlag defined in\r
669 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only\r
670 the PROCESSOR_HEALTH_STATUS_BIT is used. All other\r
671 bits are ignored. If it is NULL, this parameter\r
672 is ignored.\r
673\r
674 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.\r
675 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed\r
676 prior to this service returning.\r
677 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.\r
678 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
679 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber\r
680 does not exist.\r
681 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.\r
682 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
683\r
684**/\r
685EFI_STATUS\r
686EFIAPI\r
687MpInitLibEnableDisableAP (\r
053e878b
MK
688 IN UINTN ProcessorNumber,\r
689 IN BOOLEAN EnableAP,\r
690 IN UINT32 *HealthFlag OPTIONAL\r
3e8ad6bd
JF
691 )\r
692{\r
e37109bc 693 return EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag);\r
3e8ad6bd
JF
694}\r
695\r
c788c2b1
SF
696/**\r
697 This funtion will try to invoke platform specific microcode shadow logic to\r
698 relocate microcode update patches into memory.\r
699\r
4ac82ea1 700 @param[in, out] CpuMpData The pointer to CPU MP Data structure.\r
3e8ad6bd 701\r
c788c2b1
SF
702 @retval EFI_SUCCESS Shadow microcode success.\r
703 @retval EFI_OUT_OF_RESOURCES No enough resource to complete the operation.\r
704 @retval EFI_UNSUPPORTED Can't find platform specific microcode shadow\r
705 PPI/Protocol.\r
706**/\r
707EFI_STATUS\r
708PlatformShadowMicrocode (\r
053e878b 709 IN OUT CPU_MP_DATA *CpuMpData\r
c788c2b1
SF
710 )\r
711{\r
053e878b
MK
712 EFI_STATUS Status;\r
713 EDKII_PEI_SHADOW_MICROCODE_PPI *ShadowMicrocodePpi;\r
714 UINTN CpuCount;\r
715 EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId;\r
716 UINTN Index;\r
717 UINTN BufferSize;\r
718 VOID *Buffer;\r
c788c2b1
SF
719\r
720 Status = PeiServicesLocatePpi (\r
721 &gEdkiiPeiShadowMicrocodePpiGuid,\r
722 0,\r
723 NULL,\r
053e878b 724 (VOID **)&ShadowMicrocodePpi\r
c788c2b1
SF
725 );\r
726 if (EFI_ERROR (Status)) {\r
727 return EFI_UNSUPPORTED;\r
728 }\r
729\r
053e878b
MK
730 CpuCount = CpuMpData->CpuCount;\r
731 MicrocodeCpuId = (EDKII_PEI_MICROCODE_CPU_ID *)AllocateZeroPool (sizeof (EDKII_PEI_MICROCODE_CPU_ID) * CpuCount);\r
c788c2b1
SF
732 if (MicrocodeCpuId == NULL) {\r
733 return EFI_OUT_OF_RESOURCES;\r
734 }\r
735\r
736 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
737 MicrocodeCpuId[Index].ProcessorSignature = CpuMpData->CpuData[Index].ProcessorSignature;\r
738 MicrocodeCpuId[Index].PlatformId = CpuMpData->CpuData[Index].PlatformId;\r
739 }\r
740\r
741 Status = ShadowMicrocodePpi->ShadowMicrocode (\r
053e878b
MK
742 ShadowMicrocodePpi,\r
743 CpuCount,\r
744 MicrocodeCpuId,\r
745 &BufferSize,\r
746 &Buffer\r
747 );\r
c788c2b1
SF
748 FreePool (MicrocodeCpuId);\r
749 if (EFI_ERROR (Status)) {\r
750 return EFI_NOT_FOUND;\r
751 }\r
752\r
053e878b 753 CpuMpData->MicrocodePatchAddress = (UINTN)Buffer;\r
c788c2b1
SF
754 CpuMpData->MicrocodePatchRegionSize = BufferSize;\r
755\r
756 DEBUG ((\r
757 DEBUG_INFO,\r
758 "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n",\r
053e878b
MK
759 __FUNCTION__,\r
760 CpuMpData->MicrocodePatchAddress,\r
761 CpuMpData->MicrocodePatchRegionSize\r
c788c2b1
SF
762 ));\r
763\r
764 return EFI_SUCCESS;\r
765}\r