2 MP initialize support functions for PEI phase.
4 Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include <Library/PeiServicesLib.h>
11 #include <Guid/S3SmmInitDone.h>
14 S3 SMM Init Done notification function.
16 @param PeiServices Indirect reference to the PEI Services Table.
17 @param NotifyDesc Address of the notification descriptor data structure.
18 @param InvokePpi Address of the PPI that was invoked.
20 @retval EFI_SUCCESS The function completes successfully.
25 NotifyOnS3SmmInitDonePpi (
26 IN EFI_PEI_SERVICES
**PeiServices
,
27 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDesc
,
35 EFI_PEI_NOTIFY_DESCRIPTOR mS3SmmInitDoneNotifyDesc
= {
36 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
,
37 &gEdkiiS3SmmInitDoneGuid
,
38 NotifyOnS3SmmInitDonePpi
42 S3 SMM Init Done notification function.
44 @param PeiServices Indirect reference to the PEI Services Table.
45 @param NotifyDesc Address of the notification descriptor data structure.
46 @param InvokePpi Address of the PPI that was invoked.
48 @retval EFI_SUCCESS The function completes successfully.
53 NotifyOnS3SmmInitDonePpi (
54 IN EFI_PEI_SERVICES
**PeiServices
,
55 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDesc
,
59 CPU_MP_DATA
*CpuMpData
;
61 CpuMpData
= GetCpuMpData ();
64 // PiSmmCpuDxeSmm driver hardcode change the loop mode to HLT mode.
65 // So in this notify function, code need to check the current loop
66 // mode, if it is not HLT mode, code need to change loop mode back
67 // to the original mode.
69 if (CpuMpData
->ApLoopMode
!= ApInHltLoop
) {
70 CpuMpData
->WakeUpByInitSipiSipi
= TRUE
;
78 Enable Debug Agent to support source debugging on AP function.
89 Get pointer to CPU MP Data structure.
90 For BSP, the pointer is retrieved from HOB.
91 For AP, the structure is just after IDT.
93 @return The pointer to CPU MP Data structure.
100 CPU_MP_DATA
*CpuMpData
;
101 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr
;
102 IA32_DESCRIPTOR Idtr
;
104 ApicBaseMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_APIC_BASE
);
105 if (ApicBaseMsr
.Bits
.BSP
== 1) {
106 CpuMpData
= GetCpuMpDataFromGuidedHob ();
107 ASSERT (CpuMpData
!= NULL
);
110 CpuMpData
= (CPU_MP_DATA
*) (Idtr
.Base
+ Idtr
.Limit
+ 1);
116 Save the pointer to CPU MP Data structure.
118 @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.
122 IN CPU_MP_DATA
*CpuMpData
127 // Build location of CPU MP DATA buffer in HOB
129 Data64
= (UINT64
) (UINTN
) CpuMpData
;
131 &mCpuInitMpLibHobGuid
,
138 Check if AP wakeup buffer is overlapped with existing allocated buffer.
140 @param[in] WakeupBufferStart AP wakeup buffer start address.
141 @param[in] WakeupBufferEnd AP wakeup buffer end address.
143 @retval TRUE There is overlap.
144 @retval FALSE There is no overlap.
147 CheckOverlapWithAllocatedBuffer (
148 IN UINT64 WakeupBufferStart
,
149 IN UINT64 WakeupBufferEnd
152 EFI_PEI_HOB_POINTERS Hob
;
153 EFI_HOB_MEMORY_ALLOCATION
*MemoryHob
;
160 // Get the HOB list for processing
162 Hob
.Raw
= GetHobList ();
164 // Collect memory ranges
166 while (!END_OF_HOB_LIST (Hob
)) {
167 if (Hob
.Header
->HobType
== EFI_HOB_TYPE_MEMORY_ALLOCATION
) {
168 MemoryHob
= Hob
.MemoryAllocation
;
169 MemoryStart
= MemoryHob
->AllocDescriptor
.MemoryBaseAddress
;
170 MemoryEnd
= MemoryHob
->AllocDescriptor
.MemoryBaseAddress
+ MemoryHob
->AllocDescriptor
.MemoryLength
;
171 if (!((WakeupBufferStart
>= MemoryEnd
) || (WakeupBufferEnd
<= MemoryStart
))) {
176 Hob
.Raw
= GET_NEXT_HOB (Hob
);
182 Get available system memory below 1MB by specified size.
184 @param[in] WakeupBufferSize Wakeup buffer size required
186 @retval other Return wakeup buffer address below 1MB.
187 @retval -1 Cannot find free memory below 1MB.
191 IN UINTN WakeupBufferSize
194 EFI_PEI_HOB_POINTERS Hob
;
195 UINT64 WakeupBufferStart
;
196 UINT64 WakeupBufferEnd
;
198 WakeupBufferSize
= (WakeupBufferSize
+ SIZE_4KB
- 1) & ~(SIZE_4KB
- 1);
201 // Get the HOB list for processing
203 Hob
.Raw
= GetHobList ();
206 // Collect memory ranges
208 while (!END_OF_HOB_LIST (Hob
)) {
209 if (Hob
.Header
->HobType
== EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
210 if ((Hob
.ResourceDescriptor
->PhysicalStart
< BASE_1MB
) &&
211 (Hob
.ResourceDescriptor
->ResourceType
== EFI_RESOURCE_SYSTEM_MEMORY
) &&
212 ((Hob
.ResourceDescriptor
->ResourceAttribute
&
213 (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED
|
214 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED
|
215 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
219 // Need memory under 1MB to be collected here
221 WakeupBufferEnd
= Hob
.ResourceDescriptor
->PhysicalStart
+ Hob
.ResourceDescriptor
->ResourceLength
;
222 if (WakeupBufferEnd
> BASE_1MB
) {
224 // Wakeup buffer should be under 1MB
226 WakeupBufferEnd
= BASE_1MB
;
228 while (WakeupBufferEnd
> WakeupBufferSize
) {
230 // Wakeup buffer should be aligned on 4KB
232 WakeupBufferStart
= (WakeupBufferEnd
- WakeupBufferSize
) & ~(SIZE_4KB
- 1);
233 if (WakeupBufferStart
< Hob
.ResourceDescriptor
->PhysicalStart
) {
236 if (CheckOverlapWithAllocatedBuffer (WakeupBufferStart
, WakeupBufferEnd
)) {
238 // If this range is overlapped with existing allocated buffer, skip it
239 // and find the next range
241 WakeupBufferEnd
-= WakeupBufferSize
;
244 DEBUG ((DEBUG_INFO
, "WakeupBufferStart = %x, WakeupBufferSize = %x\n",
245 WakeupBufferStart
, WakeupBufferSize
));
246 return (UINTN
)WakeupBufferStart
;
253 Hob
.Raw
= GET_NEXT_HOB (Hob
);
260 Get available EfiBootServicesCode memory below 4GB by specified size.
262 This buffer is required to safely transfer AP from real address mode to
263 protected mode or long mode, due to the fact that the buffer returned by
264 GetWakeupBuffer() may be marked as non-executable.
266 @param[in] BufferSize Wakeup transition buffer size.
268 @retval other Return wakeup transition buffer address below 4GB.
269 @retval 0 Cannot find free memory below 4GB.
272 GetModeTransitionBuffer (
277 // PEI phase doesn't need to do such transition. So simply return 0.
283 Checks APs status and updates APs status if needed.
287 CheckAndUpdateApsStatus (
294 Initialize global data for MP support.
296 @param[in] CpuMpData The pointer to CPU MP Data structure.
300 IN CPU_MP_DATA
*CpuMpData
305 SaveCpuMpData (CpuMpData
);
310 Status
= PeiServicesNotifyPpi (&mS3SmmInitDoneNotifyDesc
);
311 ASSERT_EFI_ERROR (Status
);
315 This service executes a caller provided function on all enabled APs.
317 @param[in] Procedure A pointer to the function to be run on
318 enabled APs of the system. See type
320 @param[in] SingleThread If TRUE, then all the enabled APs execute
321 the function specified by Procedure one by
322 one, in ascending order of processor handle
323 number. If FALSE, then all the enabled APs
324 execute the function specified by Procedure
326 @param[in] WaitEvent The event created by the caller with CreateEvent()
327 service. If it is NULL, then execute in
328 blocking mode. BSP waits until all APs finish
329 or TimeoutInMicroSeconds expires. If it's
330 not NULL, then execute in non-blocking mode.
331 BSP requests the function specified by
332 Procedure to be started on all the enabled
333 APs, and go on executing immediately. If
334 all return from Procedure, or TimeoutInMicroSeconds
335 expires, this event is signaled. The BSP
336 can use the CheckEvent() or WaitForEvent()
337 services to check the state of event. Type
338 EFI_EVENT is defined in CreateEvent() in
339 the Unified Extensible Firmware Interface
341 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
342 APs to return from Procedure, either for
343 blocking or non-blocking mode. Zero means
344 infinity. If the timeout expires before
345 all APs return from Procedure, then Procedure
346 on the failed APs is terminated. All enabled
347 APs are available for next function assigned
348 by MpInitLibStartupAllAPs() or
349 MPInitLibStartupThisAP().
350 If the timeout expires in blocking mode,
351 BSP returns EFI_TIMEOUT. If the timeout
352 expires in non-blocking mode, WaitEvent
353 is signaled with SignalEvent().
354 @param[in] ProcedureArgument The parameter passed into Procedure for
356 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
357 if all APs finish successfully, then its
358 content is set to NULL. If not all APs
359 finish before timeout expires, then its
360 content is set to address of the buffer
361 holding handle numbers of the failed APs.
362 The buffer is allocated by MP Initialization
363 library, and it's the caller's responsibility to
364 free the buffer with FreePool() service.
365 In blocking mode, it is ready for consumption
366 when the call returns. In non-blocking mode,
367 it is ready when WaitEvent is signaled. The
368 list of failed CPU is terminated by
371 @retval EFI_SUCCESS In blocking mode, all APs have finished before
373 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
375 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
376 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
378 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
380 @retval EFI_DEVICE_ERROR Caller processor is AP.
381 @retval EFI_NOT_STARTED No enabled APs exist in the system.
382 @retval EFI_NOT_READY Any enabled APs are busy.
383 @retval EFI_NOT_READY MP Initialize Library is not initialized.
384 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
385 all enabled APs have finished.
386 @retval EFI_INVALID_PARAMETER Procedure is NULL.
391 MpInitLibStartupAllAPs (
392 IN EFI_AP_PROCEDURE Procedure
,
393 IN BOOLEAN SingleThread
,
394 IN EFI_EVENT WaitEvent OPTIONAL
,
395 IN UINTN TimeoutInMicroseconds
,
396 IN VOID
*ProcedureArgument OPTIONAL
,
397 OUT UINTN
**FailedCpuList OPTIONAL
400 if (WaitEvent
!= NULL
) {
401 return EFI_UNSUPPORTED
;
404 return StartupAllAPsWorker (
408 TimeoutInMicroseconds
,
415 This service lets the caller get one enabled AP to execute a caller-provided
418 @param[in] Procedure A pointer to the function to be run on the
419 designated AP of the system. See type
421 @param[in] ProcessorNumber The handle number of the AP. The range is
422 from 0 to the total number of logical
423 processors minus 1. The total number of
424 logical processors can be retrieved by
425 MpInitLibGetNumberOfProcessors().
426 @param[in] WaitEvent The event created by the caller with CreateEvent()
427 service. If it is NULL, then execute in
428 blocking mode. BSP waits until this AP finish
429 or TimeoutInMicroSeconds expires. If it's
430 not NULL, then execute in non-blocking mode.
431 BSP requests the function specified by
432 Procedure to be started on this AP,
433 and go on executing immediately. If this AP
434 return from Procedure or TimeoutInMicroSeconds
435 expires, this event is signaled. The BSP
436 can use the CheckEvent() or WaitForEvent()
437 services to check the state of event. Type
438 EFI_EVENT is defined in CreateEvent() in
439 the Unified Extensible Firmware Interface
441 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
442 this AP to finish this Procedure, either for
443 blocking or non-blocking mode. Zero means
444 infinity. If the timeout expires before
445 this AP returns from Procedure, then Procedure
446 on the AP is terminated. The
447 AP is available for next function assigned
448 by MpInitLibStartupAllAPs() or
449 MpInitLibStartupThisAP().
450 If the timeout expires in blocking mode,
451 BSP returns EFI_TIMEOUT. If the timeout
452 expires in non-blocking mode, WaitEvent
453 is signaled with SignalEvent().
454 @param[in] ProcedureArgument The parameter passed into Procedure on the
456 @param[out] Finished If NULL, this parameter is ignored. In
457 blocking mode, this parameter is ignored.
458 In non-blocking mode, if AP returns from
459 Procedure before the timeout expires, its
460 content is set to TRUE. Otherwise, the
461 value is set to FALSE. The caller can
462 determine if the AP returned from Procedure
463 by evaluating this value.
465 @retval EFI_SUCCESS In blocking mode, specified AP finished before
467 @retval EFI_SUCCESS In non-blocking mode, the function has been
468 dispatched to specified AP.
469 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
470 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
472 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
474 @retval EFI_DEVICE_ERROR The calling processor is an AP.
475 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
476 the specified AP has finished.
477 @retval EFI_NOT_READY The specified AP is busy.
478 @retval EFI_NOT_READY MP Initialize Library is not initialized.
479 @retval EFI_NOT_FOUND The processor with the handle specified by
480 ProcessorNumber does not exist.
481 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
482 @retval EFI_INVALID_PARAMETER Procedure is NULL.
487 MpInitLibStartupThisAP (
488 IN EFI_AP_PROCEDURE Procedure
,
489 IN UINTN ProcessorNumber
,
490 IN EFI_EVENT WaitEvent OPTIONAL
,
491 IN UINTN TimeoutInMicroseconds
,
492 IN VOID
*ProcedureArgument OPTIONAL
,
493 OUT BOOLEAN
*Finished OPTIONAL
496 if (WaitEvent
!= NULL
) {
497 return EFI_UNSUPPORTED
;
500 return StartupThisAPWorker (
504 TimeoutInMicroseconds
,
511 This service switches the requested AP to be the BSP from that point onward.
512 This service changes the BSP for all purposes. This call can only be performed
515 @param[in] ProcessorNumber The handle number of AP that is to become the new
516 BSP. The range is from 0 to the total number of
517 logical processors minus 1. The total number of
518 logical processors can be retrieved by
519 MpInitLibGetNumberOfProcessors().
520 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
521 enabled AP. Otherwise, it will be disabled.
523 @retval EFI_SUCCESS BSP successfully switched.
524 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
525 this service returning.
526 @retval EFI_UNSUPPORTED Switching the BSP is not supported.
527 @retval EFI_DEVICE_ERROR The calling processor is an AP.
528 @retval EFI_NOT_FOUND The processor with the handle specified by
529 ProcessorNumber does not exist.
530 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
532 @retval EFI_NOT_READY The specified AP is busy.
533 @retval EFI_NOT_READY MP Initialize Library is not initialized.
539 IN UINTN ProcessorNumber
,
540 IN BOOLEAN EnableOldBSP
543 return SwitchBSPWorker (ProcessorNumber
, EnableOldBSP
);
547 This service lets the caller enable or disable an AP from this point onward.
548 This service may only be called from the BSP.
550 @param[in] ProcessorNumber The handle number of AP.
551 The range is from 0 to the total number of
552 logical processors minus 1. The total number of
553 logical processors can be retrieved by
554 MpInitLibGetNumberOfProcessors().
555 @param[in] EnableAP Specifies the new state for the processor for
556 enabled, FALSE for disabled.
557 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
558 the new health status of the AP. This flag
559 corresponds to StatusFlag defined in
560 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
561 the PROCESSOR_HEALTH_STATUS_BIT is used. All other
562 bits are ignored. If it is NULL, this parameter
565 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
566 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
567 prior to this service returning.
568 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
569 @retval EFI_DEVICE_ERROR The calling processor is an AP.
570 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
572 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
573 @retval EFI_NOT_READY MP Initialize Library is not initialized.
578 MpInitLibEnableDisableAP (
579 IN UINTN ProcessorNumber
,
581 IN UINT32
*HealthFlag OPTIONAL
584 return EnableDisableApWorker (ProcessorNumber
, EnableAP
, HealthFlag
);