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