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 just after IDT.
94 @return The pointer to CPU MP Data structure.
101 CPU_MP_DATA
*CpuMpData
;
102 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr
;
103 IA32_DESCRIPTOR Idtr
;
105 ApicBaseMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_APIC_BASE
);
106 if (ApicBaseMsr
.Bits
.BSP
== 1) {
107 CpuMpData
= GetCpuMpDataFromGuidedHob ();
108 ASSERT (CpuMpData
!= NULL
);
111 CpuMpData
= (CPU_MP_DATA
*)(Idtr
.Base
+ Idtr
.Limit
+ 1);
118 Save the pointer to CPU MP Data structure.
120 @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.
124 IN CPU_MP_DATA
*CpuMpData
130 // Build location of CPU MP DATA buffer in HOB
132 Data64
= (UINT64
)(UINTN
)CpuMpData
;
134 &mCpuInitMpLibHobGuid
,
141 Check if AP wakeup buffer is overlapped with existing allocated buffer.
143 @param[in] WakeupBufferStart AP wakeup buffer start address.
144 @param[in] WakeupBufferEnd AP wakeup buffer end address.
146 @retval TRUE There is overlap.
147 @retval FALSE There is no overlap.
150 CheckOverlapWithAllocatedBuffer (
151 IN UINT64 WakeupBufferStart
,
152 IN UINT64 WakeupBufferEnd
155 EFI_PEI_HOB_POINTERS Hob
;
156 EFI_HOB_MEMORY_ALLOCATION
*MemoryHob
;
163 // Get the HOB list for processing
165 Hob
.Raw
= GetHobList ();
167 // Collect memory ranges
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
))) {
180 Hob
.Raw
= GET_NEXT_HOB (Hob
);
187 Get available system memory below 1MB by specified size.
189 @param[in] WakeupBufferSize Wakeup buffer size required
191 @retval other Return wakeup buffer address below 1MB.
192 @retval -1 Cannot find free memory below 1MB.
196 IN UINTN WakeupBufferSize
199 EFI_PEI_HOB_POINTERS Hob
;
200 UINT64 WakeupBufferStart
;
201 UINT64 WakeupBufferEnd
;
203 WakeupBufferSize
= (WakeupBufferSize
+ SIZE_4KB
- 1) & ~(SIZE_4KB
- 1);
206 // Get the HOB list for processing
208 Hob
.Raw
= GetHobList ();
211 // Collect memory ranges
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
225 // Need memory under 1MB to be collected here
227 WakeupBufferEnd
= Hob
.ResourceDescriptor
->PhysicalStart
+ Hob
.ResourceDescriptor
->ResourceLength
;
228 if (ConfidentialComputingGuestHas (CCAttrAmdSevEs
) &&
229 (WakeupBufferEnd
> mSevEsPeiWakeupBuffer
))
232 // SEV-ES Wakeup buffer should be under 1MB and under any previous one
234 WakeupBufferEnd
= mSevEsPeiWakeupBuffer
;
235 } else if (WakeupBufferEnd
> BASE_1MB
) {
237 // Wakeup buffer should be under 1MB
239 WakeupBufferEnd
= BASE_1MB
;
242 while (WakeupBufferEnd
> WakeupBufferSize
) {
244 // Wakeup buffer should be aligned on 4KB
246 WakeupBufferStart
= (WakeupBufferEnd
- WakeupBufferSize
) & ~(SIZE_4KB
- 1);
247 if (WakeupBufferStart
< Hob
.ResourceDescriptor
->PhysicalStart
) {
251 if (CheckOverlapWithAllocatedBuffer (WakeupBufferStart
, WakeupBufferEnd
)) {
253 // If this range is overlapped with existing allocated buffer, skip it
254 // and find the next range
256 WakeupBufferEnd
-= WakeupBufferSize
;
262 "WakeupBufferStart = %x, WakeupBufferSize = %x\n",
267 if (ConfidentialComputingGuestHas (CCAttrAmdSevEs
)) {
269 // Next SEV-ES wakeup buffer allocation must be below this
272 mSevEsPeiWakeupBuffer
= WakeupBufferStart
;
275 return (UINTN
)WakeupBufferStart
;
283 Hob
.Raw
= GET_NEXT_HOB (Hob
);
290 Get available EfiBootServicesCode memory below 4GB by specified size.
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.
296 @param[in] BufferSize Wakeup transition buffer size.
298 @retval other Return wakeup transition buffer address below 4GB.
299 @retval 0 Cannot find free memory below 4GB.
307 EFI_PHYSICAL_ADDRESS Address
;
309 Status
= PeiServicesAllocatePages (EfiBootServicesCode
, EFI_SIZE_TO_PAGES (BufferSize
), &Address
);
310 if (EFI_ERROR (Status
)) {
314 return (UINTN
)Address
;
318 Return the address of the SEV-ES AP jump table.
320 This buffer is required in order for an SEV-ES guest to transition from
323 @return Return SEV-ES AP jump table buffer
331 // PEI phase doesn't need to do such transition. So simply return 0.
337 Checks APs status and updates APs status if needed.
341 CheckAndUpdateApsStatus (
348 Build the microcode patch HOB that contains the base address and size of the
349 microcode patch stored in the memory.
351 @param[in] CpuMpData Pointer to the CPU_MP_DATA structure.
355 BuildMicrocodeCacheHob (
356 IN CPU_MP_DATA
*CpuMpData
359 EDKII_MICROCODE_PATCH_HOB
*MicrocodeHob
;
363 HobDataLength
= sizeof (EDKII_MICROCODE_PATCH_HOB
) +
364 sizeof (UINT64
) * CpuMpData
->CpuCount
;
366 MicrocodeHob
= AllocatePool (HobDataLength
);
367 if (MicrocodeHob
== NULL
) {
373 // Store the information of the memory region that holds the microcode patches.
375 MicrocodeHob
->MicrocodePatchAddress
= CpuMpData
->MicrocodePatchAddress
;
376 MicrocodeHob
->MicrocodePatchRegionSize
= CpuMpData
->MicrocodePatchRegionSize
;
379 // Store the detected microcode patch for each processor as well.
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
;
387 MicrocodeHob
->ProcessorSpecificPatchOffset
[Index
] = MAX_UINT64
;
392 &gEdkiiMicrocodePatchHobGuid
,
401 Initialize global data for MP support.
403 @param[in] CpuMpData The pointer to CPU MP Data structure.
407 IN CPU_MP_DATA
*CpuMpData
412 BuildMicrocodeCacheHob (CpuMpData
);
413 SaveCpuMpData (CpuMpData
);
418 Status
= PeiServicesNotifyPpi (&mS3SmmInitDoneNotifyDesc
);
419 ASSERT_EFI_ERROR (Status
);
423 This service executes a caller provided function on all enabled APs.
425 @param[in] Procedure A pointer to the function to be run on
426 enabled APs of the system. See type
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
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
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
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
479 @retval EFI_SUCCESS In blocking mode, all APs have finished before
481 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
483 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
484 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
486 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
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.
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
508 if (WaitEvent
!= NULL
) {
509 return EFI_UNSUPPORTED
;
512 return StartupAllCPUsWorker (
517 TimeoutInMicroseconds
,
524 This service lets the caller get one enabled AP to execute a caller-provided
527 @param[in] Procedure A pointer to the function to be run on the
528 designated AP of the system. See type
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
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
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.
574 @retval EFI_SUCCESS In blocking mode, specified AP finished before
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
581 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
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.
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
605 if (WaitEvent
!= NULL
) {
606 return EFI_UNSUPPORTED
;
609 return StartupThisAPWorker (
613 TimeoutInMicroseconds
,
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
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.
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
641 @retval EFI_NOT_READY The specified AP is busy.
642 @retval EFI_NOT_READY MP Initialize Library is not initialized.
648 IN UINTN ProcessorNumber
,
649 IN BOOLEAN EnableOldBSP
652 return SwitchBSPWorker (ProcessorNumber
, EnableOldBSP
);
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.
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
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
681 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
682 @retval EFI_NOT_READY MP Initialize Library is not initialized.
687 MpInitLibEnableDisableAP (
688 IN UINTN ProcessorNumber
,
690 IN UINT32
*HealthFlag OPTIONAL
693 return EnableDisableApWorker (ProcessorNumber
, EnableAP
, HealthFlag
);
697 This funtion will try to invoke platform specific microcode shadow logic to
698 relocate microcode update patches into memory.
700 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
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
708 PlatformShadowMicrocode (
709 IN OUT CPU_MP_DATA
*CpuMpData
713 EDKII_PEI_SHADOW_MICROCODE_PPI
*ShadowMicrocodePpi
;
715 EDKII_PEI_MICROCODE_CPU_ID
*MicrocodeCpuId
;
720 Status
= PeiServicesLocatePpi (
721 &gEdkiiPeiShadowMicrocodePpiGuid
,
724 (VOID
**)&ShadowMicrocodePpi
726 if (EFI_ERROR (Status
)) {
727 return EFI_UNSUPPORTED
;
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
;
736 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
737 MicrocodeCpuId
[Index
].ProcessorSignature
= CpuMpData
->CpuData
[Index
].ProcessorSignature
;
738 MicrocodeCpuId
[Index
].PlatformId
= CpuMpData
->CpuData
[Index
].PlatformId
;
741 Status
= ShadowMicrocodePpi
->ShadowMicrocode (
748 FreePool (MicrocodeCpuId
);
749 if (EFI_ERROR (Status
)) {
750 return EFI_NOT_FOUND
;
753 CpuMpData
->MicrocodePatchAddress
= (UINTN
)Buffer
;
754 CpuMpData
->MicrocodePatchRegionSize
= BufferSize
;
758 "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n",
760 CpuMpData
->MicrocodePatchAddress
,
761 CpuMpData
->MicrocodePatchRegionSize