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