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,
42 Sort the APIC ID of all processors.
44 This function sorts the APIC ID of all processors so that processor number is
45 assigned in the ascending order of APIC ID which eases MP debugging.
47 @param PeiCpuMpData Pointer to PEI CPU MP Data
51 IN PEI_CPU_MP_DATA
*PeiCpuMpData
58 EFI_HEALTH_FLAGS Health
;
61 ApCount
= PeiCpuMpData
->CpuCount
- 1;
64 for (Index1
= 0; Index1
< ApCount
; Index1
++) {
67 // Sort key is the hardware default APIC ID
69 ApicId
= PeiCpuMpData
->CpuData
[Index1
].ApicId
;
70 for (Index2
= Index1
+ 1; Index2
<= ApCount
; Index2
++) {
71 if (ApicId
> PeiCpuMpData
->CpuData
[Index2
].ApicId
) {
73 ApicId
= PeiCpuMpData
->CpuData
[Index2
].ApicId
;
76 if (Index3
!= Index1
) {
77 PeiCpuMpData
->CpuData
[Index3
].ApicId
= PeiCpuMpData
->CpuData
[Index1
].ApicId
;
78 PeiCpuMpData
->CpuData
[Index1
].ApicId
= ApicId
;
79 Health
= PeiCpuMpData
->CpuData
[Index3
].Health
;
80 PeiCpuMpData
->CpuData
[Index3
].Health
= PeiCpuMpData
->CpuData
[Index1
].Health
;
81 PeiCpuMpData
->CpuData
[Index1
].Health
= Health
;
86 // Get the processor number for the BSP
88 ApicId
= GetInitialApicId ();
89 for (Index1
= 0; Index1
< PeiCpuMpData
->CpuCount
; Index1
++) {
90 if (PeiCpuMpData
->CpuData
[Index1
].ApicId
== ApicId
) {
91 PeiCpuMpData
->BspNumber
= (UINT32
) Index1
;
99 Get CPU MP Data pointer from the Guided HOB.
101 @return Pointer to Pointer to PEI CPU MP Data
108 EFI_HOB_GUID_TYPE
*GuidHob
;
110 PEI_CPU_MP_DATA
*CpuMpData
;
113 GuidHob
= GetFirstGuidHob (&gEfiCallerIdGuid
);
114 if (GuidHob
!= NULL
) {
115 DataInHob
= GET_GUID_HOB_DATA (GuidHob
);
116 CpuMpData
= (PEI_CPU_MP_DATA
*)(*(UINTN
*)DataInHob
);
118 ASSERT (CpuMpData
!= NULL
);
123 This function will be called from AP reset code if BSP uses WakeUpAP.
125 @param ExchangeInfo Pointer to the MP exchange info buffer
126 @param NumApsExecuting Number of curret executing AP
131 IN MP_CPU_EXCHANGE_INFO
*ExchangeInfo
,
132 IN UINTN NumApsExecuting
135 PEI_CPU_MP_DATA
*PeiCpuMpData
;
136 UINTN ProcessorNumber
;
137 EFI_AP_PROCEDURE Procedure
;
140 PeiCpuMpData
= ExchangeInfo
->PeiCpuMpData
;
141 if (PeiCpuMpData
->InitFlag
) {
143 // This is first time AP wakeup, get BIST inforamtion from AP stack
145 BistData
= *(UINTN
*) (PeiCpuMpData
->Buffer
+ NumApsExecuting
* PeiCpuMpData
->CpuApStackSize
- sizeof (UINTN
));
146 PeiCpuMpData
->CpuData
[NumApsExecuting
].ApicId
= GetInitialApicId ();
147 PeiCpuMpData
->CpuData
[NumApsExecuting
].Health
.Uint32
= (UINT32
) BistData
;
149 // Sync BSP's Mtrr table to all wakeup APs and load microcode on APs.
151 MtrrSetAllMtrrs (&PeiCpuMpData
->MtrrTable
);
155 // Execute AP function if AP is not disabled
157 GetProcessorNumber (PeiCpuMpData
, &ProcessorNumber
);
158 if ((PeiCpuMpData
->CpuData
[ProcessorNumber
].State
!= CpuStateDisabled
) &&
159 (PeiCpuMpData
->ApFunction
!= 0)) {
160 PeiCpuMpData
->CpuData
[ProcessorNumber
].State
= CpuStateBusy
;
161 Procedure
= (EFI_AP_PROCEDURE
)(UINTN
)PeiCpuMpData
->ApFunction
;
162 Procedure ((VOID
*)(UINTN
)PeiCpuMpData
->ApFunctionArgument
);
163 PeiCpuMpData
->CpuData
[ProcessorNumber
].State
= CpuStateIdle
;
168 // AP finished executing C code
170 InterlockedIncrement ((UINT32
*)&PeiCpuMpData
->FinishedCount
);
176 This function will be called by BSP to wakeup AP.
178 @param PeiCpuMpData Pointer to PEI CPU MP Data
179 @param Broadcast TRUE: Send broadcast IPI to all APs
180 FALSE: Send IPI to AP by ApicId
181 @param ApicId Apic ID for the processor to be waked
182 @param Procedure The function to be invoked by AP
183 @param ProcedureArgument The argument to be passed into AP function
187 IN PEI_CPU_MP_DATA
*PeiCpuMpData
,
188 IN BOOLEAN Broadcast
,
190 IN EFI_AP_PROCEDURE Procedure
, OPTIONAL
191 IN VOID
*ProcedureArgument OPTIONAL
194 volatile MP_CPU_EXCHANGE_INFO
*ExchangeInfo
;
196 PeiCpuMpData
->ApFunction
= (UINTN
) Procedure
;
197 PeiCpuMpData
->ApFunctionArgument
= (UINTN
) ProcedureArgument
;
198 PeiCpuMpData
->FinishedCount
= 0;
200 ExchangeInfo
= PeiCpuMpData
->MpCpuExchangeInfo
;
201 ExchangeInfo
->Lock
= 0;
202 ExchangeInfo
->StackStart
= PeiCpuMpData
->Buffer
;
203 ExchangeInfo
->StackSize
= PeiCpuMpData
->CpuApStackSize
;
204 ExchangeInfo
->BufferStart
= PeiCpuMpData
->WakeupBuffer
;
205 ExchangeInfo
->PmodeOffset
= PeiCpuMpData
->AddressMap
.PModeEntryOffset
;
206 ExchangeInfo
->LmodeOffset
= PeiCpuMpData
->AddressMap
.LModeEntryOffset
;
207 ExchangeInfo
->Cr3
= AsmReadCr3 ();
208 ExchangeInfo
->CFunction
= (UINTN
) ApCFunction
;
209 ExchangeInfo
->NumApsExecuting
= 0;
210 ExchangeInfo
->PeiCpuMpData
= PeiCpuMpData
;
213 // Get the BSP's data of GDT and IDT
215 CopyMem ((VOID
*)&ExchangeInfo
->GdtrProfile
, &mGdt
, sizeof(mGdt
));
216 AsmReadIdtr ((IA32_DESCRIPTOR
*) &ExchangeInfo
->IdtrProfile
);
219 SendInitSipiSipiAllExcludingSelf ((UINT32
) ExchangeInfo
->BufferStart
);
221 SendInitSipiSipi (ApicId
, (UINT32
) ExchangeInfo
->BufferStart
);
228 Get available system memory below 1MB by specified size.
230 @param WakeupBufferSize Wakeup buffer size required
232 @retval other Return wakeup buffer address below 1MB.
233 @retval -1 Cannot find free memory below 1MB.
237 IN UINTN WakeupBufferSize
240 EFI_PEI_HOB_POINTERS Hob
;
241 UINTN WakeupBufferStart
;
242 UINTN WakeupBufferEnd
;
245 // Get the HOB list for processing
247 Hob
.Raw
= GetHobList ();
250 // Collect memory ranges
252 while (!END_OF_HOB_LIST (Hob
)) {
253 if (Hob
.Header
->HobType
== EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
254 if ((Hob
.ResourceDescriptor
->PhysicalStart
< BASE_1MB
) &&
255 (Hob
.ResourceDescriptor
->ResourceType
== EFI_RESOURCE_SYSTEM_MEMORY
) &&
256 ((Hob
.ResourceDescriptor
->ResourceAttribute
&
257 (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED
|
258 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED
|
259 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
263 // Need memory under 1MB to be collected here
265 WakeupBufferEnd
= (UINTN
) (Hob
.ResourceDescriptor
->PhysicalStart
+ Hob
.ResourceDescriptor
->ResourceLength
);
266 if (WakeupBufferEnd
> BASE_1MB
) {
268 // Wakeup buffer should be under 1MB
270 WakeupBufferEnd
= BASE_1MB
;
273 // Wakeup buffer should be aligned on 4KB
275 WakeupBufferStart
= (WakeupBufferEnd
- WakeupBufferSize
) & ~(SIZE_4KB
- 1);
276 if (WakeupBufferStart
< Hob
.ResourceDescriptor
->PhysicalStart
) {
280 // Create a memory allocation HOB.
282 BuildMemoryAllocationHob (
287 return WakeupBufferStart
;
293 Hob
.Raw
= GET_NEXT_HOB (Hob
);
300 Get available system memory below 1MB by specified size.
302 @param PeiCpuMpData Pointer to PEI CPU MP Data
305 BackupAndPrepareWakeupBuffer(
306 IN PEI_CPU_MP_DATA
*PeiCpuMpData
310 (VOID
*) PeiCpuMpData
->BackupBuffer
,
311 (VOID
*) PeiCpuMpData
->WakeupBuffer
,
312 PeiCpuMpData
->BackupBufferSize
315 (VOID
*) PeiCpuMpData
->WakeupBuffer
,
316 (VOID
*) PeiCpuMpData
->AddressMap
.RendezvousFunnelAddress
,
317 PeiCpuMpData
->AddressMap
.RendezvousFunnelSize
321 This function will get CPU count in the system.
323 @param PeiCpuMpData Pointer to PEI CPU MP Data
325 @return AP processor count
328 CountProcessorNumber (
329 IN PEI_CPU_MP_DATA
*PeiCpuMpData
333 // Load Microcode on BSP
337 // Store BSP's MTRR setting
339 MtrrGetAllMtrrs (&PeiCpuMpData
->MtrrTable
);
341 // Send broadcast IPI to APs to wakeup APs
343 PeiCpuMpData
->InitFlag
= 1;
344 WakeUpAP (PeiCpuMpData
, TRUE
, 0, NULL
, NULL
);
346 // Wait for AP task to complete and then exit.
348 MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds
));
349 PeiCpuMpData
->InitFlag
= 0;
350 PeiCpuMpData
->CpuCount
+= (UINT32
) PeiCpuMpData
->MpCpuExchangeInfo
->NumApsExecuting
;
352 // Sort BSP/Aps by CPU APIC ID in ascending order
354 SortApicId (PeiCpuMpData
);
356 DEBUG ((EFI_D_INFO
, "CpuMpPei: Find %d processors in system.\n", PeiCpuMpData
->CpuCount
));
357 return PeiCpuMpData
->CpuCount
;
361 Prepare for AP wakeup buffer and copy AP reset code into it.
363 Get wakeup buffer below 1MB. Allocate memory for CPU MP Data and APs Stack.
365 @return Pointer to PEI CPU MP Data
368 PrepareAPStartupVector (
374 PEI_CPU_MP_DATA
*PeiCpuMpData
;
375 EFI_PHYSICAL_ADDRESS Buffer
;
378 UINTN WakeupBufferSize
;
379 MP_ASSEMBLY_ADDRESS_MAP AddressMap
;
381 AsmGetAddressMap (&AddressMap
);
382 WakeupBufferSize
= AddressMap
.RendezvousFunnelSize
+ sizeof (MP_CPU_EXCHANGE_INFO
);
383 WakeupBuffer
= GetWakeupBuffer ((WakeupBufferSize
+ SIZE_4KB
- 1) & ~(SIZE_4KB
- 1));
384 DEBUG ((EFI_D_INFO
, "CpuMpPei: WakeupBuffer = 0x%x\n", WakeupBuffer
));
387 // Allocate Pages for APs stack, CPU MP Data and backup buffer for wakeup buffer
389 MaxCpuCount
= PcdGet32(PcdCpuMaxLogicalProcessorNumber
);
390 BufferSize
= PcdGet32 (PcdCpuApStackSize
) * MaxCpuCount
+ sizeof (PEI_CPU_MP_DATA
)
391 + WakeupBufferSize
+ sizeof (PEI_CPU_DATA
) * MaxCpuCount
;
392 Status
= PeiServicesAllocatePages (
394 EFI_SIZE_TO_PAGES (BufferSize
),
397 ASSERT_EFI_ERROR (Status
);
399 PeiCpuMpData
= (PEI_CPU_MP_DATA
*) (UINTN
) (Buffer
+ PcdGet32 (PcdCpuApStackSize
) * MaxCpuCount
);
400 PeiCpuMpData
->Buffer
= (UINTN
) Buffer
;
401 PeiCpuMpData
->CpuApStackSize
= PcdGet32 (PcdCpuApStackSize
);
402 PeiCpuMpData
->WakeupBuffer
= WakeupBuffer
;
403 PeiCpuMpData
->BackupBuffer
= (UINTN
)PeiCpuMpData
+ sizeof (PEI_CPU_MP_DATA
);
404 PeiCpuMpData
->BackupBufferSize
= WakeupBufferSize
;
405 PeiCpuMpData
->MpCpuExchangeInfo
= (MP_CPU_EXCHANGE_INFO
*) (UINTN
) (WakeupBuffer
+ AddressMap
.RendezvousFunnelSize
);
407 PeiCpuMpData
->CpuCount
= 1;
408 PeiCpuMpData
->BspNumber
= 0;
409 PeiCpuMpData
->CpuData
= (PEI_CPU_DATA
*) (PeiCpuMpData
->MpCpuExchangeInfo
+ 1);
410 PeiCpuMpData
->CpuData
[0].ApicId
= GetInitialApicId ();
411 PeiCpuMpData
->CpuData
[0].Health
.Uint32
= 0;
412 CopyMem (&PeiCpuMpData
->AddressMap
, &AddressMap
, sizeof (MP_ASSEMBLY_ADDRESS_MAP
));
415 // Backup original data and copy AP reset code in it
417 BackupAndPrepareWakeupBuffer(PeiCpuMpData
);
422 The Entry point of the MP CPU PEIM.
424 This function will wakeup APs and collect CPU AP count and install the
427 @param FileHandle Handle of the file being invoked.
428 @param PeiServices Describes the list of possible PEI Services.
430 @retval EFI_SUCCESS MpServicePpi is installed successfully.
436 IN EFI_PEI_FILE_HANDLE FileHandle
,
437 IN CONST EFI_PEI_SERVICES
**PeiServices
441 PEI_CPU_MP_DATA
*PeiCpuMpData
;
442 UINT32 ProcessorCount
;
445 // Load new GDT table on BSP
447 AsmInitializeGdt (&mGdt
);
449 // Get wakeup buffer and copy AP reset code in it
451 PeiCpuMpData
= PrepareAPStartupVector ();
453 // Count processor number and collect processor information
455 ProcessorCount
= CountProcessorNumber (PeiCpuMpData
);
457 // Build location of PEI CPU MP DATA buffer in HOB
461 (VOID
*)&PeiCpuMpData
,
465 // Update and publish CPU BIST information
467 CollectBistDataFromPpi (PeiServices
, PeiCpuMpData
);
469 // Install CPU MP PPI
471 Status
= PeiServicesInstallPpi(&mPeiCpuMpPpiDesc
);
472 ASSERT_EFI_ERROR (Status
);