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 This function will be called from AP reset code if BSP uses WakeUpAP.
44 @param ExchangeInfo Pointer to the MP exchange info buffer
45 @param NumApsExecuting Number of curret executing AP
50 IN MP_CPU_EXCHANGE_INFO
*ExchangeInfo
,
51 IN UINTN NumApsExecuting
54 PEI_CPU_MP_DATA
*PeiCpuMpData
;
57 PeiCpuMpData
= ExchangeInfo
->PeiCpuMpData
;
58 if (PeiCpuMpData
->InitFlag
) {
60 // This is first time AP wakeup, get BIST inforamtion from AP stack
62 BistData
= *(UINTN
*) (PeiCpuMpData
->Buffer
+ NumApsExecuting
* PeiCpuMpData
->CpuApStackSize
- sizeof (UINTN
));
63 PeiCpuMpData
->CpuData
[NumApsExecuting
].ApicId
= GetInitialApicId ();
64 PeiCpuMpData
->CpuData
[NumApsExecuting
].Health
.Uint32
= (UINT32
) BistData
;
68 // AP finished executing C code
70 InterlockedIncrement ((UINT32
*)&PeiCpuMpData
->FinishedCount
);
75 This function will be called by BSP to wakeup AP.
77 @param PeiCpuMpData Pointer to PEI CPU MP Data
78 @param Broadcast TRUE: Send broadcast IPI to all APs
79 FALSE: Send IPI to AP by ApicId
80 @param ApicId Apic ID for the processor to be waked
81 @param Procedure The function to be invoked by AP
82 @param ProcedureArgument The argument to be passed into AP function
86 IN PEI_CPU_MP_DATA
*PeiCpuMpData
,
89 IN EFI_AP_PROCEDURE Procedure
, OPTIONAL
90 IN VOID
*ProcedureArgument OPTIONAL
93 volatile MP_CPU_EXCHANGE_INFO
*ExchangeInfo
;
95 PeiCpuMpData
->ApFunction
= (UINTN
) Procedure
;
96 PeiCpuMpData
->ApFunctionArgument
= (UINTN
) ProcedureArgument
;
97 PeiCpuMpData
->FinishedCount
= 0;
99 ExchangeInfo
= PeiCpuMpData
->MpCpuExchangeInfo
;
100 ExchangeInfo
->Lock
= 0;
101 ExchangeInfo
->StackStart
= PeiCpuMpData
->Buffer
;
102 ExchangeInfo
->StackSize
= PeiCpuMpData
->CpuApStackSize
;
103 ExchangeInfo
->BufferStart
= PeiCpuMpData
->WakeupBuffer
;
104 ExchangeInfo
->PmodeOffset
= PeiCpuMpData
->AddressMap
.PModeEntryOffset
;
105 ExchangeInfo
->LmodeOffset
= PeiCpuMpData
->AddressMap
.LModeEntryOffset
;
106 ExchangeInfo
->Cr3
= AsmReadCr3 ();
107 ExchangeInfo
->CFunction
= (UINTN
) ApCFunction
;
108 ExchangeInfo
->NumApsExecuting
= 0;
109 ExchangeInfo
->PeiCpuMpData
= PeiCpuMpData
;
112 // Get the BSP's data of GDT and IDT
114 CopyMem ((VOID
*)&ExchangeInfo
->GdtrProfile
, &mGdt
, sizeof(mGdt
));
115 AsmReadIdtr ((IA32_DESCRIPTOR
*) &ExchangeInfo
->IdtrProfile
);
118 SendInitSipiSipiAllExcludingSelf ((UINT32
) ExchangeInfo
->BufferStart
);
120 SendInitSipiSipi (ApicId
, (UINT32
) ExchangeInfo
->BufferStart
);
127 Get available system memory below 1MB by specified size.
129 @param WakeupBufferSize Wakeup buffer size required
131 @retval other Return wakeup buffer address below 1MB.
132 @retval -1 Cannot find free memory below 1MB.
136 IN UINTN WakeupBufferSize
139 EFI_PEI_HOB_POINTERS Hob
;
140 UINTN WakeupBufferStart
;
141 UINTN WakeupBufferEnd
;
144 // Get the HOB list for processing
146 Hob
.Raw
= GetHobList ();
149 // Collect memory ranges
151 while (!END_OF_HOB_LIST (Hob
)) {
152 if (Hob
.Header
->HobType
== EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
153 if ((Hob
.ResourceDescriptor
->PhysicalStart
< BASE_1MB
) &&
154 (Hob
.ResourceDescriptor
->ResourceType
== EFI_RESOURCE_SYSTEM_MEMORY
) &&
155 ((Hob
.ResourceDescriptor
->ResourceAttribute
&
156 (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED
|
157 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED
|
158 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
162 // Need memory under 1MB to be collected here
164 WakeupBufferEnd
= (UINTN
) (Hob
.ResourceDescriptor
->PhysicalStart
+ Hob
.ResourceDescriptor
->ResourceLength
);
165 if (WakeupBufferEnd
> BASE_1MB
) {
167 // Wakeup buffer should be under 1MB
169 WakeupBufferEnd
= BASE_1MB
;
172 // Wakeup buffer should be aligned on 4KB
174 WakeupBufferStart
= (WakeupBufferEnd
- WakeupBufferSize
) & ~(SIZE_4KB
- 1);
175 if (WakeupBufferStart
< Hob
.ResourceDescriptor
->PhysicalStart
) {
179 // Create a memory allocation HOB.
181 BuildMemoryAllocationHob (
186 return WakeupBufferStart
;
192 Hob
.Raw
= GET_NEXT_HOB (Hob
);
199 Get available system memory below 1MB by specified size.
201 @param PeiCpuMpData Pointer to PEI CPU MP Data
204 BackupAndPrepareWakeupBuffer(
205 IN PEI_CPU_MP_DATA
*PeiCpuMpData
209 (VOID
*) PeiCpuMpData
->BackupBuffer
,
210 (VOID
*) PeiCpuMpData
->WakeupBuffer
,
211 PeiCpuMpData
->BackupBufferSize
214 (VOID
*) PeiCpuMpData
->WakeupBuffer
,
215 (VOID
*) PeiCpuMpData
->AddressMap
.RendezvousFunnelAddress
,
216 PeiCpuMpData
->AddressMap
.RendezvousFunnelSize
220 This function will get CPU count in the system.
222 @param PeiCpuMpData Pointer to PEI CPU MP Data
224 @return AP processor count
227 CountProcessorNumber (
228 IN PEI_CPU_MP_DATA
*PeiCpuMpData
233 // Send broadcast IPI to APs to wakeup APs
235 PeiCpuMpData
->InitFlag
= 1;
236 WakeUpAP (PeiCpuMpData
, TRUE
, 0, NULL
, NULL
);
238 // Wait for AP task to complete and then exit.
240 MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds
));
241 PeiCpuMpData
->InitFlag
= 0;
242 PeiCpuMpData
->CpuCount
+= (UINT32
) PeiCpuMpData
->MpCpuExchangeInfo
->NumApsExecuting
;
244 DEBUG ((EFI_D_INFO
, "CpuMpPei: Find %d processors in system.\n", PeiCpuMpData
->CpuCount
));
245 return PeiCpuMpData
->CpuCount
;
249 Prepare for AP wakeup buffer and copy AP reset code into it.
251 Get wakeup buffer below 1MB. Allocate memory for CPU MP Data and APs Stack.
253 @return Pointer to PEI CPU MP Data
256 PrepareAPStartupVector (
262 PEI_CPU_MP_DATA
*PeiCpuMpData
;
263 EFI_PHYSICAL_ADDRESS Buffer
;
266 UINTN WakeupBufferSize
;
267 MP_ASSEMBLY_ADDRESS_MAP AddressMap
;
269 AsmGetAddressMap (&AddressMap
);
270 WakeupBufferSize
= AddressMap
.RendezvousFunnelSize
+ sizeof (MP_CPU_EXCHANGE_INFO
);
271 WakeupBuffer
= GetWakeupBuffer ((WakeupBufferSize
+ SIZE_4KB
- 1) & ~(SIZE_4KB
- 1));
272 DEBUG ((EFI_D_INFO
, "CpuMpPei: WakeupBuffer = 0x%x\n", WakeupBuffer
));
275 // Allocate Pages for APs stack, CPU MP Data and backup buffer for wakeup buffer
277 MaxCpuCount
= PcdGet32(PcdCpuMaxLogicalProcessorNumber
);
278 BufferSize
= PcdGet32 (PcdCpuApStackSize
) * MaxCpuCount
+ sizeof (PEI_CPU_MP_DATA
)
279 + WakeupBufferSize
+ sizeof (PEI_CPU_DATA
) * MaxCpuCount
;
280 Status
= PeiServicesAllocatePages (
282 EFI_SIZE_TO_PAGES (BufferSize
),
285 ASSERT_EFI_ERROR (Status
);
287 PeiCpuMpData
= (PEI_CPU_MP_DATA
*) (UINTN
) (Buffer
+ PcdGet32 (PcdCpuApStackSize
) * MaxCpuCount
);
288 PeiCpuMpData
->Buffer
= (UINTN
) Buffer
;
289 PeiCpuMpData
->CpuApStackSize
= PcdGet32 (PcdCpuApStackSize
);
290 PeiCpuMpData
->WakeupBuffer
= WakeupBuffer
;
291 PeiCpuMpData
->BackupBuffer
= (UINTN
)PeiCpuMpData
+ sizeof (PEI_CPU_MP_DATA
);
292 PeiCpuMpData
->BackupBufferSize
= WakeupBufferSize
;
293 PeiCpuMpData
->MpCpuExchangeInfo
= (MP_CPU_EXCHANGE_INFO
*) (UINTN
) (WakeupBuffer
+ AddressMap
.RendezvousFunnelSize
);
295 PeiCpuMpData
->CpuCount
= 1;
296 PeiCpuMpData
->BspNumber
= 0;
297 PeiCpuMpData
->CpuData
= (PEI_CPU_DATA
*) (PeiCpuMpData
->MpCpuExchangeInfo
+ 1);
298 PeiCpuMpData
->CpuData
[0].ApicId
= GetInitialApicId ();
299 PeiCpuMpData
->CpuData
[0].Health
.Uint32
= 0;
300 CopyMem (&PeiCpuMpData
->AddressMap
, &AddressMap
, sizeof (MP_ASSEMBLY_ADDRESS_MAP
));
303 // Backup original data and copy AP reset code in it
305 BackupAndPrepareWakeupBuffer(PeiCpuMpData
);
310 The Entry point of the MP CPU PEIM.
312 This function will wakeup APs and collect CPU AP count and install the
315 @param FileHandle Handle of the file being invoked.
316 @param PeiServices Describes the list of possible PEI Services.
318 @retval EFI_SUCCESS MpServicePpi is installed successfully.
324 IN EFI_PEI_FILE_HANDLE FileHandle
,
325 IN CONST EFI_PEI_SERVICES
**PeiServices
329 PEI_CPU_MP_DATA
*PeiCpuMpData
;
330 UINT32 ProcessorCount
;
333 // Load new GDT table on BSP
335 AsmInitializeGdt (&mGdt
);
337 // Get wakeup buffer and copy AP reset code in it
339 PeiCpuMpData
= PrepareAPStartupVector ();
341 // Count processor number and collect processor information
343 ProcessorCount
= CountProcessorNumber (PeiCpuMpData
);