]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/CpuMpPei/CpuMpPei.c
UefiCpuPkg/CpuMpPei: Add CPU_VOLATILE_REGISTERS & worker functions
[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
24930b56 64 PEI_CPU_DATA CpuData;\r
ea0f431c
JF
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
24930b56
JF
83 CopyMem (&CpuData, &PeiCpuMpData->CpuData[Index3], sizeof (PEI_CPU_DATA));\r
84 CopyMem (\r
85 &PeiCpuMpData->CpuData[Index3],\r
86 &PeiCpuMpData->CpuData[Index1],\r
87 sizeof (PEI_CPU_DATA)\r
88 );\r
89 CopyMem (&PeiCpuMpData->CpuData[Index1], &CpuData, sizeof (PEI_CPU_DATA));\r
ea0f431c
JF
90 }\r
91 }\r
92\r
93 //\r
94 // Get the processor number for the BSP\r
95 //\r
96 ApicId = GetInitialApicId ();\r
97 for (Index1 = 0; Index1 < PeiCpuMpData->CpuCount; Index1++) {\r
98 if (PeiCpuMpData->CpuData[Index1].ApicId == ApicId) {\r
99 PeiCpuMpData->BspNumber = (UINT32) Index1;\r
100 break;\r
101 }\r
102 }\r
103 }\r
104}\r
105\r
c7981a11
JF
106/**\r
107 Enable x2APIC mode on APs.\r
108\r
109 @param Buffer Pointer to private data buffer.\r
110**/\r
111VOID\r
112EFIAPI\r
113ApFuncEnableX2Apic (\r
114 IN OUT VOID *Buffer\r
115 )\r
116{\r
117 SetApicMode (LOCAL_APIC_MODE_X2APIC);\r
118}\r
119\r
ea0f431c
JF
120/**\r
121 Get CPU MP Data pointer from the Guided HOB.\r
122\r
123 @return Pointer to Pointer to PEI CPU MP Data\r
124**/\r
125PEI_CPU_MP_DATA *\r
126GetMpHobData (\r
127 VOID\r
128 )\r
129{\r
130 EFI_HOB_GUID_TYPE *GuidHob;\r
131 VOID *DataInHob;\r
132 PEI_CPU_MP_DATA *CpuMpData;\r
133\r
134 CpuMpData = NULL;\r
135 GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);\r
136 if (GuidHob != NULL) {\r
137 DataInHob = GET_GUID_HOB_DATA (GuidHob);\r
138 CpuMpData = (PEI_CPU_MP_DATA *)(*(UINTN *)DataInHob);\r
139 }\r
140 ASSERT (CpuMpData != NULL);\r
141 return CpuMpData;\r
142}\r
143\r
ef1fdb80
JF
144/**\r
145 Save the volatile registers required to be restored following INIT IPI\r
146 \r
147 @param VolatileRegisters Returns buffer saved the volatile resisters\r
148**/\r
149VOID\r
150SaveVolatileRegisters (\r
151 OUT CPU_VOLATILE_REGISTERS *VolatileRegisters\r
152 )\r
153{\r
154 UINT32 RegEdx;\r
155\r
156 VolatileRegisters->Cr0 = AsmReadCr0 ();\r
157 VolatileRegisters->Cr3 = AsmReadCr3 ();\r
158 VolatileRegisters->Cr4 = AsmReadCr4 ();\r
159\r
160 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx);\r
161 if ((RegEdx & BIT2) != 0) {\r
162 //\r
163 // If processor supports Debugging Extensions feature\r
164 // by CPUID.[EAX=01H]:EDX.BIT2\r
165 //\r
166 VolatileRegisters->Dr0 = AsmReadDr0 ();\r
167 VolatileRegisters->Dr1 = AsmReadDr1 ();\r
168 VolatileRegisters->Dr2 = AsmReadDr2 ();\r
169 VolatileRegisters->Dr3 = AsmReadDr3 ();\r
170 VolatileRegisters->Dr6 = AsmReadDr6 ();\r
171 VolatileRegisters->Dr7 = AsmReadDr7 ();\r
172 }\r
173}\r
174\r
175/**\r
176 Restore the volatile registers following INIT IPI\r
177 \r
178 @param VolatileRegisters Pointer to volatile resisters\r
179 @param IsRestoreDr TRUE: Restore DRx if supported\r
180 FALSE: Do not restore DRx\r
181**/\r
182VOID\r
183RestoreVolatileRegisters (\r
184 IN CPU_VOLATILE_REGISTERS *VolatileRegisters,\r
185 IN BOOLEAN IsRestoreDr\r
186 )\r
187{\r
188 UINT32 RegEdx;\r
189\r
190 AsmWriteCr0 (VolatileRegisters->Cr0);\r
191 AsmWriteCr3 (VolatileRegisters->Cr3);\r
192 AsmWriteCr4 (VolatileRegisters->Cr4);\r
193\r
194 if (IsRestoreDr) {\r
195 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx);\r
196 if ((RegEdx & BIT2) != 0) {\r
197 //\r
198 // If processor supports Debugging Extensions feature\r
199 // by CPUID.[EAX=01H]:EDX.BIT2\r
200 //\r
201 AsmWriteDr0 (VolatileRegisters->Dr0);\r
202 AsmWriteDr1 (VolatileRegisters->Dr1);\r
203 AsmWriteDr2 (VolatileRegisters->Dr2);\r
204 AsmWriteDr3 (VolatileRegisters->Dr3);\r
205 AsmWriteDr6 (VolatileRegisters->Dr6);\r
206 AsmWriteDr7 (VolatileRegisters->Dr7);\r
207 }\r
208 }\r
209}\r
210\r
ea0f431c
JF
211/**\r
212 This function will be called from AP reset code if BSP uses WakeUpAP.\r
213\r
214 @param ExchangeInfo Pointer to the MP exchange info buffer\r
215 @param NumApsExecuting Number of curret executing AP\r
216**/\r
217VOID\r
218EFIAPI\r
219ApCFunction (\r
220 IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,\r
221 IN UINTN NumApsExecuting\r
222 )\r
223{\r
224 PEI_CPU_MP_DATA *PeiCpuMpData;\r
225 UINTN ProcessorNumber;\r
226 EFI_AP_PROCEDURE Procedure;\r
227 UINTN BistData;\r
228\r
229 PeiCpuMpData = ExchangeInfo->PeiCpuMpData;\r
230 if (PeiCpuMpData->InitFlag) {\r
231 //\r
2f0261b7 232 // This is first time AP wakeup, get BIST information from AP stack\r
ea0f431c
JF
233 //\r
234 BistData = *(UINTN *) (PeiCpuMpData->Buffer + NumApsExecuting * PeiCpuMpData->CpuApStackSize - sizeof (UINTN));\r
ea0f431c 235 PeiCpuMpData->CpuData[NumApsExecuting].Health.Uint32 = (UINT32) BistData;\r
2f0261b7
JF
236 PeiCpuMpData->CpuData[NumApsExecuting].ApicId = GetInitialApicId ();\r
237 if (PeiCpuMpData->CpuData[NumApsExecuting].ApicId >= 0xFF) {\r
238 //\r
239 // Set x2APIC mode if there are any logical processor reporting\r
240 // an APIC ID of 255 or greater.\r
241 //\r
242 AcquireSpinLock(&PeiCpuMpData->MpLock);\r
243 PeiCpuMpData->X2ApicEnable = TRUE;\r
244 ReleaseSpinLock(&PeiCpuMpData->MpLock);\r
245 }\r
ea0f431c
JF
246 //\r
247 // Sync BSP's Mtrr table to all wakeup APs and load microcode on APs.\r
248 //\r
249 MtrrSetAllMtrrs (&PeiCpuMpData->MtrrTable);\r
250 MicrocodeDetect ();\r
251 } else {\r
252 //\r
253 // Execute AP function if AP is not disabled\r
254 //\r
255 GetProcessorNumber (PeiCpuMpData, &ProcessorNumber);\r
256 if ((PeiCpuMpData->CpuData[ProcessorNumber].State != CpuStateDisabled) &&\r
257 (PeiCpuMpData->ApFunction != 0)) {\r
258 PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateBusy;\r
259 Procedure = (EFI_AP_PROCEDURE)(UINTN)PeiCpuMpData->ApFunction;\r
260 Procedure ((VOID *)(UINTN)PeiCpuMpData->ApFunctionArgument);\r
261 PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle;\r
262 }\r
263 }\r
264\r
265 //\r
266 // AP finished executing C code\r
267 //\r
268 InterlockedIncrement ((UINT32 *)&PeiCpuMpData->FinishedCount);\r
269\r
270 AsmCliHltLoop ();\r
271}\r
272\r
273/**\r
274 This function will be called by BSP to wakeup AP.\r
275\r
276 @param PeiCpuMpData Pointer to PEI CPU MP Data\r
277 @param Broadcast TRUE: Send broadcast IPI to all APs\r
278 FALSE: Send IPI to AP by ApicId\r
279 @param ApicId Apic ID for the processor to be waked\r
280 @param Procedure The function to be invoked by AP\r
281 @param ProcedureArgument The argument to be passed into AP function\r
282**/\r
283VOID\r
284WakeUpAP (\r
285 IN PEI_CPU_MP_DATA *PeiCpuMpData,\r
286 IN BOOLEAN Broadcast,\r
287 IN UINT32 ApicId,\r
288 IN EFI_AP_PROCEDURE Procedure, OPTIONAL\r
289 IN VOID *ProcedureArgument OPTIONAL\r
290 )\r
291{\r
292 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;\r
293\r
294 PeiCpuMpData->ApFunction = (UINTN) Procedure;\r
295 PeiCpuMpData->ApFunctionArgument = (UINTN) ProcedureArgument;\r
296 PeiCpuMpData->FinishedCount = 0;\r
297\r
298 ExchangeInfo = PeiCpuMpData->MpCpuExchangeInfo;\r
299 ExchangeInfo->Lock = 0;\r
300 ExchangeInfo->StackStart = PeiCpuMpData->Buffer;\r
301 ExchangeInfo->StackSize = PeiCpuMpData->CpuApStackSize;\r
302 ExchangeInfo->BufferStart = PeiCpuMpData->WakeupBuffer;\r
303 ExchangeInfo->PmodeOffset = PeiCpuMpData->AddressMap.PModeEntryOffset;\r
304 ExchangeInfo->LmodeOffset = PeiCpuMpData->AddressMap.LModeEntryOffset;\r
305 ExchangeInfo->Cr3 = AsmReadCr3 ();\r
306 ExchangeInfo->CFunction = (UINTN) ApCFunction;\r
307 ExchangeInfo->NumApsExecuting = 0;\r
308 ExchangeInfo->PeiCpuMpData = PeiCpuMpData;\r
309\r
310 //\r
311 // Get the BSP's data of GDT and IDT\r
312 //\r
313 CopyMem ((VOID *)&ExchangeInfo->GdtrProfile, &mGdt, sizeof(mGdt));\r
314 AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);\r
315\r
316 if (Broadcast) {\r
317 SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);\r
318 } else {\r
319 SendInitSipiSipi (ApicId, (UINT32) ExchangeInfo->BufferStart);\r
320 }\r
321\r
322 return ;\r
323}\r
324\r
325/**\r
326 Get available system memory below 1MB by specified size.\r
327\r
328 @param WakeupBufferSize Wakeup buffer size required\r
329\r
330 @retval other Return wakeup buffer address below 1MB.\r
331 @retval -1 Cannot find free memory below 1MB.\r
332**/\r
333UINTN\r
334GetWakeupBuffer (\r
335 IN UINTN WakeupBufferSize\r
336 )\r
337{\r
338 EFI_PEI_HOB_POINTERS Hob;\r
339 UINTN WakeupBufferStart;\r
340 UINTN WakeupBufferEnd;\r
341\r
342 //\r
343 // Get the HOB list for processing\r
344 //\r
345 Hob.Raw = GetHobList ();\r
346\r
347 //\r
348 // Collect memory ranges\r
349 //\r
350 while (!END_OF_HOB_LIST (Hob)) {\r
351 if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
352 if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) &&\r
353 (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&\r
354 ((Hob.ResourceDescriptor->ResourceAttribute &\r
355 (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |\r
356 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |\r
357 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED\r
358 )) == 0)\r
359 ) {\r
360 //\r
361 // Need memory under 1MB to be collected here\r
362 //\r
363 WakeupBufferEnd = (UINTN) (Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength);\r
364 if (WakeupBufferEnd > BASE_1MB) {\r
365 //\r
366 // Wakeup buffer should be under 1MB\r
367 //\r
368 WakeupBufferEnd = BASE_1MB;\r
369 }\r
370 //\r
371 // Wakeup buffer should be aligned on 4KB\r
372 //\r
373 WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1);\r
374 if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) {\r
375 continue;\r
376 }\r
377 //\r
378 // Create a memory allocation HOB.\r
379 //\r
380 BuildMemoryAllocationHob (\r
381 WakeupBufferStart,\r
382 WakeupBufferSize,\r
383 EfiBootServicesData\r
384 );\r
385 return WakeupBufferStart;\r
386 }\r
387 }\r
388 //\r
389 // Find the next HOB\r
390 //\r
391 Hob.Raw = GET_NEXT_HOB (Hob);\r
392 }\r
393\r
394 return (UINTN) -1;\r
395}\r
396\r
397/**\r
398 Get available system memory below 1MB by specified size.\r
399\r
400 @param PeiCpuMpData Pointer to PEI CPU MP Data\r
401**/\r
402VOID\r
403BackupAndPrepareWakeupBuffer(\r
404 IN PEI_CPU_MP_DATA *PeiCpuMpData\r
405 )\r
406{\r
407 CopyMem (\r
408 (VOID *) PeiCpuMpData->BackupBuffer,\r
409 (VOID *) PeiCpuMpData->WakeupBuffer,\r
410 PeiCpuMpData->BackupBufferSize\r
411 );\r
412 CopyMem (\r
413 (VOID *) PeiCpuMpData->WakeupBuffer,\r
414 (VOID *) PeiCpuMpData->AddressMap.RendezvousFunnelAddress,\r
415 PeiCpuMpData->AddressMap.RendezvousFunnelSize\r
416 );\r
417}\r
418\r
419/**\r
420 Restore wakeup buffer data.\r
421\r
422 @param PeiCpuMpData Pointer to PEI CPU MP Data\r
423**/\r
424VOID\r
425RestoreWakeupBuffer(\r
426 IN PEI_CPU_MP_DATA *PeiCpuMpData\r
427 )\r
428{\r
429 CopyMem ((VOID *) PeiCpuMpData->WakeupBuffer, (VOID *) PeiCpuMpData->BackupBuffer, PeiCpuMpData->BackupBufferSize);\r
430}\r
431\r
432/**\r
433 This function will get CPU count in the system.\r
434\r
435 @param PeiCpuMpData Pointer to PEI CPU MP Data\r
436\r
437 @return AP processor count\r
438**/\r
439UINT32\r
440CountProcessorNumber (\r
441 IN PEI_CPU_MP_DATA *PeiCpuMpData\r
442 )\r
443{\r
444 //\r
445 // Load Microcode on BSP\r
446 //\r
447 MicrocodeDetect ();\r
448 //\r
449 // Store BSP's MTRR setting\r
450 //\r
451 MtrrGetAllMtrrs (&PeiCpuMpData->MtrrTable);\r
944f45ae 452\r
ea0f431c 453 //\r
944f45ae 454 // Only perform AP detection if PcdCpuMaxLogicalProcessorNumber is greater than 1\r
ea0f431c 455 //\r
944f45ae
MK
456 if (PcdGet32 (PcdCpuMaxLogicalProcessorNumber) > 1) {\r
457 //\r
2f0261b7 458 // Send 1st broadcast IPI to APs to wakeup APs\r
944f45ae 459 //\r
2f0261b7
JF
460 PeiCpuMpData->InitFlag = TRUE;\r
461 PeiCpuMpData->X2ApicEnable = FALSE;\r
944f45ae
MK
462 WakeUpAP (PeiCpuMpData, TRUE, 0, NULL, NULL);\r
463 //\r
464 // Wait for AP task to complete and then exit.\r
465 //\r
466 MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds));\r
2f0261b7 467 PeiCpuMpData->InitFlag = FALSE;\r
944f45ae
MK
468 PeiCpuMpData->CpuCount += (UINT32)PeiCpuMpData->MpCpuExchangeInfo->NumApsExecuting;\r
469 ASSERT (PeiCpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));\r
470 //\r
c7981a11
JF
471 // Wait for all APs finished the initialization\r
472 //\r
473 while (PeiCpuMpData->FinishedCount < (PeiCpuMpData->CpuCount - 1)) {\r
474 CpuPause ();\r
475 }\r
476\r
477 if (PeiCpuMpData->X2ApicEnable) {\r
478 DEBUG ((EFI_D_INFO, "Force x2APIC mode!\n"));\r
479 //\r
480 // Send 2nd broadcast IPI to all APs to enable x2APIC mode\r
481 //\r
482 WakeUpAP (PeiCpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL);\r
483 //\r
484 // Wait for all known APs finished\r
485 //\r
486 while (PeiCpuMpData->FinishedCount < (PeiCpuMpData->CpuCount - 1)) {\r
487 CpuPause ();\r
488 }\r
489 //\r
490 // Enable x2APIC on BSP\r
491 //\r
492 SetApicMode (LOCAL_APIC_MODE_X2APIC);\r
493 }\r
494 DEBUG ((EFI_D_INFO, "APIC MODE is %d\n", GetApicMode ()));\r
495 //\r
944f45ae
MK
496 // Sort BSP/Aps by CPU APIC ID in ascending order\r
497 //\r
498 SortApicId (PeiCpuMpData);\r
499 }\r
ea0f431c
JF
500\r
501 DEBUG ((EFI_D_INFO, "CpuMpPei: Find %d processors in system.\n", PeiCpuMpData->CpuCount));\r
502 return PeiCpuMpData->CpuCount;\r
503}\r
504\r
505/**\r
506 Prepare for AP wakeup buffer and copy AP reset code into it.\r
507\r
508 Get wakeup buffer below 1MB. Allocate memory for CPU MP Data and APs Stack.\r
509\r
510 @return Pointer to PEI CPU MP Data\r
511**/\r
512PEI_CPU_MP_DATA *\r
513PrepareAPStartupVector (\r
514 VOID\r
515 )\r
516{\r
517 EFI_STATUS Status;\r
518 UINT32 MaxCpuCount;\r
519 PEI_CPU_MP_DATA *PeiCpuMpData;\r
520 EFI_PHYSICAL_ADDRESS Buffer;\r
521 UINTN BufferSize;\r
522 UINTN WakeupBuffer;\r
523 UINTN WakeupBufferSize;\r
524 MP_ASSEMBLY_ADDRESS_MAP AddressMap;\r
525\r
526 AsmGetAddressMap (&AddressMap);\r
527 WakeupBufferSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);\r
528 WakeupBuffer = GetWakeupBuffer ((WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1));\r
529 ASSERT (WakeupBuffer != (UINTN) -1);\r
530 DEBUG ((EFI_D_INFO, "CpuMpPei: WakeupBuffer = 0x%x\n", WakeupBuffer));\r
531\r
532 //\r
533 // Allocate Pages for APs stack, CPU MP Data and backup buffer for wakeup buffer\r
534 //\r
535 MaxCpuCount = PcdGet32(PcdCpuMaxLogicalProcessorNumber);\r
536 BufferSize = PcdGet32 (PcdCpuApStackSize) * MaxCpuCount + sizeof (PEI_CPU_MP_DATA)\r
537 + WakeupBufferSize + sizeof (PEI_CPU_DATA) * MaxCpuCount;\r
538 Status = PeiServicesAllocatePages (\r
539 EfiBootServicesData,\r
540 EFI_SIZE_TO_PAGES (BufferSize),\r
541 &Buffer\r
542 );\r
543 ASSERT_EFI_ERROR (Status);\r
544\r
545 PeiCpuMpData = (PEI_CPU_MP_DATA *) (UINTN) (Buffer + PcdGet32 (PcdCpuApStackSize) * MaxCpuCount);\r
546 PeiCpuMpData->Buffer = (UINTN) Buffer;\r
547 PeiCpuMpData->CpuApStackSize = PcdGet32 (PcdCpuApStackSize);\r
548 PeiCpuMpData->WakeupBuffer = WakeupBuffer;\r
549 PeiCpuMpData->BackupBuffer = (UINTN)PeiCpuMpData + sizeof (PEI_CPU_MP_DATA);\r
550 PeiCpuMpData->BackupBufferSize = WakeupBufferSize;\r
551 PeiCpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeupBuffer + AddressMap.RendezvousFunnelSize);\r
552\r
553 PeiCpuMpData->CpuCount = 1;\r
554 PeiCpuMpData->BspNumber = 0;\r
28f27af6
JF
555 PeiCpuMpData->CpuData = (PEI_CPU_DATA *) (PeiCpuMpData->BackupBuffer +\r
556 PeiCpuMpData->BackupBufferSize);\r
ea0f431c
JF
557 PeiCpuMpData->CpuData[0].ApicId = GetInitialApicId ();\r
558 PeiCpuMpData->CpuData[0].Health.Uint32 = 0;\r
559 PeiCpuMpData->EndOfPeiFlag = FALSE;\r
2f0261b7 560 InitializeSpinLock(&PeiCpuMpData->MpLock);\r
ea0f431c
JF
561 CopyMem (&PeiCpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));\r
562\r
563 //\r
564 // Backup original data and copy AP reset code in it\r
565 //\r
566 BackupAndPrepareWakeupBuffer(PeiCpuMpData);\r
567\r
568 return PeiCpuMpData;\r
569}\r
570\r
571/**\r
572 Notify function on End Of Pei PPI.\r
573\r
574 On S3 boot, this function will restore wakeup buffer data.\r
575 On normal boot, this function will flag wakeup buffer to be un-used type.\r
576\r
577 @param PeiServices The pointer to the PEI Services Table.\r
578 @param NotifyDescriptor Address of the notification descriptor data structure.\r
579 @param Ppi Address of the PPI that was installed.\r
580\r
581 @retval EFI_SUCCESS When everything is OK.\r
582\r
583**/\r
584EFI_STATUS\r
585EFIAPI\r
586CpuMpEndOfPeiCallback (\r
587 IN EFI_PEI_SERVICES **PeiServices,\r
588 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
589 IN VOID *Ppi\r
590 )\r
591{\r
592 EFI_STATUS Status;\r
593 EFI_BOOT_MODE BootMode;\r
594 PEI_CPU_MP_DATA *PeiCpuMpData;\r
595 EFI_PEI_HOB_POINTERS Hob;\r
596 EFI_HOB_MEMORY_ALLOCATION *MemoryHob;\r
597\r
598 DEBUG ((EFI_D_INFO, "CpuMpPei: CpuMpEndOfPeiCallback () invokded\n"));\r
599\r
600 Status = PeiServicesGetBootMode (&BootMode);\r
601 ASSERT_EFI_ERROR (Status);\r
602\r
603 PeiCpuMpData = GetMpHobData ();\r
604 ASSERT (PeiCpuMpData != NULL);\r
605\r
606 if (BootMode != BOOT_ON_S3_RESUME) {\r
607 //\r
608 // Get the HOB list for processing\r
609 //\r
610 Hob.Raw = GetHobList ();\r
611 //\r
612 // Collect memory ranges\r
613 //\r
614 while (!END_OF_HOB_LIST (Hob)) {\r
615 if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {\r
616 MemoryHob = Hob.MemoryAllocation;\r
617 if(MemoryHob->AllocDescriptor.MemoryBaseAddress == PeiCpuMpData->WakeupBuffer) {\r
618 //\r
619 // Flag this HOB type to un-used\r
620 //\r
621 GET_HOB_TYPE (Hob) = EFI_HOB_TYPE_UNUSED;\r
622 break;\r
623 }\r
624 }\r
625 Hob.Raw = GET_NEXT_HOB (Hob);\r
626 }\r
627 } else {\r
628 RestoreWakeupBuffer (PeiCpuMpData);\r
629 PeiCpuMpData->EndOfPeiFlag = TRUE;\r
630 }\r
631 return EFI_SUCCESS;\r
632}\r
633\r
634/**\r
635 The Entry point of the MP CPU PEIM.\r
636\r
637 This function will wakeup APs and collect CPU AP count and install the\r
638 Mp Service Ppi.\r
639\r
640 @param FileHandle Handle of the file being invoked.\r
641 @param PeiServices Describes the list of possible PEI Services.\r
642\r
643 @retval EFI_SUCCESS MpServicePpi is installed successfully.\r
644\r
645**/\r
646EFI_STATUS\r
647EFIAPI\r
648CpuMpPeimInit (\r
649 IN EFI_PEI_FILE_HANDLE FileHandle,\r
650 IN CONST EFI_PEI_SERVICES **PeiServices\r
651 )\r
652{\r
653 EFI_STATUS Status;\r
654 PEI_CPU_MP_DATA *PeiCpuMpData;\r
655 UINT32 ProcessorCount;\r
656\r
657 //\r
658 // Load new GDT table on BSP\r
659 //\r
660 AsmInitializeGdt (&mGdt);\r
661 //\r
662 // Get wakeup buffer and copy AP reset code in it\r
663 //\r
664 PeiCpuMpData = PrepareAPStartupVector ();\r
665 //\r
666 // Count processor number and collect processor information\r
667 //\r
668 ProcessorCount = CountProcessorNumber (PeiCpuMpData);\r
669 //\r
670 // Build location of PEI CPU MP DATA buffer in HOB\r
671 //\r
672 BuildGuidDataHob (\r
673 &gEfiCallerIdGuid,\r
674 (VOID *)&PeiCpuMpData,\r
675 sizeof(UINT64)\r
676 );\r
677 //\r
678 // Update and publish CPU BIST information\r
679 //\r
680 CollectBistDataFromPpi (PeiServices, PeiCpuMpData);\r
681 //\r
682 // register an event for EndOfPei\r
683 //\r
684 Status = PeiServicesNotifyPpi (&mNotifyList);\r
685 ASSERT_EFI_ERROR (Status);\r
686 //\r
687 // Install CPU MP PPI\r
688 //\r
689 Status = PeiServicesInstallPpi(&mPeiCpuMpPpiDesc);\r
690 ASSERT_EFI_ERROR (Status);\r
691\r
692 return Status;\r
693}\r