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>
15 S3 SMM Init Done notification function.
17 @param PeiServices Indirect reference to the PEI Services Table.
18 @param NotifyDesc Address of the notification descriptor data structure.
19 @param InvokePpi Address of the PPI that was invoked.
21 @retval EFI_SUCCESS The function completes successfully.
26 NotifyOnS3SmmInitDonePpi (
27 IN EFI_PEI_SERVICES
**PeiServices
,
28 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDesc
,
36 EFI_PEI_NOTIFY_DESCRIPTOR mS3SmmInitDoneNotifyDesc
= {
37 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
,
38 &gEdkiiS3SmmInitDoneGuid
,
39 NotifyOnS3SmmInitDonePpi
43 S3 SMM Init Done notification function.
45 @param PeiServices Indirect reference to the PEI Services Table.
46 @param NotifyDesc Address of the notification descriptor data structure.
47 @param InvokePpi Address of the PPI that was invoked.
49 @retval EFI_SUCCESS The function completes successfully.
54 NotifyOnS3SmmInitDonePpi (
55 IN EFI_PEI_SERVICES
**PeiServices
,
56 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDesc
,
60 CPU_MP_DATA
*CpuMpData
;
62 CpuMpData
= GetCpuMpData ();
65 // PiSmmCpuDxeSmm driver hardcode change the loop mode to HLT mode.
66 // So in this notify function, code need to check the current loop
67 // mode, if it is not HLT mode, code need to change loop mode back
68 // to the original mode.
70 if (CpuMpData
->ApLoopMode
!= ApInHltLoop
) {
71 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);
117 Save the pointer to CPU MP Data structure.
119 @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.
123 IN CPU_MP_DATA
*CpuMpData
128 // Build location of CPU MP DATA buffer in HOB
130 Data64
= (UINT64
) (UINTN
) CpuMpData
;
132 &mCpuInitMpLibHobGuid
,
139 Check if AP wakeup buffer is overlapped with existing allocated buffer.
141 @param[in] WakeupBufferStart AP wakeup buffer start address.
142 @param[in] WakeupBufferEnd AP wakeup buffer end address.
144 @retval TRUE There is overlap.
145 @retval FALSE There is no overlap.
148 CheckOverlapWithAllocatedBuffer (
149 IN UINT64 WakeupBufferStart
,
150 IN UINT64 WakeupBufferEnd
153 EFI_PEI_HOB_POINTERS Hob
;
154 EFI_HOB_MEMORY_ALLOCATION
*MemoryHob
;
161 // Get the HOB list for processing
163 Hob
.Raw
= GetHobList ();
165 // Collect memory ranges
167 while (!END_OF_HOB_LIST (Hob
)) {
168 if (Hob
.Header
->HobType
== EFI_HOB_TYPE_MEMORY_ALLOCATION
) {
169 MemoryHob
= Hob
.MemoryAllocation
;
170 MemoryStart
= MemoryHob
->AllocDescriptor
.MemoryBaseAddress
;
171 MemoryEnd
= MemoryHob
->AllocDescriptor
.MemoryBaseAddress
+ MemoryHob
->AllocDescriptor
.MemoryLength
;
172 if (!((WakeupBufferStart
>= MemoryEnd
) || (WakeupBufferEnd
<= MemoryStart
))) {
177 Hob
.Raw
= GET_NEXT_HOB (Hob
);
183 Get available system memory below 1MB by specified size.
185 @param[in] WakeupBufferSize Wakeup buffer size required
187 @retval other Return wakeup buffer address below 1MB.
188 @retval -1 Cannot find free memory below 1MB.
192 IN UINTN WakeupBufferSize
195 EFI_PEI_HOB_POINTERS Hob
;
196 UINT64 WakeupBufferStart
;
197 UINT64 WakeupBufferEnd
;
199 WakeupBufferSize
= (WakeupBufferSize
+ SIZE_4KB
- 1) & ~(SIZE_4KB
- 1);
202 // Get the HOB list for processing
204 Hob
.Raw
= GetHobList ();
207 // Collect memory ranges
209 while (!END_OF_HOB_LIST (Hob
)) {
210 if (Hob
.Header
->HobType
== EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
211 if ((Hob
.ResourceDescriptor
->PhysicalStart
< BASE_1MB
) &&
212 (Hob
.ResourceDescriptor
->ResourceType
== EFI_RESOURCE_SYSTEM_MEMORY
) &&
213 ((Hob
.ResourceDescriptor
->ResourceAttribute
&
214 (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED
|
215 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED
|
216 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
220 // Need memory under 1MB to be collected here
222 WakeupBufferEnd
= Hob
.ResourceDescriptor
->PhysicalStart
+ Hob
.ResourceDescriptor
->ResourceLength
;
223 if (WakeupBufferEnd
> BASE_1MB
) {
225 // Wakeup buffer should be under 1MB
227 WakeupBufferEnd
= BASE_1MB
;
229 while (WakeupBufferEnd
> WakeupBufferSize
) {
231 // Wakeup buffer should be aligned on 4KB
233 WakeupBufferStart
= (WakeupBufferEnd
- WakeupBufferSize
) & ~(SIZE_4KB
- 1);
234 if (WakeupBufferStart
< Hob
.ResourceDescriptor
->PhysicalStart
) {
237 if (CheckOverlapWithAllocatedBuffer (WakeupBufferStart
, WakeupBufferEnd
)) {
239 // If this range is overlapped with existing allocated buffer, skip it
240 // and find the next range
242 WakeupBufferEnd
-= WakeupBufferSize
;
245 DEBUG ((DEBUG_INFO
, "WakeupBufferStart = %x, WakeupBufferSize = %x\n",
246 WakeupBufferStart
, WakeupBufferSize
));
247 return (UINTN
)WakeupBufferStart
;
254 Hob
.Raw
= GET_NEXT_HOB (Hob
);
261 Get available EfiBootServicesCode memory below 4GB by specified size.
263 This buffer is required to safely transfer AP from real address mode to
264 protected mode or long mode, due to the fact that the buffer returned by
265 GetWakeupBuffer() may be marked as non-executable.
267 @param[in] BufferSize Wakeup transition buffer size.
269 @retval other Return wakeup transition buffer address below 4GB.
270 @retval 0 Cannot find free memory below 4GB.
273 GetModeTransitionBuffer (
278 // PEI phase doesn't need to do such transition. So simply return 0.
284 Return the address of the SEV-ES AP jump table.
286 This buffer is required in order for an SEV-ES guest to transition from
289 @return Return SEV-ES AP jump table buffer
297 // PEI phase doesn't need to do such transition. So simply return 0.
303 Checks APs status and updates APs status if needed.
307 CheckAndUpdateApsStatus (
314 Build the microcode patch HOB that contains the base address and size of the
315 microcode patch stored in the memory.
317 @param[in] CpuMpData Pointer to the CPU_MP_DATA structure.
321 BuildMicrocodeCacheHob (
322 IN CPU_MP_DATA
*CpuMpData
325 EDKII_MICROCODE_PATCH_HOB
*MicrocodeHob
;
329 HobDataLength
= sizeof (EDKII_MICROCODE_PATCH_HOB
) +
330 sizeof (UINT64
) * CpuMpData
->CpuCount
;
332 MicrocodeHob
= AllocatePool (HobDataLength
);
333 if (MicrocodeHob
== NULL
) {
339 // Store the information of the memory region that holds the microcode patches.
341 MicrocodeHob
->MicrocodePatchAddress
= CpuMpData
->MicrocodePatchAddress
;
342 MicrocodeHob
->MicrocodePatchRegionSize
= CpuMpData
->MicrocodePatchRegionSize
;
345 // Store the detected microcode patch for each processor as well.
347 MicrocodeHob
->ProcessorCount
= CpuMpData
->CpuCount
;
348 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
349 if (CpuMpData
->CpuData
[Index
].MicrocodeEntryAddr
!= 0) {
350 MicrocodeHob
->ProcessorSpecificPatchOffset
[Index
] =
351 CpuMpData
->CpuData
[Index
].MicrocodeEntryAddr
- CpuMpData
->MicrocodePatchAddress
;
353 MicrocodeHob
->ProcessorSpecificPatchOffset
[Index
] = MAX_UINT64
;
358 &gEdkiiMicrocodePatchHobGuid
,
367 Initialize global data for MP support.
369 @param[in] CpuMpData The pointer to CPU MP Data structure.
373 IN CPU_MP_DATA
*CpuMpData
378 BuildMicrocodeCacheHob (CpuMpData
);
379 SaveCpuMpData (CpuMpData
);
384 Status
= PeiServicesNotifyPpi (&mS3SmmInitDoneNotifyDesc
);
385 ASSERT_EFI_ERROR (Status
);
389 This service executes a caller provided function on all enabled APs.
391 @param[in] Procedure A pointer to the function to be run on
392 enabled APs of the system. See type
394 @param[in] SingleThread If TRUE, then all the enabled APs execute
395 the function specified by Procedure one by
396 one, in ascending order of processor handle
397 number. If FALSE, then all the enabled APs
398 execute the function specified by Procedure
400 @param[in] WaitEvent The event created by the caller with CreateEvent()
401 service. If it is NULL, then execute in
402 blocking mode. BSP waits until all APs finish
403 or TimeoutInMicroSeconds expires. If it's
404 not NULL, then execute in non-blocking mode.
405 BSP requests the function specified by
406 Procedure to be started on all the enabled
407 APs, and go on executing immediately. If
408 all return from Procedure, or TimeoutInMicroSeconds
409 expires, this event is signaled. The BSP
410 can use the CheckEvent() or WaitForEvent()
411 services to check the state of event. Type
412 EFI_EVENT is defined in CreateEvent() in
413 the Unified Extensible Firmware Interface
415 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
416 APs to return from Procedure, either for
417 blocking or non-blocking mode. Zero means
418 infinity. If the timeout expires before
419 all APs return from Procedure, then Procedure
420 on the failed APs is terminated. All enabled
421 APs are available for next function assigned
422 by MpInitLibStartupAllAPs() or
423 MPInitLibStartupThisAP().
424 If the timeout expires in blocking mode,
425 BSP returns EFI_TIMEOUT. If the timeout
426 expires in non-blocking mode, WaitEvent
427 is signaled with SignalEvent().
428 @param[in] ProcedureArgument The parameter passed into Procedure for
430 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
431 if all APs finish successfully, then its
432 content is set to NULL. If not all APs
433 finish before timeout expires, then its
434 content is set to address of the buffer
435 holding handle numbers of the failed APs.
436 The buffer is allocated by MP Initialization
437 library, and it's the caller's responsibility to
438 free the buffer with FreePool() service.
439 In blocking mode, it is ready for consumption
440 when the call returns. In non-blocking mode,
441 it is ready when WaitEvent is signaled. The
442 list of failed CPU is terminated by
445 @retval EFI_SUCCESS In blocking mode, all APs have finished before
447 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
449 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
450 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
452 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
454 @retval EFI_DEVICE_ERROR Caller processor is AP.
455 @retval EFI_NOT_STARTED No enabled APs exist in the system.
456 @retval EFI_NOT_READY Any enabled APs are busy.
457 @retval EFI_NOT_READY MP Initialize Library is not initialized.
458 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
459 all enabled APs have finished.
460 @retval EFI_INVALID_PARAMETER Procedure is NULL.
465 MpInitLibStartupAllAPs (
466 IN EFI_AP_PROCEDURE Procedure
,
467 IN BOOLEAN SingleThread
,
468 IN EFI_EVENT WaitEvent OPTIONAL
,
469 IN UINTN TimeoutInMicroseconds
,
470 IN VOID
*ProcedureArgument OPTIONAL
,
471 OUT UINTN
**FailedCpuList OPTIONAL
474 if (WaitEvent
!= NULL
) {
475 return EFI_UNSUPPORTED
;
478 return StartupAllCPUsWorker (
483 TimeoutInMicroseconds
,
490 This service lets the caller get one enabled AP to execute a caller-provided
493 @param[in] Procedure A pointer to the function to be run on the
494 designated AP of the system. See type
496 @param[in] ProcessorNumber The handle number of the AP. The range is
497 from 0 to the total number of logical
498 processors minus 1. The total number of
499 logical processors can be retrieved by
500 MpInitLibGetNumberOfProcessors().
501 @param[in] WaitEvent The event created by the caller with CreateEvent()
502 service. If it is NULL, then execute in
503 blocking mode. BSP waits until this AP finish
504 or TimeoutInMicroSeconds expires. If it's
505 not NULL, then execute in non-blocking mode.
506 BSP requests the function specified by
507 Procedure to be started on this AP,
508 and go on executing immediately. If this AP
509 return from Procedure or TimeoutInMicroSeconds
510 expires, this event is signaled. The BSP
511 can use the CheckEvent() or WaitForEvent()
512 services to check the state of event. Type
513 EFI_EVENT is defined in CreateEvent() in
514 the Unified Extensible Firmware Interface
516 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
517 this AP to finish this Procedure, either for
518 blocking or non-blocking mode. Zero means
519 infinity. If the timeout expires before
520 this AP returns from Procedure, then Procedure
521 on the AP is terminated. The
522 AP is available for next function assigned
523 by MpInitLibStartupAllAPs() or
524 MpInitLibStartupThisAP().
525 If the timeout expires in blocking mode,
526 BSP returns EFI_TIMEOUT. If the timeout
527 expires in non-blocking mode, WaitEvent
528 is signaled with SignalEvent().
529 @param[in] ProcedureArgument The parameter passed into Procedure on the
531 @param[out] Finished If NULL, this parameter is ignored. In
532 blocking mode, this parameter is ignored.
533 In non-blocking mode, if AP returns from
534 Procedure before the timeout expires, its
535 content is set to TRUE. Otherwise, the
536 value is set to FALSE. The caller can
537 determine if the AP returned from Procedure
538 by evaluating this value.
540 @retval EFI_SUCCESS In blocking mode, specified AP finished before
542 @retval EFI_SUCCESS In non-blocking mode, the function has been
543 dispatched to specified AP.
544 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
545 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
547 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
549 @retval EFI_DEVICE_ERROR The calling processor is an AP.
550 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
551 the specified AP has finished.
552 @retval EFI_NOT_READY The specified AP is busy.
553 @retval EFI_NOT_READY MP Initialize Library is not initialized.
554 @retval EFI_NOT_FOUND The processor with the handle specified by
555 ProcessorNumber does not exist.
556 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
557 @retval EFI_INVALID_PARAMETER Procedure is NULL.
562 MpInitLibStartupThisAP (
563 IN EFI_AP_PROCEDURE Procedure
,
564 IN UINTN ProcessorNumber
,
565 IN EFI_EVENT WaitEvent OPTIONAL
,
566 IN UINTN TimeoutInMicroseconds
,
567 IN VOID
*ProcedureArgument OPTIONAL
,
568 OUT BOOLEAN
*Finished OPTIONAL
571 if (WaitEvent
!= NULL
) {
572 return EFI_UNSUPPORTED
;
575 return StartupThisAPWorker (
579 TimeoutInMicroseconds
,
586 This service switches the requested AP to be the BSP from that point onward.
587 This service changes the BSP for all purposes. This call can only be performed
590 @param[in] ProcessorNumber The handle number of AP that is to become the new
591 BSP. The range is from 0 to the total number of
592 logical processors minus 1. The total number of
593 logical processors can be retrieved by
594 MpInitLibGetNumberOfProcessors().
595 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
596 enabled AP. Otherwise, it will be disabled.
598 @retval EFI_SUCCESS BSP successfully switched.
599 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
600 this service returning.
601 @retval EFI_UNSUPPORTED Switching the BSP is not supported.
602 @retval EFI_DEVICE_ERROR The calling processor is an AP.
603 @retval EFI_NOT_FOUND The processor with the handle specified by
604 ProcessorNumber does not exist.
605 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
607 @retval EFI_NOT_READY The specified AP is busy.
608 @retval EFI_NOT_READY MP Initialize Library is not initialized.
614 IN UINTN ProcessorNumber
,
615 IN BOOLEAN EnableOldBSP
618 return SwitchBSPWorker (ProcessorNumber
, EnableOldBSP
);
622 This service lets the caller enable or disable an AP from this point onward.
623 This service may only be called from the BSP.
625 @param[in] ProcessorNumber The handle number of AP.
626 The range is from 0 to the total number of
627 logical processors minus 1. The total number of
628 logical processors can be retrieved by
629 MpInitLibGetNumberOfProcessors().
630 @param[in] EnableAP Specifies the new state for the processor for
631 enabled, FALSE for disabled.
632 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
633 the new health status of the AP. This flag
634 corresponds to StatusFlag defined in
635 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
636 the PROCESSOR_HEALTH_STATUS_BIT is used. All other
637 bits are ignored. If it is NULL, this parameter
640 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
641 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
642 prior to this service returning.
643 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
644 @retval EFI_DEVICE_ERROR The calling processor is an AP.
645 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
647 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
648 @retval EFI_NOT_READY MP Initialize Library is not initialized.
653 MpInitLibEnableDisableAP (
654 IN UINTN ProcessorNumber
,
656 IN UINT32
*HealthFlag OPTIONAL
659 return EnableDisableApWorker (ProcessorNumber
, EnableAP
, HealthFlag
);
663 This funtion will try to invoke platform specific microcode shadow logic to
664 relocate microcode update patches into memory.
666 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
668 @retval EFI_SUCCESS Shadow microcode success.
669 @retval EFI_OUT_OF_RESOURCES No enough resource to complete the operation.
670 @retval EFI_UNSUPPORTED Can't find platform specific microcode shadow
674 PlatformShadowMicrocode (
675 IN OUT CPU_MP_DATA
*CpuMpData
679 EDKII_PEI_SHADOW_MICROCODE_PPI
*ShadowMicrocodePpi
;
681 EDKII_PEI_MICROCODE_CPU_ID
*MicrocodeCpuId
;
686 Status
= PeiServicesLocatePpi (
687 &gEdkiiPeiShadowMicrocodePpiGuid
,
690 (VOID
**) &ShadowMicrocodePpi
692 if (EFI_ERROR (Status
)) {
693 return EFI_UNSUPPORTED
;
696 CpuCount
= CpuMpData
->CpuCount
;
697 MicrocodeCpuId
= (EDKII_PEI_MICROCODE_CPU_ID
*) AllocateZeroPool (sizeof (EDKII_PEI_MICROCODE_CPU_ID
) * CpuCount
);
698 if (MicrocodeCpuId
== NULL
) {
699 return EFI_OUT_OF_RESOURCES
;
702 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
703 MicrocodeCpuId
[Index
].ProcessorSignature
= CpuMpData
->CpuData
[Index
].ProcessorSignature
;
704 MicrocodeCpuId
[Index
].PlatformId
= CpuMpData
->CpuData
[Index
].PlatformId
;
707 Status
= ShadowMicrocodePpi
->ShadowMicrocode (
714 FreePool (MicrocodeCpuId
);
715 if (EFI_ERROR (Status
)) {
716 return EFI_NOT_FOUND
;
719 CpuMpData
->MicrocodePatchAddress
= (UINTN
) Buffer
;
720 CpuMpData
->MicrocodePatchRegionSize
= BufferSize
;
724 "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n",
725 __FUNCTION__
, CpuMpData
->MicrocodePatchAddress
, CpuMpData
->MicrocodePatchRegionSize