]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
UefiCpuPkg/MpInitLib: use PcdConfidentialComputingAttr to check SEV status
[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
302GetModeTransitionBuffer (\r
053e878b 303 IN UINTN BufferSize\r
f32bfe6d
JW
304 )\r
305{\r
306 //\r
307 // PEI phase doesn't need to do such transition. So simply return 0.\r
308 //\r
309 return 0;\r
310}\r
311\r
7b7508ad
TL
312/**\r
313 Return the address of the SEV-ES AP jump table.\r
314\r
315 This buffer is required in order for an SEV-ES guest to transition from\r
316 UEFI into an OS.\r
317\r
318 @return Return SEV-ES AP jump table buffer\r
319**/\r
320UINTN\r
321GetSevEsAPMemory (\r
322 VOID\r
323 )\r
324{\r
325 //\r
326 // PEI phase doesn't need to do such transition. So simply return 0.\r
327 //\r
328 return 0;\r
329}\r
330\r
08085f08
JF
331/**\r
332 Checks APs status and updates APs status if needed.\r
333\r
334**/\r
335VOID\r
336CheckAndUpdateApsStatus (\r
337 VOID\r
338 )\r
339{\r
340}\r
341\r
e1ed5573
HW
342/**\r
343 Build the microcode patch HOB that contains the base address and size of the\r
344 microcode patch stored in the memory.\r
345\r
346 @param[in] CpuMpData Pointer to the CPU_MP_DATA structure.\r
347\r
348**/\r
349VOID\r
350BuildMicrocodeCacheHob (\r
053e878b 351 IN CPU_MP_DATA *CpuMpData\r
e1ed5573
HW
352 )\r
353{\r
053e878b
MK
354 EDKII_MICROCODE_PATCH_HOB *MicrocodeHob;\r
355 UINTN HobDataLength;\r
356 UINT32 Index;\r
e1ed5573
HW
357\r
358 HobDataLength = sizeof (EDKII_MICROCODE_PATCH_HOB) +\r
359 sizeof (UINT64) * CpuMpData->CpuCount;\r
360\r
053e878b 361 MicrocodeHob = AllocatePool (HobDataLength);\r
e1ed5573
HW
362 if (MicrocodeHob == NULL) {\r
363 ASSERT (FALSE);\r
364 return;\r
365 }\r
366\r
367 //\r
368 // Store the information of the memory region that holds the microcode patches.\r
369 //\r
370 MicrocodeHob->MicrocodePatchAddress = CpuMpData->MicrocodePatchAddress;\r
371 MicrocodeHob->MicrocodePatchRegionSize = CpuMpData->MicrocodePatchRegionSize;\r
372\r
373 //\r
374 // Store the detected microcode patch for each processor as well.\r
375 //\r
376 MicrocodeHob->ProcessorCount = CpuMpData->CpuCount;\r
377 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
378 if (CpuMpData->CpuData[Index].MicrocodeEntryAddr != 0) {\r
379 MicrocodeHob->ProcessorSpecificPatchOffset[Index] =\r
380 CpuMpData->CpuData[Index].MicrocodeEntryAddr - CpuMpData->MicrocodePatchAddress;\r
381 } else {\r
382 MicrocodeHob->ProcessorSpecificPatchOffset[Index] = MAX_UINT64;\r
383 }\r
384 }\r
385\r
386 BuildGuidDataHob (\r
387 &gEdkiiMicrocodePatchHobGuid,\r
388 MicrocodeHob,\r
389 HobDataLength\r
390 );\r
391\r
392 return;\r
393}\r
394\r
93ca4c0f
JF
395/**\r
396 Initialize global data for MP support.\r
397\r
398 @param[in] CpuMpData The pointer to CPU MP Data structure.\r
399**/\r
400VOID\r
401InitMpGlobalData (\r
053e878b 402 IN CPU_MP_DATA *CpuMpData\r
93ca4c0f
JF
403 )\r
404{\r
58942277
ED
405 EFI_STATUS Status;\r
406\r
e1ed5573 407 BuildMicrocodeCacheHob (CpuMpData);\r
93ca4c0f 408 SaveCpuMpData (CpuMpData);\r
58942277
ED
409\r
410 ///\r
411 /// Install Notify\r
412 ///\r
413 Status = PeiServicesNotifyPpi (&mS3SmmInitDoneNotifyDesc);\r
414 ASSERT_EFI_ERROR (Status);\r
93ca4c0f
JF
415}\r
416\r
3e8ad6bd
JF
417/**\r
418 This service executes a caller provided function on all enabled APs.\r
419\r
420 @param[in] Procedure A pointer to the function to be run on\r
421 enabled APs of the system. See type\r
422 EFI_AP_PROCEDURE.\r
423 @param[in] SingleThread If TRUE, then all the enabled APs execute\r
424 the function specified by Procedure one by\r
425 one, in ascending order of processor handle\r
426 number. If FALSE, then all the enabled APs\r
427 execute the function specified by Procedure\r
428 simultaneously.\r
429 @param[in] WaitEvent The event created by the caller with CreateEvent()\r
430 service. If it is NULL, then execute in\r
431 blocking mode. BSP waits until all APs finish\r
432 or TimeoutInMicroSeconds expires. If it's\r
433 not NULL, then execute in non-blocking mode.\r
434 BSP requests the function specified by\r
435 Procedure to be started on all the enabled\r
436 APs, and go on executing immediately. If\r
437 all return from Procedure, or TimeoutInMicroSeconds\r
438 expires, this event is signaled. The BSP\r
439 can use the CheckEvent() or WaitForEvent()\r
440 services to check the state of event. Type\r
441 EFI_EVENT is defined in CreateEvent() in\r
442 the Unified Extensible Firmware Interface\r
443 Specification.\r
367284e7 444 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for\r
3e8ad6bd
JF
445 APs to return from Procedure, either for\r
446 blocking or non-blocking mode. Zero means\r
447 infinity. If the timeout expires before\r
448 all APs return from Procedure, then Procedure\r
449 on the failed APs is terminated. All enabled\r
450 APs are available for next function assigned\r
451 by MpInitLibStartupAllAPs() or\r
452 MPInitLibStartupThisAP().\r
453 If the timeout expires in blocking mode,\r
454 BSP returns EFI_TIMEOUT. If the timeout\r
455 expires in non-blocking mode, WaitEvent\r
456 is signaled with SignalEvent().\r
457 @param[in] ProcedureArgument The parameter passed into Procedure for\r
458 all APs.\r
459 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,\r
460 if all APs finish successfully, then its\r
461 content is set to NULL. If not all APs\r
462 finish before timeout expires, then its\r
463 content is set to address of the buffer\r
464 holding handle numbers of the failed APs.\r
465 The buffer is allocated by MP Initialization\r
466 library, and it's the caller's responsibility to\r
467 free the buffer with FreePool() service.\r
468 In blocking mode, it is ready for consumption\r
469 when the call returns. In non-blocking mode,\r
470 it is ready when WaitEvent is signaled. The\r
471 list of failed CPU is terminated by\r
472 END_OF_CPU_LIST.\r
473\r
474 @retval EFI_SUCCESS In blocking mode, all APs have finished before\r
475 the timeout expired.\r
476 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched\r
477 to all enabled APs.\r
478 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the\r
479 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was\r
480 signaled.\r
481 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not\r
482 supported.\r
483 @retval EFI_DEVICE_ERROR Caller processor is AP.\r
484 @retval EFI_NOT_STARTED No enabled APs exist in the system.\r
485 @retval EFI_NOT_READY Any enabled APs are busy.\r
486 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
487 @retval EFI_TIMEOUT In blocking mode, the timeout expired before\r
488 all enabled APs have finished.\r
489 @retval EFI_INVALID_PARAMETER Procedure is NULL.\r
490\r
491**/\r
492EFI_STATUS\r
493EFIAPI\r
494MpInitLibStartupAllAPs (\r
053e878b
MK
495 IN EFI_AP_PROCEDURE Procedure,\r
496 IN BOOLEAN SingleThread,\r
497 IN EFI_EVENT WaitEvent OPTIONAL,\r
498 IN UINTN TimeoutInMicroseconds,\r
499 IN VOID *ProcedureArgument OPTIONAL,\r
500 OUT UINTN **FailedCpuList OPTIONAL\r
3e8ad6bd
JF
501 )\r
502{\r
86efe976
JF
503 if (WaitEvent != NULL) {\r
504 return EFI_UNSUPPORTED;\r
505 }\r
506\r
ee0c39fa 507 return StartupAllCPUsWorker (\r
86efe976
JF
508 Procedure,\r
509 SingleThread,\r
ee0c39fa 510 TRUE,\r
86efe976
JF
511 NULL,\r
512 TimeoutInMicroseconds,\r
513 ProcedureArgument,\r
514 FailedCpuList\r
515 );\r
3e8ad6bd
JF
516}\r
517\r
518/**\r
519 This service lets the caller get one enabled AP to execute a caller-provided\r
520 function.\r
521\r
522 @param[in] Procedure A pointer to the function to be run on the\r
523 designated AP of the system. See type\r
524 EFI_AP_PROCEDURE.\r
525 @param[in] ProcessorNumber The handle number of the AP. The range is\r
526 from 0 to the total number of logical\r
527 processors minus 1. The total number of\r
528 logical processors can be retrieved by\r
529 MpInitLibGetNumberOfProcessors().\r
530 @param[in] WaitEvent The event created by the caller with CreateEvent()\r
531 service. If it is NULL, then execute in\r
532 blocking mode. BSP waits until this AP finish\r
533 or TimeoutInMicroSeconds expires. If it's\r
534 not NULL, then execute in non-blocking mode.\r
535 BSP requests the function specified by\r
536 Procedure to be started on this AP,\r
537 and go on executing immediately. If this AP\r
538 return from Procedure or TimeoutInMicroSeconds\r
539 expires, this event is signaled. The BSP\r
540 can use the CheckEvent() or WaitForEvent()\r
541 services to check the state of event. Type\r
542 EFI_EVENT is defined in CreateEvent() in\r
543 the Unified Extensible Firmware Interface\r
544 Specification.\r
367284e7 545 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for\r
3e8ad6bd
JF
546 this AP to finish this Procedure, either for\r
547 blocking or non-blocking mode. Zero means\r
548 infinity. If the timeout expires before\r
549 this AP returns from Procedure, then Procedure\r
550 on the AP is terminated. The\r
551 AP is available for next function assigned\r
552 by MpInitLibStartupAllAPs() or\r
553 MpInitLibStartupThisAP().\r
554 If the timeout expires in blocking mode,\r
555 BSP returns EFI_TIMEOUT. If the timeout\r
556 expires in non-blocking mode, WaitEvent\r
557 is signaled with SignalEvent().\r
558 @param[in] ProcedureArgument The parameter passed into Procedure on the\r
559 specified AP.\r
560 @param[out] Finished If NULL, this parameter is ignored. In\r
561 blocking mode, this parameter is ignored.\r
562 In non-blocking mode, if AP returns from\r
563 Procedure before the timeout expires, its\r
564 content is set to TRUE. Otherwise, the\r
565 value is set to FALSE. The caller can\r
566 determine if the AP returned from Procedure\r
567 by evaluating this value.\r
568\r
569 @retval EFI_SUCCESS In blocking mode, specified AP finished before\r
570 the timeout expires.\r
571 @retval EFI_SUCCESS In non-blocking mode, the function has been\r
572 dispatched to specified AP.\r
573 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the\r
574 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was\r
575 signaled.\r
576 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not\r
577 supported.\r
578 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
579 @retval EFI_TIMEOUT In blocking mode, the timeout expired before\r
580 the specified AP has finished.\r
581 @retval EFI_NOT_READY The specified AP is busy.\r
582 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
583 @retval EFI_NOT_FOUND The processor with the handle specified by\r
584 ProcessorNumber does not exist.\r
585 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.\r
586 @retval EFI_INVALID_PARAMETER Procedure is NULL.\r
587\r
588**/\r
589EFI_STATUS\r
590EFIAPI\r
591MpInitLibStartupThisAP (\r
053e878b
MK
592 IN EFI_AP_PROCEDURE Procedure,\r
593 IN UINTN ProcessorNumber,\r
594 IN EFI_EVENT WaitEvent OPTIONAL,\r
595 IN UINTN TimeoutInMicroseconds,\r
596 IN VOID *ProcedureArgument OPTIONAL,\r
597 OUT BOOLEAN *Finished OPTIONAL\r
3e8ad6bd
JF
598 )\r
599{\r
20ae5774
JF
600 if (WaitEvent != NULL) {\r
601 return EFI_UNSUPPORTED;\r
602 }\r
603\r
604 return StartupThisAPWorker (\r
605 Procedure,\r
606 ProcessorNumber,\r
607 NULL,\r
608 TimeoutInMicroseconds,\r
609 ProcedureArgument,\r
610 Finished\r
611 );\r
3e8ad6bd
JF
612}\r
613\r
614/**\r
615 This service switches the requested AP to be the BSP from that point onward.\r
616 This service changes the BSP for all purposes. This call can only be performed\r
617 by the current BSP.\r
618\r
619 @param[in] ProcessorNumber The handle number of AP that is to become the new\r
620 BSP. The range is from 0 to the total number of\r
621 logical processors minus 1. The total number of\r
622 logical processors can be retrieved by\r
623 MpInitLibGetNumberOfProcessors().\r
624 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an\r
625 enabled AP. Otherwise, it will be disabled.\r
626\r
627 @retval EFI_SUCCESS BSP successfully switched.\r
628 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to\r
629 this service returning.\r
630 @retval EFI_UNSUPPORTED Switching the BSP is not supported.\r
631 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
632 @retval EFI_NOT_FOUND The processor with the handle specified by\r
633 ProcessorNumber does not exist.\r
634 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or\r
635 a disabled AP.\r
636 @retval EFI_NOT_READY The specified AP is busy.\r
637 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
638\r
639**/\r
640EFI_STATUS\r
641EFIAPI\r
642MpInitLibSwitchBSP (\r
053e878b
MK
643 IN UINTN ProcessorNumber,\r
644 IN BOOLEAN EnableOldBSP\r
3e8ad6bd
JF
645 )\r
646{\r
41be0da5 647 return SwitchBSPWorker (ProcessorNumber, EnableOldBSP);\r
3e8ad6bd
JF
648}\r
649\r
650/**\r
651 This service lets the caller enable or disable an AP from this point onward.\r
652 This service may only be called from the BSP.\r
653\r
654 @param[in] ProcessorNumber The handle number of AP.\r
655 The range is from 0 to the total number of\r
656 logical processors minus 1. The total number of\r
657 logical processors can be retrieved by\r
658 MpInitLibGetNumberOfProcessors().\r
659 @param[in] EnableAP Specifies the new state for the processor for\r
660 enabled, FALSE for disabled.\r
661 @param[in] HealthFlag If not NULL, a pointer to a value that specifies\r
662 the new health status of the AP. This flag\r
663 corresponds to StatusFlag defined in\r
664 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only\r
665 the PROCESSOR_HEALTH_STATUS_BIT is used. All other\r
666 bits are ignored. If it is NULL, this parameter\r
667 is ignored.\r
668\r
669 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.\r
670 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed\r
671 prior to this service returning.\r
672 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.\r
673 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
674 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber\r
675 does not exist.\r
676 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.\r
677 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
678\r
679**/\r
680EFI_STATUS\r
681EFIAPI\r
682MpInitLibEnableDisableAP (\r
053e878b
MK
683 IN UINTN ProcessorNumber,\r
684 IN BOOLEAN EnableAP,\r
685 IN UINT32 *HealthFlag OPTIONAL\r
3e8ad6bd
JF
686 )\r
687{\r
e37109bc 688 return EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag);\r
3e8ad6bd
JF
689}\r
690\r
c788c2b1
SF
691/**\r
692 This funtion will try to invoke platform specific microcode shadow logic to\r
693 relocate microcode update patches into memory.\r
694\r
4ac82ea1 695 @param[in, out] CpuMpData The pointer to CPU MP Data structure.\r
3e8ad6bd 696\r
c788c2b1
SF
697 @retval EFI_SUCCESS Shadow microcode success.\r
698 @retval EFI_OUT_OF_RESOURCES No enough resource to complete the operation.\r
699 @retval EFI_UNSUPPORTED Can't find platform specific microcode shadow\r
700 PPI/Protocol.\r
701**/\r
702EFI_STATUS\r
703PlatformShadowMicrocode (\r
053e878b 704 IN OUT CPU_MP_DATA *CpuMpData\r
c788c2b1
SF
705 )\r
706{\r
053e878b
MK
707 EFI_STATUS Status;\r
708 EDKII_PEI_SHADOW_MICROCODE_PPI *ShadowMicrocodePpi;\r
709 UINTN CpuCount;\r
710 EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId;\r
711 UINTN Index;\r
712 UINTN BufferSize;\r
713 VOID *Buffer;\r
c788c2b1
SF
714\r
715 Status = PeiServicesLocatePpi (\r
716 &gEdkiiPeiShadowMicrocodePpiGuid,\r
717 0,\r
718 NULL,\r
053e878b 719 (VOID **)&ShadowMicrocodePpi\r
c788c2b1
SF
720 );\r
721 if (EFI_ERROR (Status)) {\r
722 return EFI_UNSUPPORTED;\r
723 }\r
724\r
053e878b
MK
725 CpuCount = CpuMpData->CpuCount;\r
726 MicrocodeCpuId = (EDKII_PEI_MICROCODE_CPU_ID *)AllocateZeroPool (sizeof (EDKII_PEI_MICROCODE_CPU_ID) * CpuCount);\r
c788c2b1
SF
727 if (MicrocodeCpuId == NULL) {\r
728 return EFI_OUT_OF_RESOURCES;\r
729 }\r
730\r
731 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
732 MicrocodeCpuId[Index].ProcessorSignature = CpuMpData->CpuData[Index].ProcessorSignature;\r
733 MicrocodeCpuId[Index].PlatformId = CpuMpData->CpuData[Index].PlatformId;\r
734 }\r
735\r
736 Status = ShadowMicrocodePpi->ShadowMicrocode (\r
053e878b
MK
737 ShadowMicrocodePpi,\r
738 CpuCount,\r
739 MicrocodeCpuId,\r
740 &BufferSize,\r
741 &Buffer\r
742 );\r
c788c2b1
SF
743 FreePool (MicrocodeCpuId);\r
744 if (EFI_ERROR (Status)) {\r
745 return EFI_NOT_FOUND;\r
746 }\r
747\r
053e878b 748 CpuMpData->MicrocodePatchAddress = (UINTN)Buffer;\r
c788c2b1
SF
749 CpuMpData->MicrocodePatchRegionSize = BufferSize;\r
750\r
751 DEBUG ((\r
752 DEBUG_INFO,\r
753 "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n",\r
053e878b
MK
754 __FUNCTION__,\r
755 CpuMpData->MicrocodePatchAddress,\r
756 CpuMpData->MicrocodePatchRegionSize\r
c788c2b1
SF
757 ));\r
758\r
759 return EFI_SUCCESS;\r
760}\r