2 MP initialize support functions for PEI phase.
4 Copyright (c) 2016 - 2019, 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 <Guid/MicrocodePatchHob.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 Checks APs status and updates APs status if needed.
288 CheckAndUpdateApsStatus (
295 Build the microcode patch HOB that contains the base address and size of the
296 microcode patch stored in the memory.
298 @param[in] CpuMpData Pointer to the CPU_MP_DATA structure.
302 BuildMicrocodeCacheHob (
303 IN CPU_MP_DATA
*CpuMpData
306 EDKII_MICROCODE_PATCH_HOB
*MicrocodeHob
;
310 HobDataLength
= sizeof (EDKII_MICROCODE_PATCH_HOB
) +
311 sizeof (UINT64
) * CpuMpData
->CpuCount
;
313 MicrocodeHob
= AllocatePool (HobDataLength
);
314 if (MicrocodeHob
== NULL
) {
320 // Store the information of the memory region that holds the microcode patches.
322 MicrocodeHob
->MicrocodePatchAddress
= CpuMpData
->MicrocodePatchAddress
;
323 MicrocodeHob
->MicrocodePatchRegionSize
= CpuMpData
->MicrocodePatchRegionSize
;
326 // Store the detected microcode patch for each processor as well.
328 MicrocodeHob
->ProcessorCount
= CpuMpData
->CpuCount
;
329 for (Index
= 0; Index
< CpuMpData
->CpuCount
; Index
++) {
330 if (CpuMpData
->CpuData
[Index
].MicrocodeEntryAddr
!= 0) {
331 MicrocodeHob
->ProcessorSpecificPatchOffset
[Index
] =
332 CpuMpData
->CpuData
[Index
].MicrocodeEntryAddr
- CpuMpData
->MicrocodePatchAddress
;
334 MicrocodeHob
->ProcessorSpecificPatchOffset
[Index
] = MAX_UINT64
;
339 &gEdkiiMicrocodePatchHobGuid
,
348 Initialize global data for MP support.
350 @param[in] CpuMpData The pointer to CPU MP Data structure.
354 IN CPU_MP_DATA
*CpuMpData
359 BuildMicrocodeCacheHob (CpuMpData
);
360 SaveCpuMpData (CpuMpData
);
365 Status
= PeiServicesNotifyPpi (&mS3SmmInitDoneNotifyDesc
);
366 ASSERT_EFI_ERROR (Status
);
370 This service executes a caller provided function on all enabled APs.
372 @param[in] Procedure A pointer to the function to be run on
373 enabled APs of the system. See type
375 @param[in] SingleThread If TRUE, then all the enabled APs execute
376 the function specified by Procedure one by
377 one, in ascending order of processor handle
378 number. If FALSE, then all the enabled APs
379 execute the function specified by Procedure
381 @param[in] WaitEvent The event created by the caller with CreateEvent()
382 service. If it is NULL, then execute in
383 blocking mode. BSP waits until all APs finish
384 or TimeoutInMicroSeconds expires. If it's
385 not NULL, then execute in non-blocking mode.
386 BSP requests the function specified by
387 Procedure to be started on all the enabled
388 APs, and go on executing immediately. If
389 all return from Procedure, or TimeoutInMicroSeconds
390 expires, this event is signaled. The BSP
391 can use the CheckEvent() or WaitForEvent()
392 services to check the state of event. Type
393 EFI_EVENT is defined in CreateEvent() in
394 the Unified Extensible Firmware Interface
396 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
397 APs to return from Procedure, either for
398 blocking or non-blocking mode. Zero means
399 infinity. If the timeout expires before
400 all APs return from Procedure, then Procedure
401 on the failed APs is terminated. All enabled
402 APs are available for next function assigned
403 by MpInitLibStartupAllAPs() or
404 MPInitLibStartupThisAP().
405 If the timeout expires in blocking mode,
406 BSP returns EFI_TIMEOUT. If the timeout
407 expires in non-blocking mode, WaitEvent
408 is signaled with SignalEvent().
409 @param[in] ProcedureArgument The parameter passed into Procedure for
411 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
412 if all APs finish successfully, then its
413 content is set to NULL. If not all APs
414 finish before timeout expires, then its
415 content is set to address of the buffer
416 holding handle numbers of the failed APs.
417 The buffer is allocated by MP Initialization
418 library, and it's the caller's responsibility to
419 free the buffer with FreePool() service.
420 In blocking mode, it is ready for consumption
421 when the call returns. In non-blocking mode,
422 it is ready when WaitEvent is signaled. The
423 list of failed CPU is terminated by
426 @retval EFI_SUCCESS In blocking mode, all APs have finished before
428 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
430 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
431 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
433 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
435 @retval EFI_DEVICE_ERROR Caller processor is AP.
436 @retval EFI_NOT_STARTED No enabled APs exist in the system.
437 @retval EFI_NOT_READY Any enabled APs are busy.
438 @retval EFI_NOT_READY MP Initialize Library is not initialized.
439 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
440 all enabled APs have finished.
441 @retval EFI_INVALID_PARAMETER Procedure is NULL.
446 MpInitLibStartupAllAPs (
447 IN EFI_AP_PROCEDURE Procedure
,
448 IN BOOLEAN SingleThread
,
449 IN EFI_EVENT WaitEvent OPTIONAL
,
450 IN UINTN TimeoutInMicroseconds
,
451 IN VOID
*ProcedureArgument OPTIONAL
,
452 OUT UINTN
**FailedCpuList OPTIONAL
455 if (WaitEvent
!= NULL
) {
456 return EFI_UNSUPPORTED
;
459 return StartupAllCPUsWorker (
464 TimeoutInMicroseconds
,
471 This service lets the caller get one enabled AP to execute a caller-provided
474 @param[in] Procedure A pointer to the function to be run on the
475 designated AP of the system. See type
477 @param[in] ProcessorNumber The handle number of the AP. The range is
478 from 0 to the total number of logical
479 processors minus 1. The total number of
480 logical processors can be retrieved by
481 MpInitLibGetNumberOfProcessors().
482 @param[in] WaitEvent The event created by the caller with CreateEvent()
483 service. If it is NULL, then execute in
484 blocking mode. BSP waits until this AP finish
485 or TimeoutInMicroSeconds expires. If it's
486 not NULL, then execute in non-blocking mode.
487 BSP requests the function specified by
488 Procedure to be started on this AP,
489 and go on executing immediately. If this AP
490 return from Procedure or TimeoutInMicroSeconds
491 expires, this event is signaled. The BSP
492 can use the CheckEvent() or WaitForEvent()
493 services to check the state of event. Type
494 EFI_EVENT is defined in CreateEvent() in
495 the Unified Extensible Firmware Interface
497 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
498 this AP to finish this Procedure, either for
499 blocking or non-blocking mode. Zero means
500 infinity. If the timeout expires before
501 this AP returns from Procedure, then Procedure
502 on the AP is terminated. The
503 AP is available for next function assigned
504 by MpInitLibStartupAllAPs() or
505 MpInitLibStartupThisAP().
506 If the timeout expires in blocking mode,
507 BSP returns EFI_TIMEOUT. If the timeout
508 expires in non-blocking mode, WaitEvent
509 is signaled with SignalEvent().
510 @param[in] ProcedureArgument The parameter passed into Procedure on the
512 @param[out] Finished If NULL, this parameter is ignored. In
513 blocking mode, this parameter is ignored.
514 In non-blocking mode, if AP returns from
515 Procedure before the timeout expires, its
516 content is set to TRUE. Otherwise, the
517 value is set to FALSE. The caller can
518 determine if the AP returned from Procedure
519 by evaluating this value.
521 @retval EFI_SUCCESS In blocking mode, specified AP finished before
523 @retval EFI_SUCCESS In non-blocking mode, the function has been
524 dispatched to specified AP.
525 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
526 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
528 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
530 @retval EFI_DEVICE_ERROR The calling processor is an AP.
531 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
532 the specified AP has finished.
533 @retval EFI_NOT_READY The specified AP is busy.
534 @retval EFI_NOT_READY MP Initialize Library is not initialized.
535 @retval EFI_NOT_FOUND The processor with the handle specified by
536 ProcessorNumber does not exist.
537 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
538 @retval EFI_INVALID_PARAMETER Procedure is NULL.
543 MpInitLibStartupThisAP (
544 IN EFI_AP_PROCEDURE Procedure
,
545 IN UINTN ProcessorNumber
,
546 IN EFI_EVENT WaitEvent OPTIONAL
,
547 IN UINTN TimeoutInMicroseconds
,
548 IN VOID
*ProcedureArgument OPTIONAL
,
549 OUT BOOLEAN
*Finished OPTIONAL
552 if (WaitEvent
!= NULL
) {
553 return EFI_UNSUPPORTED
;
556 return StartupThisAPWorker (
560 TimeoutInMicroseconds
,
567 This service switches the requested AP to be the BSP from that point onward.
568 This service changes the BSP for all purposes. This call can only be performed
571 @param[in] ProcessorNumber The handle number of AP that is to become the new
572 BSP. The range is from 0 to the total number of
573 logical processors minus 1. The total number of
574 logical processors can be retrieved by
575 MpInitLibGetNumberOfProcessors().
576 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
577 enabled AP. Otherwise, it will be disabled.
579 @retval EFI_SUCCESS BSP successfully switched.
580 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
581 this service returning.
582 @retval EFI_UNSUPPORTED Switching the BSP is not supported.
583 @retval EFI_DEVICE_ERROR The calling processor is an AP.
584 @retval EFI_NOT_FOUND The processor with the handle specified by
585 ProcessorNumber does not exist.
586 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
588 @retval EFI_NOT_READY The specified AP is busy.
589 @retval EFI_NOT_READY MP Initialize Library is not initialized.
595 IN UINTN ProcessorNumber
,
596 IN BOOLEAN EnableOldBSP
599 return SwitchBSPWorker (ProcessorNumber
, EnableOldBSP
);
603 This service lets the caller enable or disable an AP from this point onward.
604 This service may only be called from the BSP.
606 @param[in] ProcessorNumber The handle number of AP.
607 The range is from 0 to the total number of
608 logical processors minus 1. The total number of
609 logical processors can be retrieved by
610 MpInitLibGetNumberOfProcessors().
611 @param[in] EnableAP Specifies the new state for the processor for
612 enabled, FALSE for disabled.
613 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
614 the new health status of the AP. This flag
615 corresponds to StatusFlag defined in
616 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
617 the PROCESSOR_HEALTH_STATUS_BIT is used. All other
618 bits are ignored. If it is NULL, this parameter
621 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
622 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
623 prior to this service returning.
624 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
625 @retval EFI_DEVICE_ERROR The calling processor is an AP.
626 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
628 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
629 @retval EFI_NOT_READY MP Initialize Library is not initialized.
634 MpInitLibEnableDisableAP (
635 IN UINTN ProcessorNumber
,
637 IN UINT32
*HealthFlag OPTIONAL
640 return EnableDisableApWorker (ProcessorNumber
, EnableAP
, HealthFlag
);