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
33 IN PEI_CPU_MP_DATA
*PeiCpuMpData
43 ApCount
= PeiCpuMpData
->CpuCount
- 1;
46 for (Index1
= 0; Index1
< ApCount
; Index1
++) {
49 // Sort key is the hardware default APIC ID
51 ApicId
= PeiCpuMpData
->CpuData
[Index1
].ApicId
;
52 for (Index2
= Index1
+ 1; Index2
<= ApCount
; Index2
++) {
53 if (ApicId
> PeiCpuMpData
->CpuData
[Index2
].ApicId
) {
55 ApicId
= PeiCpuMpData
->CpuData
[Index2
].ApicId
;
58 if (Index3
!= Index1
) {
59 CopyMem (&CpuData
, &PeiCpuMpData
->CpuData
[Index3
], sizeof (PEI_CPU_DATA
));
61 &PeiCpuMpData
->CpuData
[Index3
],
62 &PeiCpuMpData
->CpuData
[Index1
],
65 CopyMem (&PeiCpuMpData
->CpuData
[Index1
], &CpuData
, sizeof (PEI_CPU_DATA
));
70 // Get the processor number for the BSP
72 ApicId
= GetInitialApicId ();
73 for (Index1
= 0; Index1
< PeiCpuMpData
->CpuCount
; Index1
++) {
74 if (PeiCpuMpData
->CpuData
[Index1
].ApicId
== ApicId
) {
75 PeiCpuMpData
->BspNumber
= (UINT32
) Index1
;
83 Enable x2APIC mode on APs.
85 @param Buffer Pointer to private data buffer.
93 SetApicMode (LOCAL_APIC_MODE_X2APIC
);
99 @param MonitorFilterSize Returns the largest monitor-line size in bytes.
101 @return The AP loop mode.
105 OUT UINT16
*MonitorFilterSize
113 ASSERT (MonitorFilterSize
!= NULL
);
115 ApLoopMode
= PcdGet8 (PcdCpuApLoopMode
);
116 ASSERT (ApLoopMode
>= ApInHltLoop
&& ApLoopMode
<= ApInRunLoop
);
117 if (ApLoopMode
== ApInMwaitLoop
) {
118 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, &RegEcx
, NULL
);
119 if ((RegEcx
& BIT3
) == 0) {
121 // If processor does not support MONITOR/MWAIT feature
122 // by CPUID.[EAX=01H]:ECX.BIT3, force AP in Hlt-loop mode
124 ApLoopMode
= ApInHltLoop
;
128 if (ApLoopMode
== ApInHltLoop
) {
129 *MonitorFilterSize
= 0;
130 } else if (ApLoopMode
== ApInRunLoop
) {
131 *MonitorFilterSize
= sizeof (UINT32
);
132 } else if (ApLoopMode
== ApInMwaitLoop
) {
134 // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes
135 // CPUID.[EAX=05H].EDX: C-states supported using MWAIT
137 AsmCpuid (CPUID_MONITOR_MWAIT
, NULL
, &RegEbx
, NULL
, &RegEdx
);
138 *MonitorFilterSize
= RegEbx
& 0xFFFF;
145 Get CPU MP Data pointer from the Guided HOB.
147 @return Pointer to Pointer to PEI CPU MP Data
154 EFI_HOB_GUID_TYPE
*GuidHob
;
156 PEI_CPU_MP_DATA
*CpuMpData
;
159 GuidHob
= GetFirstGuidHob (&gEfiCallerIdGuid
);
160 if (GuidHob
!= NULL
) {
161 DataInHob
= GET_GUID_HOB_DATA (GuidHob
);
162 CpuMpData
= (PEI_CPU_MP_DATA
*)(*(UINTN
*)DataInHob
);
164 ASSERT (CpuMpData
!= NULL
);
169 Save the volatile registers required to be restored following INIT IPI.
171 @param VolatileRegisters Returns buffer saved the volatile resisters
174 SaveVolatileRegisters (
175 OUT CPU_VOLATILE_REGISTERS
*VolatileRegisters
180 VolatileRegisters
->Cr0
= AsmReadCr0 ();
181 VolatileRegisters
->Cr3
= AsmReadCr3 ();
182 VolatileRegisters
->Cr4
= AsmReadCr4 ();
184 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &RegEdx
);
185 if ((RegEdx
& BIT2
) != 0) {
187 // If processor supports Debugging Extensions feature
188 // by CPUID.[EAX=01H]:EDX.BIT2
190 VolatileRegisters
->Dr0
= AsmReadDr0 ();
191 VolatileRegisters
->Dr1
= AsmReadDr1 ();
192 VolatileRegisters
->Dr2
= AsmReadDr2 ();
193 VolatileRegisters
->Dr3
= AsmReadDr3 ();
194 VolatileRegisters
->Dr6
= AsmReadDr6 ();
195 VolatileRegisters
->Dr7
= AsmReadDr7 ();
200 Restore the volatile registers following INIT IPI.
202 @param VolatileRegisters Pointer to volatile resisters
203 @param IsRestoreDr TRUE: Restore DRx if supported
204 FALSE: Do not restore DRx
207 RestoreVolatileRegisters (
208 IN CPU_VOLATILE_REGISTERS
*VolatileRegisters
,
209 IN BOOLEAN IsRestoreDr
214 AsmWriteCr0 (VolatileRegisters
->Cr0
);
215 AsmWriteCr3 (VolatileRegisters
->Cr3
);
216 AsmWriteCr4 (VolatileRegisters
->Cr4
);
219 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &RegEdx
);
220 if ((RegEdx
& BIT2
) != 0) {
222 // If processor supports Debugging Extensions feature
223 // by CPUID.[EAX=01H]:EDX.BIT2
225 AsmWriteDr0 (VolatileRegisters
->Dr0
);
226 AsmWriteDr1 (VolatileRegisters
->Dr1
);
227 AsmWriteDr2 (VolatileRegisters
->Dr2
);
228 AsmWriteDr3 (VolatileRegisters
->Dr3
);
229 AsmWriteDr6 (VolatileRegisters
->Dr6
);
230 AsmWriteDr7 (VolatileRegisters
->Dr7
);
236 This function will be called from AP reset code if BSP uses WakeUpAP.
238 @param ExchangeInfo Pointer to the MP exchange info buffer
239 @param NumApsExecuting Number of current executing AP
244 IN MP_CPU_EXCHANGE_INFO
*ExchangeInfo
,
245 IN UINTN NumApsExecuting
248 PEI_CPU_MP_DATA
*PeiCpuMpData
;
249 UINTN ProcessorNumber
;
250 EFI_AP_PROCEDURE Procedure
;
252 volatile UINT32
*ApStartupSignalBuffer
;
254 PeiCpuMpData
= ExchangeInfo
->PeiCpuMpData
;
256 if (PeiCpuMpData
->InitFlag
) {
257 ProcessorNumber
= NumApsExecuting
;
259 // Sync BSP's Control registers to APs
261 RestoreVolatileRegisters (&PeiCpuMpData
->CpuData
[0].VolatileRegisters
, FALSE
);
263 // This is first time AP wakeup, get BIST information from AP stack
265 BistData
= *(UINTN
*) (PeiCpuMpData
->Buffer
+ ProcessorNumber
* PeiCpuMpData
->CpuApStackSize
- sizeof (UINTN
));
266 PeiCpuMpData
->CpuData
[ProcessorNumber
].Health
.Uint32
= (UINT32
) BistData
;
267 PeiCpuMpData
->CpuData
[ProcessorNumber
].ApicId
= GetInitialApicId ();
268 if (PeiCpuMpData
->CpuData
[ProcessorNumber
].ApicId
>= 0xFF) {
270 // Set x2APIC mode if there are any logical processor reporting
271 // an APIC ID of 255 or greater.
273 AcquireSpinLock(&PeiCpuMpData
->MpLock
);
274 PeiCpuMpData
->X2ApicEnable
= TRUE
;
275 ReleaseSpinLock(&PeiCpuMpData
->MpLock
);
278 // Sync BSP's Mtrr table to all wakeup APs and load microcode on APs.
280 MtrrSetAllMtrrs (&PeiCpuMpData
->MtrrTable
);
281 MicrocodeDetect (PeiCpuMpData
);
282 PeiCpuMpData
->CpuData
[ProcessorNumber
].State
= CpuStateIdle
;
285 // Execute AP function if AP is not disabled
287 GetProcessorNumber (PeiCpuMpData
, &ProcessorNumber
);
288 if (PeiCpuMpData
->ApLoopMode
== ApInHltLoop
) {
290 // Restore AP's volatile registers saved
292 RestoreVolatileRegisters (&PeiCpuMpData
->CpuData
[ProcessorNumber
].VolatileRegisters
, TRUE
);
295 if ((PeiCpuMpData
->CpuData
[ProcessorNumber
].State
!= CpuStateDisabled
) &&
296 (PeiCpuMpData
->ApFunction
!= 0)) {
297 PeiCpuMpData
->CpuData
[ProcessorNumber
].State
= CpuStateBusy
;
298 Procedure
= (EFI_AP_PROCEDURE
)(UINTN
)PeiCpuMpData
->ApFunction
;
300 // Invoke AP function here
302 Procedure ((VOID
*)(UINTN
)PeiCpuMpData
->ApFunctionArgument
);
304 // Re-get the processor number due to BSP/AP maybe exchange in AP function
306 GetProcessorNumber (PeiCpuMpData
, &ProcessorNumber
);
307 PeiCpuMpData
->CpuData
[ProcessorNumber
].State
= CpuStateIdle
;
312 // AP finished executing C code
314 InterlockedIncrement ((UINT32
*)&PeiCpuMpData
->FinishedCount
);
317 // Place AP is specified loop mode
319 if (PeiCpuMpData
->ApLoopMode
== ApInHltLoop
) {
321 // Save AP volatile registers
323 SaveVolatileRegisters (&PeiCpuMpData
->CpuData
[ProcessorNumber
].VolatileRegisters
);
325 // Place AP in Hlt-loop
328 DisableInterrupts ();
333 ApStartupSignalBuffer
= PeiCpuMpData
->CpuData
[ProcessorNumber
].StartupApSignal
;
335 DisableInterrupts ();
336 if (PeiCpuMpData
->ApLoopMode
== ApInMwaitLoop
) {
338 // Place AP in Mwait-loop
340 AsmMonitor ((UINTN
)ApStartupSignalBuffer
, 0, 0);
341 if (*ApStartupSignalBuffer
!= WAKEUP_AP_SIGNAL
) {
343 // If AP start-up signal is not set, place AP into
344 // the maximum C-state
346 AsmMwait (PeiCpuMpData
->ApTargetCState
<< 4, 0);
348 } else if (PeiCpuMpData
->ApLoopMode
== ApInRunLoop
) {
350 // Place AP in Run-loop
358 // If AP start-up signal is written, AP is waken up
359 // otherwise place AP in loop again
361 if (*ApStartupSignalBuffer
== WAKEUP_AP_SIGNAL
) {
363 // Clear AP start-up signal when AP waken up
365 InterlockedCompareExchange32 (
366 (UINT32
*)ApStartupSignalBuffer
,
377 Write AP start-up signal to wakeup AP.
379 @param ApStartupSignalBuffer Pointer to AP wakeup signal
383 IN
volatile UINT32
*ApStartupSignalBuffer
386 *ApStartupSignalBuffer
= WAKEUP_AP_SIGNAL
;
388 // If AP is waken up, StartupApSignal should be cleared.
389 // Otherwise, write StartupApSignal again till AP waken up.
391 while (InterlockedCompareExchange32 (
392 (UINT32
*)ApStartupSignalBuffer
,
401 This function will be called by BSP to wakeup AP.
403 @param PeiCpuMpData Pointer to PEI CPU MP Data
404 @param Broadcast TRUE: Send broadcast IPI to all APs
405 FALSE: Send IPI to AP by ApicId
406 @param ProcessorNumber The handle number of specified processor
407 @param Procedure The function to be invoked by AP
408 @param ProcedureArgument The argument to be passed into AP function
412 IN PEI_CPU_MP_DATA
*PeiCpuMpData
,
413 IN BOOLEAN Broadcast
,
414 IN UINTN ProcessorNumber
,
415 IN EFI_AP_PROCEDURE Procedure
, OPTIONAL
416 IN VOID
*ProcedureArgument OPTIONAL
419 volatile MP_CPU_EXCHANGE_INFO
*ExchangeInfo
;
422 PeiCpuMpData
->ApFunction
= (UINTN
) Procedure
;
423 PeiCpuMpData
->ApFunctionArgument
= (UINTN
) ProcedureArgument
;
424 PeiCpuMpData
->FinishedCount
= 0;
426 ExchangeInfo
= PeiCpuMpData
->MpCpuExchangeInfo
;
427 ExchangeInfo
->Lock
= 0;
428 ExchangeInfo
->StackStart
= PeiCpuMpData
->Buffer
;
429 ExchangeInfo
->StackSize
= PeiCpuMpData
->CpuApStackSize
;
430 ExchangeInfo
->BufferStart
= PeiCpuMpData
->WakeupBuffer
;
431 ExchangeInfo
->ModeOffset
= PeiCpuMpData
->AddressMap
.ModeEntryOffset
;
432 ExchangeInfo
->Cr3
= AsmReadCr3 ();
433 ExchangeInfo
->CodeSegment
= AsmReadCs ();
434 ExchangeInfo
->DataSegment
= AsmReadDs ();
435 ExchangeInfo
->CFunction
= (UINTN
) ApCFunction
;
436 ExchangeInfo
->NumApsExecuting
= 0;
437 ExchangeInfo
->PeiCpuMpData
= PeiCpuMpData
;
440 // Get the BSP's data of GDT and IDT
442 AsmReadGdtr ((IA32_DESCRIPTOR
*) &ExchangeInfo
->GdtrProfile
);
443 AsmReadIdtr ((IA32_DESCRIPTOR
*) &ExchangeInfo
->IdtrProfile
);
445 if (PeiCpuMpData
->ApLoopMode
== ApInMwaitLoop
) {
447 // Get AP target C-state each time when waking up AP,
448 // for it maybe updated by platform again
450 PeiCpuMpData
->ApTargetCState
= PcdGet8 (PcdCpuApTargetCstate
);
454 // Wakeup APs per AP loop state
456 if (PeiCpuMpData
->ApLoopMode
== ApInHltLoop
|| PeiCpuMpData
->InitFlag
) {
458 SendInitSipiSipiAllExcludingSelf ((UINT32
) ExchangeInfo
->BufferStart
);
461 PeiCpuMpData
->CpuData
[ProcessorNumber
].ApicId
,
462 (UINT32
) ExchangeInfo
->BufferStart
465 } else if ((PeiCpuMpData
->ApLoopMode
== ApInMwaitLoop
) ||
466 (PeiCpuMpData
->ApLoopMode
== ApInRunLoop
)) {
468 for (Index
= 0; Index
< PeiCpuMpData
->CpuCount
; Index
++) {
469 if (Index
!= PeiCpuMpData
->BspNumber
) {
470 WriteStartupSignal (PeiCpuMpData
->CpuData
[Index
].StartupApSignal
);
474 WriteStartupSignal (PeiCpuMpData
->CpuData
[ProcessorNumber
].StartupApSignal
);
483 Get available system memory below 1MB by specified size.
485 @param WakeupBufferSize Wakeup buffer size required
487 @retval other Return wakeup buffer address below 1MB.
488 @retval -1 Cannot find free memory below 1MB.
492 IN UINTN WakeupBufferSize
495 EFI_PEI_HOB_POINTERS Hob
;
496 UINTN WakeupBufferStart
;
497 UINTN WakeupBufferEnd
;
500 // Get the HOB list for processing
502 Hob
.Raw
= GetHobList ();
505 // Collect memory ranges
507 while (!END_OF_HOB_LIST (Hob
)) {
508 if (Hob
.Header
->HobType
== EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
509 if ((Hob
.ResourceDescriptor
->PhysicalStart
< BASE_1MB
) &&
510 (Hob
.ResourceDescriptor
->ResourceType
== EFI_RESOURCE_SYSTEM_MEMORY
) &&
511 ((Hob
.ResourceDescriptor
->ResourceAttribute
&
512 (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED
|
513 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED
|
514 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
518 // Need memory under 1MB to be collected here
520 WakeupBufferEnd
= (UINTN
) (Hob
.ResourceDescriptor
->PhysicalStart
+ Hob
.ResourceDescriptor
->ResourceLength
);
521 if (WakeupBufferEnd
> BASE_1MB
) {
523 // Wakeup buffer should be under 1MB
525 WakeupBufferEnd
= BASE_1MB
;
528 // Wakeup buffer should be aligned on 4KB
530 WakeupBufferStart
= (WakeupBufferEnd
- WakeupBufferSize
) & ~(SIZE_4KB
- 1);
531 if (WakeupBufferStart
< Hob
.ResourceDescriptor
->PhysicalStart
) {
535 // Create a memory allocation HOB.
537 BuildMemoryAllocationHob (
542 return WakeupBufferStart
;
548 Hob
.Raw
= GET_NEXT_HOB (Hob
);
555 Get available system memory below 1MB by specified size.
557 @param PeiCpuMpData Pointer to PEI CPU MP Data
560 BackupAndPrepareWakeupBuffer(
561 IN PEI_CPU_MP_DATA
*PeiCpuMpData
565 (VOID
*) PeiCpuMpData
->BackupBuffer
,
566 (VOID
*) PeiCpuMpData
->WakeupBuffer
,
567 PeiCpuMpData
->BackupBufferSize
570 (VOID
*) PeiCpuMpData
->WakeupBuffer
,
571 (VOID
*) PeiCpuMpData
->AddressMap
.RendezvousFunnelAddress
,
572 PeiCpuMpData
->AddressMap
.RendezvousFunnelSize
577 Restore wakeup buffer data.
579 @param PeiCpuMpData Pointer to PEI CPU MP Data
583 IN PEI_CPU_MP_DATA
*PeiCpuMpData
586 CopyMem ((VOID
*) PeiCpuMpData
->WakeupBuffer
, (VOID
*) PeiCpuMpData
->BackupBuffer
, PeiCpuMpData
->BackupBufferSize
);
590 This function will get CPU count in the system.
592 @param PeiCpuMpData Pointer to PEI CPU MP Data
594 @return AP processor count
597 CountProcessorNumber (
598 IN PEI_CPU_MP_DATA
*PeiCpuMpData
602 // Load Microcode on BSP
604 MicrocodeDetect (PeiCpuMpData
);
606 // Store BSP's MTRR setting
608 MtrrGetAllMtrrs (&PeiCpuMpData
->MtrrTable
);
611 // Only perform AP detection if PcdCpuMaxLogicalProcessorNumber is greater than 1
613 if (PcdGet32 (PcdCpuMaxLogicalProcessorNumber
) > 1) {
615 // Send 1st broadcast IPI to APs to wakeup APs
617 PeiCpuMpData
->InitFlag
= TRUE
;
618 PeiCpuMpData
->X2ApicEnable
= FALSE
;
619 WakeUpAP (PeiCpuMpData
, TRUE
, 0, NULL
, NULL
);
621 // Wait for AP task to complete and then exit.
623 MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds
));
624 PeiCpuMpData
->InitFlag
= FALSE
;
625 PeiCpuMpData
->CpuCount
+= (UINT32
)PeiCpuMpData
->MpCpuExchangeInfo
->NumApsExecuting
;
626 ASSERT (PeiCpuMpData
->CpuCount
<= PcdGet32 (PcdCpuMaxLogicalProcessorNumber
));
628 // Wait for all APs finished the initialization
630 while (PeiCpuMpData
->FinishedCount
< (PeiCpuMpData
->CpuCount
- 1)) {
634 if (PeiCpuMpData
->X2ApicEnable
) {
635 DEBUG ((EFI_D_INFO
, "Force x2APIC mode!\n"));
637 // Wakeup all APs to enable x2APIC mode
639 WakeUpAP (PeiCpuMpData
, TRUE
, 0, ApFuncEnableX2Apic
, NULL
);
641 // Wait for all known APs finished
643 while (PeiCpuMpData
->FinishedCount
< (PeiCpuMpData
->CpuCount
- 1)) {
647 // Enable x2APIC on BSP
649 SetApicMode (LOCAL_APIC_MODE_X2APIC
);
651 DEBUG ((EFI_D_INFO
, "APIC MODE is %d\n", GetApicMode ()));
653 // Sort BSP/Aps by CPU APIC ID in ascending order
655 SortApicId (PeiCpuMpData
);
658 DEBUG ((EFI_D_INFO
, "CpuMpPei: Find %d processors in system.\n", PeiCpuMpData
->CpuCount
));
659 return PeiCpuMpData
->CpuCount
;
663 Prepare for AP wakeup buffer and copy AP reset code into it.
665 Get wakeup buffer below 1MB. Allocate memory for CPU MP Data and APs Stack.
667 @return Pointer to PEI CPU MP Data
670 PrepareAPStartupVector (
676 PEI_CPU_MP_DATA
*PeiCpuMpData
;
677 EFI_PHYSICAL_ADDRESS Buffer
;
680 UINTN WakeupBufferSize
;
681 MP_ASSEMBLY_ADDRESS_MAP AddressMap
;
683 UINT16 MonitorFilterSize
;
684 UINT8
*MonitorBuffer
;
687 AsmGetAddressMap (&AddressMap
);
688 WakeupBufferSize
= AddressMap
.RendezvousFunnelSize
+ sizeof (MP_CPU_EXCHANGE_INFO
);
689 WakeupBuffer
= GetWakeupBuffer ((WakeupBufferSize
+ SIZE_4KB
- 1) & ~(SIZE_4KB
- 1));
690 ASSERT (WakeupBuffer
!= (UINTN
) -1);
691 DEBUG ((EFI_D_INFO
, "CpuMpPei: WakeupBuffer = 0x%x\n", WakeupBuffer
));
694 // Allocate Pages for APs stack, CPU MP Data, backup buffer for wakeup buffer,
695 // and monitor buffer if required.
697 MaxCpuCount
= PcdGet32(PcdCpuMaxLogicalProcessorNumber
);
698 BufferSize
= PcdGet32 (PcdCpuApStackSize
) * MaxCpuCount
+ sizeof (PEI_CPU_MP_DATA
)
699 + WakeupBufferSize
+ sizeof (PEI_CPU_DATA
) * MaxCpuCount
;
700 ApLoopMode
= GetApLoopMode (&MonitorFilterSize
);
701 BufferSize
+= MonitorFilterSize
* MaxCpuCount
;
702 Status
= PeiServicesAllocatePages (
704 EFI_SIZE_TO_PAGES (BufferSize
),
707 ASSERT_EFI_ERROR (Status
);
709 PeiCpuMpData
= (PEI_CPU_MP_DATA
*) (UINTN
) (Buffer
+ PcdGet32 (PcdCpuApStackSize
) * MaxCpuCount
);
710 PeiCpuMpData
->Buffer
= (UINTN
) Buffer
;
711 PeiCpuMpData
->CpuApStackSize
= PcdGet32 (PcdCpuApStackSize
);
712 PeiCpuMpData
->WakeupBuffer
= WakeupBuffer
;
713 PeiCpuMpData
->BackupBuffer
= (UINTN
)PeiCpuMpData
+ sizeof (PEI_CPU_MP_DATA
);
714 PeiCpuMpData
->BackupBufferSize
= WakeupBufferSize
;
715 PeiCpuMpData
->MpCpuExchangeInfo
= (MP_CPU_EXCHANGE_INFO
*) (UINTN
) (WakeupBuffer
+ AddressMap
.RendezvousFunnelSize
);
717 PeiCpuMpData
->CpuCount
= 1;
718 PeiCpuMpData
->BspNumber
= 0;
719 PeiCpuMpData
->CpuData
= (PEI_CPU_DATA
*) (PeiCpuMpData
->BackupBuffer
+
720 PeiCpuMpData
->BackupBufferSize
);
721 PeiCpuMpData
->CpuData
[0].ApicId
= GetInitialApicId ();
722 PeiCpuMpData
->CpuData
[0].Health
.Uint32
= 0;
723 PeiCpuMpData
->EndOfPeiFlag
= FALSE
;
724 InitializeSpinLock(&PeiCpuMpData
->MpLock
);
725 SaveVolatileRegisters (&PeiCpuMpData
->CpuData
[0].VolatileRegisters
);
726 CopyMem (&PeiCpuMpData
->AddressMap
, &AddressMap
, sizeof (MP_ASSEMBLY_ADDRESS_MAP
));
728 // Initialize AP loop mode
730 PeiCpuMpData
->ApLoopMode
= ApLoopMode
;
731 DEBUG ((EFI_D_INFO
, "AP Loop Mode is %d\n", PeiCpuMpData
->ApLoopMode
));
732 MonitorBuffer
= (UINT8
*)(PeiCpuMpData
->CpuData
+ MaxCpuCount
);
733 if (PeiCpuMpData
->ApLoopMode
!= ApInHltLoop
) {
735 // Set up APs wakeup signal buffer
737 for (Index
= 0; Index
< MaxCpuCount
; Index
++) {
738 PeiCpuMpData
->CpuData
[Index
].StartupApSignal
=
739 (UINT32
*)(MonitorBuffer
+ MonitorFilterSize
* Index
);
743 // Backup original data and copy AP reset code in it
745 BackupAndPrepareWakeupBuffer(PeiCpuMpData
);
751 Notify function on End Of Pei PPI.
753 On S3 boot, this function will restore wakeup buffer data.
754 On normal boot, this function will flag wakeup buffer to be un-used type.
756 @param PeiServices The pointer to the PEI Services Table.
757 @param NotifyDescriptor Address of the notification descriptor data structure.
758 @param Ppi Address of the PPI that was installed.
760 @retval EFI_SUCCESS When everything is OK.
765 CpuMpEndOfPeiCallback (
766 IN EFI_PEI_SERVICES
**PeiServices
,
767 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
772 EFI_BOOT_MODE BootMode
;
773 PEI_CPU_MP_DATA
*PeiCpuMpData
;
774 EFI_PEI_HOB_POINTERS Hob
;
775 EFI_HOB_MEMORY_ALLOCATION
*MemoryHob
;
777 DEBUG ((EFI_D_INFO
, "CpuMpPei: CpuMpEndOfPeiCallback () invoked\n"));
779 Status
= PeiServicesGetBootMode (&BootMode
);
780 ASSERT_EFI_ERROR (Status
);
782 PeiCpuMpData
= GetMpHobData ();
783 ASSERT (PeiCpuMpData
!= NULL
);
785 if (BootMode
!= BOOT_ON_S3_RESUME
) {
787 // Get the HOB list for processing
789 Hob
.Raw
= GetHobList ();
791 // Collect memory ranges
793 while (!END_OF_HOB_LIST (Hob
)) {
794 if (Hob
.Header
->HobType
== EFI_HOB_TYPE_MEMORY_ALLOCATION
) {
795 MemoryHob
= Hob
.MemoryAllocation
;
796 if(MemoryHob
->AllocDescriptor
.MemoryBaseAddress
== PeiCpuMpData
->WakeupBuffer
) {
798 // Flag this HOB type to un-used
800 GET_HOB_TYPE (Hob
) = EFI_HOB_TYPE_UNUSED
;
804 Hob
.Raw
= GET_NEXT_HOB (Hob
);
807 RestoreWakeupBuffer (PeiCpuMpData
);
808 PeiCpuMpData
->EndOfPeiFlag
= TRUE
;
814 The Entry point of the MP CPU PEIM.
816 This function will wakeup APs and collect CPU AP count and install the
819 @param FileHandle Handle of the file being invoked.
820 @param PeiServices Describes the list of possible PEI Services.
822 @retval EFI_SUCCESS MpServicePpi is installed successfully.
828 IN EFI_PEI_FILE_HANDLE FileHandle
,
829 IN CONST EFI_PEI_SERVICES
**PeiServices
833 PEI_CPU_MP_DATA
*PeiCpuMpData
;
834 EFI_VECTOR_HANDOFF_INFO
*VectorInfo
;
835 EFI_PEI_VECTOR_HANDOFF_INFO_PPI
*VectorHandoffInfoPpi
;
838 // Get Vector Hand-off Info PPI
841 Status
= PeiServicesLocatePpi (
842 &gEfiVectorHandoffInfoPpiGuid
,
845 (VOID
**)&VectorHandoffInfoPpi
847 if (Status
== EFI_SUCCESS
) {
848 VectorInfo
= VectorHandoffInfoPpi
->Info
;
850 Status
= InitializeCpuExceptionHandlers (VectorInfo
);
851 ASSERT_EFI_ERROR (Status
);
853 // Get wakeup buffer and copy AP reset code in it
855 PeiCpuMpData
= PrepareAPStartupVector ();
857 // Count processor number and collect processor information
859 CountProcessorNumber (PeiCpuMpData
);
861 // Build location of PEI CPU MP DATA buffer in HOB
865 (VOID
*)&PeiCpuMpData
,
869 // Update and publish CPU BIST information
871 CollectBistDataFromPpi (PeiServices
, PeiCpuMpData
);
873 // register an event for EndOfPei
875 Status
= PeiServicesNotifyPpi (&mNotifyList
);
876 ASSERT_EFI_ERROR (Status
);
878 // Install CPU MP PPI
880 Status
= PeiServicesInstallPpi(&mPeiCpuMpPpiDesc
);
881 ASSERT_EFI_ERROR (Status
);