]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/CpuMpPei/CpuMpPei.c
UefiCpuPkg/CpuMpPei: Add missing point at function header
[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 144/**\r
5ac96e3a 145 Save the volatile registers required to be restored following INIT IPI.\r
ef1fdb80
JF
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
5ac96e3a 176 Restore the volatile registers following INIT IPI.\r
ef1fdb80
JF
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
c972495e 215 @param NumApsExecuting Number of current executing AP\r
ea0f431c
JF
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
10c6c206 231 ProcessorNumber = NumApsExecuting;\r
ea0f431c 232 //\r
22cfe73a
JF
233 // Sync BSP's Control registers to APs\r
234 //\r
235 RestoreVolatileRegisters (&PeiCpuMpData->CpuData[0].VolatileRegisters, FALSE);\r
236 //\r
2f0261b7 237 // This is first time AP wakeup, get BIST information from AP stack\r
ea0f431c 238 //\r
10c6c206
JF
239 BistData = *(UINTN *) (PeiCpuMpData->Buffer + ProcessorNumber * PeiCpuMpData->CpuApStackSize - sizeof (UINTN));\r
240 PeiCpuMpData->CpuData[ProcessorNumber].Health.Uint32 = (UINT32) BistData;\r
241 PeiCpuMpData->CpuData[ProcessorNumber].ApicId = GetInitialApicId ();\r
242 if (PeiCpuMpData->CpuData[ProcessorNumber].ApicId >= 0xFF) {\r
2f0261b7
JF
243 //\r
244 // Set x2APIC mode if there are any logical processor reporting\r
245 // an APIC ID of 255 or greater.\r
246 //\r
247 AcquireSpinLock(&PeiCpuMpData->MpLock);\r
248 PeiCpuMpData->X2ApicEnable = TRUE;\r
249 ReleaseSpinLock(&PeiCpuMpData->MpLock);\r
250 }\r
ea0f431c
JF
251 //\r
252 // Sync BSP's Mtrr table to all wakeup APs and load microcode on APs.\r
253 //\r
254 MtrrSetAllMtrrs (&PeiCpuMpData->MtrrTable);\r
255 MicrocodeDetect ();\r
10c6c206 256 PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle;\r
ea0f431c
JF
257 } else {\r
258 //\r
259 // Execute AP function if AP is not disabled\r
260 //\r
261 GetProcessorNumber (PeiCpuMpData, &ProcessorNumber);\r
f40a7de4
JF
262 //\r
263 // Restore AP's volatile registers saved\r
264 //\r
265 RestoreVolatileRegisters (&PeiCpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);\r
266\r
ea0f431c
JF
267 if ((PeiCpuMpData->CpuData[ProcessorNumber].State != CpuStateDisabled) &&\r
268 (PeiCpuMpData->ApFunction != 0)) {\r
269 PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateBusy;\r
270 Procedure = (EFI_AP_PROCEDURE)(UINTN)PeiCpuMpData->ApFunction;\r
c972495e
JF
271 //\r
272 // Invoke AP function here\r
273 //\r
ea0f431c
JF
274 Procedure ((VOID *)(UINTN)PeiCpuMpData->ApFunctionArgument);\r
275 PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle;\r
276 }\r
277 }\r
278\r
279 //\r
280 // AP finished executing C code\r
281 //\r
282 InterlockedIncrement ((UINT32 *)&PeiCpuMpData->FinishedCount);\r
283\r
f40a7de4
JF
284 //\r
285 // Save AP volatile registers\r
286 //\r
287 SaveVolatileRegisters (&PeiCpuMpData->CpuData[ProcessorNumber].VolatileRegisters);\r
288\r
ea0f431c
JF
289 AsmCliHltLoop ();\r
290}\r
291\r
292/**\r
293 This function will be called by BSP to wakeup AP.\r
294\r
295 @param PeiCpuMpData Pointer to PEI CPU MP Data\r
296 @param Broadcast TRUE: Send broadcast IPI to all APs\r
297 FALSE: Send IPI to AP by ApicId\r
298 @param ApicId Apic ID for the processor to be waked\r
299 @param Procedure The function to be invoked by AP\r
300 @param ProcedureArgument The argument to be passed into AP function\r
301**/\r
302VOID\r
303WakeUpAP (\r
304 IN PEI_CPU_MP_DATA *PeiCpuMpData,\r
305 IN BOOLEAN Broadcast,\r
306 IN UINT32 ApicId,\r
307 IN EFI_AP_PROCEDURE Procedure, OPTIONAL\r
308 IN VOID *ProcedureArgument OPTIONAL\r
309 )\r
310{\r
311 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;\r
312\r
313 PeiCpuMpData->ApFunction = (UINTN) Procedure;\r
314 PeiCpuMpData->ApFunctionArgument = (UINTN) ProcedureArgument;\r
315 PeiCpuMpData->FinishedCount = 0;\r
316\r
317 ExchangeInfo = PeiCpuMpData->MpCpuExchangeInfo;\r
318 ExchangeInfo->Lock = 0;\r
319 ExchangeInfo->StackStart = PeiCpuMpData->Buffer;\r
320 ExchangeInfo->StackSize = PeiCpuMpData->CpuApStackSize;\r
321 ExchangeInfo->BufferStart = PeiCpuMpData->WakeupBuffer;\r
322 ExchangeInfo->PmodeOffset = PeiCpuMpData->AddressMap.PModeEntryOffset;\r
323 ExchangeInfo->LmodeOffset = PeiCpuMpData->AddressMap.LModeEntryOffset;\r
324 ExchangeInfo->Cr3 = AsmReadCr3 ();\r
325 ExchangeInfo->CFunction = (UINTN) ApCFunction;\r
326 ExchangeInfo->NumApsExecuting = 0;\r
327 ExchangeInfo->PeiCpuMpData = PeiCpuMpData;\r
328\r
329 //\r
330 // Get the BSP's data of GDT and IDT\r
331 //\r
332 CopyMem ((VOID *)&ExchangeInfo->GdtrProfile, &mGdt, sizeof(mGdt));\r
333 AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);\r
334\r
335 if (Broadcast) {\r
336 SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);\r
337 } else {\r
338 SendInitSipiSipi (ApicId, (UINT32) ExchangeInfo->BufferStart);\r
339 }\r
340\r
341 return ;\r
342}\r
343\r
344/**\r
345 Get available system memory below 1MB by specified size.\r
346\r
347 @param WakeupBufferSize Wakeup buffer size required\r
348\r
349 @retval other Return wakeup buffer address below 1MB.\r
350 @retval -1 Cannot find free memory below 1MB.\r
351**/\r
352UINTN\r
353GetWakeupBuffer (\r
354 IN UINTN WakeupBufferSize\r
355 )\r
356{\r
357 EFI_PEI_HOB_POINTERS Hob;\r
358 UINTN WakeupBufferStart;\r
359 UINTN WakeupBufferEnd;\r
360\r
361 //\r
362 // Get the HOB list for processing\r
363 //\r
364 Hob.Raw = GetHobList ();\r
365\r
366 //\r
367 // Collect memory ranges\r
368 //\r
369 while (!END_OF_HOB_LIST (Hob)) {\r
370 if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
371 if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) &&\r
372 (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&\r
373 ((Hob.ResourceDescriptor->ResourceAttribute &\r
374 (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |\r
375 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |\r
376 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED\r
377 )) == 0)\r
378 ) {\r
379 //\r
380 // Need memory under 1MB to be collected here\r
381 //\r
382 WakeupBufferEnd = (UINTN) (Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength);\r
383 if (WakeupBufferEnd > BASE_1MB) {\r
384 //\r
385 // Wakeup buffer should be under 1MB\r
386 //\r
387 WakeupBufferEnd = BASE_1MB;\r
388 }\r
389 //\r
390 // Wakeup buffer should be aligned on 4KB\r
391 //\r
392 WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1);\r
393 if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) {\r
394 continue;\r
395 }\r
396 //\r
397 // Create a memory allocation HOB.\r
398 //\r
399 BuildMemoryAllocationHob (\r
400 WakeupBufferStart,\r
401 WakeupBufferSize,\r
402 EfiBootServicesData\r
403 );\r
404 return WakeupBufferStart;\r
405 }\r
406 }\r
407 //\r
408 // Find the next HOB\r
409 //\r
410 Hob.Raw = GET_NEXT_HOB (Hob);\r
411 }\r
412\r
413 return (UINTN) -1;\r
414}\r
415\r
416/**\r
417 Get available system memory below 1MB by specified size.\r
418\r
419 @param PeiCpuMpData Pointer to PEI CPU MP Data\r
420**/\r
421VOID\r
422BackupAndPrepareWakeupBuffer(\r
423 IN PEI_CPU_MP_DATA *PeiCpuMpData\r
424 )\r
425{\r
426 CopyMem (\r
427 (VOID *) PeiCpuMpData->BackupBuffer,\r
428 (VOID *) PeiCpuMpData->WakeupBuffer,\r
429 PeiCpuMpData->BackupBufferSize\r
430 );\r
431 CopyMem (\r
432 (VOID *) PeiCpuMpData->WakeupBuffer,\r
433 (VOID *) PeiCpuMpData->AddressMap.RendezvousFunnelAddress,\r
434 PeiCpuMpData->AddressMap.RendezvousFunnelSize\r
435 );\r
436}\r
437\r
438/**\r
439 Restore wakeup buffer data.\r
440\r
441 @param PeiCpuMpData Pointer to PEI CPU MP Data\r
442**/\r
443VOID\r
444RestoreWakeupBuffer(\r
445 IN PEI_CPU_MP_DATA *PeiCpuMpData\r
446 )\r
447{\r
448 CopyMem ((VOID *) PeiCpuMpData->WakeupBuffer, (VOID *) PeiCpuMpData->BackupBuffer, PeiCpuMpData->BackupBufferSize);\r
449}\r
450\r
451/**\r
452 This function will get CPU count in the system.\r
453\r
454 @param PeiCpuMpData Pointer to PEI CPU MP Data\r
455\r
456 @return AP processor count\r
457**/\r
458UINT32\r
459CountProcessorNumber (\r
460 IN PEI_CPU_MP_DATA *PeiCpuMpData\r
461 )\r
462{\r
463 //\r
464 // Load Microcode on BSP\r
465 //\r
466 MicrocodeDetect ();\r
467 //\r
468 // Store BSP's MTRR setting\r
469 //\r
470 MtrrGetAllMtrrs (&PeiCpuMpData->MtrrTable);\r
944f45ae 471\r
ea0f431c 472 //\r
944f45ae 473 // Only perform AP detection if PcdCpuMaxLogicalProcessorNumber is greater than 1\r
ea0f431c 474 //\r
944f45ae
MK
475 if (PcdGet32 (PcdCpuMaxLogicalProcessorNumber) > 1) {\r
476 //\r
2f0261b7 477 // Send 1st broadcast IPI to APs to wakeup APs\r
944f45ae 478 //\r
2f0261b7
JF
479 PeiCpuMpData->InitFlag = TRUE;\r
480 PeiCpuMpData->X2ApicEnable = FALSE;\r
944f45ae
MK
481 WakeUpAP (PeiCpuMpData, TRUE, 0, NULL, NULL);\r
482 //\r
483 // Wait for AP task to complete and then exit.\r
484 //\r
485 MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds));\r
2f0261b7 486 PeiCpuMpData->InitFlag = FALSE;\r
944f45ae
MK
487 PeiCpuMpData->CpuCount += (UINT32)PeiCpuMpData->MpCpuExchangeInfo->NumApsExecuting;\r
488 ASSERT (PeiCpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));\r
489 //\r
c7981a11
JF
490 // Wait for all APs finished the initialization\r
491 //\r
492 while (PeiCpuMpData->FinishedCount < (PeiCpuMpData->CpuCount - 1)) {\r
493 CpuPause ();\r
494 }\r
495\r
496 if (PeiCpuMpData->X2ApicEnable) {\r
497 DEBUG ((EFI_D_INFO, "Force x2APIC mode!\n"));\r
498 //\r
499 // Send 2nd broadcast IPI to all APs to enable x2APIC mode\r
500 //\r
501 WakeUpAP (PeiCpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL);\r
502 //\r
503 // Wait for all known APs finished\r
504 //\r
505 while (PeiCpuMpData->FinishedCount < (PeiCpuMpData->CpuCount - 1)) {\r
506 CpuPause ();\r
507 }\r
508 //\r
509 // Enable x2APIC on BSP\r
510 //\r
511 SetApicMode (LOCAL_APIC_MODE_X2APIC);\r
512 }\r
513 DEBUG ((EFI_D_INFO, "APIC MODE is %d\n", GetApicMode ()));\r
514 //\r
944f45ae
MK
515 // Sort BSP/Aps by CPU APIC ID in ascending order\r
516 //\r
517 SortApicId (PeiCpuMpData);\r
518 }\r
ea0f431c
JF
519\r
520 DEBUG ((EFI_D_INFO, "CpuMpPei: Find %d processors in system.\n", PeiCpuMpData->CpuCount));\r
521 return PeiCpuMpData->CpuCount;\r
522}\r
523\r
524/**\r
525 Prepare for AP wakeup buffer and copy AP reset code into it.\r
526\r
527 Get wakeup buffer below 1MB. Allocate memory for CPU MP Data and APs Stack.\r
528\r
529 @return Pointer to PEI CPU MP Data\r
530**/\r
531PEI_CPU_MP_DATA *\r
532PrepareAPStartupVector (\r
533 VOID\r
534 )\r
535{\r
536 EFI_STATUS Status;\r
537 UINT32 MaxCpuCount;\r
538 PEI_CPU_MP_DATA *PeiCpuMpData;\r
539 EFI_PHYSICAL_ADDRESS Buffer;\r
540 UINTN BufferSize;\r
541 UINTN WakeupBuffer;\r
542 UINTN WakeupBufferSize;\r
543 MP_ASSEMBLY_ADDRESS_MAP AddressMap;\r
544\r
545 AsmGetAddressMap (&AddressMap);\r
546 WakeupBufferSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);\r
547 WakeupBuffer = GetWakeupBuffer ((WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1));\r
548 ASSERT (WakeupBuffer != (UINTN) -1);\r
549 DEBUG ((EFI_D_INFO, "CpuMpPei: WakeupBuffer = 0x%x\n", WakeupBuffer));\r
550\r
551 //\r
552 // Allocate Pages for APs stack, CPU MP Data and backup buffer for wakeup buffer\r
553 //\r
554 MaxCpuCount = PcdGet32(PcdCpuMaxLogicalProcessorNumber);\r
555 BufferSize = PcdGet32 (PcdCpuApStackSize) * MaxCpuCount + sizeof (PEI_CPU_MP_DATA)\r
556 + WakeupBufferSize + sizeof (PEI_CPU_DATA) * MaxCpuCount;\r
557 Status = PeiServicesAllocatePages (\r
558 EfiBootServicesData,\r
559 EFI_SIZE_TO_PAGES (BufferSize),\r
560 &Buffer\r
561 );\r
562 ASSERT_EFI_ERROR (Status);\r
563\r
564 PeiCpuMpData = (PEI_CPU_MP_DATA *) (UINTN) (Buffer + PcdGet32 (PcdCpuApStackSize) * MaxCpuCount);\r
565 PeiCpuMpData->Buffer = (UINTN) Buffer;\r
566 PeiCpuMpData->CpuApStackSize = PcdGet32 (PcdCpuApStackSize);\r
567 PeiCpuMpData->WakeupBuffer = WakeupBuffer;\r
568 PeiCpuMpData->BackupBuffer = (UINTN)PeiCpuMpData + sizeof (PEI_CPU_MP_DATA);\r
569 PeiCpuMpData->BackupBufferSize = WakeupBufferSize;\r
570 PeiCpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeupBuffer + AddressMap.RendezvousFunnelSize);\r
571\r
572 PeiCpuMpData->CpuCount = 1;\r
573 PeiCpuMpData->BspNumber = 0;\r
28f27af6
JF
574 PeiCpuMpData->CpuData = (PEI_CPU_DATA *) (PeiCpuMpData->BackupBuffer +\r
575 PeiCpuMpData->BackupBufferSize);\r
ea0f431c
JF
576 PeiCpuMpData->CpuData[0].ApicId = GetInitialApicId ();\r
577 PeiCpuMpData->CpuData[0].Health.Uint32 = 0;\r
578 PeiCpuMpData->EndOfPeiFlag = FALSE;\r
2f0261b7 579 InitializeSpinLock(&PeiCpuMpData->MpLock);\r
22cfe73a 580 SaveVolatileRegisters (&PeiCpuMpData->CpuData[0].VolatileRegisters);\r
ea0f431c
JF
581 CopyMem (&PeiCpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));\r
582\r
583 //\r
584 // Backup original data and copy AP reset code in it\r
585 //\r
586 BackupAndPrepareWakeupBuffer(PeiCpuMpData);\r
587\r
588 return PeiCpuMpData;\r
589}\r
590\r
591/**\r
592 Notify function on End Of Pei PPI.\r
593\r
594 On S3 boot, this function will restore wakeup buffer data.\r
595 On normal boot, this function will flag wakeup buffer to be un-used type.\r
596\r
597 @param PeiServices The pointer to the PEI Services Table.\r
598 @param NotifyDescriptor Address of the notification descriptor data structure.\r
599 @param Ppi Address of the PPI that was installed.\r
600\r
601 @retval EFI_SUCCESS When everything is OK.\r
602\r
603**/\r
604EFI_STATUS\r
605EFIAPI\r
606CpuMpEndOfPeiCallback (\r
607 IN EFI_PEI_SERVICES **PeiServices,\r
608 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
609 IN VOID *Ppi\r
610 )\r
611{\r
612 EFI_STATUS Status;\r
613 EFI_BOOT_MODE BootMode;\r
614 PEI_CPU_MP_DATA *PeiCpuMpData;\r
615 EFI_PEI_HOB_POINTERS Hob;\r
616 EFI_HOB_MEMORY_ALLOCATION *MemoryHob;\r
617\r
c972495e 618 DEBUG ((EFI_D_INFO, "CpuMpPei: CpuMpEndOfPeiCallback () invoked\n"));\r
ea0f431c
JF
619\r
620 Status = PeiServicesGetBootMode (&BootMode);\r
621 ASSERT_EFI_ERROR (Status);\r
622\r
623 PeiCpuMpData = GetMpHobData ();\r
624 ASSERT (PeiCpuMpData != NULL);\r
625\r
626 if (BootMode != BOOT_ON_S3_RESUME) {\r
627 //\r
628 // Get the HOB list for processing\r
629 //\r
630 Hob.Raw = GetHobList ();\r
631 //\r
632 // Collect memory ranges\r
633 //\r
634 while (!END_OF_HOB_LIST (Hob)) {\r
635 if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {\r
636 MemoryHob = Hob.MemoryAllocation;\r
637 if(MemoryHob->AllocDescriptor.MemoryBaseAddress == PeiCpuMpData->WakeupBuffer) {\r
638 //\r
639 // Flag this HOB type to un-used\r
640 //\r
641 GET_HOB_TYPE (Hob) = EFI_HOB_TYPE_UNUSED;\r
642 break;\r
643 }\r
644 }\r
645 Hob.Raw = GET_NEXT_HOB (Hob);\r
646 }\r
647 } else {\r
648 RestoreWakeupBuffer (PeiCpuMpData);\r
649 PeiCpuMpData->EndOfPeiFlag = TRUE;\r
650 }\r
651 return EFI_SUCCESS;\r
652}\r
653\r
654/**\r
655 The Entry point of the MP CPU PEIM.\r
656\r
657 This function will wakeup APs and collect CPU AP count and install the\r
658 Mp Service Ppi.\r
659\r
660 @param FileHandle Handle of the file being invoked.\r
661 @param PeiServices Describes the list of possible PEI Services.\r
662\r
663 @retval EFI_SUCCESS MpServicePpi is installed successfully.\r
664\r
665**/\r
666EFI_STATUS\r
667EFIAPI\r
668CpuMpPeimInit (\r
669 IN EFI_PEI_FILE_HANDLE FileHandle,\r
670 IN CONST EFI_PEI_SERVICES **PeiServices\r
671 )\r
672{\r
673 EFI_STATUS Status;\r
674 PEI_CPU_MP_DATA *PeiCpuMpData;\r
675 UINT32 ProcessorCount;\r
676\r
677 //\r
678 // Load new GDT table on BSP\r
679 //\r
680 AsmInitializeGdt (&mGdt);\r
681 //\r
682 // Get wakeup buffer and copy AP reset code in it\r
683 //\r
684 PeiCpuMpData = PrepareAPStartupVector ();\r
685 //\r
686 // Count processor number and collect processor information\r
687 //\r
688 ProcessorCount = CountProcessorNumber (PeiCpuMpData);\r
689 //\r
690 // Build location of PEI CPU MP DATA buffer in HOB\r
691 //\r
692 BuildGuidDataHob (\r
693 &gEfiCallerIdGuid,\r
694 (VOID *)&PeiCpuMpData,\r
695 sizeof(UINT64)\r
696 );\r
697 //\r
698 // Update and publish CPU BIST information\r
699 //\r
700 CollectBistDataFromPpi (PeiServices, PeiCpuMpData);\r
701 //\r
702 // register an event for EndOfPei\r
703 //\r
704 Status = PeiServicesNotifyPpi (&mNotifyList);\r
705 ASSERT_EFI_ERROR (Status);\r
706 //\r
707 // Install CPU MP PPI\r
708 //\r
709 Status = PeiServicesInstallPpi(&mPeiCpuMpPpiDesc);\r
710 ASSERT_EFI_ERROR (Status);\r
711\r
712 return Status;\r
713}\r