]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/CpuMpPei/CpuMpPei.c
UefiCpuPkg/CpuMpPei: Enable x2APIC mode on BSP/APs
[mirror_edk2.git] / UefiCpuPkg / CpuMpPei / CpuMpPei.c
CommitLineData
ea0f431c
JF
1/** @file\r
2 CPU PEI Module installs CPU Multiple Processor PPI.\r
3\r
4 Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "CpuMpPei.h"\r
16\r
17//\r
18// Global Descriptor Table (GDT)\r
19//\r
20GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT mGdtEntries[] = {\r
21/* selector { Global Segment Descriptor } */\r
22/* 0x00 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //null descriptor\r
23/* 0x08 */ {{0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear data segment descriptor\r
24/* 0x10 */ {{0xffff, 0, 0, 0xf, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear code segment descriptor\r
25/* 0x18 */ {{0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor\r
26/* 0x20 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system code segment descriptor\r
27/* 0x28 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor\r
28/* 0x30 */ {{0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor\r
29/* 0x38 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 1, 0, 1, 0}}, //system code segment descriptor\r
30/* 0x40 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor\r
31};\r
32\r
33//\r
34// IA32 Gdt register\r
35//\r
36GLOBAL_REMOVE_IF_UNREFERENCED IA32_DESCRIPTOR mGdt = {\r
37 sizeof (mGdtEntries) - 1,\r
38 (UINTN) mGdtEntries\r
39 };\r
40\r
41GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = {\r
42 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
43 &gEfiEndOfPeiSignalPpiGuid,\r
44 CpuMpEndOfPeiCallback\r
45};\r
46\r
47/**\r
48 Sort the APIC ID of all processors.\r
49\r
50 This function sorts the APIC ID of all processors so that processor number is\r
51 assigned in the ascending order of APIC ID which eases MP debugging.\r
52\r
53 @param PeiCpuMpData Pointer to PEI CPU MP Data\r
54**/\r
55VOID\r
56SortApicId (\r
57 IN PEI_CPU_MP_DATA *PeiCpuMpData\r
58 )\r
59{\r
60 UINTN Index1;\r
61 UINTN Index2;\r
62 UINTN Index3;\r
63 UINT32 ApicId;\r
64 EFI_HEALTH_FLAGS Health;\r
65 UINT32 ApCount;\r
66\r
67 ApCount = PeiCpuMpData->CpuCount - 1;\r
68\r
69 if (ApCount != 0) {\r
70 for (Index1 = 0; Index1 < ApCount; Index1++) {\r
71 Index3 = Index1;\r
72 //\r
73 // Sort key is the hardware default APIC ID\r
74 //\r
75 ApicId = PeiCpuMpData->CpuData[Index1].ApicId;\r
76 for (Index2 = Index1 + 1; Index2 <= ApCount; Index2++) {\r
77 if (ApicId > PeiCpuMpData->CpuData[Index2].ApicId) {\r
78 Index3 = Index2;\r
79 ApicId = PeiCpuMpData->CpuData[Index2].ApicId;\r
80 }\r
81 }\r
82 if (Index3 != Index1) {\r
83 PeiCpuMpData->CpuData[Index3].ApicId = PeiCpuMpData->CpuData[Index1].ApicId;\r
84 PeiCpuMpData->CpuData[Index1].ApicId = ApicId;\r
85 Health = PeiCpuMpData->CpuData[Index3].Health;\r
86 PeiCpuMpData->CpuData[Index3].Health = PeiCpuMpData->CpuData[Index1].Health;\r
87 PeiCpuMpData->CpuData[Index1].Health = Health;\r
88 }\r
89 }\r
90\r
91 //\r
92 // Get the processor number for the BSP\r
93 //\r
94 ApicId = GetInitialApicId ();\r
95 for (Index1 = 0; Index1 < PeiCpuMpData->CpuCount; Index1++) {\r
96 if (PeiCpuMpData->CpuData[Index1].ApicId == ApicId) {\r
97 PeiCpuMpData->BspNumber = (UINT32) Index1;\r
98 break;\r
99 }\r
100 }\r
101 }\r
102}\r
103\r
c7981a11
JF
104/**\r
105 Enable x2APIC mode on APs.\r
106\r
107 @param Buffer Pointer to private data buffer.\r
108**/\r
109VOID\r
110EFIAPI\r
111ApFuncEnableX2Apic (\r
112 IN OUT VOID *Buffer\r
113 )\r
114{\r
115 SetApicMode (LOCAL_APIC_MODE_X2APIC);\r
116}\r
117\r
ea0f431c
JF
118/**\r
119 Get CPU MP Data pointer from the Guided HOB.\r
120\r
121 @return Pointer to Pointer to PEI CPU MP Data\r
122**/\r
123PEI_CPU_MP_DATA *\r
124GetMpHobData (\r
125 VOID\r
126 )\r
127{\r
128 EFI_HOB_GUID_TYPE *GuidHob;\r
129 VOID *DataInHob;\r
130 PEI_CPU_MP_DATA *CpuMpData;\r
131\r
132 CpuMpData = NULL;\r
133 GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);\r
134 if (GuidHob != NULL) {\r
135 DataInHob = GET_GUID_HOB_DATA (GuidHob);\r
136 CpuMpData = (PEI_CPU_MP_DATA *)(*(UINTN *)DataInHob);\r
137 }\r
138 ASSERT (CpuMpData != NULL);\r
139 return CpuMpData;\r
140}\r
141\r
142/**\r
143 This function will be called from AP reset code if BSP uses WakeUpAP.\r
144\r
145 @param ExchangeInfo Pointer to the MP exchange info buffer\r
146 @param NumApsExecuting Number of curret executing AP\r
147**/\r
148VOID\r
149EFIAPI\r
150ApCFunction (\r
151 IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,\r
152 IN UINTN NumApsExecuting\r
153 )\r
154{\r
155 PEI_CPU_MP_DATA *PeiCpuMpData;\r
156 UINTN ProcessorNumber;\r
157 EFI_AP_PROCEDURE Procedure;\r
158 UINTN BistData;\r
159\r
160 PeiCpuMpData = ExchangeInfo->PeiCpuMpData;\r
161 if (PeiCpuMpData->InitFlag) {\r
162 //\r
2f0261b7 163 // This is first time AP wakeup, get BIST information from AP stack\r
ea0f431c
JF
164 //\r
165 BistData = *(UINTN *) (PeiCpuMpData->Buffer + NumApsExecuting * PeiCpuMpData->CpuApStackSize - sizeof (UINTN));\r
ea0f431c 166 PeiCpuMpData->CpuData[NumApsExecuting].Health.Uint32 = (UINT32) BistData;\r
2f0261b7
JF
167 PeiCpuMpData->CpuData[NumApsExecuting].ApicId = GetInitialApicId ();\r
168 if (PeiCpuMpData->CpuData[NumApsExecuting].ApicId >= 0xFF) {\r
169 //\r
170 // Set x2APIC mode if there are any logical processor reporting\r
171 // an APIC ID of 255 or greater.\r
172 //\r
173 AcquireSpinLock(&PeiCpuMpData->MpLock);\r
174 PeiCpuMpData->X2ApicEnable = TRUE;\r
175 ReleaseSpinLock(&PeiCpuMpData->MpLock);\r
176 }\r
ea0f431c
JF
177 //\r
178 // Sync BSP's Mtrr table to all wakeup APs and load microcode on APs.\r
179 //\r
180 MtrrSetAllMtrrs (&PeiCpuMpData->MtrrTable);\r
181 MicrocodeDetect ();\r
182 } else {\r
183 //\r
184 // Execute AP function if AP is not disabled\r
185 //\r
186 GetProcessorNumber (PeiCpuMpData, &ProcessorNumber);\r
187 if ((PeiCpuMpData->CpuData[ProcessorNumber].State != CpuStateDisabled) &&\r
188 (PeiCpuMpData->ApFunction != 0)) {\r
189 PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateBusy;\r
190 Procedure = (EFI_AP_PROCEDURE)(UINTN)PeiCpuMpData->ApFunction;\r
191 Procedure ((VOID *)(UINTN)PeiCpuMpData->ApFunctionArgument);\r
192 PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle;\r
193 }\r
194 }\r
195\r
196 //\r
197 // AP finished executing C code\r
198 //\r
199 InterlockedIncrement ((UINT32 *)&PeiCpuMpData->FinishedCount);\r
200\r
201 AsmCliHltLoop ();\r
202}\r
203\r
204/**\r
205 This function will be called by BSP to wakeup AP.\r
206\r
207 @param PeiCpuMpData Pointer to PEI CPU MP Data\r
208 @param Broadcast TRUE: Send broadcast IPI to all APs\r
209 FALSE: Send IPI to AP by ApicId\r
210 @param ApicId Apic ID for the processor to be waked\r
211 @param Procedure The function to be invoked by AP\r
212 @param ProcedureArgument The argument to be passed into AP function\r
213**/\r
214VOID\r
215WakeUpAP (\r
216 IN PEI_CPU_MP_DATA *PeiCpuMpData,\r
217 IN BOOLEAN Broadcast,\r
218 IN UINT32 ApicId,\r
219 IN EFI_AP_PROCEDURE Procedure, OPTIONAL\r
220 IN VOID *ProcedureArgument OPTIONAL\r
221 )\r
222{\r
223 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;\r
224\r
225 PeiCpuMpData->ApFunction = (UINTN) Procedure;\r
226 PeiCpuMpData->ApFunctionArgument = (UINTN) ProcedureArgument;\r
227 PeiCpuMpData->FinishedCount = 0;\r
228\r
229 ExchangeInfo = PeiCpuMpData->MpCpuExchangeInfo;\r
230 ExchangeInfo->Lock = 0;\r
231 ExchangeInfo->StackStart = PeiCpuMpData->Buffer;\r
232 ExchangeInfo->StackSize = PeiCpuMpData->CpuApStackSize;\r
233 ExchangeInfo->BufferStart = PeiCpuMpData->WakeupBuffer;\r
234 ExchangeInfo->PmodeOffset = PeiCpuMpData->AddressMap.PModeEntryOffset;\r
235 ExchangeInfo->LmodeOffset = PeiCpuMpData->AddressMap.LModeEntryOffset;\r
236 ExchangeInfo->Cr3 = AsmReadCr3 ();\r
237 ExchangeInfo->CFunction = (UINTN) ApCFunction;\r
238 ExchangeInfo->NumApsExecuting = 0;\r
239 ExchangeInfo->PeiCpuMpData = PeiCpuMpData;\r
240\r
241 //\r
242 // Get the BSP's data of GDT and IDT\r
243 //\r
244 CopyMem ((VOID *)&ExchangeInfo->GdtrProfile, &mGdt, sizeof(mGdt));\r
245 AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);\r
246\r
247 if (Broadcast) {\r
248 SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);\r
249 } else {\r
250 SendInitSipiSipi (ApicId, (UINT32) ExchangeInfo->BufferStart);\r
251 }\r
252\r
253 return ;\r
254}\r
255\r
256/**\r
257 Get available system memory below 1MB by specified size.\r
258\r
259 @param WakeupBufferSize Wakeup buffer size required\r
260\r
261 @retval other Return wakeup buffer address below 1MB.\r
262 @retval -1 Cannot find free memory below 1MB.\r
263**/\r
264UINTN\r
265GetWakeupBuffer (\r
266 IN UINTN WakeupBufferSize\r
267 )\r
268{\r
269 EFI_PEI_HOB_POINTERS Hob;\r
270 UINTN WakeupBufferStart;\r
271 UINTN WakeupBufferEnd;\r
272\r
273 //\r
274 // Get the HOB list for processing\r
275 //\r
276 Hob.Raw = GetHobList ();\r
277\r
278 //\r
279 // Collect memory ranges\r
280 //\r
281 while (!END_OF_HOB_LIST (Hob)) {\r
282 if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
283 if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) &&\r
284 (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&\r
285 ((Hob.ResourceDescriptor->ResourceAttribute &\r
286 (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |\r
287 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |\r
288 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED\r
289 )) == 0)\r
290 ) {\r
291 //\r
292 // Need memory under 1MB to be collected here\r
293 //\r
294 WakeupBufferEnd = (UINTN) (Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength);\r
295 if (WakeupBufferEnd > BASE_1MB) {\r
296 //\r
297 // Wakeup buffer should be under 1MB\r
298 //\r
299 WakeupBufferEnd = BASE_1MB;\r
300 }\r
301 //\r
302 // Wakeup buffer should be aligned on 4KB\r
303 //\r
304 WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1);\r
305 if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) {\r
306 continue;\r
307 }\r
308 //\r
309 // Create a memory allocation HOB.\r
310 //\r
311 BuildMemoryAllocationHob (\r
312 WakeupBufferStart,\r
313 WakeupBufferSize,\r
314 EfiBootServicesData\r
315 );\r
316 return WakeupBufferStart;\r
317 }\r
318 }\r
319 //\r
320 // Find the next HOB\r
321 //\r
322 Hob.Raw = GET_NEXT_HOB (Hob);\r
323 }\r
324\r
325 return (UINTN) -1;\r
326}\r
327\r
328/**\r
329 Get available system memory below 1MB by specified size.\r
330\r
331 @param PeiCpuMpData Pointer to PEI CPU MP Data\r
332**/\r
333VOID\r
334BackupAndPrepareWakeupBuffer(\r
335 IN PEI_CPU_MP_DATA *PeiCpuMpData\r
336 )\r
337{\r
338 CopyMem (\r
339 (VOID *) PeiCpuMpData->BackupBuffer,\r
340 (VOID *) PeiCpuMpData->WakeupBuffer,\r
341 PeiCpuMpData->BackupBufferSize\r
342 );\r
343 CopyMem (\r
344 (VOID *) PeiCpuMpData->WakeupBuffer,\r
345 (VOID *) PeiCpuMpData->AddressMap.RendezvousFunnelAddress,\r
346 PeiCpuMpData->AddressMap.RendezvousFunnelSize\r
347 );\r
348}\r
349\r
350/**\r
351 Restore wakeup buffer data.\r
352\r
353 @param PeiCpuMpData Pointer to PEI CPU MP Data\r
354**/\r
355VOID\r
356RestoreWakeupBuffer(\r
357 IN PEI_CPU_MP_DATA *PeiCpuMpData\r
358 )\r
359{\r
360 CopyMem ((VOID *) PeiCpuMpData->WakeupBuffer, (VOID *) PeiCpuMpData->BackupBuffer, PeiCpuMpData->BackupBufferSize);\r
361}\r
362\r
363/**\r
364 This function will get CPU count in the system.\r
365\r
366 @param PeiCpuMpData Pointer to PEI CPU MP Data\r
367\r
368 @return AP processor count\r
369**/\r
370UINT32\r
371CountProcessorNumber (\r
372 IN PEI_CPU_MP_DATA *PeiCpuMpData\r
373 )\r
374{\r
375 //\r
376 // Load Microcode on BSP\r
377 //\r
378 MicrocodeDetect ();\r
379 //\r
380 // Store BSP's MTRR setting\r
381 //\r
382 MtrrGetAllMtrrs (&PeiCpuMpData->MtrrTable);\r
944f45ae 383\r
ea0f431c 384 //\r
944f45ae 385 // Only perform AP detection if PcdCpuMaxLogicalProcessorNumber is greater than 1\r
ea0f431c 386 //\r
944f45ae
MK
387 if (PcdGet32 (PcdCpuMaxLogicalProcessorNumber) > 1) {\r
388 //\r
2f0261b7 389 // Send 1st broadcast IPI to APs to wakeup APs\r
944f45ae 390 //\r
2f0261b7
JF
391 PeiCpuMpData->InitFlag = TRUE;\r
392 PeiCpuMpData->X2ApicEnable = FALSE;\r
944f45ae
MK
393 WakeUpAP (PeiCpuMpData, TRUE, 0, NULL, NULL);\r
394 //\r
395 // Wait for AP task to complete and then exit.\r
396 //\r
397 MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds));\r
2f0261b7 398 PeiCpuMpData->InitFlag = FALSE;\r
944f45ae
MK
399 PeiCpuMpData->CpuCount += (UINT32)PeiCpuMpData->MpCpuExchangeInfo->NumApsExecuting;\r
400 ASSERT (PeiCpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));\r
401 //\r
c7981a11
JF
402 // Wait for all APs finished the initialization\r
403 //\r
404 while (PeiCpuMpData->FinishedCount < (PeiCpuMpData->CpuCount - 1)) {\r
405 CpuPause ();\r
406 }\r
407\r
408 if (PeiCpuMpData->X2ApicEnable) {\r
409 DEBUG ((EFI_D_INFO, "Force x2APIC mode!\n"));\r
410 //\r
411 // Send 2nd broadcast IPI to all APs to enable x2APIC mode\r
412 //\r
413 WakeUpAP (PeiCpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL);\r
414 //\r
415 // Wait for all known APs finished\r
416 //\r
417 while (PeiCpuMpData->FinishedCount < (PeiCpuMpData->CpuCount - 1)) {\r
418 CpuPause ();\r
419 }\r
420 //\r
421 // Enable x2APIC on BSP\r
422 //\r
423 SetApicMode (LOCAL_APIC_MODE_X2APIC);\r
424 }\r
425 DEBUG ((EFI_D_INFO, "APIC MODE is %d\n", GetApicMode ()));\r
426 //\r
944f45ae
MK
427 // Sort BSP/Aps by CPU APIC ID in ascending order\r
428 //\r
429 SortApicId (PeiCpuMpData);\r
430 }\r
ea0f431c
JF
431\r
432 DEBUG ((EFI_D_INFO, "CpuMpPei: Find %d processors in system.\n", PeiCpuMpData->CpuCount));\r
433 return PeiCpuMpData->CpuCount;\r
434}\r
435\r
436/**\r
437 Prepare for AP wakeup buffer and copy AP reset code into it.\r
438\r
439 Get wakeup buffer below 1MB. Allocate memory for CPU MP Data and APs Stack.\r
440\r
441 @return Pointer to PEI CPU MP Data\r
442**/\r
443PEI_CPU_MP_DATA *\r
444PrepareAPStartupVector (\r
445 VOID\r
446 )\r
447{\r
448 EFI_STATUS Status;\r
449 UINT32 MaxCpuCount;\r
450 PEI_CPU_MP_DATA *PeiCpuMpData;\r
451 EFI_PHYSICAL_ADDRESS Buffer;\r
452 UINTN BufferSize;\r
453 UINTN WakeupBuffer;\r
454 UINTN WakeupBufferSize;\r
455 MP_ASSEMBLY_ADDRESS_MAP AddressMap;\r
456\r
457 AsmGetAddressMap (&AddressMap);\r
458 WakeupBufferSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);\r
459 WakeupBuffer = GetWakeupBuffer ((WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1));\r
460 ASSERT (WakeupBuffer != (UINTN) -1);\r
461 DEBUG ((EFI_D_INFO, "CpuMpPei: WakeupBuffer = 0x%x\n", WakeupBuffer));\r
462\r
463 //\r
464 // Allocate Pages for APs stack, CPU MP Data and backup buffer for wakeup buffer\r
465 //\r
466 MaxCpuCount = PcdGet32(PcdCpuMaxLogicalProcessorNumber);\r
467 BufferSize = PcdGet32 (PcdCpuApStackSize) * MaxCpuCount + sizeof (PEI_CPU_MP_DATA)\r
468 + WakeupBufferSize + sizeof (PEI_CPU_DATA) * MaxCpuCount;\r
469 Status = PeiServicesAllocatePages (\r
470 EfiBootServicesData,\r
471 EFI_SIZE_TO_PAGES (BufferSize),\r
472 &Buffer\r
473 );\r
474 ASSERT_EFI_ERROR (Status);\r
475\r
476 PeiCpuMpData = (PEI_CPU_MP_DATA *) (UINTN) (Buffer + PcdGet32 (PcdCpuApStackSize) * MaxCpuCount);\r
477 PeiCpuMpData->Buffer = (UINTN) Buffer;\r
478 PeiCpuMpData->CpuApStackSize = PcdGet32 (PcdCpuApStackSize);\r
479 PeiCpuMpData->WakeupBuffer = WakeupBuffer;\r
480 PeiCpuMpData->BackupBuffer = (UINTN)PeiCpuMpData + sizeof (PEI_CPU_MP_DATA);\r
481 PeiCpuMpData->BackupBufferSize = WakeupBufferSize;\r
482 PeiCpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeupBuffer + AddressMap.RendezvousFunnelSize);\r
483\r
484 PeiCpuMpData->CpuCount = 1;\r
485 PeiCpuMpData->BspNumber = 0;\r
28f27af6
JF
486 PeiCpuMpData->CpuData = (PEI_CPU_DATA *) (PeiCpuMpData->BackupBuffer +\r
487 PeiCpuMpData->BackupBufferSize);\r
ea0f431c
JF
488 PeiCpuMpData->CpuData[0].ApicId = GetInitialApicId ();\r
489 PeiCpuMpData->CpuData[0].Health.Uint32 = 0;\r
490 PeiCpuMpData->EndOfPeiFlag = FALSE;\r
2f0261b7 491 InitializeSpinLock(&PeiCpuMpData->MpLock);\r
ea0f431c
JF
492 CopyMem (&PeiCpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));\r
493\r
494 //\r
495 // Backup original data and copy AP reset code in it\r
496 //\r
497 BackupAndPrepareWakeupBuffer(PeiCpuMpData);\r
498\r
499 return PeiCpuMpData;\r
500}\r
501\r
502/**\r
503 Notify function on End Of Pei PPI.\r
504\r
505 On S3 boot, this function will restore wakeup buffer data.\r
506 On normal boot, this function will flag wakeup buffer to be un-used type.\r
507\r
508 @param PeiServices The pointer to the PEI Services Table.\r
509 @param NotifyDescriptor Address of the notification descriptor data structure.\r
510 @param Ppi Address of the PPI that was installed.\r
511\r
512 @retval EFI_SUCCESS When everything is OK.\r
513\r
514**/\r
515EFI_STATUS\r
516EFIAPI\r
517CpuMpEndOfPeiCallback (\r
518 IN EFI_PEI_SERVICES **PeiServices,\r
519 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
520 IN VOID *Ppi\r
521 )\r
522{\r
523 EFI_STATUS Status;\r
524 EFI_BOOT_MODE BootMode;\r
525 PEI_CPU_MP_DATA *PeiCpuMpData;\r
526 EFI_PEI_HOB_POINTERS Hob;\r
527 EFI_HOB_MEMORY_ALLOCATION *MemoryHob;\r
528\r
529 DEBUG ((EFI_D_INFO, "CpuMpPei: CpuMpEndOfPeiCallback () invokded\n"));\r
530\r
531 Status = PeiServicesGetBootMode (&BootMode);\r
532 ASSERT_EFI_ERROR (Status);\r
533\r
534 PeiCpuMpData = GetMpHobData ();\r
535 ASSERT (PeiCpuMpData != NULL);\r
536\r
537 if (BootMode != BOOT_ON_S3_RESUME) {\r
538 //\r
539 // Get the HOB list for processing\r
540 //\r
541 Hob.Raw = GetHobList ();\r
542 //\r
543 // Collect memory ranges\r
544 //\r
545 while (!END_OF_HOB_LIST (Hob)) {\r
546 if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {\r
547 MemoryHob = Hob.MemoryAllocation;\r
548 if(MemoryHob->AllocDescriptor.MemoryBaseAddress == PeiCpuMpData->WakeupBuffer) {\r
549 //\r
550 // Flag this HOB type to un-used\r
551 //\r
552 GET_HOB_TYPE (Hob) = EFI_HOB_TYPE_UNUSED;\r
553 break;\r
554 }\r
555 }\r
556 Hob.Raw = GET_NEXT_HOB (Hob);\r
557 }\r
558 } else {\r
559 RestoreWakeupBuffer (PeiCpuMpData);\r
560 PeiCpuMpData->EndOfPeiFlag = TRUE;\r
561 }\r
562 return EFI_SUCCESS;\r
563}\r
564\r
565/**\r
566 The Entry point of the MP CPU PEIM.\r
567\r
568 This function will wakeup APs and collect CPU AP count and install the\r
569 Mp Service Ppi.\r
570\r
571 @param FileHandle Handle of the file being invoked.\r
572 @param PeiServices Describes the list of possible PEI Services.\r
573\r
574 @retval EFI_SUCCESS MpServicePpi is installed successfully.\r
575\r
576**/\r
577EFI_STATUS\r
578EFIAPI\r
579CpuMpPeimInit (\r
580 IN EFI_PEI_FILE_HANDLE FileHandle,\r
581 IN CONST EFI_PEI_SERVICES **PeiServices\r
582 )\r
583{\r
584 EFI_STATUS Status;\r
585 PEI_CPU_MP_DATA *PeiCpuMpData;\r
586 UINT32 ProcessorCount;\r
587\r
588 //\r
589 // Load new GDT table on BSP\r
590 //\r
591 AsmInitializeGdt (&mGdt);\r
592 //\r
593 // Get wakeup buffer and copy AP reset code in it\r
594 //\r
595 PeiCpuMpData = PrepareAPStartupVector ();\r
596 //\r
597 // Count processor number and collect processor information\r
598 //\r
599 ProcessorCount = CountProcessorNumber (PeiCpuMpData);\r
600 //\r
601 // Build location of PEI CPU MP DATA buffer in HOB\r
602 //\r
603 BuildGuidDataHob (\r
604 &gEfiCallerIdGuid,\r
605 (VOID *)&PeiCpuMpData,\r
606 sizeof(UINT64)\r
607 );\r
608 //\r
609 // Update and publish CPU BIST information\r
610 //\r
611 CollectBistDataFromPpi (PeiServices, PeiCpuMpData);\r
612 //\r
613 // register an event for EndOfPei\r
614 //\r
615 Status = PeiServicesNotifyPpi (&mNotifyList);\r
616 ASSERT_EFI_ERROR (Status);\r
617 //\r
618 // Install CPU MP PPI\r
619 //\r
620 Status = PeiServicesInstallPpi(&mPeiCpuMpPpiDesc);\r
621 ASSERT_EFI_ERROR (Status);\r
622\r
623 return Status;\r
624}\r