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
;
98 This function will be called from AP reset code if BSP uses WakeUpAP.
100 @param ExchangeInfo Pointer to the MP exchange info buffer
101 @param NumApsExecuting Number of curret executing AP
106 IN MP_CPU_EXCHANGE_INFO
*ExchangeInfo
,
107 IN UINTN NumApsExecuting
110 PEI_CPU_MP_DATA
*PeiCpuMpData
;
113 PeiCpuMpData
= ExchangeInfo
->PeiCpuMpData
;
114 if (PeiCpuMpData
->InitFlag
) {
116 // This is first time AP wakeup, get BIST inforamtion from AP stack
118 BistData
= *(UINTN
*) (PeiCpuMpData
->Buffer
+ NumApsExecuting
* PeiCpuMpData
->CpuApStackSize
- sizeof (UINTN
));
119 PeiCpuMpData
->CpuData
[NumApsExecuting
].ApicId
= GetInitialApicId ();
120 PeiCpuMpData
->CpuData
[NumApsExecuting
].Health
.Uint32
= (UINT32
) BistData
;
122 // Sync BSP's Mtrr table to all wakeup APs and load microcode on APs.
124 MtrrSetAllMtrrs (&PeiCpuMpData
->MtrrTable
);
129 // AP finished executing C code
131 InterlockedIncrement ((UINT32
*)&PeiCpuMpData
->FinishedCount
);
136 This function will be called by BSP to wakeup AP.
138 @param PeiCpuMpData Pointer to PEI CPU MP Data
139 @param Broadcast TRUE: Send broadcast IPI to all APs
140 FALSE: Send IPI to AP by ApicId
141 @param ApicId Apic ID for the processor to be waked
142 @param Procedure The function to be invoked by AP
143 @param ProcedureArgument The argument to be passed into AP function
147 IN PEI_CPU_MP_DATA
*PeiCpuMpData
,
148 IN BOOLEAN Broadcast
,
150 IN EFI_AP_PROCEDURE Procedure
, OPTIONAL
151 IN VOID
*ProcedureArgument OPTIONAL
154 volatile MP_CPU_EXCHANGE_INFO
*ExchangeInfo
;
156 PeiCpuMpData
->ApFunction
= (UINTN
) Procedure
;
157 PeiCpuMpData
->ApFunctionArgument
= (UINTN
) ProcedureArgument
;
158 PeiCpuMpData
->FinishedCount
= 0;
160 ExchangeInfo
= PeiCpuMpData
->MpCpuExchangeInfo
;
161 ExchangeInfo
->Lock
= 0;
162 ExchangeInfo
->StackStart
= PeiCpuMpData
->Buffer
;
163 ExchangeInfo
->StackSize
= PeiCpuMpData
->CpuApStackSize
;
164 ExchangeInfo
->BufferStart
= PeiCpuMpData
->WakeupBuffer
;
165 ExchangeInfo
->PmodeOffset
= PeiCpuMpData
->AddressMap
.PModeEntryOffset
;
166 ExchangeInfo
->LmodeOffset
= PeiCpuMpData
->AddressMap
.LModeEntryOffset
;
167 ExchangeInfo
->Cr3
= AsmReadCr3 ();
168 ExchangeInfo
->CFunction
= (UINTN
) ApCFunction
;
169 ExchangeInfo
->NumApsExecuting
= 0;
170 ExchangeInfo
->PeiCpuMpData
= PeiCpuMpData
;
173 // Get the BSP's data of GDT and IDT
175 CopyMem ((VOID
*)&ExchangeInfo
->GdtrProfile
, &mGdt
, sizeof(mGdt
));
176 AsmReadIdtr ((IA32_DESCRIPTOR
*) &ExchangeInfo
->IdtrProfile
);
179 SendInitSipiSipiAllExcludingSelf ((UINT32
) ExchangeInfo
->BufferStart
);
181 SendInitSipiSipi (ApicId
, (UINT32
) ExchangeInfo
->BufferStart
);
188 Get available system memory below 1MB by specified size.
190 @param WakeupBufferSize Wakeup buffer size required
192 @retval other Return wakeup buffer address below 1MB.
193 @retval -1 Cannot find free memory below 1MB.
197 IN UINTN WakeupBufferSize
200 EFI_PEI_HOB_POINTERS Hob
;
201 UINTN WakeupBufferStart
;
202 UINTN WakeupBufferEnd
;
205 // Get the HOB list for processing
207 Hob
.Raw
= GetHobList ();
210 // Collect memory ranges
212 while (!END_OF_HOB_LIST (Hob
)) {
213 if (Hob
.Header
->HobType
== EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
214 if ((Hob
.ResourceDescriptor
->PhysicalStart
< BASE_1MB
) &&
215 (Hob
.ResourceDescriptor
->ResourceType
== EFI_RESOURCE_SYSTEM_MEMORY
) &&
216 ((Hob
.ResourceDescriptor
->ResourceAttribute
&
217 (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED
|
218 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED
|
219 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
223 // Need memory under 1MB to be collected here
225 WakeupBufferEnd
= (UINTN
) (Hob
.ResourceDescriptor
->PhysicalStart
+ Hob
.ResourceDescriptor
->ResourceLength
);
226 if (WakeupBufferEnd
> BASE_1MB
) {
228 // Wakeup buffer should be under 1MB
230 WakeupBufferEnd
= BASE_1MB
;
233 // Wakeup buffer should be aligned on 4KB
235 WakeupBufferStart
= (WakeupBufferEnd
- WakeupBufferSize
) & ~(SIZE_4KB
- 1);
236 if (WakeupBufferStart
< Hob
.ResourceDescriptor
->PhysicalStart
) {
240 // Create a memory allocation HOB.
242 BuildMemoryAllocationHob (
247 return WakeupBufferStart
;
253 Hob
.Raw
= GET_NEXT_HOB (Hob
);
260 Get available system memory below 1MB by specified size.
262 @param PeiCpuMpData Pointer to PEI CPU MP Data
265 BackupAndPrepareWakeupBuffer(
266 IN PEI_CPU_MP_DATA
*PeiCpuMpData
270 (VOID
*) PeiCpuMpData
->BackupBuffer
,
271 (VOID
*) PeiCpuMpData
->WakeupBuffer
,
272 PeiCpuMpData
->BackupBufferSize
275 (VOID
*) PeiCpuMpData
->WakeupBuffer
,
276 (VOID
*) PeiCpuMpData
->AddressMap
.RendezvousFunnelAddress
,
277 PeiCpuMpData
->AddressMap
.RendezvousFunnelSize
281 This function will get CPU count in the system.
283 @param PeiCpuMpData Pointer to PEI CPU MP Data
285 @return AP processor count
288 CountProcessorNumber (
289 IN PEI_CPU_MP_DATA
*PeiCpuMpData
293 // Load Microcode on BSP
297 // Store BSP's MTRR setting
299 MtrrGetAllMtrrs (&PeiCpuMpData
->MtrrTable
);
301 // Send broadcast IPI to APs to wakeup APs
303 PeiCpuMpData
->InitFlag
= 1;
304 WakeUpAP (PeiCpuMpData
, TRUE
, 0, NULL
, NULL
);
306 // Wait for AP task to complete and then exit.
308 MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds
));
309 PeiCpuMpData
->InitFlag
= 0;
310 PeiCpuMpData
->CpuCount
+= (UINT32
) PeiCpuMpData
->MpCpuExchangeInfo
->NumApsExecuting
;
312 // Sort BSP/Aps by CPU APIC ID in ascending order
314 SortApicId (PeiCpuMpData
);
316 DEBUG ((EFI_D_INFO
, "CpuMpPei: Find %d processors in system.\n", PeiCpuMpData
->CpuCount
));
317 return PeiCpuMpData
->CpuCount
;
321 Prepare for AP wakeup buffer and copy AP reset code into it.
323 Get wakeup buffer below 1MB. Allocate memory for CPU MP Data and APs Stack.
325 @return Pointer to PEI CPU MP Data
328 PrepareAPStartupVector (
334 PEI_CPU_MP_DATA
*PeiCpuMpData
;
335 EFI_PHYSICAL_ADDRESS Buffer
;
338 UINTN WakeupBufferSize
;
339 MP_ASSEMBLY_ADDRESS_MAP AddressMap
;
341 AsmGetAddressMap (&AddressMap
);
342 WakeupBufferSize
= AddressMap
.RendezvousFunnelSize
+ sizeof (MP_CPU_EXCHANGE_INFO
);
343 WakeupBuffer
= GetWakeupBuffer ((WakeupBufferSize
+ SIZE_4KB
- 1) & ~(SIZE_4KB
- 1));
344 DEBUG ((EFI_D_INFO
, "CpuMpPei: WakeupBuffer = 0x%x\n", WakeupBuffer
));
347 // Allocate Pages for APs stack, CPU MP Data and backup buffer for wakeup buffer
349 MaxCpuCount
= PcdGet32(PcdCpuMaxLogicalProcessorNumber
);
350 BufferSize
= PcdGet32 (PcdCpuApStackSize
) * MaxCpuCount
+ sizeof (PEI_CPU_MP_DATA
)
351 + WakeupBufferSize
+ sizeof (PEI_CPU_DATA
) * MaxCpuCount
;
352 Status
= PeiServicesAllocatePages (
354 EFI_SIZE_TO_PAGES (BufferSize
),
357 ASSERT_EFI_ERROR (Status
);
359 PeiCpuMpData
= (PEI_CPU_MP_DATA
*) (UINTN
) (Buffer
+ PcdGet32 (PcdCpuApStackSize
) * MaxCpuCount
);
360 PeiCpuMpData
->Buffer
= (UINTN
) Buffer
;
361 PeiCpuMpData
->CpuApStackSize
= PcdGet32 (PcdCpuApStackSize
);
362 PeiCpuMpData
->WakeupBuffer
= WakeupBuffer
;
363 PeiCpuMpData
->BackupBuffer
= (UINTN
)PeiCpuMpData
+ sizeof (PEI_CPU_MP_DATA
);
364 PeiCpuMpData
->BackupBufferSize
= WakeupBufferSize
;
365 PeiCpuMpData
->MpCpuExchangeInfo
= (MP_CPU_EXCHANGE_INFO
*) (UINTN
) (WakeupBuffer
+ AddressMap
.RendezvousFunnelSize
);
367 PeiCpuMpData
->CpuCount
= 1;
368 PeiCpuMpData
->BspNumber
= 0;
369 PeiCpuMpData
->CpuData
= (PEI_CPU_DATA
*) (PeiCpuMpData
->MpCpuExchangeInfo
+ 1);
370 PeiCpuMpData
->CpuData
[0].ApicId
= GetInitialApicId ();
371 PeiCpuMpData
->CpuData
[0].Health
.Uint32
= 0;
372 CopyMem (&PeiCpuMpData
->AddressMap
, &AddressMap
, sizeof (MP_ASSEMBLY_ADDRESS_MAP
));
375 // Backup original data and copy AP reset code in it
377 BackupAndPrepareWakeupBuffer(PeiCpuMpData
);
382 The Entry point of the MP CPU PEIM.
384 This function will wakeup APs and collect CPU AP count and install the
387 @param FileHandle Handle of the file being invoked.
388 @param PeiServices Describes the list of possible PEI Services.
390 @retval EFI_SUCCESS MpServicePpi is installed successfully.
396 IN EFI_PEI_FILE_HANDLE FileHandle
,
397 IN CONST EFI_PEI_SERVICES
**PeiServices
401 PEI_CPU_MP_DATA
*PeiCpuMpData
;
402 UINT32 ProcessorCount
;
405 // Load new GDT table on BSP
407 AsmInitializeGdt (&mGdt
);
409 // Get wakeup buffer and copy AP reset code in it
411 PeiCpuMpData
= PrepareAPStartupVector ();
413 // Count processor number and collect processor information
415 ProcessorCount
= CountProcessorNumber (PeiCpuMpData
);