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