2 MP initialize support functions for PEI phase.
4 Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include <Library/PeiServicesLib.h>
17 #include <Guid/S3SmmInitDone.h>
20 S3 SMM Init Done notification function.
22 @param PeiServices Indirect reference to the PEI Services Table.
23 @param NotifyDesc Address of the notification descriptor data structure.
24 @param InvokePpi Address of the PPI that was invoked.
26 @retval EFI_SUCCESS The function completes successfully.
31 NotifyOnS3SmmInitDonePpi (
32 IN EFI_PEI_SERVICES
**PeiServices
,
33 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDesc
,
41 EFI_PEI_NOTIFY_DESCRIPTOR mS3SmmInitDoneNotifyDesc
= {
42 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
,
43 &gEdkiiS3SmmInitDoneGuid
,
44 NotifyOnS3SmmInitDonePpi
48 The function prototype for invoking a function on an Application Processor.
50 This definition is used by the UEFI MP Serices Protocol, and the
53 @param[in,out] Buffer The pointer to private data buffer.
63 S3 SMM Init Done notification function.
65 @param PeiServices Indirect reference to the PEI Services Table.
66 @param NotifyDesc Address of the notification descriptor data structure.
67 @param InvokePpi Address of the PPI that was invoked.
69 @retval EFI_SUCCESS The function completes successfully.
74 NotifyOnS3SmmInitDonePpi (
75 IN EFI_PEI_SERVICES
**PeiServices
,
76 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDesc
,
80 CPU_MP_DATA
*CpuMpData
;
82 CpuMpData
= GetCpuMpData ();
85 // PiSmmCpuDxeSmm driver hardcode change the loop mode to HLT mode.
86 // So in this notify function, code need to check the current loop
87 // mode, if it is not HLT mode, code need to change loop mode back
88 // to the original mode.
90 if (CpuMpData
->ApLoopMode
!= ApInHltLoop
) {
91 CpuMpData
->WakeUpByInitSipiSipi
= TRUE
;
99 Enable Debug Agent to support source debugging on AP function.
110 Get pointer to CPU MP Data structure.
111 For BSP, the pointer is retrieved from HOB.
112 For AP, the structure is just after IDT.
114 @return The pointer to CPU MP Data structure.
121 CPU_MP_DATA
*CpuMpData
;
122 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr
;
123 IA32_DESCRIPTOR Idtr
;
125 ApicBaseMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_APIC_BASE
);
126 if (ApicBaseMsr
.Bits
.BSP
== 1) {
127 CpuMpData
= GetCpuMpDataFromGuidedHob ();
128 ASSERT (CpuMpData
!= NULL
);
131 CpuMpData
= (CPU_MP_DATA
*) (Idtr
.Base
+ Idtr
.Limit
+ 1);
137 Save the pointer to CPU MP Data structure.
139 @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.
143 IN CPU_MP_DATA
*CpuMpData
148 // Build location of CPU MP DATA buffer in HOB
150 Data64
= (UINT64
) (UINTN
) CpuMpData
;
152 &mCpuInitMpLibHobGuid
,
159 Check if AP wakeup buffer is overlapped with existing allocated buffer.
161 @param[in] WakeupBufferStart AP wakeup buffer start address.
162 @param[in] WakeupBufferEnd AP wakeup buffer end address.
164 @retval TRUE There is overlap.
165 @retval FALSE There is no overlap.
168 CheckOverlapWithAllocatedBuffer (
169 IN UINT64 WakeupBufferStart
,
170 IN UINT64 WakeupBufferEnd
173 EFI_PEI_HOB_POINTERS Hob
;
174 EFI_HOB_MEMORY_ALLOCATION
*MemoryHob
;
181 // Get the HOB list for processing
183 Hob
.Raw
= GetHobList ();
185 // Collect memory ranges
187 while (!END_OF_HOB_LIST (Hob
)) {
188 if (Hob
.Header
->HobType
== EFI_HOB_TYPE_MEMORY_ALLOCATION
) {
189 MemoryHob
= Hob
.MemoryAllocation
;
190 MemoryStart
= MemoryHob
->AllocDescriptor
.MemoryBaseAddress
;
191 MemoryEnd
= MemoryHob
->AllocDescriptor
.MemoryBaseAddress
+ MemoryHob
->AllocDescriptor
.MemoryLength
;
192 if (!((WakeupBufferStart
>= MemoryEnd
) || (WakeupBufferEnd
<= MemoryStart
))) {
197 Hob
.Raw
= GET_NEXT_HOB (Hob
);
203 Get available system memory below 1MB by specified size.
205 @param[in] WakeupBufferSize Wakeup buffer size required
207 @retval other Return wakeup buffer address below 1MB.
208 @retval -1 Cannot find free memory below 1MB.
212 IN UINTN WakeupBufferSize
215 EFI_PEI_HOB_POINTERS Hob
;
216 UINT64 WakeupBufferStart
;
217 UINT64 WakeupBufferEnd
;
219 WakeupBufferSize
= (WakeupBufferSize
+ SIZE_4KB
- 1) & ~(SIZE_4KB
- 1);
222 // Get the HOB list for processing
224 Hob
.Raw
= GetHobList ();
227 // Collect memory ranges
229 while (!END_OF_HOB_LIST (Hob
)) {
230 if (Hob
.Header
->HobType
== EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
231 if ((Hob
.ResourceDescriptor
->PhysicalStart
< BASE_1MB
) &&
232 (Hob
.ResourceDescriptor
->ResourceType
== EFI_RESOURCE_SYSTEM_MEMORY
) &&
233 ((Hob
.ResourceDescriptor
->ResourceAttribute
&
234 (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED
|
235 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED
|
236 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
240 // Need memory under 1MB to be collected here
242 WakeupBufferEnd
= Hob
.ResourceDescriptor
->PhysicalStart
+ Hob
.ResourceDescriptor
->ResourceLength
;
243 if (WakeupBufferEnd
> BASE_1MB
) {
245 // Wakeup buffer should be under 1MB
247 WakeupBufferEnd
= BASE_1MB
;
249 while (WakeupBufferEnd
> WakeupBufferSize
) {
251 // Wakeup buffer should be aligned on 4KB
253 WakeupBufferStart
= (WakeupBufferEnd
- WakeupBufferSize
) & ~(SIZE_4KB
- 1);
254 if (WakeupBufferStart
< Hob
.ResourceDescriptor
->PhysicalStart
) {
257 if (CheckOverlapWithAllocatedBuffer (WakeupBufferStart
, WakeupBufferEnd
)) {
259 // If this range is overlapped with existing allocated buffer, skip it
260 // and find the next range
262 WakeupBufferEnd
-= WakeupBufferSize
;
265 DEBUG ((DEBUG_INFO
, "WakeupBufferStart = %x, WakeupBufferSize = %x\n",
266 WakeupBufferStart
, WakeupBufferSize
));
267 return (UINTN
)WakeupBufferStart
;
274 Hob
.Raw
= GET_NEXT_HOB (Hob
);
281 Get available EfiBootServicesCode memory below 4GB by specified size.
283 This buffer is required to safely transfer AP from real address mode to
284 protected mode or long mode, due to the fact that the buffer returned by
285 GetWakeupBuffer() may be marked as non-executable.
287 @param[in] BufferSize Wakeup transition buffer size.
289 @retval other Return wakeup transition buffer address below 4GB.
290 @retval 0 Cannot find free memory below 4GB.
293 GetModeTransitionBuffer (
298 // PEI phase doesn't need to do such transition. So simply return 0.
304 Checks APs status and updates APs status if needed.
308 CheckAndUpdateApsStatus (
315 Initialize global data for MP support.
317 @param[in] CpuMpData The pointer to CPU MP Data structure.
321 IN CPU_MP_DATA
*CpuMpData
326 SaveCpuMpData (CpuMpData
);
331 Status
= PeiServicesNotifyPpi (&mS3SmmInitDoneNotifyDesc
);
332 ASSERT_EFI_ERROR (Status
);
336 This service executes a caller provided function on all enabled APs.
338 @param[in] Procedure A pointer to the function to be run on
339 enabled APs of the system. See type
341 @param[in] SingleThread If TRUE, then all the enabled APs execute
342 the function specified by Procedure one by
343 one, in ascending order of processor handle
344 number. If FALSE, then all the enabled APs
345 execute the function specified by Procedure
347 @param[in] WaitEvent The event created by the caller with CreateEvent()
348 service. If it is NULL, then execute in
349 blocking mode. BSP waits until all APs finish
350 or TimeoutInMicroSeconds expires. If it's
351 not NULL, then execute in non-blocking mode.
352 BSP requests the function specified by
353 Procedure to be started on all the enabled
354 APs, and go on executing immediately. If
355 all return from Procedure, or TimeoutInMicroSeconds
356 expires, this event is signaled. The BSP
357 can use the CheckEvent() or WaitForEvent()
358 services to check the state of event. Type
359 EFI_EVENT is defined in CreateEvent() in
360 the Unified Extensible Firmware Interface
362 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
363 APs to return from Procedure, either for
364 blocking or non-blocking mode. Zero means
365 infinity. If the timeout expires before
366 all APs return from Procedure, then Procedure
367 on the failed APs is terminated. All enabled
368 APs are available for next function assigned
369 by MpInitLibStartupAllAPs() or
370 MPInitLibStartupThisAP().
371 If the timeout expires in blocking mode,
372 BSP returns EFI_TIMEOUT. If the timeout
373 expires in non-blocking mode, WaitEvent
374 is signaled with SignalEvent().
375 @param[in] ProcedureArgument The parameter passed into Procedure for
377 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
378 if all APs finish successfully, then its
379 content is set to NULL. If not all APs
380 finish before timeout expires, then its
381 content is set to address of the buffer
382 holding handle numbers of the failed APs.
383 The buffer is allocated by MP Initialization
384 library, and it's the caller's responsibility to
385 free the buffer with FreePool() service.
386 In blocking mode, it is ready for consumption
387 when the call returns. In non-blocking mode,
388 it is ready when WaitEvent is signaled. The
389 list of failed CPU is terminated by
392 @retval EFI_SUCCESS In blocking mode, all APs have finished before
394 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
396 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
397 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
399 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
401 @retval EFI_DEVICE_ERROR Caller processor is AP.
402 @retval EFI_NOT_STARTED No enabled APs exist in the system.
403 @retval EFI_NOT_READY Any enabled APs are busy.
404 @retval EFI_NOT_READY MP Initialize Library is not initialized.
405 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
406 all enabled APs have finished.
407 @retval EFI_INVALID_PARAMETER Procedure is NULL.
412 MpInitLibStartupAllAPs (
413 IN EFI_AP_PROCEDURE Procedure
,
414 IN BOOLEAN SingleThread
,
415 IN EFI_EVENT WaitEvent OPTIONAL
,
416 IN UINTN TimeoutInMicroseconds
,
417 IN VOID
*ProcedureArgument OPTIONAL
,
418 OUT UINTN
**FailedCpuList OPTIONAL
421 if (WaitEvent
!= NULL
) {
422 return EFI_UNSUPPORTED
;
425 return StartupAllAPsWorker (
429 TimeoutInMicroseconds
,
436 This service lets the caller get one enabled AP to execute a caller-provided
439 @param[in] Procedure A pointer to the function to be run on the
440 designated AP of the system. See type
442 @param[in] ProcessorNumber The handle number of the AP. The range is
443 from 0 to the total number of logical
444 processors minus 1. The total number of
445 logical processors can be retrieved by
446 MpInitLibGetNumberOfProcessors().
447 @param[in] WaitEvent The event created by the caller with CreateEvent()
448 service. If it is NULL, then execute in
449 blocking mode. BSP waits until this AP finish
450 or TimeoutInMicroSeconds expires. If it's
451 not NULL, then execute in non-blocking mode.
452 BSP requests the function specified by
453 Procedure to be started on this AP,
454 and go on executing immediately. If this AP
455 return from Procedure or TimeoutInMicroSeconds
456 expires, this event is signaled. The BSP
457 can use the CheckEvent() or WaitForEvent()
458 services to check the state of event. Type
459 EFI_EVENT is defined in CreateEvent() in
460 the Unified Extensible Firmware Interface
462 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
463 this AP to finish this Procedure, either for
464 blocking or non-blocking mode. Zero means
465 infinity. If the timeout expires before
466 this AP returns from Procedure, then Procedure
467 on the AP is terminated. The
468 AP is available for next function assigned
469 by MpInitLibStartupAllAPs() or
470 MpInitLibStartupThisAP().
471 If the timeout expires in blocking mode,
472 BSP returns EFI_TIMEOUT. If the timeout
473 expires in non-blocking mode, WaitEvent
474 is signaled with SignalEvent().
475 @param[in] ProcedureArgument The parameter passed into Procedure on the
477 @param[out] Finished If NULL, this parameter is ignored. In
478 blocking mode, this parameter is ignored.
479 In non-blocking mode, if AP returns from
480 Procedure before the timeout expires, its
481 content is set to TRUE. Otherwise, the
482 value is set to FALSE. The caller can
483 determine if the AP returned from Procedure
484 by evaluating this value.
486 @retval EFI_SUCCESS In blocking mode, specified AP finished before
488 @retval EFI_SUCCESS In non-blocking mode, the function has been
489 dispatched to specified AP.
490 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
491 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
493 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
495 @retval EFI_DEVICE_ERROR The calling processor is an AP.
496 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
497 the specified AP has finished.
498 @retval EFI_NOT_READY The specified AP is busy.
499 @retval EFI_NOT_READY MP Initialize Library is not initialized.
500 @retval EFI_NOT_FOUND The processor with the handle specified by
501 ProcessorNumber does not exist.
502 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
503 @retval EFI_INVALID_PARAMETER Procedure is NULL.
508 MpInitLibStartupThisAP (
509 IN EFI_AP_PROCEDURE Procedure
,
510 IN UINTN ProcessorNumber
,
511 IN EFI_EVENT WaitEvent OPTIONAL
,
512 IN UINTN TimeoutInMicroseconds
,
513 IN VOID
*ProcedureArgument OPTIONAL
,
514 OUT BOOLEAN
*Finished OPTIONAL
517 if (WaitEvent
!= NULL
) {
518 return EFI_UNSUPPORTED
;
521 return StartupThisAPWorker (
525 TimeoutInMicroseconds
,
532 This service switches the requested AP to be the BSP from that point onward.
533 This service changes the BSP for all purposes. This call can only be performed
536 @param[in] ProcessorNumber The handle number of AP that is to become the new
537 BSP. The range is from 0 to the total number of
538 logical processors minus 1. The total number of
539 logical processors can be retrieved by
540 MpInitLibGetNumberOfProcessors().
541 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
542 enabled AP. Otherwise, it will be disabled.
544 @retval EFI_SUCCESS BSP successfully switched.
545 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
546 this service returning.
547 @retval EFI_UNSUPPORTED Switching the BSP is not supported.
548 @retval EFI_DEVICE_ERROR The calling processor is an AP.
549 @retval EFI_NOT_FOUND The processor with the handle specified by
550 ProcessorNumber does not exist.
551 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
553 @retval EFI_NOT_READY The specified AP is busy.
554 @retval EFI_NOT_READY MP Initialize Library is not initialized.
560 IN UINTN ProcessorNumber
,
561 IN BOOLEAN EnableOldBSP
564 return SwitchBSPWorker (ProcessorNumber
, EnableOldBSP
);
568 This service lets the caller enable or disable an AP from this point onward.
569 This service may only be called from the BSP.
571 @param[in] ProcessorNumber The handle number of AP.
572 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] EnableAP Specifies the new state for the processor for
577 enabled, FALSE for disabled.
578 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
579 the new health status of the AP. This flag
580 corresponds to StatusFlag defined in
581 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
582 the PROCESSOR_HEALTH_STATUS_BIT is used. All other
583 bits are ignored. If it is NULL, this parameter
586 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
587 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
588 prior to this service returning.
589 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
590 @retval EFI_DEVICE_ERROR The calling processor is an AP.
591 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
593 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
594 @retval EFI_NOT_READY MP Initialize Library is not initialized.
599 MpInitLibEnableDisableAP (
600 IN UINTN ProcessorNumber
,
602 IN UINT32
*HealthFlag OPTIONAL
605 return EnableDisableApWorker (ProcessorNumber
, EnableAP
, HealthFlag
);