2 CPU PEI Module installs CPU Multiple Processor PPI.
4 Copyright (c) 2015, 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.
18 // Global Descriptor Table (GDT)
20 GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT mGdtEntries
[] = {
21 /* selector { Global Segment Descriptor } */
22 /* 0x00 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //null descriptor
23 /* 0x08 */ {{0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear data segment descriptor
24 /* 0x10 */ {{0xffff, 0, 0, 0xf, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear code segment descriptor
25 /* 0x18 */ {{0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor
26 /* 0x20 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system code segment descriptor
27 /* 0x28 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor
28 /* 0x30 */ {{0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor
29 /* 0x38 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 1, 0, 1, 0}}, //system code segment descriptor
30 /* 0x40 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor
36 GLOBAL_REMOVE_IF_UNREFERENCED IA32_DESCRIPTOR mGdt
= {
37 sizeof (mGdtEntries
) - 1,
41 GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList
= {
42 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
43 &gEfiEndOfPeiSignalPpiGuid
,
48 Sort the APIC ID of all processors.
50 This function sorts the APIC ID of all processors so that processor number is
51 assigned in the ascending order of APIC ID which eases MP debugging.
53 @param PeiCpuMpData Pointer to PEI CPU MP Data
57 IN PEI_CPU_MP_DATA
*PeiCpuMpData
67 ApCount
= PeiCpuMpData
->CpuCount
- 1;
70 for (Index1
= 0; Index1
< ApCount
; Index1
++) {
73 // Sort key is the hardware default APIC ID
75 ApicId
= PeiCpuMpData
->CpuData
[Index1
].ApicId
;
76 for (Index2
= Index1
+ 1; Index2
<= ApCount
; Index2
++) {
77 if (ApicId
> PeiCpuMpData
->CpuData
[Index2
].ApicId
) {
79 ApicId
= PeiCpuMpData
->CpuData
[Index2
].ApicId
;
82 if (Index3
!= Index1
) {
83 CopyMem (&CpuData
, &PeiCpuMpData
->CpuData
[Index3
], sizeof (PEI_CPU_DATA
));
85 &PeiCpuMpData
->CpuData
[Index3
],
86 &PeiCpuMpData
->CpuData
[Index1
],
89 CopyMem (&PeiCpuMpData
->CpuData
[Index1
], &CpuData
, sizeof (PEI_CPU_DATA
));
94 // Get the processor number for the BSP
96 ApicId
= GetInitialApicId ();
97 for (Index1
= 0; Index1
< PeiCpuMpData
->CpuCount
; Index1
++) {
98 if (PeiCpuMpData
->CpuData
[Index1
].ApicId
== ApicId
) {
99 PeiCpuMpData
->BspNumber
= (UINT32
) Index1
;
107 Enable x2APIC mode on APs.
109 @param Buffer Pointer to private data buffer.
117 SetApicMode (LOCAL_APIC_MODE_X2APIC
);
123 @param MonitorFilterSize Returns the largest monitor-line size in bytes.
125 @return The AP loop mode.
129 OUT UINT16
*MonitorFilterSize
137 ASSERT (MonitorFilterSize
!= NULL
);
139 ApLoopMode
= PcdGet8 (PcdCpuApLoopMode
);
140 ASSERT (ApLoopMode
>= ApInHltLoop
&& ApLoopMode
<= ApInRunLoop
);
141 if (ApLoopMode
== ApInMwaitLoop
) {
142 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, &RegEcx
, NULL
);
143 if ((RegEcx
& BIT3
) == 0) {
145 // If processor does not support MONITOR/MWAIT feature
146 // by CPUID.[EAX=01H]:ECX.BIT3, force AP in Hlt-loop mode
148 ApLoopMode
= ApInHltLoop
;
152 if (ApLoopMode
== ApInHltLoop
) {
153 *MonitorFilterSize
= 0;
154 } else if (ApLoopMode
== ApInRunLoop
) {
155 *MonitorFilterSize
= sizeof (UINT32
);
156 } else if (ApLoopMode
== ApInMwaitLoop
) {
158 // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes
159 // CPUID.[EAX=05H].EDX: C-states supported using MWAIT
161 AsmCpuid (CPUID_MONITOR_MWAIT
, NULL
, &RegEbx
, NULL
, &RegEdx
);
162 *MonitorFilterSize
= RegEbx
& 0xFFFF;
169 Get CPU MP Data pointer from the Guided HOB.
171 @return Pointer to Pointer to PEI CPU MP Data
178 EFI_HOB_GUID_TYPE
*GuidHob
;
180 PEI_CPU_MP_DATA
*CpuMpData
;
183 GuidHob
= GetFirstGuidHob (&gEfiCallerIdGuid
);
184 if (GuidHob
!= NULL
) {
185 DataInHob
= GET_GUID_HOB_DATA (GuidHob
);
186 CpuMpData
= (PEI_CPU_MP_DATA
*)(*(UINTN
*)DataInHob
);
188 ASSERT (CpuMpData
!= NULL
);
193 Save the volatile registers required to be restored following INIT IPI.
195 @param VolatileRegisters Returns buffer saved the volatile resisters
198 SaveVolatileRegisters (
199 OUT CPU_VOLATILE_REGISTERS
*VolatileRegisters
204 VolatileRegisters
->Cr0
= AsmReadCr0 ();
205 VolatileRegisters
->Cr3
= AsmReadCr3 ();
206 VolatileRegisters
->Cr4
= AsmReadCr4 ();
208 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &RegEdx
);
209 if ((RegEdx
& BIT2
) != 0) {
211 // If processor supports Debugging Extensions feature
212 // by CPUID.[EAX=01H]:EDX.BIT2
214 VolatileRegisters
->Dr0
= AsmReadDr0 ();
215 VolatileRegisters
->Dr1
= AsmReadDr1 ();
216 VolatileRegisters
->Dr2
= AsmReadDr2 ();
217 VolatileRegisters
->Dr3
= AsmReadDr3 ();
218 VolatileRegisters
->Dr6
= AsmReadDr6 ();
219 VolatileRegisters
->Dr7
= AsmReadDr7 ();
224 Restore the volatile registers following INIT IPI.
226 @param VolatileRegisters Pointer to volatile resisters
227 @param IsRestoreDr TRUE: Restore DRx if supported
228 FALSE: Do not restore DRx
231 RestoreVolatileRegisters (
232 IN CPU_VOLATILE_REGISTERS
*VolatileRegisters
,
233 IN BOOLEAN IsRestoreDr
238 AsmWriteCr0 (VolatileRegisters
->Cr0
);
239 AsmWriteCr3 (VolatileRegisters
->Cr3
);
240 AsmWriteCr4 (VolatileRegisters
->Cr4
);
243 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &RegEdx
);
244 if ((RegEdx
& BIT2
) != 0) {
246 // If processor supports Debugging Extensions feature
247 // by CPUID.[EAX=01H]:EDX.BIT2
249 AsmWriteDr0 (VolatileRegisters
->Dr0
);
250 AsmWriteDr1 (VolatileRegisters
->Dr1
);
251 AsmWriteDr2 (VolatileRegisters
->Dr2
);
252 AsmWriteDr3 (VolatileRegisters
->Dr3
);
253 AsmWriteDr6 (VolatileRegisters
->Dr6
);
254 AsmWriteDr7 (VolatileRegisters
->Dr7
);
260 This function will be called from AP reset code if BSP uses WakeUpAP.
262 @param ExchangeInfo Pointer to the MP exchange info buffer
263 @param NumApsExecuting Number of current executing AP
268 IN MP_CPU_EXCHANGE_INFO
*ExchangeInfo
,
269 IN UINTN NumApsExecuting
272 PEI_CPU_MP_DATA
*PeiCpuMpData
;
273 UINTN ProcessorNumber
;
274 EFI_AP_PROCEDURE Procedure
;
276 volatile UINT32
*ApStartupSignalBuffer
;
278 PeiCpuMpData
= ExchangeInfo
->PeiCpuMpData
;
280 if (PeiCpuMpData
->InitFlag
) {
281 ProcessorNumber
= NumApsExecuting
;
283 // Sync BSP's Control registers to APs
285 RestoreVolatileRegisters (&PeiCpuMpData
->CpuData
[0].VolatileRegisters
, FALSE
);
287 // This is first time AP wakeup, get BIST information from AP stack
289 BistData
= *(UINTN
*) (PeiCpuMpData
->Buffer
+ ProcessorNumber
* PeiCpuMpData
->CpuApStackSize
- sizeof (UINTN
));
290 PeiCpuMpData
->CpuData
[ProcessorNumber
].Health
.Uint32
= (UINT32
) BistData
;
291 PeiCpuMpData
->CpuData
[ProcessorNumber
].ApicId
= GetInitialApicId ();
292 if (PeiCpuMpData
->CpuData
[ProcessorNumber
].ApicId
>= 0xFF) {
294 // Set x2APIC mode if there are any logical processor reporting
295 // an APIC ID of 255 or greater.
297 AcquireSpinLock(&PeiCpuMpData
->MpLock
);
298 PeiCpuMpData
->X2ApicEnable
= TRUE
;
299 ReleaseSpinLock(&PeiCpuMpData
->MpLock
);
302 // Sync BSP's Mtrr table to all wakeup APs and load microcode on APs.
304 MtrrSetAllMtrrs (&PeiCpuMpData
->MtrrTable
);
306 PeiCpuMpData
->CpuData
[ProcessorNumber
].State
= CpuStateIdle
;
309 // Execute AP function if AP is not disabled
311 GetProcessorNumber (PeiCpuMpData
, &ProcessorNumber
);
312 if (PeiCpuMpData
->ApLoopMode
== ApInHltLoop
) {
314 // Restore AP's volatile registers saved
316 RestoreVolatileRegisters (&PeiCpuMpData
->CpuData
[ProcessorNumber
].VolatileRegisters
, TRUE
);
319 if ((PeiCpuMpData
->CpuData
[ProcessorNumber
].State
!= CpuStateDisabled
) &&
320 (PeiCpuMpData
->ApFunction
!= 0)) {
321 PeiCpuMpData
->CpuData
[ProcessorNumber
].State
= CpuStateBusy
;
322 Procedure
= (EFI_AP_PROCEDURE
)(UINTN
)PeiCpuMpData
->ApFunction
;
324 // Invoke AP function here
326 Procedure ((VOID
*)(UINTN
)PeiCpuMpData
->ApFunctionArgument
);
328 // Re-get the processor number due to BSP/AP maybe exchange in AP function
330 GetProcessorNumber (PeiCpuMpData
, &ProcessorNumber
);
331 PeiCpuMpData
->CpuData
[ProcessorNumber
].State
= CpuStateIdle
;
336 // AP finished executing C code
338 InterlockedIncrement ((UINT32
*)&PeiCpuMpData
->FinishedCount
);
341 // Place AP is specified loop mode
343 if (PeiCpuMpData
->ApLoopMode
== ApInHltLoop
) {
345 // Save AP volatile registers
347 SaveVolatileRegisters (&PeiCpuMpData
->CpuData
[ProcessorNumber
].VolatileRegisters
);
349 // Place AP in Hlt-loop
352 DisableInterrupts ();
357 ApStartupSignalBuffer
= PeiCpuMpData
->CpuData
[ProcessorNumber
].StartupApSignal
;
359 // Clear AP start-up signal
361 *ApStartupSignalBuffer
= 0;
363 DisableInterrupts ();
364 if (PeiCpuMpData
->ApLoopMode
== ApInMwaitLoop
) {
366 // Place AP in Mwait-loop
368 AsmMonitor ((UINTN
)ApStartupSignalBuffer
, 0, 0);
369 if (*ApStartupSignalBuffer
!= WAKEUP_AP_SIGNAL
) {
371 // If AP start-up signal is not set, place AP into
372 // the maximum C-state
374 AsmMwait (PeiCpuMpData
->ApTargetCState
<< 4, 0);
376 } else if (PeiCpuMpData
->ApLoopMode
== ApInRunLoop
) {
378 // Place AP in Run-loop
386 // If AP start-up signal is written, AP is waken up
387 // otherwise place AP in loop again
389 if (*ApStartupSignalBuffer
== WAKEUP_AP_SIGNAL
) {
397 This function will be called by BSP to wakeup AP.
399 @param PeiCpuMpData Pointer to PEI CPU MP Data
400 @param Broadcast TRUE: Send broadcast IPI to all APs
401 FALSE: Send IPI to AP by ApicId
402 @param ProcessorNumber The handle number of specified processor
403 @param Procedure The function to be invoked by AP
404 @param ProcedureArgument The argument to be passed into AP function
408 IN PEI_CPU_MP_DATA
*PeiCpuMpData
,
409 IN BOOLEAN Broadcast
,
410 IN UINTN ProcessorNumber
,
411 IN EFI_AP_PROCEDURE Procedure
, OPTIONAL
412 IN VOID
*ProcedureArgument OPTIONAL
415 volatile MP_CPU_EXCHANGE_INFO
*ExchangeInfo
;
418 PeiCpuMpData
->ApFunction
= (UINTN
) Procedure
;
419 PeiCpuMpData
->ApFunctionArgument
= (UINTN
) ProcedureArgument
;
420 PeiCpuMpData
->FinishedCount
= 0;
422 ExchangeInfo
= PeiCpuMpData
->MpCpuExchangeInfo
;
423 ExchangeInfo
->Lock
= 0;
424 ExchangeInfo
->StackStart
= PeiCpuMpData
->Buffer
;
425 ExchangeInfo
->StackSize
= PeiCpuMpData
->CpuApStackSize
;
426 ExchangeInfo
->BufferStart
= PeiCpuMpData
->WakeupBuffer
;
427 ExchangeInfo
->PmodeOffset
= PeiCpuMpData
->AddressMap
.PModeEntryOffset
;
428 ExchangeInfo
->LmodeOffset
= PeiCpuMpData
->AddressMap
.LModeEntryOffset
;
429 ExchangeInfo
->Cr3
= AsmReadCr3 ();
430 ExchangeInfo
->CFunction
= (UINTN
) ApCFunction
;
431 ExchangeInfo
->NumApsExecuting
= 0;
432 ExchangeInfo
->PeiCpuMpData
= PeiCpuMpData
;
435 // Get the BSP's data of GDT and IDT
437 CopyMem ((VOID
*)&ExchangeInfo
->GdtrProfile
, &mGdt
, sizeof(mGdt
));
438 AsmReadIdtr ((IA32_DESCRIPTOR
*) &ExchangeInfo
->IdtrProfile
);
440 if (PeiCpuMpData
->ApLoopMode
== ApInMwaitLoop
) {
442 // Get AP target C-state each time when waking up AP,
443 // for it maybe updated by platform again
445 PeiCpuMpData
->ApTargetCState
= PcdGet8 (PcdCpuApTargetCstate
);
449 // Wakeup APs per AP loop state
451 if (PeiCpuMpData
->ApLoopMode
== ApInHltLoop
|| PeiCpuMpData
->InitFlag
) {
453 SendInitSipiSipiAllExcludingSelf ((UINT32
) ExchangeInfo
->BufferStart
);
456 PeiCpuMpData
->CpuData
[ProcessorNumber
].ApicId
,
457 (UINT32
) ExchangeInfo
->BufferStart
460 } else if ((PeiCpuMpData
->ApLoopMode
== ApInMwaitLoop
) ||
461 (PeiCpuMpData
->ApLoopMode
== ApInRunLoop
)) {
463 for (Index
= 0; Index
< PeiCpuMpData
->CpuCount
; Index
++) {
464 if (Index
!= PeiCpuMpData
->BspNumber
) {
465 *(PeiCpuMpData
->CpuData
[Index
].StartupApSignal
) = WAKEUP_AP_SIGNAL
;
469 *(PeiCpuMpData
->CpuData
[ProcessorNumber
].StartupApSignal
) = WAKEUP_AP_SIGNAL
;
478 Get available system memory below 1MB by specified size.
480 @param WakeupBufferSize Wakeup buffer size required
482 @retval other Return wakeup buffer address below 1MB.
483 @retval -1 Cannot find free memory below 1MB.
487 IN UINTN WakeupBufferSize
490 EFI_PEI_HOB_POINTERS Hob
;
491 UINTN WakeupBufferStart
;
492 UINTN WakeupBufferEnd
;
495 // Get the HOB list for processing
497 Hob
.Raw
= GetHobList ();
500 // Collect memory ranges
502 while (!END_OF_HOB_LIST (Hob
)) {
503 if (Hob
.Header
->HobType
== EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
504 if ((Hob
.ResourceDescriptor
->PhysicalStart
< BASE_1MB
) &&
505 (Hob
.ResourceDescriptor
->ResourceType
== EFI_RESOURCE_SYSTEM_MEMORY
) &&
506 ((Hob
.ResourceDescriptor
->ResourceAttribute
&
507 (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED
|
508 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED
|
509 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
513 // Need memory under 1MB to be collected here
515 WakeupBufferEnd
= (UINTN
) (Hob
.ResourceDescriptor
->PhysicalStart
+ Hob
.ResourceDescriptor
->ResourceLength
);
516 if (WakeupBufferEnd
> BASE_1MB
) {
518 // Wakeup buffer should be under 1MB
520 WakeupBufferEnd
= BASE_1MB
;
523 // Wakeup buffer should be aligned on 4KB
525 WakeupBufferStart
= (WakeupBufferEnd
- WakeupBufferSize
) & ~(SIZE_4KB
- 1);
526 if (WakeupBufferStart
< Hob
.ResourceDescriptor
->PhysicalStart
) {
530 // Create a memory allocation HOB.
532 BuildMemoryAllocationHob (
537 return WakeupBufferStart
;
543 Hob
.Raw
= GET_NEXT_HOB (Hob
);
550 Get available system memory below 1MB by specified size.
552 @param PeiCpuMpData Pointer to PEI CPU MP Data
555 BackupAndPrepareWakeupBuffer(
556 IN PEI_CPU_MP_DATA
*PeiCpuMpData
560 (VOID
*) PeiCpuMpData
->BackupBuffer
,
561 (VOID
*) PeiCpuMpData
->WakeupBuffer
,
562 PeiCpuMpData
->BackupBufferSize
565 (VOID
*) PeiCpuMpData
->WakeupBuffer
,
566 (VOID
*) PeiCpuMpData
->AddressMap
.RendezvousFunnelAddress
,
567 PeiCpuMpData
->AddressMap
.RendezvousFunnelSize
572 Restore wakeup buffer data.
574 @param PeiCpuMpData Pointer to PEI CPU MP Data
578 IN PEI_CPU_MP_DATA
*PeiCpuMpData
581 CopyMem ((VOID
*) PeiCpuMpData
->WakeupBuffer
, (VOID
*) PeiCpuMpData
->BackupBuffer
, PeiCpuMpData
->BackupBufferSize
);
585 This function will get CPU count in the system.
587 @param PeiCpuMpData Pointer to PEI CPU MP Data
589 @return AP processor count
592 CountProcessorNumber (
593 IN PEI_CPU_MP_DATA
*PeiCpuMpData
597 // Load Microcode on BSP
601 // Store BSP's MTRR setting
603 MtrrGetAllMtrrs (&PeiCpuMpData
->MtrrTable
);
606 // Only perform AP detection if PcdCpuMaxLogicalProcessorNumber is greater than 1
608 if (PcdGet32 (PcdCpuMaxLogicalProcessorNumber
) > 1) {
610 // Send 1st broadcast IPI to APs to wakeup APs
612 PeiCpuMpData
->InitFlag
= TRUE
;
613 PeiCpuMpData
->X2ApicEnable
= FALSE
;
614 WakeUpAP (PeiCpuMpData
, TRUE
, 0, NULL
, NULL
);
616 // Wait for AP task to complete and then exit.
618 MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds
));
619 PeiCpuMpData
->InitFlag
= FALSE
;
620 PeiCpuMpData
->CpuCount
+= (UINT32
)PeiCpuMpData
->MpCpuExchangeInfo
->NumApsExecuting
;
621 ASSERT (PeiCpuMpData
->CpuCount
<= PcdGet32 (PcdCpuMaxLogicalProcessorNumber
));
623 // Wait for all APs finished the initialization
625 while (PeiCpuMpData
->FinishedCount
< (PeiCpuMpData
->CpuCount
- 1)) {
629 if (PeiCpuMpData
->X2ApicEnable
) {
630 DEBUG ((EFI_D_INFO
, "Force x2APIC mode!\n"));
632 // Wakeup all APs to enable x2APIC mode
634 WakeUpAP (PeiCpuMpData
, TRUE
, 0, ApFuncEnableX2Apic
, NULL
);
636 // Wait for all known APs finished
638 while (PeiCpuMpData
->FinishedCount
< (PeiCpuMpData
->CpuCount
- 1)) {
642 // Enable x2APIC on BSP
644 SetApicMode (LOCAL_APIC_MODE_X2APIC
);
646 DEBUG ((EFI_D_INFO
, "APIC MODE is %d\n", GetApicMode ()));
648 // Sort BSP/Aps by CPU APIC ID in ascending order
650 SortApicId (PeiCpuMpData
);
653 DEBUG ((EFI_D_INFO
, "CpuMpPei: Find %d processors in system.\n", PeiCpuMpData
->CpuCount
));
654 return PeiCpuMpData
->CpuCount
;
658 Prepare for AP wakeup buffer and copy AP reset code into it.
660 Get wakeup buffer below 1MB. Allocate memory for CPU MP Data and APs Stack.
662 @return Pointer to PEI CPU MP Data
665 PrepareAPStartupVector (
671 PEI_CPU_MP_DATA
*PeiCpuMpData
;
672 EFI_PHYSICAL_ADDRESS Buffer
;
675 UINTN WakeupBufferSize
;
676 MP_ASSEMBLY_ADDRESS_MAP AddressMap
;
678 UINT16 MonitorFilterSize
;
679 UINT8
*MonitorBuffer
;
682 AsmGetAddressMap (&AddressMap
);
683 WakeupBufferSize
= AddressMap
.RendezvousFunnelSize
+ sizeof (MP_CPU_EXCHANGE_INFO
);
684 WakeupBuffer
= GetWakeupBuffer ((WakeupBufferSize
+ SIZE_4KB
- 1) & ~(SIZE_4KB
- 1));
685 ASSERT (WakeupBuffer
!= (UINTN
) -1);
686 DEBUG ((EFI_D_INFO
, "CpuMpPei: WakeupBuffer = 0x%x\n", WakeupBuffer
));
689 // Allocate Pages for APs stack, CPU MP Data, backup buffer for wakeup buffer,
690 // and monitor buffer if required.
692 MaxCpuCount
= PcdGet32(PcdCpuMaxLogicalProcessorNumber
);
693 BufferSize
= PcdGet32 (PcdCpuApStackSize
) * MaxCpuCount
+ sizeof (PEI_CPU_MP_DATA
)
694 + WakeupBufferSize
+ sizeof (PEI_CPU_DATA
) * MaxCpuCount
;
695 ApLoopMode
= GetApLoopMode (&MonitorFilterSize
);
696 BufferSize
+= MonitorFilterSize
* MaxCpuCount
;
697 Status
= PeiServicesAllocatePages (
699 EFI_SIZE_TO_PAGES (BufferSize
),
702 ASSERT_EFI_ERROR (Status
);
704 PeiCpuMpData
= (PEI_CPU_MP_DATA
*) (UINTN
) (Buffer
+ PcdGet32 (PcdCpuApStackSize
) * MaxCpuCount
);
705 PeiCpuMpData
->Buffer
= (UINTN
) Buffer
;
706 PeiCpuMpData
->CpuApStackSize
= PcdGet32 (PcdCpuApStackSize
);
707 PeiCpuMpData
->WakeupBuffer
= WakeupBuffer
;
708 PeiCpuMpData
->BackupBuffer
= (UINTN
)PeiCpuMpData
+ sizeof (PEI_CPU_MP_DATA
);
709 PeiCpuMpData
->BackupBufferSize
= WakeupBufferSize
;
710 PeiCpuMpData
->MpCpuExchangeInfo
= (MP_CPU_EXCHANGE_INFO
*) (UINTN
) (WakeupBuffer
+ AddressMap
.RendezvousFunnelSize
);
712 PeiCpuMpData
->CpuCount
= 1;
713 PeiCpuMpData
->BspNumber
= 0;
714 PeiCpuMpData
->CpuData
= (PEI_CPU_DATA
*) (PeiCpuMpData
->BackupBuffer
+
715 PeiCpuMpData
->BackupBufferSize
);
716 PeiCpuMpData
->CpuData
[0].ApicId
= GetInitialApicId ();
717 PeiCpuMpData
->CpuData
[0].Health
.Uint32
= 0;
718 PeiCpuMpData
->EndOfPeiFlag
= FALSE
;
719 InitializeSpinLock(&PeiCpuMpData
->MpLock
);
720 SaveVolatileRegisters (&PeiCpuMpData
->CpuData
[0].VolatileRegisters
);
721 CopyMem (&PeiCpuMpData
->AddressMap
, &AddressMap
, sizeof (MP_ASSEMBLY_ADDRESS_MAP
));
723 // Initialize AP loop mode
725 PeiCpuMpData
->ApLoopMode
= ApLoopMode
;
726 DEBUG ((EFI_D_INFO
, "AP Loop Mode is %d\n", PeiCpuMpData
->ApLoopMode
));
727 MonitorBuffer
= (UINT8
*)(PeiCpuMpData
->CpuData
+ MaxCpuCount
);
728 if (PeiCpuMpData
->ApLoopMode
!= ApInHltLoop
) {
730 // Set up APs wakeup signal buffer
732 for (Index
= 0; Index
< MaxCpuCount
; Index
++) {
733 PeiCpuMpData
->CpuData
[Index
].StartupApSignal
=
734 (UINT32
*)(MonitorBuffer
+ MonitorFilterSize
* Index
);
738 // Backup original data and copy AP reset code in it
740 BackupAndPrepareWakeupBuffer(PeiCpuMpData
);
746 Notify function on End Of Pei PPI.
748 On S3 boot, this function will restore wakeup buffer data.
749 On normal boot, this function will flag wakeup buffer to be un-used type.
751 @param PeiServices The pointer to the PEI Services Table.
752 @param NotifyDescriptor Address of the notification descriptor data structure.
753 @param Ppi Address of the PPI that was installed.
755 @retval EFI_SUCCESS When everything is OK.
760 CpuMpEndOfPeiCallback (
761 IN EFI_PEI_SERVICES
**PeiServices
,
762 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
767 EFI_BOOT_MODE BootMode
;
768 PEI_CPU_MP_DATA
*PeiCpuMpData
;
769 EFI_PEI_HOB_POINTERS Hob
;
770 EFI_HOB_MEMORY_ALLOCATION
*MemoryHob
;
772 DEBUG ((EFI_D_INFO
, "CpuMpPei: CpuMpEndOfPeiCallback () invoked\n"));
774 Status
= PeiServicesGetBootMode (&BootMode
);
775 ASSERT_EFI_ERROR (Status
);
777 PeiCpuMpData
= GetMpHobData ();
778 ASSERT (PeiCpuMpData
!= NULL
);
780 if (BootMode
!= BOOT_ON_S3_RESUME
) {
782 // Get the HOB list for processing
784 Hob
.Raw
= GetHobList ();
786 // Collect memory ranges
788 while (!END_OF_HOB_LIST (Hob
)) {
789 if (Hob
.Header
->HobType
== EFI_HOB_TYPE_MEMORY_ALLOCATION
) {
790 MemoryHob
= Hob
.MemoryAllocation
;
791 if(MemoryHob
->AllocDescriptor
.MemoryBaseAddress
== PeiCpuMpData
->WakeupBuffer
) {
793 // Flag this HOB type to un-used
795 GET_HOB_TYPE (Hob
) = EFI_HOB_TYPE_UNUSED
;
799 Hob
.Raw
= GET_NEXT_HOB (Hob
);
802 RestoreWakeupBuffer (PeiCpuMpData
);
803 PeiCpuMpData
->EndOfPeiFlag
= TRUE
;
809 The Entry point of the MP CPU PEIM.
811 This function will wakeup APs and collect CPU AP count and install the
814 @param FileHandle Handle of the file being invoked.
815 @param PeiServices Describes the list of possible PEI Services.
817 @retval EFI_SUCCESS MpServicePpi is installed successfully.
823 IN EFI_PEI_FILE_HANDLE FileHandle
,
824 IN CONST EFI_PEI_SERVICES
**PeiServices
828 PEI_CPU_MP_DATA
*PeiCpuMpData
;
829 UINT32 ProcessorCount
;
832 // Load new GDT table on BSP
834 AsmInitializeGdt (&mGdt
);
836 // Get wakeup buffer and copy AP reset code in it
838 PeiCpuMpData
= PrepareAPStartupVector ();
840 // Count processor number and collect processor information
842 ProcessorCount
= CountProcessorNumber (PeiCpuMpData
);
844 // Build location of PEI CPU MP DATA buffer in HOB
848 (VOID
*)&PeiCpuMpData
,
852 // Update and publish CPU BIST information
854 CollectBistDataFromPpi (PeiServices
, PeiCpuMpData
);
856 // register an event for EndOfPei
858 Status
= PeiServicesNotifyPpi (&mNotifyList
);
859 ASSERT_EFI_ERROR (Status
);
861 // Install CPU MP PPI
863 Status
= PeiServicesInstallPpi(&mPeiCpuMpPpiDesc
);
864 ASSERT_EFI_ERROR (Status
);