2 MP initialize support functions for PEI phase.
4 Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include <Library/PeiServicesLib.h>
11 #include <Guid/S3SmmInitDone.h>
12 #include <Ppi/ShadowMicrocode.h>
14 STATIC UINT64 mSevEsPeiWakeupBuffer
= BASE_1MB
;
17 S3 SMM Init Done notification function.
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.
23 @retval EFI_SUCCESS The function completes successfully.
28 NotifyOnS3SmmInitDonePpi (
29 IN EFI_PEI_SERVICES
**PeiServices
,
30 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDesc
,
37 EFI_PEI_NOTIFY_DESCRIPTOR mS3SmmInitDoneNotifyDesc
= {
38 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
,
39 &gEdkiiS3SmmInitDoneGuid
,
40 NotifyOnS3SmmInitDonePpi
44 S3 SMM Init Done notification function.
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.
50 @retval EFI_SUCCESS The function completes successfully.
55 NotifyOnS3SmmInitDonePpi (
56 IN EFI_PEI_SERVICES
**PeiServices
,
57 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDesc
,
61 CPU_MP_DATA
*CpuMpData
;
63 CpuMpData
= GetCpuMpData ();
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.
71 if (CpuMpData
->ApLoopMode
!= ApInHltLoop
) {
72 CpuMpData
->WakeUpByInitSipiSipi
= TRUE
;
79 Enable Debug Agent to support source debugging on AP function.
90 Get pointer to CPU MP Data structure.
91 For BSP, the pointer is retrieved from HOB.
92 For AP, the structure is stored in the top of each AP's stack.
94 @return The pointer to CPU MP Data structure.
101 CPU_MP_DATA
*CpuMpData
;
102 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr
;
104 AP_STACK_DATA
*ApStackData
;
106 ApicBaseMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_APIC_BASE
);
107 if (ApicBaseMsr
.Bits
.BSP
== 1) {
108 CpuMpData
= GetCpuMpDataFromGuidedHob ();
109 ASSERT (CpuMpData
!= NULL
);
111 ApTopOfStack
= ALIGN_VALUE ((UINTN
)&ApTopOfStack
, (UINTN
)PcdGet32 (PcdCpuApStackSize
));
112 ApStackData
= (AP_STACK_DATA
*)((UINTN
)ApTopOfStack
- sizeof (AP_STACK_DATA
));
113 CpuMpData
= (CPU_MP_DATA
*)ApStackData
->MpData
;
120 Save the pointer to CPU MP Data structure.
122 @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.
126 IN CPU_MP_DATA
*CpuMpData
132 // Build location of CPU MP DATA buffer in HOB
134 Data64
= (UINT64
)(UINTN
)CpuMpData
;
136 &mCpuInitMpLibHobGuid
,
143 Check if AP wakeup buffer is overlapped with existing allocated buffer.
145 @param[in] WakeupBufferStart AP wakeup buffer start address.
146 @param[in] WakeupBufferEnd AP wakeup buffer end address.
148 @retval TRUE There is overlap.
149 @retval FALSE There is no overlap.
152 CheckOverlapWithAllocatedBuffer (
153 IN UINT64 WakeupBufferStart
,
154 IN UINT64 WakeupBufferEnd
157 EFI_PEI_HOB_POINTERS Hob
;
158 EFI_HOB_MEMORY_ALLOCATION
*MemoryHob
;
165 // Get the HOB list for processing
167 Hob
.Raw
= GetHobList ();
169 // Collect memory ranges
171 while (!END_OF_HOB_LIST (Hob
)) {
172 if (Hob
.Header
->HobType
== EFI_HOB_TYPE_MEMORY_ALLOCATION
) {
173 MemoryHob
= Hob
.MemoryAllocation
;
174 MemoryStart
= MemoryHob
->AllocDescriptor
.MemoryBaseAddress
;
175 MemoryEnd
= MemoryHob
->AllocDescriptor
.MemoryBaseAddress
+ MemoryHob
->AllocDescriptor
.MemoryLength
;
176 if (!((WakeupBufferStart
>= MemoryEnd
) || (WakeupBufferEnd
<= MemoryStart
))) {
182 Hob
.Raw
= GET_NEXT_HOB (Hob
);
189 Get available system memory below 1MB by specified size.
191 @param[in] WakeupBufferSize Wakeup buffer size required
193 @retval other Return wakeup buffer address below 1MB.
194 @retval -1 Cannot find free memory below 1MB.
198 IN UINTN WakeupBufferSize
201 EFI_PEI_HOB_POINTERS Hob
;
202 UINT64 WakeupBufferStart
;
203 UINT64 WakeupBufferEnd
;
205 WakeupBufferSize
= (WakeupBufferSize
+ SIZE_4KB
- 1) & ~(SIZE_4KB
- 1);
208 // Get the HOB list for processing
210 Hob
.Raw
= GetHobList ();
213 // Collect memory ranges
215 while (!END_OF_HOB_LIST (Hob
)) {
216 if (Hob
.Header
->HobType
== EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
217 if ((Hob
.ResourceDescriptor
->PhysicalStart
< BASE_1MB
) &&
218 (Hob
.ResourceDescriptor
->ResourceType
== EFI_RESOURCE_SYSTEM_MEMORY
) &&
219 ((Hob
.ResourceDescriptor
->ResourceAttribute
&
220 (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED
|
221 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED
|
222 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
227 // Need memory under 1MB to be collected here
229 WakeupBufferEnd
= Hob
.ResourceDescriptor
->PhysicalStart
+ Hob
.ResourceDescriptor
->ResourceLength
;
230 if (ConfidentialComputingGuestHas (CCAttrAmdSevEs
) &&
231 (WakeupBufferEnd
> mSevEsPeiWakeupBuffer
))
234 // SEV-ES Wakeup buffer should be under 1MB and under any previous one
236 WakeupBufferEnd
= mSevEsPeiWakeupBuffer
;
237 } else if (WakeupBufferEnd
> BASE_1MB
) {
239 // Wakeup buffer should be under 1MB
241 WakeupBufferEnd
= BASE_1MB
;
244 while (WakeupBufferEnd
> WakeupBufferSize
) {
246 // Wakeup buffer should be aligned on 4KB
248 WakeupBufferStart
= (WakeupBufferEnd
- WakeupBufferSize
) & ~(SIZE_4KB
- 1);
249 if (WakeupBufferStart
< Hob
.ResourceDescriptor
->PhysicalStart
) {
253 if (CheckOverlapWithAllocatedBuffer (WakeupBufferStart
, WakeupBufferEnd
)) {
255 // If this range is overlapped with existing allocated buffer, skip it
256 // and find the next range
258 WakeupBufferEnd
-= WakeupBufferSize
;
264 "WakeupBufferStart = %x, WakeupBufferSize = %x\n",
269 if (ConfidentialComputingGuestHas (CCAttrAmdSevEs
)) {
271 // Next SEV-ES wakeup buffer allocation must be below this
274 mSevEsPeiWakeupBuffer
= WakeupBufferStart
;
277 return (UINTN
)WakeupBufferStart
;
285 Hob
.Raw
= GET_NEXT_HOB (Hob
);
292 Get available EfiBootServicesCode memory below 4GB by specified size.
294 This buffer is required to safely transfer AP from real address mode to
295 protected mode or long mode, due to the fact that the buffer returned by
296 GetWakeupBuffer() may be marked as non-executable.
298 @param[in] BufferSize Wakeup transition buffer size.
300 @retval other Return wakeup transition buffer address below 4GB.
301 @retval 0 Cannot find free memory below 4GB.
309 EFI_PHYSICAL_ADDRESS Address
;
311 Status
= PeiServicesAllocatePages (EfiBootServicesCode
, EFI_SIZE_TO_PAGES (BufferSize
), &Address
);
312 if (EFI_ERROR (Status
)) {
316 return (UINTN
)Address
;
320 Return the address of the SEV-ES AP jump table.
322 This buffer is required in order for an SEV-ES guest to transition from
325 @return Return SEV-ES AP jump table buffer
333 // PEI phase doesn't need to do such transition. So simply return 0.
339 Checks APs status and updates APs status if needed.
343 CheckAndUpdateApsStatus (
350 Build the microcode patch HOB that contains the base address and size of the
351 microcode patch stored in the memory.
353 @param[in] CpuMpData Pointer to the CPU_MP_DATA structure.
357 BuildMicrocodeCacheHob (
358 IN CPU_MP_DATA
*CpuMpData
361 EDKII_MICROCODE_PATCH_HOB
*MicrocodeHob
;
365 HobDataLength
= sizeof (EDKII_MICROCODE_PATCH_HOB
) +
366 sizeof (UINT64
) * CpuMpData
->CpuCount
;
368 MicrocodeHob
= AllocatePool (HobDataLength
);
369 if (MicrocodeHob
== NULL
) {
375 // Store the information of the memory region that holds the microcode patches.
377 MicrocodeHob
->MicrocodePatchAddress
= CpuMpData
->MicrocodePatchAddress
;
378 MicrocodeHob
->MicrocodePatchRegionSize
= CpuMpData
->MicrocodePatchRegionSize
;
381 // Store the detected microcode patch for each processor as well.
383 MicrocodeHob
->ProcessorCount
= CpuMpData
->CpuCount
;
384 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
385 if (CpuMpData
->CpuData
[Index
].MicrocodeEntryAddr
!= 0) {
386 MicrocodeHob
->ProcessorSpecificPatchOffset
[Index
] =
387 CpuMpData
->CpuData
[Index
].MicrocodeEntryAddr
- CpuMpData
->MicrocodePatchAddress
;
389 MicrocodeHob
->ProcessorSpecificPatchOffset
[Index
] = MAX_UINT64
;
394 &gEdkiiMicrocodePatchHobGuid
,
403 Initialize global data for MP support.
405 @param[in] CpuMpData The pointer to CPU MP Data structure.
409 IN CPU_MP_DATA
*CpuMpData
414 BuildMicrocodeCacheHob (CpuMpData
);
415 SaveCpuMpData (CpuMpData
);
420 Status
= PeiServicesNotifyPpi (&mS3SmmInitDoneNotifyDesc
);
421 ASSERT_EFI_ERROR (Status
);
425 This service executes a caller provided function on all enabled APs.
427 @param[in] Procedure A pointer to the function to be run on
428 enabled APs of the system. See type
430 @param[in] SingleThread If TRUE, then all the enabled APs execute
431 the function specified by Procedure one by
432 one, in ascending order of processor handle
433 number. If FALSE, then all the enabled APs
434 execute the function specified by Procedure
436 @param[in] WaitEvent The event created by the caller with CreateEvent()
437 service. If it is NULL, then execute in
438 blocking mode. BSP waits until all APs finish
439 or TimeoutInMicroSeconds expires. If it's
440 not NULL, then execute in non-blocking mode.
441 BSP requests the function specified by
442 Procedure to be started on all the enabled
443 APs, and go on executing immediately. If
444 all return from Procedure, or TimeoutInMicroSeconds
445 expires, this event is signaled. The BSP
446 can use the CheckEvent() or WaitForEvent()
447 services to check the state of event. Type
448 EFI_EVENT is defined in CreateEvent() in
449 the Unified Extensible Firmware Interface
451 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
452 APs to return from Procedure, either for
453 blocking or non-blocking mode. Zero means
454 infinity. If the timeout expires before
455 all APs return from Procedure, then Procedure
456 on the failed APs is terminated. All enabled
457 APs are available for next function assigned
458 by MpInitLibStartupAllAPs() or
459 MPInitLibStartupThisAP().
460 If the timeout expires in blocking mode,
461 BSP returns EFI_TIMEOUT. If the timeout
462 expires in non-blocking mode, WaitEvent
463 is signaled with SignalEvent().
464 @param[in] ProcedureArgument The parameter passed into Procedure for
466 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
467 if all APs finish successfully, then its
468 content is set to NULL. If not all APs
469 finish before timeout expires, then its
470 content is set to address of the buffer
471 holding handle numbers of the failed APs.
472 The buffer is allocated by MP Initialization
473 library, and it's the caller's responsibility to
474 free the buffer with FreePool() service.
475 In blocking mode, it is ready for consumption
476 when the call returns. In non-blocking mode,
477 it is ready when WaitEvent is signaled. The
478 list of failed CPU is terminated by
481 @retval EFI_SUCCESS In blocking mode, all APs have finished before
483 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
485 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
486 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
488 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
490 @retval EFI_DEVICE_ERROR Caller processor is AP.
491 @retval EFI_NOT_STARTED No enabled APs exist in the system.
492 @retval EFI_NOT_READY Any enabled APs are busy.
493 @retval EFI_NOT_READY MP Initialize Library is not initialized.
494 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
495 all enabled APs have finished.
496 @retval EFI_INVALID_PARAMETER Procedure is NULL.
501 MpInitLibStartupAllAPs (
502 IN EFI_AP_PROCEDURE Procedure
,
503 IN BOOLEAN SingleThread
,
504 IN EFI_EVENT WaitEvent OPTIONAL
,
505 IN UINTN TimeoutInMicroseconds
,
506 IN VOID
*ProcedureArgument OPTIONAL
,
507 OUT UINTN
**FailedCpuList OPTIONAL
510 if (WaitEvent
!= NULL
) {
511 return EFI_UNSUPPORTED
;
514 return StartupAllCPUsWorker (
519 TimeoutInMicroseconds
,
526 This service lets the caller get one enabled AP to execute a caller-provided
529 @param[in] Procedure A pointer to the function to be run on the
530 designated AP of the system. See type
532 @param[in] ProcessorNumber The handle number of the AP. The range is
533 from 0 to the total number of logical
534 processors minus 1. The total number of
535 logical processors can be retrieved by
536 MpInitLibGetNumberOfProcessors().
537 @param[in] WaitEvent The event created by the caller with CreateEvent()
538 service. If it is NULL, then execute in
539 blocking mode. BSP waits until this AP finish
540 or TimeoutInMicroSeconds expires. If it's
541 not NULL, then execute in non-blocking mode.
542 BSP requests the function specified by
543 Procedure to be started on this AP,
544 and go on executing immediately. If this AP
545 return from Procedure or TimeoutInMicroSeconds
546 expires, this event is signaled. The BSP
547 can use the CheckEvent() or WaitForEvent()
548 services to check the state of event. Type
549 EFI_EVENT is defined in CreateEvent() in
550 the Unified Extensible Firmware Interface
552 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
553 this AP to finish this Procedure, either for
554 blocking or non-blocking mode. Zero means
555 infinity. If the timeout expires before
556 this AP returns from Procedure, then Procedure
557 on the AP is terminated. The
558 AP is available for next function assigned
559 by MpInitLibStartupAllAPs() or
560 MpInitLibStartupThisAP().
561 If the timeout expires in blocking mode,
562 BSP returns EFI_TIMEOUT. If the timeout
563 expires in non-blocking mode, WaitEvent
564 is signaled with SignalEvent().
565 @param[in] ProcedureArgument The parameter passed into Procedure on the
567 @param[out] Finished If NULL, this parameter is ignored. In
568 blocking mode, this parameter is ignored.
569 In non-blocking mode, if AP returns from
570 Procedure before the timeout expires, its
571 content is set to TRUE. Otherwise, the
572 value is set to FALSE. The caller can
573 determine if the AP returned from Procedure
574 by evaluating this value.
576 @retval EFI_SUCCESS In blocking mode, specified AP finished before
578 @retval EFI_SUCCESS In non-blocking mode, the function has been
579 dispatched to specified AP.
580 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
581 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
583 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
585 @retval EFI_DEVICE_ERROR The calling processor is an AP.
586 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
587 the specified AP has finished.
588 @retval EFI_NOT_READY The specified AP is busy.
589 @retval EFI_NOT_READY MP Initialize Library is not initialized.
590 @retval EFI_NOT_FOUND The processor with the handle specified by
591 ProcessorNumber does not exist.
592 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
593 @retval EFI_INVALID_PARAMETER Procedure is NULL.
598 MpInitLibStartupThisAP (
599 IN EFI_AP_PROCEDURE Procedure
,
600 IN UINTN ProcessorNumber
,
601 IN EFI_EVENT WaitEvent OPTIONAL
,
602 IN UINTN TimeoutInMicroseconds
,
603 IN VOID
*ProcedureArgument OPTIONAL
,
604 OUT BOOLEAN
*Finished OPTIONAL
607 if (WaitEvent
!= NULL
) {
608 return EFI_UNSUPPORTED
;
611 return StartupThisAPWorker (
615 TimeoutInMicroseconds
,
622 This service switches the requested AP to be the BSP from that point onward.
623 This service changes the BSP for all purposes. This call can only be performed
626 @param[in] ProcessorNumber The handle number of AP that is to become the new
627 BSP. The range is from 0 to the total number of
628 logical processors minus 1. The total number of
629 logical processors can be retrieved by
630 MpInitLibGetNumberOfProcessors().
631 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
632 enabled AP. Otherwise, it will be disabled.
634 @retval EFI_SUCCESS BSP successfully switched.
635 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
636 this service returning.
637 @retval EFI_UNSUPPORTED Switching the BSP is not supported.
638 @retval EFI_DEVICE_ERROR The calling processor is an AP.
639 @retval EFI_NOT_FOUND The processor with the handle specified by
640 ProcessorNumber does not exist.
641 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
643 @retval EFI_NOT_READY The specified AP is busy.
644 @retval EFI_NOT_READY MP Initialize Library is not initialized.
650 IN UINTN ProcessorNumber
,
651 IN BOOLEAN EnableOldBSP
654 return SwitchBSPWorker (ProcessorNumber
, EnableOldBSP
);
658 This service lets the caller enable or disable an AP from this point onward.
659 This service may only be called from the BSP.
661 @param[in] ProcessorNumber The handle number of AP.
662 The range is from 0 to the total number of
663 logical processors minus 1. The total number of
664 logical processors can be retrieved by
665 MpInitLibGetNumberOfProcessors().
666 @param[in] EnableAP Specifies the new state for the processor for
667 enabled, FALSE for disabled.
668 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
669 the new health status of the AP. This flag
670 corresponds to StatusFlag defined in
671 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
672 the PROCESSOR_HEALTH_STATUS_BIT is used. All other
673 bits are ignored. If it is NULL, this parameter
676 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
677 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
678 prior to this service returning.
679 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
680 @retval EFI_DEVICE_ERROR The calling processor is an AP.
681 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
683 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
684 @retval EFI_NOT_READY MP Initialize Library is not initialized.
689 MpInitLibEnableDisableAP (
690 IN UINTN ProcessorNumber
,
692 IN UINT32
*HealthFlag OPTIONAL
695 return EnableDisableApWorker (ProcessorNumber
, EnableAP
, HealthFlag
);
699 This funtion will try to invoke platform specific microcode shadow logic to
700 relocate microcode update patches into memory.
702 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
704 @retval EFI_SUCCESS Shadow microcode success.
705 @retval EFI_OUT_OF_RESOURCES No enough resource to complete the operation.
706 @retval EFI_UNSUPPORTED Can't find platform specific microcode shadow
710 PlatformShadowMicrocode (
711 IN OUT CPU_MP_DATA
*CpuMpData
715 EDKII_PEI_SHADOW_MICROCODE_PPI
*ShadowMicrocodePpi
;
717 EDKII_PEI_MICROCODE_CPU_ID
*MicrocodeCpuId
;
722 Status
= PeiServicesLocatePpi (
723 &gEdkiiPeiShadowMicrocodePpiGuid
,
726 (VOID
**)&ShadowMicrocodePpi
728 if (EFI_ERROR (Status
)) {
729 return EFI_UNSUPPORTED
;
732 CpuCount
= CpuMpData
->CpuCount
;
733 MicrocodeCpuId
= (EDKII_PEI_MICROCODE_CPU_ID
*)AllocateZeroPool (sizeof (EDKII_PEI_MICROCODE_CPU_ID
) * CpuCount
);
734 if (MicrocodeCpuId
== NULL
) {
735 return EFI_OUT_OF_RESOURCES
;
738 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
739 MicrocodeCpuId
[Index
].ProcessorSignature
= CpuMpData
->CpuData
[Index
].ProcessorSignature
;
740 MicrocodeCpuId
[Index
].PlatformId
= CpuMpData
->CpuData
[Index
].PlatformId
;
743 Status
= ShadowMicrocodePpi
->ShadowMicrocode (
750 FreePool (MicrocodeCpuId
);
751 if (EFI_ERROR (Status
)) {
752 return EFI_NOT_FOUND
;
755 CpuMpData
->MicrocodePatchAddress
= (UINTN
)Buffer
;
756 CpuMpData
->MicrocodePatchRegionSize
= BufferSize
;
760 "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n",
762 CpuMpData
->MicrocodePatchAddress
,
763 CpuMpData
->MicrocodePatchRegionSize