2 CPU PEI Module installs CPU Multiple Processor PPI.
4 Copyright (c) 2015 - 2016, 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.
17 GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList
= {
18 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
19 &gEfiEndOfPeiSignalPpiGuid
,
24 Sort the APIC ID of all processors.
26 This function sorts the APIC ID of all processors so that processor number is
27 assigned in the ascending order of APIC ID which eases MP debugging.
29 @param PeiCpuMpData Pointer to PEI CPU MP Data
34 IN PEI_CPU_MP_DATA
*PeiCpuMpData
44 ApCount
= PeiCpuMpData
->CpuCount
- 1;
47 for (Index1
= 0; Index1
< ApCount
; Index1
++) {
50 // Sort key is the hardware default APIC ID
52 ApicId
= PeiCpuMpData
->CpuData
[Index1
].ApicId
;
53 for (Index2
= Index1
+ 1; Index2
<= ApCount
; Index2
++) {
54 if (ApicId
> PeiCpuMpData
->CpuData
[Index2
].ApicId
) {
56 ApicId
= PeiCpuMpData
->CpuData
[Index2
].ApicId
;
59 if (Index3
!= Index1
) {
60 CopyMem (&CpuData
, &PeiCpuMpData
->CpuData
[Index3
], sizeof (PEI_CPU_DATA
));
62 &PeiCpuMpData
->CpuData
[Index3
],
63 &PeiCpuMpData
->CpuData
[Index1
],
66 CopyMem (&PeiCpuMpData
->CpuData
[Index1
], &CpuData
, sizeof (PEI_CPU_DATA
));
71 // Get the processor number for the BSP
73 ApicId
= GetInitialApicId ();
74 for (Index1
= 0; Index1
< PeiCpuMpData
->CpuCount
; Index1
++) {
75 if (PeiCpuMpData
->CpuData
[Index1
].ApicId
== ApicId
) {
76 PeiCpuMpData
->BspNumber
= (UINT32
) Index1
;
84 Enable x2APIC mode on APs.
86 @param Buffer Pointer to private data buffer.
95 SetApicMode (LOCAL_APIC_MODE_X2APIC
);
101 @param MonitorFilterSize Returns the largest monitor-line size in bytes.
103 @return The AP loop mode.
108 OUT UINT16
*MonitorFilterSize
116 ASSERT (MonitorFilterSize
!= NULL
);
118 ApLoopMode
= PcdGet8 (PcdCpuApLoopMode
);
119 ASSERT (ApLoopMode
>= ApInHltLoop
&& ApLoopMode
<= ApInRunLoop
);
120 if (ApLoopMode
== ApInMwaitLoop
) {
121 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, &RegEcx
, NULL
);
122 if ((RegEcx
& BIT3
) == 0) {
124 // If processor does not support MONITOR/MWAIT feature
125 // by CPUID.[EAX=01H]:ECX.BIT3, force AP in Hlt-loop mode
127 ApLoopMode
= ApInHltLoop
;
131 if (ApLoopMode
== ApInHltLoop
) {
132 *MonitorFilterSize
= 0;
133 } else if (ApLoopMode
== ApInRunLoop
) {
134 *MonitorFilterSize
= sizeof (UINT32
);
135 } else if (ApLoopMode
== ApInMwaitLoop
) {
137 // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes
138 // CPUID.[EAX=05H].EDX: C-states supported using MWAIT
140 AsmCpuid (CPUID_MONITOR_MWAIT
, NULL
, &RegEbx
, NULL
, &RegEdx
);
141 *MonitorFilterSize
= RegEbx
& 0xFFFF;
148 Get CPU MP Data pointer from the Guided HOB.
150 @return Pointer to Pointer to PEI CPU MP Data
157 EFI_HOB_GUID_TYPE
*GuidHob
;
159 PEI_CPU_MP_DATA
*CpuMpData
;
162 GuidHob
= GetFirstGuidHob (&gEfiCallerIdGuid
);
163 if (GuidHob
!= NULL
) {
164 DataInHob
= GET_GUID_HOB_DATA (GuidHob
);
165 CpuMpData
= (PEI_CPU_MP_DATA
*)(*(UINTN
*)DataInHob
);
167 ASSERT (CpuMpData
!= NULL
);
172 Save the volatile registers required to be restored following INIT IPI.
174 @param VolatileRegisters Returns buffer saved the volatile resisters
178 SaveVolatileRegisters (
179 OUT CPU_VOLATILE_REGISTERS
*VolatileRegisters
184 VolatileRegisters
->Cr0
= AsmReadCr0 ();
185 VolatileRegisters
->Cr3
= AsmReadCr3 ();
186 VolatileRegisters
->Cr4
= AsmReadCr4 ();
188 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &RegEdx
);
189 if ((RegEdx
& BIT2
) != 0) {
191 // If processor supports Debugging Extensions feature
192 // by CPUID.[EAX=01H]:EDX.BIT2
194 VolatileRegisters
->Dr0
= AsmReadDr0 ();
195 VolatileRegisters
->Dr1
= AsmReadDr1 ();
196 VolatileRegisters
->Dr2
= AsmReadDr2 ();
197 VolatileRegisters
->Dr3
= AsmReadDr3 ();
198 VolatileRegisters
->Dr6
= AsmReadDr6 ();
199 VolatileRegisters
->Dr7
= AsmReadDr7 ();
204 Restore the volatile registers following INIT IPI.
206 @param VolatileRegisters Pointer to volatile resisters
207 @param IsRestoreDr TRUE: Restore DRx if supported
208 FALSE: Do not restore DRx
212 RestoreVolatileRegisters (
213 IN CPU_VOLATILE_REGISTERS
*VolatileRegisters
,
214 IN BOOLEAN IsRestoreDr
219 AsmWriteCr0 (VolatileRegisters
->Cr0
);
220 AsmWriteCr3 (VolatileRegisters
->Cr3
);
221 AsmWriteCr4 (VolatileRegisters
->Cr4
);
224 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &RegEdx
);
225 if ((RegEdx
& BIT2
) != 0) {
227 // If processor supports Debugging Extensions feature
228 // by CPUID.[EAX=01H]:EDX.BIT2
230 AsmWriteDr0 (VolatileRegisters
->Dr0
);
231 AsmWriteDr1 (VolatileRegisters
->Dr1
);
232 AsmWriteDr2 (VolatileRegisters
->Dr2
);
233 AsmWriteDr3 (VolatileRegisters
->Dr3
);
234 AsmWriteDr6 (VolatileRegisters
->Dr6
);
235 AsmWriteDr7 (VolatileRegisters
->Dr7
);
241 Find the current Processor number by APIC ID.
243 @param PeiCpuMpData Pointer to PEI CPU MP Data
244 @param ProcessorNumber Return the pocessor number found
246 @retval EFI_SUCCESS ProcessorNumber is found and returned.
247 @retval EFI_NOT_FOUND ProcessorNumber is not found.
252 IN PEI_CPU_MP_DATA
*PeiCpuMpData
,
253 OUT UINTN
*ProcessorNumber
256 UINTN TotalProcessorNumber
;
259 TotalProcessorNumber
= PeiCpuMpData
->CpuCount
;
260 for (Index
= 0; Index
< TotalProcessorNumber
; Index
++) {
261 if (PeiCpuMpData
->CpuData
[Index
].ApicId
== GetInitialApicId ()) {
262 *ProcessorNumber
= Index
;
266 return EFI_NOT_FOUND
;
270 This function will be called from AP reset code if BSP uses WakeUpAP.
272 @param ExchangeInfo Pointer to the MP exchange info buffer
273 @param NumApsExecuting Number of current executing AP
279 IN MP_CPU_EXCHANGE_INFO
*ExchangeInfo
,
280 IN UINTN NumApsExecuting
283 PEI_CPU_MP_DATA
*PeiCpuMpData
;
284 UINTN ProcessorNumber
;
285 EFI_AP_PROCEDURE Procedure
;
287 volatile UINT32
*ApStartupSignalBuffer
;
289 PeiCpuMpData
= ExchangeInfo
->PeiCpuMpData
;
291 if (PeiCpuMpData
->InitFlag
) {
292 ProcessorNumber
= NumApsExecuting
;
294 // Sync BSP's Control registers to APs
296 RestoreVolatileRegisters (&PeiCpuMpData
->CpuData
[0].VolatileRegisters
, FALSE
);
298 // This is first time AP wakeup, get BIST information from AP stack
300 BistData
= *(UINTN
*) (PeiCpuMpData
->Buffer
+ ProcessorNumber
* PeiCpuMpData
->CpuApStackSize
- sizeof (UINTN
));
301 PeiCpuMpData
->CpuData
[ProcessorNumber
].Health
.Uint32
= (UINT32
) BistData
;
302 PeiCpuMpData
->CpuData
[ProcessorNumber
].ApicId
= GetInitialApicId ();
303 if (PeiCpuMpData
->CpuData
[ProcessorNumber
].ApicId
>= 0xFF) {
305 // Set x2APIC mode if there are any logical processor reporting
306 // an APIC ID of 255 or greater.
308 AcquireSpinLock(&PeiCpuMpData
->MpLock
);
309 PeiCpuMpData
->X2ApicEnable
= TRUE
;
310 ReleaseSpinLock(&PeiCpuMpData
->MpLock
);
313 // Sync BSP's Mtrr table to all wakeup APs and load microcode on APs.
315 MtrrSetAllMtrrs (&PeiCpuMpData
->MtrrTable
);
316 MicrocodeDetect (PeiCpuMpData
);
317 PeiCpuMpData
->CpuData
[ProcessorNumber
].State
= CpuStateIdle
;
320 // Execute AP function if AP is not disabled
322 GetProcessorNumber (PeiCpuMpData
, &ProcessorNumber
);
323 if (PeiCpuMpData
->ApLoopMode
== ApInHltLoop
) {
325 // Restore AP's volatile registers saved
327 RestoreVolatileRegisters (&PeiCpuMpData
->CpuData
[ProcessorNumber
].VolatileRegisters
, TRUE
);
330 if ((PeiCpuMpData
->CpuData
[ProcessorNumber
].State
!= CpuStateDisabled
) &&
331 (PeiCpuMpData
->ApFunction
!= 0)) {
332 PeiCpuMpData
->CpuData
[ProcessorNumber
].State
= CpuStateBusy
;
333 Procedure
= (EFI_AP_PROCEDURE
)(UINTN
)PeiCpuMpData
->ApFunction
;
335 // Invoke AP function here
337 Procedure ((VOID
*)(UINTN
)PeiCpuMpData
->ApFunctionArgument
);
339 // Re-get the processor number due to BSP/AP maybe exchange in AP function
341 GetProcessorNumber (PeiCpuMpData
, &ProcessorNumber
);
342 PeiCpuMpData
->CpuData
[ProcessorNumber
].State
= CpuStateIdle
;
347 // AP finished executing C code
349 InterlockedIncrement ((UINT32
*)&PeiCpuMpData
->FinishedCount
);
352 // Place AP is specified loop mode
354 if (PeiCpuMpData
->ApLoopMode
== ApInHltLoop
) {
356 // Save AP volatile registers
358 SaveVolatileRegisters (&PeiCpuMpData
->CpuData
[ProcessorNumber
].VolatileRegisters
);
360 // Place AP in Hlt-loop
363 DisableInterrupts ();
368 ApStartupSignalBuffer
= PeiCpuMpData
->CpuData
[ProcessorNumber
].StartupApSignal
;
370 DisableInterrupts ();
371 if (PeiCpuMpData
->ApLoopMode
== ApInMwaitLoop
) {
373 // Place AP in Mwait-loop
375 AsmMonitor ((UINTN
)ApStartupSignalBuffer
, 0, 0);
376 if (*ApStartupSignalBuffer
!= WAKEUP_AP_SIGNAL
) {
378 // If AP start-up signal is not set, place AP into
379 // the maximum C-state
381 AsmMwait (PeiCpuMpData
->ApTargetCState
<< 4, 0);
383 } else if (PeiCpuMpData
->ApLoopMode
== ApInRunLoop
) {
385 // Place AP in Run-loop
393 // If AP start-up signal is written, AP is waken up
394 // otherwise place AP in loop again
396 if (*ApStartupSignalBuffer
== WAKEUP_AP_SIGNAL
) {
398 // Clear AP start-up signal when AP waken up
400 InterlockedCompareExchange32 (
401 (UINT32
*)ApStartupSignalBuffer
,
412 Write AP start-up signal to wakeup AP.
414 @param ApStartupSignalBuffer Pointer to AP wakeup signal
418 IN
volatile UINT32
*ApStartupSignalBuffer
421 *ApStartupSignalBuffer
= WAKEUP_AP_SIGNAL
;
423 // If AP is waken up, StartupApSignal should be cleared.
424 // Otherwise, write StartupApSignal again till AP waken up.
426 while (InterlockedCompareExchange32 (
427 (UINT32
*)ApStartupSignalBuffer
,
436 This function will be called by BSP to wakeup AP.
438 @param PeiCpuMpData Pointer to PEI CPU MP Data
439 @param Broadcast TRUE: Send broadcast IPI to all APs
440 FALSE: Send IPI to AP by ApicId
441 @param ProcessorNumber The handle number of specified processor
442 @param Procedure The function to be invoked by AP
443 @param ProcedureArgument The argument to be passed into AP function
448 IN PEI_CPU_MP_DATA
*PeiCpuMpData
,
449 IN BOOLEAN Broadcast
,
450 IN UINTN ProcessorNumber
,
451 IN EFI_AP_PROCEDURE Procedure
, OPTIONAL
452 IN VOID
*ProcedureArgument OPTIONAL
455 volatile MP_CPU_EXCHANGE_INFO
*ExchangeInfo
;
458 PeiCpuMpData
->ApFunction
= (UINTN
) Procedure
;
459 PeiCpuMpData
->ApFunctionArgument
= (UINTN
) ProcedureArgument
;
460 PeiCpuMpData
->FinishedCount
= 0;
462 ExchangeInfo
= PeiCpuMpData
->MpCpuExchangeInfo
;
463 ExchangeInfo
->Lock
= 0;
464 ExchangeInfo
->StackStart
= PeiCpuMpData
->Buffer
;
465 ExchangeInfo
->StackSize
= PeiCpuMpData
->CpuApStackSize
;
466 ExchangeInfo
->BufferStart
= PeiCpuMpData
->WakeupBuffer
;
467 ExchangeInfo
->ModeOffset
= PeiCpuMpData
->AddressMap
.ModeEntryOffset
;
468 ExchangeInfo
->Cr3
= AsmReadCr3 ();
469 ExchangeInfo
->CodeSegment
= AsmReadCs ();
470 ExchangeInfo
->DataSegment
= AsmReadDs ();
471 ExchangeInfo
->CFunction
= (UINTN
) ApCFunction
;
472 ExchangeInfo
->NumApsExecuting
= 0;
473 ExchangeInfo
->PeiCpuMpData
= PeiCpuMpData
;
476 // Get the BSP's data of GDT and IDT
478 AsmReadGdtr ((IA32_DESCRIPTOR
*) &ExchangeInfo
->GdtrProfile
);
479 AsmReadIdtr ((IA32_DESCRIPTOR
*) &ExchangeInfo
->IdtrProfile
);
481 if (PeiCpuMpData
->ApLoopMode
== ApInMwaitLoop
) {
483 // Get AP target C-state each time when waking up AP,
484 // for it maybe updated by platform again
486 PeiCpuMpData
->ApTargetCState
= PcdGet8 (PcdCpuApTargetCstate
);
490 // Wakeup APs per AP loop state
492 if (PeiCpuMpData
->ApLoopMode
== ApInHltLoop
|| PeiCpuMpData
->InitFlag
) {
494 SendInitSipiSipiAllExcludingSelf ((UINT32
) ExchangeInfo
->BufferStart
);
497 PeiCpuMpData
->CpuData
[ProcessorNumber
].ApicId
,
498 (UINT32
) ExchangeInfo
->BufferStart
501 } else if ((PeiCpuMpData
->ApLoopMode
== ApInMwaitLoop
) ||
502 (PeiCpuMpData
->ApLoopMode
== ApInRunLoop
)) {
504 for (Index
= 0; Index
< PeiCpuMpData
->CpuCount
; Index
++) {
505 if (Index
!= PeiCpuMpData
->BspNumber
) {
506 WriteStartupSignal (PeiCpuMpData
->CpuData
[Index
].StartupApSignal
);
510 WriteStartupSignal (PeiCpuMpData
->CpuData
[ProcessorNumber
].StartupApSignal
);
519 Get available system memory below 1MB by specified size.
521 @param WakeupBufferSize Wakeup buffer size required
523 @retval other Return wakeup buffer address below 1MB.
524 @retval -1 Cannot find free memory below 1MB.
529 IN UINTN WakeupBufferSize
532 EFI_PEI_HOB_POINTERS Hob
;
533 UINTN WakeupBufferStart
;
534 UINTN WakeupBufferEnd
;
537 // Get the HOB list for processing
539 Hob
.Raw
= GetHobList ();
542 // Collect memory ranges
544 while (!END_OF_HOB_LIST (Hob
)) {
545 if (Hob
.Header
->HobType
== EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
546 if ((Hob
.ResourceDescriptor
->PhysicalStart
< BASE_1MB
) &&
547 (Hob
.ResourceDescriptor
->ResourceType
== EFI_RESOURCE_SYSTEM_MEMORY
) &&
548 ((Hob
.ResourceDescriptor
->ResourceAttribute
&
549 (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED
|
550 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED
|
551 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
555 // Need memory under 1MB to be collected here
557 WakeupBufferEnd
= (UINTN
) (Hob
.ResourceDescriptor
->PhysicalStart
+ Hob
.ResourceDescriptor
->ResourceLength
);
558 if (WakeupBufferEnd
> BASE_1MB
) {
560 // Wakeup buffer should be under 1MB
562 WakeupBufferEnd
= BASE_1MB
;
565 // Wakeup buffer should be aligned on 4KB
567 WakeupBufferStart
= (WakeupBufferEnd
- WakeupBufferSize
) & ~(SIZE_4KB
- 1);
568 if (WakeupBufferStart
< Hob
.ResourceDescriptor
->PhysicalStart
) {
572 // Create a memory allocation HOB.
574 BuildMemoryAllocationHob (
579 return WakeupBufferStart
;
585 Hob
.Raw
= GET_NEXT_HOB (Hob
);
592 Get available system memory below 1MB by specified size.
594 @param PeiCpuMpData Pointer to PEI CPU MP Data
598 BackupAndPrepareWakeupBuffer(
599 IN PEI_CPU_MP_DATA
*PeiCpuMpData
603 (VOID
*) PeiCpuMpData
->BackupBuffer
,
604 (VOID
*) PeiCpuMpData
->WakeupBuffer
,
605 PeiCpuMpData
->BackupBufferSize
608 (VOID
*) PeiCpuMpData
->WakeupBuffer
,
609 (VOID
*) PeiCpuMpData
->AddressMap
.RendezvousFunnelAddress
,
610 PeiCpuMpData
->AddressMap
.RendezvousFunnelSize
615 Restore wakeup buffer data.
617 @param PeiCpuMpData Pointer to PEI CPU MP Data
622 IN PEI_CPU_MP_DATA
*PeiCpuMpData
625 CopyMem ((VOID
*) PeiCpuMpData
->WakeupBuffer
, (VOID
*) PeiCpuMpData
->BackupBuffer
, PeiCpuMpData
->BackupBufferSize
);
629 This function will get CPU count in the system.
631 @param PeiCpuMpData Pointer to PEI CPU MP Data
633 @return AP processor count
636 CountProcessorNumber (
637 IN PEI_CPU_MP_DATA
*PeiCpuMpData
641 // Load Microcode on BSP
643 MicrocodeDetect (PeiCpuMpData
);
645 // Store BSP's MTRR setting
647 MtrrGetAllMtrrs (&PeiCpuMpData
->MtrrTable
);
650 // Only perform AP detection if PcdCpuMaxLogicalProcessorNumber is greater than 1
652 if (PcdGet32 (PcdCpuMaxLogicalProcessorNumber
) > 1) {
654 // Send 1st broadcast IPI to APs to wakeup APs
656 PeiCpuMpData
->InitFlag
= TRUE
;
657 PeiCpuMpData
->X2ApicEnable
= FALSE
;
658 WakeUpAP (PeiCpuMpData
, TRUE
, 0, NULL
, NULL
);
660 // Wait for AP task to complete and then exit.
662 MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds
));
663 PeiCpuMpData
->InitFlag
= FALSE
;
664 PeiCpuMpData
->CpuCount
+= (UINT32
)PeiCpuMpData
->MpCpuExchangeInfo
->NumApsExecuting
;
665 ASSERT (PeiCpuMpData
->CpuCount
<= PcdGet32 (PcdCpuMaxLogicalProcessorNumber
));
667 // Wait for all APs finished the initialization
669 while (PeiCpuMpData
->FinishedCount
< (PeiCpuMpData
->CpuCount
- 1)) {
673 if (PeiCpuMpData
->X2ApicEnable
) {
674 DEBUG ((EFI_D_INFO
, "Force x2APIC mode!\n"));
676 // Wakeup all APs to enable x2APIC mode
678 WakeUpAP (PeiCpuMpData
, TRUE
, 0, ApFuncEnableX2Apic
, NULL
);
680 // Wait for all known APs finished
682 while (PeiCpuMpData
->FinishedCount
< (PeiCpuMpData
->CpuCount
- 1)) {
686 // Enable x2APIC on BSP
688 SetApicMode (LOCAL_APIC_MODE_X2APIC
);
690 DEBUG ((EFI_D_INFO
, "APIC MODE is %d\n", GetApicMode ()));
692 // Sort BSP/Aps by CPU APIC ID in ascending order
694 SortApicId (PeiCpuMpData
);
697 DEBUG ((EFI_D_INFO
, "CpuMpPei: Find %d processors in system.\n", PeiCpuMpData
->CpuCount
));
698 return PeiCpuMpData
->CpuCount
;
702 Prepare for AP wakeup buffer and copy AP reset code into it.
704 Get wakeup buffer below 1MB. Allocate memory for CPU MP Data and APs Stack.
706 @return Pointer to PEI CPU MP Data
709 PrepareAPStartupVector (
715 PEI_CPU_MP_DATA
*PeiCpuMpData
;
716 EFI_PHYSICAL_ADDRESS Buffer
;
719 UINTN WakeupBufferSize
;
720 MP_ASSEMBLY_ADDRESS_MAP AddressMap
;
722 UINT16 MonitorFilterSize
;
723 UINT8
*MonitorBuffer
;
726 AsmGetAddressMap (&AddressMap
);
727 WakeupBufferSize
= AddressMap
.RendezvousFunnelSize
+ sizeof (MP_CPU_EXCHANGE_INFO
);
728 WakeupBuffer
= GetWakeupBuffer ((WakeupBufferSize
+ SIZE_4KB
- 1) & ~(SIZE_4KB
- 1));
729 ASSERT (WakeupBuffer
!= (UINTN
) -1);
730 DEBUG ((EFI_D_INFO
, "CpuMpPei: WakeupBuffer = 0x%x\n", WakeupBuffer
));
733 // Allocate Pages for APs stack, CPU MP Data, backup buffer for wakeup buffer,
734 // and monitor buffer if required.
736 MaxCpuCount
= PcdGet32(PcdCpuMaxLogicalProcessorNumber
);
737 BufferSize
= PcdGet32 (PcdCpuApStackSize
) * MaxCpuCount
+ sizeof (PEI_CPU_MP_DATA
)
738 + WakeupBufferSize
+ sizeof (PEI_CPU_DATA
) * MaxCpuCount
;
739 ApLoopMode
= GetApLoopMode (&MonitorFilterSize
);
740 BufferSize
+= MonitorFilterSize
* MaxCpuCount
;
741 Status
= PeiServicesAllocatePages (
743 EFI_SIZE_TO_PAGES (BufferSize
),
746 ASSERT_EFI_ERROR (Status
);
748 PeiCpuMpData
= (PEI_CPU_MP_DATA
*) (UINTN
) (Buffer
+ PcdGet32 (PcdCpuApStackSize
) * MaxCpuCount
);
749 PeiCpuMpData
->Buffer
= (UINTN
) Buffer
;
750 PeiCpuMpData
->CpuApStackSize
= PcdGet32 (PcdCpuApStackSize
);
751 PeiCpuMpData
->WakeupBuffer
= WakeupBuffer
;
752 PeiCpuMpData
->BackupBuffer
= (UINTN
)PeiCpuMpData
+ sizeof (PEI_CPU_MP_DATA
);
753 PeiCpuMpData
->BackupBufferSize
= WakeupBufferSize
;
754 PeiCpuMpData
->MpCpuExchangeInfo
= (MP_CPU_EXCHANGE_INFO
*) (UINTN
) (WakeupBuffer
+ AddressMap
.RendezvousFunnelSize
);
756 PeiCpuMpData
->CpuCount
= 1;
757 PeiCpuMpData
->BspNumber
= 0;
758 PeiCpuMpData
->CpuData
= (PEI_CPU_DATA
*) (PeiCpuMpData
->BackupBuffer
+
759 PeiCpuMpData
->BackupBufferSize
);
760 PeiCpuMpData
->CpuData
[0].ApicId
= GetInitialApicId ();
761 PeiCpuMpData
->CpuData
[0].Health
.Uint32
= 0;
762 PeiCpuMpData
->EndOfPeiFlag
= FALSE
;
763 InitializeSpinLock(&PeiCpuMpData
->MpLock
);
764 SaveVolatileRegisters (&PeiCpuMpData
->CpuData
[0].VolatileRegisters
);
765 CopyMem (&PeiCpuMpData
->AddressMap
, &AddressMap
, sizeof (MP_ASSEMBLY_ADDRESS_MAP
));
767 // Initialize AP loop mode
769 PeiCpuMpData
->ApLoopMode
= ApLoopMode
;
770 DEBUG ((EFI_D_INFO
, "AP Loop Mode is %d\n", PeiCpuMpData
->ApLoopMode
));
771 MonitorBuffer
= (UINT8
*)(PeiCpuMpData
->CpuData
+ MaxCpuCount
);
772 if (PeiCpuMpData
->ApLoopMode
!= ApInHltLoop
) {
774 // Set up APs wakeup signal buffer
776 for (Index
= 0; Index
< MaxCpuCount
; Index
++) {
777 PeiCpuMpData
->CpuData
[Index
].StartupApSignal
=
778 (UINT32
*)(MonitorBuffer
+ MonitorFilterSize
* Index
);
782 // Backup original data and copy AP reset code in it
784 BackupAndPrepareWakeupBuffer(PeiCpuMpData
);
790 Notify function on End Of Pei PPI.
792 On S3 boot, this function will restore wakeup buffer data.
793 On normal boot, this function will flag wakeup buffer to be un-used type.
795 @param PeiServices The pointer to the PEI Services Table.
796 @param NotifyDescriptor Address of the notification descriptor data structure.
797 @param Ppi Address of the PPI that was installed.
799 @retval EFI_SUCCESS When everything is OK.
805 CpuMpEndOfPeiCallback (
806 IN EFI_PEI_SERVICES
**PeiServices
,
807 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
812 EFI_BOOT_MODE BootMode
;
813 PEI_CPU_MP_DATA
*PeiCpuMpData
;
814 EFI_PEI_HOB_POINTERS Hob
;
815 EFI_HOB_MEMORY_ALLOCATION
*MemoryHob
;
817 DEBUG ((EFI_D_INFO
, "CpuMpPei: CpuMpEndOfPeiCallback () invoked\n"));
819 Status
= PeiServicesGetBootMode (&BootMode
);
820 ASSERT_EFI_ERROR (Status
);
822 PeiCpuMpData
= GetMpHobData ();
823 ASSERT (PeiCpuMpData
!= NULL
);
825 if (BootMode
!= BOOT_ON_S3_RESUME
) {
827 // Get the HOB list for processing
829 Hob
.Raw
= GetHobList ();
831 // Collect memory ranges
833 while (!END_OF_HOB_LIST (Hob
)) {
834 if (Hob
.Header
->HobType
== EFI_HOB_TYPE_MEMORY_ALLOCATION
) {
835 MemoryHob
= Hob
.MemoryAllocation
;
836 if(MemoryHob
->AllocDescriptor
.MemoryBaseAddress
== PeiCpuMpData
->WakeupBuffer
) {
838 // Flag this HOB type to un-used
840 GET_HOB_TYPE (Hob
) = EFI_HOB_TYPE_UNUSED
;
844 Hob
.Raw
= GET_NEXT_HOB (Hob
);
847 RestoreWakeupBuffer (PeiCpuMpData
);
848 PeiCpuMpData
->EndOfPeiFlag
= TRUE
;
854 The Entry point of the MP CPU PEIM.
856 This function will wakeup APs and collect CPU AP count and install the
859 @param FileHandle Handle of the file being invoked.
860 @param PeiServices Describes the list of possible PEI Services.
862 @retval EFI_SUCCESS MpServicePpi is installed successfully.
868 IN EFI_PEI_FILE_HANDLE FileHandle
,
869 IN CONST EFI_PEI_SERVICES
**PeiServices
873 EFI_VECTOR_HANDOFF_INFO
*VectorInfo
;
874 EFI_PEI_VECTOR_HANDOFF_INFO_PPI
*VectorHandoffInfoPpi
;
877 // Get Vector Hand-off Info PPI
880 Status
= PeiServicesLocatePpi (
881 &gEfiVectorHandoffInfoPpiGuid
,
884 (VOID
**)&VectorHandoffInfoPpi
886 if (Status
== EFI_SUCCESS
) {
887 VectorInfo
= VectorHandoffInfoPpi
->Info
;
889 Status
= InitializeCpuExceptionHandlers (VectorInfo
);
890 ASSERT_EFI_ERROR (Status
);
893 // Wakeup APs to do initialization
895 Status
= MpInitLibInitialize ();
896 ASSERT_EFI_ERROR (Status
);
899 // Update and publish CPU BIST information
901 CollectBistDataFromPpi (PeiServices
);
904 // Install CPU MP PPI
906 Status
= PeiServicesInstallPpi(&mPeiCpuMpPpiDesc
);
907 ASSERT_EFI_ERROR (Status
);