]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/CpuMpPei/CpuMpPei.c
UefiCpuPkg/CpuMpPei: Remove un-used variables and 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
4da1ebf3 4 Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
ea0f431c
JF
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
ea0f431c
JF
16\r
17GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = {\r
18 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
19 &gEfiEndOfPeiSignalPpiGuid,\r
20 CpuMpEndOfPeiCallback\r
21};\r
22\r
23/**\r
24 Sort the APIC ID of all processors.\r
25\r
26 This function sorts the APIC ID of all processors so that processor number is\r
27 assigned in the ascending order of APIC ID which eases MP debugging.\r
28\r
29 @param PeiCpuMpData Pointer to PEI CPU MP Data\r
30**/\r
31VOID\r
32SortApicId (\r
33 IN PEI_CPU_MP_DATA *PeiCpuMpData\r
34 )\r
35{\r
36 UINTN Index1;\r
37 UINTN Index2;\r
38 UINTN Index3;\r
39 UINT32 ApicId;\r
24930b56 40 PEI_CPU_DATA CpuData;\r
ea0f431c
JF
41 UINT32 ApCount;\r
42\r
43 ApCount = PeiCpuMpData->CpuCount - 1;\r
44\r
45 if (ApCount != 0) {\r
46 for (Index1 = 0; Index1 < ApCount; Index1++) {\r
47 Index3 = Index1;\r
48 //\r
49 // Sort key is the hardware default APIC ID\r
50 //\r
51 ApicId = PeiCpuMpData->CpuData[Index1].ApicId;\r
52 for (Index2 = Index1 + 1; Index2 <= ApCount; Index2++) {\r
53 if (ApicId > PeiCpuMpData->CpuData[Index2].ApicId) {\r
54 Index3 = Index2;\r
55 ApicId = PeiCpuMpData->CpuData[Index2].ApicId;\r
56 }\r
57 }\r
58 if (Index3 != Index1) {\r
24930b56
JF
59 CopyMem (&CpuData, &PeiCpuMpData->CpuData[Index3], sizeof (PEI_CPU_DATA));\r
60 CopyMem (\r
61 &PeiCpuMpData->CpuData[Index3],\r
62 &PeiCpuMpData->CpuData[Index1],\r
63 sizeof (PEI_CPU_DATA)\r
64 );\r
65 CopyMem (&PeiCpuMpData->CpuData[Index1], &CpuData, sizeof (PEI_CPU_DATA));\r
ea0f431c
JF
66 }\r
67 }\r
68\r
69 //\r
70 // Get the processor number for the BSP\r
71 //\r
72 ApicId = GetInitialApicId ();\r
73 for (Index1 = 0; Index1 < PeiCpuMpData->CpuCount; Index1++) {\r
74 if (PeiCpuMpData->CpuData[Index1].ApicId == ApicId) {\r
75 PeiCpuMpData->BspNumber = (UINT32) Index1;\r
76 break;\r
77 }\r
78 }\r
79 }\r
80}\r
81\r
c7981a11
JF
82/**\r
83 Enable x2APIC mode on APs.\r
84\r
85 @param Buffer Pointer to private data buffer.\r
86**/\r
87VOID\r
88EFIAPI\r
89ApFuncEnableX2Apic (\r
90 IN OUT VOID *Buffer\r
91 )\r
92{\r
93 SetApicMode (LOCAL_APIC_MODE_X2APIC);\r
94}\r
95\r
4de216c0
JF
96/**\r
97 Get AP loop mode.\r
98\r
99 @param MonitorFilterSize Returns the largest monitor-line size in bytes.\r
100\r
101 @return The AP loop mode.\r
102**/\r
103UINT8\r
104GetApLoopMode (\r
105 OUT UINT16 *MonitorFilterSize\r
106 )\r
107{\r
108 UINT8 ApLoopMode;\r
109 UINT32 RegEbx;\r
110 UINT32 RegEcx;\r
111 UINT32 RegEdx;\r
112\r
113 ASSERT (MonitorFilterSize != NULL);\r
114\r
115 ApLoopMode = PcdGet8 (PcdCpuApLoopMode);\r
116 ASSERT (ApLoopMode >= ApInHltLoop && ApLoopMode <= ApInRunLoop);\r
117 if (ApLoopMode == ApInMwaitLoop) {\r
118 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &RegEcx, NULL);\r
119 if ((RegEcx & BIT3) == 0) {\r
120 //\r
121 // If processor does not support MONITOR/MWAIT feature\r
122 // by CPUID.[EAX=01H]:ECX.BIT3, force AP in Hlt-loop mode\r
123 //\r
124 ApLoopMode = ApInHltLoop;\r
125 }\r
126 }\r
127\r
128 if (ApLoopMode == ApInHltLoop) {\r
129 *MonitorFilterSize = 0;\r
130 } else if (ApLoopMode == ApInRunLoop) {\r
131 *MonitorFilterSize = sizeof (UINT32);\r
132 } else if (ApLoopMode == ApInMwaitLoop) {\r
133 //\r
134 // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes\r
135 // CPUID.[EAX=05H].EDX: C-states supported using MWAIT\r
136 //\r
137 AsmCpuid (CPUID_MONITOR_MWAIT, NULL, &RegEbx, NULL, &RegEdx);\r
138 *MonitorFilterSize = RegEbx & 0xFFFF;\r
139 }\r
140\r
141 return ApLoopMode;\r
142}\r
143\r
ea0f431c
JF
144/**\r
145 Get CPU MP Data pointer from the Guided HOB.\r
146\r
147 @return Pointer to Pointer to PEI CPU MP Data\r
148**/\r
149PEI_CPU_MP_DATA *\r
150GetMpHobData (\r
151 VOID\r
152 )\r
153{\r
154 EFI_HOB_GUID_TYPE *GuidHob;\r
155 VOID *DataInHob;\r
156 PEI_CPU_MP_DATA *CpuMpData;\r
157\r
158 CpuMpData = NULL;\r
159 GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);\r
160 if (GuidHob != NULL) {\r
161 DataInHob = GET_GUID_HOB_DATA (GuidHob);\r
162 CpuMpData = (PEI_CPU_MP_DATA *)(*(UINTN *)DataInHob);\r
163 }\r
164 ASSERT (CpuMpData != NULL);\r
165 return CpuMpData;\r
166}\r
167\r
ef1fdb80 168/**\r
5ac96e3a 169 Save the volatile registers required to be restored following INIT IPI.\r
ef1fdb80
JF
170 \r
171 @param VolatileRegisters Returns buffer saved the volatile resisters\r
172**/\r
173VOID\r
174SaveVolatileRegisters (\r
175 OUT CPU_VOLATILE_REGISTERS *VolatileRegisters\r
176 )\r
177{\r
178 UINT32 RegEdx;\r
179\r
180 VolatileRegisters->Cr0 = AsmReadCr0 ();\r
181 VolatileRegisters->Cr3 = AsmReadCr3 ();\r
182 VolatileRegisters->Cr4 = AsmReadCr4 ();\r
183\r
184 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx);\r
185 if ((RegEdx & BIT2) != 0) {\r
186 //\r
187 // If processor supports Debugging Extensions feature\r
188 // by CPUID.[EAX=01H]:EDX.BIT2\r
189 //\r
190 VolatileRegisters->Dr0 = AsmReadDr0 ();\r
191 VolatileRegisters->Dr1 = AsmReadDr1 ();\r
192 VolatileRegisters->Dr2 = AsmReadDr2 ();\r
193 VolatileRegisters->Dr3 = AsmReadDr3 ();\r
194 VolatileRegisters->Dr6 = AsmReadDr6 ();\r
195 VolatileRegisters->Dr7 = AsmReadDr7 ();\r
196 }\r
197}\r
198\r
199/**\r
5ac96e3a 200 Restore the volatile registers following INIT IPI.\r
ef1fdb80
JF
201 \r
202 @param VolatileRegisters Pointer to volatile resisters\r
203 @param IsRestoreDr TRUE: Restore DRx if supported\r
204 FALSE: Do not restore DRx\r
205**/\r
206VOID\r
207RestoreVolatileRegisters (\r
208 IN CPU_VOLATILE_REGISTERS *VolatileRegisters,\r
209 IN BOOLEAN IsRestoreDr\r
210 )\r
211{\r
212 UINT32 RegEdx;\r
213\r
214 AsmWriteCr0 (VolatileRegisters->Cr0);\r
215 AsmWriteCr3 (VolatileRegisters->Cr3);\r
216 AsmWriteCr4 (VolatileRegisters->Cr4);\r
217\r
218 if (IsRestoreDr) {\r
219 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx);\r
220 if ((RegEdx & BIT2) != 0) {\r
221 //\r
222 // If processor supports Debugging Extensions feature\r
223 // by CPUID.[EAX=01H]:EDX.BIT2\r
224 //\r
225 AsmWriteDr0 (VolatileRegisters->Dr0);\r
226 AsmWriteDr1 (VolatileRegisters->Dr1);\r
227 AsmWriteDr2 (VolatileRegisters->Dr2);\r
228 AsmWriteDr3 (VolatileRegisters->Dr3);\r
229 AsmWriteDr6 (VolatileRegisters->Dr6);\r
230 AsmWriteDr7 (VolatileRegisters->Dr7);\r
231 }\r
232 }\r
233}\r
234\r
ea0f431c
JF
235/**\r
236 This function will be called from AP reset code if BSP uses WakeUpAP.\r
237\r
238 @param ExchangeInfo Pointer to the MP exchange info buffer\r
c972495e 239 @param NumApsExecuting Number of current executing AP\r
ea0f431c
JF
240**/\r
241VOID\r
242EFIAPI\r
243ApCFunction (\r
244 IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,\r
245 IN UINTN NumApsExecuting\r
246 )\r
247{\r
248 PEI_CPU_MP_DATA *PeiCpuMpData;\r
249 UINTN ProcessorNumber;\r
250 EFI_AP_PROCEDURE Procedure;\r
251 UINTN BistData;\r
c87e41b4 252 volatile UINT32 *ApStartupSignalBuffer;\r
ea0f431c
JF
253\r
254 PeiCpuMpData = ExchangeInfo->PeiCpuMpData;\r
c87e41b4
JF
255 while (TRUE) {\r
256 if (PeiCpuMpData->InitFlag) {\r
257 ProcessorNumber = NumApsExecuting;\r
258 //\r
259 // Sync BSP's Control registers to APs\r
260 //\r
261 RestoreVolatileRegisters (&PeiCpuMpData->CpuData[0].VolatileRegisters, FALSE);\r
262 //\r
263 // This is first time AP wakeup, get BIST information from AP stack\r
264 //\r
265 BistData = *(UINTN *) (PeiCpuMpData->Buffer + ProcessorNumber * PeiCpuMpData->CpuApStackSize - sizeof (UINTN));\r
266 PeiCpuMpData->CpuData[ProcessorNumber].Health.Uint32 = (UINT32) BistData;\r
267 PeiCpuMpData->CpuData[ProcessorNumber].ApicId = GetInitialApicId ();\r
268 if (PeiCpuMpData->CpuData[ProcessorNumber].ApicId >= 0xFF) {\r
269 //\r
270 // Set x2APIC mode if there are any logical processor reporting\r
271 // an APIC ID of 255 or greater.\r
272 //\r
273 AcquireSpinLock(&PeiCpuMpData->MpLock);\r
274 PeiCpuMpData->X2ApicEnable = TRUE;\r
275 ReleaseSpinLock(&PeiCpuMpData->MpLock);\r
276 }\r
277 //\r
278 // Sync BSP's Mtrr table to all wakeup APs and load microcode on APs.\r
279 //\r
280 MtrrSetAllMtrrs (&PeiCpuMpData->MtrrTable);\r
719ff8cf 281 MicrocodeDetect (PeiCpuMpData);\r
c87e41b4
JF
282 PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle;\r
283 } else {\r
2f0261b7 284 //\r
c87e41b4 285 // Execute AP function if AP is not disabled\r
2f0261b7 286 //\r
c87e41b4
JF
287 GetProcessorNumber (PeiCpuMpData, &ProcessorNumber);\r
288 if (PeiCpuMpData->ApLoopMode == ApInHltLoop) {\r
289 //\r
290 // Restore AP's volatile registers saved\r
291 //\r
292 RestoreVolatileRegisters (&PeiCpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);\r
293 }\r
294\r
295 if ((PeiCpuMpData->CpuData[ProcessorNumber].State != CpuStateDisabled) &&\r
296 (PeiCpuMpData->ApFunction != 0)) {\r
297 PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateBusy;\r
298 Procedure = (EFI_AP_PROCEDURE)(UINTN)PeiCpuMpData->ApFunction;\r
299 //\r
300 // Invoke AP function here\r
301 //\r
302 Procedure ((VOID *)(UINTN)PeiCpuMpData->ApFunctionArgument);\r
303 //\r
304 // Re-get the processor number due to BSP/AP maybe exchange in AP function\r
305 //\r
306 GetProcessorNumber (PeiCpuMpData, &ProcessorNumber);\r
307 PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle;\r
308 }\r
2f0261b7 309 }\r
c87e41b4 310\r
ea0f431c 311 //\r
c87e41b4 312 // AP finished executing C code\r
ea0f431c 313 //\r
c87e41b4
JF
314 InterlockedIncrement ((UINT32 *)&PeiCpuMpData->FinishedCount);\r
315\r
ea0f431c 316 //\r
c87e41b4 317 // Place AP is specified loop mode\r
ea0f431c 318 //\r
c87e41b4
JF
319 if (PeiCpuMpData->ApLoopMode == ApInHltLoop) {\r
320 //\r
321 // Save AP volatile registers\r
322 //\r
323 SaveVolatileRegisters (&PeiCpuMpData->CpuData[ProcessorNumber].VolatileRegisters);\r
324 //\r
325 // Place AP in Hlt-loop\r
326 //\r
327 while (TRUE) {\r
328 DisableInterrupts ();\r
329 CpuSleep ();\r
330 CpuPause ();\r
331 }\r
332 }\r
333 ApStartupSignalBuffer = PeiCpuMpData->CpuData[ProcessorNumber].StartupApSignal;\r
c87e41b4
JF
334 while (TRUE) {\r
335 DisableInterrupts ();\r
336 if (PeiCpuMpData->ApLoopMode == ApInMwaitLoop) {\r
337 //\r
338 // Place AP in Mwait-loop\r
339 //\r
340 AsmMonitor ((UINTN)ApStartupSignalBuffer, 0, 0);\r
341 if (*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) {\r
342 //\r
343 // If AP start-up signal is not set, place AP into\r
344 // the maximum C-state\r
345 //\r
346 AsmMwait (PeiCpuMpData->ApTargetCState << 4, 0);\r
347 }\r
348 } else if (PeiCpuMpData->ApLoopMode == ApInRunLoop) {\r
349 //\r
350 // Place AP in Run-loop\r
351 //\r
352 CpuPause ();\r
353 } else {\r
354 ASSERT (FALSE);\r
355 }\r
f40a7de4 356\r
c972495e 357 //\r
c87e41b4
JF
358 // If AP start-up signal is written, AP is waken up\r
359 // otherwise place AP in loop again\r
c972495e 360 //\r
c87e41b4 361 if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) {\r
4da1ebf3
JF
362 //\r
363 // Clear AP start-up signal when AP waken up\r
364 //\r
365 InterlockedCompareExchange32 (\r
366 (UINT32 *)ApStartupSignalBuffer,\r
367 WAKEUP_AP_SIGNAL,\r
368 0\r
369 );\r
c87e41b4
JF
370 break;\r
371 }\r
ea0f431c
JF
372 }\r
373 }\r
ea0f431c
JF
374}\r
375\r
4da1ebf3
JF
376/**\r
377 Write AP start-up signal to wakeup AP.\r
378\r
379 @param ApStartupSignalBuffer Pointer to AP wakeup signal\r
380**/\r
381VOID\r
382WriteStartupSignal (\r
383 IN volatile UINT32 *ApStartupSignalBuffer\r
384 )\r
385{\r
386 *ApStartupSignalBuffer = WAKEUP_AP_SIGNAL;\r
387 //\r
388 // If AP is waken up, StartupApSignal should be cleared.\r
389 // Otherwise, write StartupApSignal again till AP waken up.\r
390 //\r
391 while (InterlockedCompareExchange32 (\r
392 (UINT32 *)ApStartupSignalBuffer,\r
393 WAKEUP_AP_SIGNAL,\r
394 WAKEUP_AP_SIGNAL\r
395 ) != 0) {\r
396 CpuPause ();\r
397 }\r
398}\r
399\r
ea0f431c
JF
400/**\r
401 This function will be called by BSP to wakeup AP.\r
402\r
403 @param PeiCpuMpData Pointer to PEI CPU MP Data\r
404 @param Broadcast TRUE: Send broadcast IPI to all APs\r
405 FALSE: Send IPI to AP by ApicId\r
a09647f3 406 @param ProcessorNumber The handle number of specified processor\r
ea0f431c
JF
407 @param Procedure The function to be invoked by AP\r
408 @param ProcedureArgument The argument to be passed into AP function\r
409**/\r
410VOID\r
411WakeUpAP (\r
412 IN PEI_CPU_MP_DATA *PeiCpuMpData,\r
413 IN BOOLEAN Broadcast,\r
a09647f3 414 IN UINTN ProcessorNumber,\r
ea0f431c
JF
415 IN EFI_AP_PROCEDURE Procedure, OPTIONAL\r
416 IN VOID *ProcedureArgument OPTIONAL\r
417 )\r
418{\r
419 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;\r
a09647f3 420 UINTN Index;\r
ea0f431c
JF
421\r
422 PeiCpuMpData->ApFunction = (UINTN) Procedure;\r
423 PeiCpuMpData->ApFunctionArgument = (UINTN) ProcedureArgument;\r
424 PeiCpuMpData->FinishedCount = 0;\r
425\r
426 ExchangeInfo = PeiCpuMpData->MpCpuExchangeInfo;\r
427 ExchangeInfo->Lock = 0;\r
428 ExchangeInfo->StackStart = PeiCpuMpData->Buffer;\r
429 ExchangeInfo->StackSize = PeiCpuMpData->CpuApStackSize;\r
430 ExchangeInfo->BufferStart = PeiCpuMpData->WakeupBuffer;\r
431 ExchangeInfo->PmodeOffset = PeiCpuMpData->AddressMap.PModeEntryOffset;\r
432 ExchangeInfo->LmodeOffset = PeiCpuMpData->AddressMap.LModeEntryOffset;\r
433 ExchangeInfo->Cr3 = AsmReadCr3 ();\r
ed04bffe
JF
434 ExchangeInfo->CodeSegment = AsmReadCs ();\r
435 ExchangeInfo->DataSegment = AsmReadDs ();\r
ea0f431c
JF
436 ExchangeInfo->CFunction = (UINTN) ApCFunction;\r
437 ExchangeInfo->NumApsExecuting = 0;\r
438 ExchangeInfo->PeiCpuMpData = PeiCpuMpData;\r
439\r
440 //\r
441 // Get the BSP's data of GDT and IDT\r
442 //\r
9c3d2f9a 443 AsmReadGdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->GdtrProfile);\r
ea0f431c
JF
444 AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);\r
445\r
a09647f3
JF
446 if (PeiCpuMpData->ApLoopMode == ApInMwaitLoop) {\r
447 //\r
448 // Get AP target C-state each time when waking up AP,\r
449 // for it maybe updated by platform again\r
450 //\r
451 PeiCpuMpData->ApTargetCState = PcdGet8 (PcdCpuApTargetCstate);\r
ea0f431c
JF
452 }\r
453\r
a09647f3
JF
454 //\r
455 // Wakeup APs per AP loop state\r
456 //\r
457 if (PeiCpuMpData->ApLoopMode == ApInHltLoop || PeiCpuMpData->InitFlag) {\r
458 if (Broadcast) {\r
459 SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);\r
460 } else {\r
461 SendInitSipiSipi (\r
462 PeiCpuMpData->CpuData[ProcessorNumber].ApicId,\r
463 (UINT32) ExchangeInfo->BufferStart\r
464 );\r
465 }\r
466 } else if ((PeiCpuMpData->ApLoopMode == ApInMwaitLoop) ||\r
467 (PeiCpuMpData->ApLoopMode == ApInRunLoop)) {\r
468 if (Broadcast) {\r
469 for (Index = 0; Index < PeiCpuMpData->CpuCount; Index++) {\r
470 if (Index != PeiCpuMpData->BspNumber) {\r
4da1ebf3 471 WriteStartupSignal (PeiCpuMpData->CpuData[Index].StartupApSignal);\r
a09647f3
JF
472 }\r
473 }\r
474 } else {\r
4da1ebf3 475 WriteStartupSignal (PeiCpuMpData->CpuData[ProcessorNumber].StartupApSignal);\r
a09647f3
JF
476 }\r
477 } else {\r
478 ASSERT (FALSE);\r
479 }\r
ea0f431c
JF
480 return ;\r
481}\r
482\r
483/**\r
484 Get available system memory below 1MB by specified size.\r
485\r
486 @param WakeupBufferSize Wakeup buffer size required\r
487\r
488 @retval other Return wakeup buffer address below 1MB.\r
489 @retval -1 Cannot find free memory below 1MB.\r
490**/\r
491UINTN\r
492GetWakeupBuffer (\r
493 IN UINTN WakeupBufferSize\r
494 )\r
495{\r
496 EFI_PEI_HOB_POINTERS Hob;\r
497 UINTN WakeupBufferStart;\r
498 UINTN WakeupBufferEnd;\r
499\r
500 //\r
501 // Get the HOB list for processing\r
502 //\r
503 Hob.Raw = GetHobList ();\r
504\r
505 //\r
506 // Collect memory ranges\r
507 //\r
508 while (!END_OF_HOB_LIST (Hob)) {\r
509 if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
510 if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) &&\r
511 (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&\r
512 ((Hob.ResourceDescriptor->ResourceAttribute &\r
513 (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |\r
514 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |\r
515 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED\r
516 )) == 0)\r
517 ) {\r
518 //\r
519 // Need memory under 1MB to be collected here\r
520 //\r
521 WakeupBufferEnd = (UINTN) (Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength);\r
522 if (WakeupBufferEnd > BASE_1MB) {\r
523 //\r
524 // Wakeup buffer should be under 1MB\r
525 //\r
526 WakeupBufferEnd = BASE_1MB;\r
527 }\r
528 //\r
529 // Wakeup buffer should be aligned on 4KB\r
530 //\r
531 WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1);\r
532 if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) {\r
533 continue;\r
534 }\r
535 //\r
536 // Create a memory allocation HOB.\r
537 //\r
538 BuildMemoryAllocationHob (\r
539 WakeupBufferStart,\r
540 WakeupBufferSize,\r
541 EfiBootServicesData\r
542 );\r
543 return WakeupBufferStart;\r
544 }\r
545 }\r
546 //\r
547 // Find the next HOB\r
548 //\r
549 Hob.Raw = GET_NEXT_HOB (Hob);\r
550 }\r
551\r
552 return (UINTN) -1;\r
553}\r
554\r
555/**\r
556 Get available system memory below 1MB by specified size.\r
557\r
558 @param PeiCpuMpData Pointer to PEI CPU MP Data\r
559**/\r
560VOID\r
561BackupAndPrepareWakeupBuffer(\r
562 IN PEI_CPU_MP_DATA *PeiCpuMpData\r
563 )\r
564{\r
565 CopyMem (\r
566 (VOID *) PeiCpuMpData->BackupBuffer,\r
567 (VOID *) PeiCpuMpData->WakeupBuffer,\r
568 PeiCpuMpData->BackupBufferSize\r
569 );\r
570 CopyMem (\r
571 (VOID *) PeiCpuMpData->WakeupBuffer,\r
572 (VOID *) PeiCpuMpData->AddressMap.RendezvousFunnelAddress,\r
573 PeiCpuMpData->AddressMap.RendezvousFunnelSize\r
574 );\r
575}\r
576\r
577/**\r
578 Restore wakeup buffer data.\r
579\r
580 @param PeiCpuMpData Pointer to PEI CPU MP Data\r
581**/\r
582VOID\r
583RestoreWakeupBuffer(\r
584 IN PEI_CPU_MP_DATA *PeiCpuMpData\r
585 )\r
586{\r
587 CopyMem ((VOID *) PeiCpuMpData->WakeupBuffer, (VOID *) PeiCpuMpData->BackupBuffer, PeiCpuMpData->BackupBufferSize);\r
588}\r
589\r
590/**\r
591 This function will get CPU count in the system.\r
592\r
593 @param PeiCpuMpData Pointer to PEI CPU MP Data\r
594\r
595 @return AP processor count\r
596**/\r
597UINT32\r
598CountProcessorNumber (\r
599 IN PEI_CPU_MP_DATA *PeiCpuMpData\r
600 )\r
601{\r
602 //\r
603 // Load Microcode on BSP\r
604 //\r
719ff8cf 605 MicrocodeDetect (PeiCpuMpData);\r
ea0f431c
JF
606 //\r
607 // Store BSP's MTRR setting\r
608 //\r
609 MtrrGetAllMtrrs (&PeiCpuMpData->MtrrTable);\r
944f45ae 610\r
ea0f431c 611 //\r
944f45ae 612 // Only perform AP detection if PcdCpuMaxLogicalProcessorNumber is greater than 1\r
ea0f431c 613 //\r
944f45ae
MK
614 if (PcdGet32 (PcdCpuMaxLogicalProcessorNumber) > 1) {\r
615 //\r
2f0261b7 616 // Send 1st broadcast IPI to APs to wakeup APs\r
944f45ae 617 //\r
2f0261b7
JF
618 PeiCpuMpData->InitFlag = TRUE;\r
619 PeiCpuMpData->X2ApicEnable = FALSE;\r
944f45ae
MK
620 WakeUpAP (PeiCpuMpData, TRUE, 0, NULL, NULL);\r
621 //\r
622 // Wait for AP task to complete and then exit.\r
623 //\r
624 MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds));\r
2f0261b7 625 PeiCpuMpData->InitFlag = FALSE;\r
944f45ae
MK
626 PeiCpuMpData->CpuCount += (UINT32)PeiCpuMpData->MpCpuExchangeInfo->NumApsExecuting;\r
627 ASSERT (PeiCpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));\r
628 //\r
c7981a11
JF
629 // Wait for all APs finished the initialization\r
630 //\r
631 while (PeiCpuMpData->FinishedCount < (PeiCpuMpData->CpuCount - 1)) {\r
632 CpuPause ();\r
633 }\r
634\r
635 if (PeiCpuMpData->X2ApicEnable) {\r
636 DEBUG ((EFI_D_INFO, "Force x2APIC mode!\n"));\r
637 //\r
a09647f3 638 // Wakeup all APs to enable x2APIC mode\r
c7981a11
JF
639 //\r
640 WakeUpAP (PeiCpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL);\r
641 //\r
642 // Wait for all known APs finished\r
643 //\r
644 while (PeiCpuMpData->FinishedCount < (PeiCpuMpData->CpuCount - 1)) {\r
645 CpuPause ();\r
646 }\r
647 //\r
648 // Enable x2APIC on BSP\r
649 //\r
650 SetApicMode (LOCAL_APIC_MODE_X2APIC);\r
651 }\r
652 DEBUG ((EFI_D_INFO, "APIC MODE is %d\n", GetApicMode ()));\r
653 //\r
944f45ae
MK
654 // Sort BSP/Aps by CPU APIC ID in ascending order\r
655 //\r
656 SortApicId (PeiCpuMpData);\r
657 }\r
ea0f431c
JF
658\r
659 DEBUG ((EFI_D_INFO, "CpuMpPei: Find %d processors in system.\n", PeiCpuMpData->CpuCount));\r
660 return PeiCpuMpData->CpuCount;\r
661}\r
662\r
663/**\r
664 Prepare for AP wakeup buffer and copy AP reset code into it.\r
665\r
666 Get wakeup buffer below 1MB. Allocate memory for CPU MP Data and APs Stack.\r
667\r
668 @return Pointer to PEI CPU MP Data\r
669**/\r
670PEI_CPU_MP_DATA *\r
671PrepareAPStartupVector (\r
672 VOID\r
673 )\r
674{\r
675 EFI_STATUS Status;\r
676 UINT32 MaxCpuCount;\r
677 PEI_CPU_MP_DATA *PeiCpuMpData;\r
678 EFI_PHYSICAL_ADDRESS Buffer;\r
679 UINTN BufferSize;\r
680 UINTN WakeupBuffer;\r
681 UINTN WakeupBufferSize;\r
682 MP_ASSEMBLY_ADDRESS_MAP AddressMap;\r
e001e11f
JF
683 UINT8 ApLoopMode;\r
684 UINT16 MonitorFilterSize;\r
685 UINT8 *MonitorBuffer;\r
686 UINTN Index;\r
ea0f431c
JF
687\r
688 AsmGetAddressMap (&AddressMap);\r
689 WakeupBufferSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);\r
690 WakeupBuffer = GetWakeupBuffer ((WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1));\r
691 ASSERT (WakeupBuffer != (UINTN) -1);\r
692 DEBUG ((EFI_D_INFO, "CpuMpPei: WakeupBuffer = 0x%x\n", WakeupBuffer));\r
693\r
694 //\r
e001e11f
JF
695 // Allocate Pages for APs stack, CPU MP Data, backup buffer for wakeup buffer,\r
696 // and monitor buffer if required.\r
ea0f431c
JF
697 //\r
698 MaxCpuCount = PcdGet32(PcdCpuMaxLogicalProcessorNumber);\r
699 BufferSize = PcdGet32 (PcdCpuApStackSize) * MaxCpuCount + sizeof (PEI_CPU_MP_DATA)\r
700 + WakeupBufferSize + sizeof (PEI_CPU_DATA) * MaxCpuCount;\r
e001e11f
JF
701 ApLoopMode = GetApLoopMode (&MonitorFilterSize);\r
702 BufferSize += MonitorFilterSize * MaxCpuCount;\r
ea0f431c
JF
703 Status = PeiServicesAllocatePages (\r
704 EfiBootServicesData,\r
705 EFI_SIZE_TO_PAGES (BufferSize),\r
706 &Buffer\r
707 );\r
708 ASSERT_EFI_ERROR (Status);\r
709\r
710 PeiCpuMpData = (PEI_CPU_MP_DATA *) (UINTN) (Buffer + PcdGet32 (PcdCpuApStackSize) * MaxCpuCount);\r
711 PeiCpuMpData->Buffer = (UINTN) Buffer;\r
712 PeiCpuMpData->CpuApStackSize = PcdGet32 (PcdCpuApStackSize);\r
713 PeiCpuMpData->WakeupBuffer = WakeupBuffer;\r
714 PeiCpuMpData->BackupBuffer = (UINTN)PeiCpuMpData + sizeof (PEI_CPU_MP_DATA);\r
715 PeiCpuMpData->BackupBufferSize = WakeupBufferSize;\r
716 PeiCpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeupBuffer + AddressMap.RendezvousFunnelSize);\r
717\r
718 PeiCpuMpData->CpuCount = 1;\r
719 PeiCpuMpData->BspNumber = 0;\r
28f27af6
JF
720 PeiCpuMpData->CpuData = (PEI_CPU_DATA *) (PeiCpuMpData->BackupBuffer +\r
721 PeiCpuMpData->BackupBufferSize);\r
ea0f431c
JF
722 PeiCpuMpData->CpuData[0].ApicId = GetInitialApicId ();\r
723 PeiCpuMpData->CpuData[0].Health.Uint32 = 0;\r
724 PeiCpuMpData->EndOfPeiFlag = FALSE;\r
2f0261b7 725 InitializeSpinLock(&PeiCpuMpData->MpLock);\r
22cfe73a 726 SaveVolatileRegisters (&PeiCpuMpData->CpuData[0].VolatileRegisters);\r
ea0f431c 727 CopyMem (&PeiCpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));\r
e001e11f
JF
728 //\r
729 // Initialize AP loop mode\r
730 //\r
731 PeiCpuMpData->ApLoopMode = ApLoopMode;\r
732 DEBUG ((EFI_D_INFO, "AP Loop Mode is %d\n", PeiCpuMpData->ApLoopMode));\r
733 MonitorBuffer = (UINT8 *)(PeiCpuMpData->CpuData + MaxCpuCount);\r
734 if (PeiCpuMpData->ApLoopMode != ApInHltLoop) {\r
735 //\r
736 // Set up APs wakeup signal buffer\r
737 //\r
738 for (Index = 0; Index < MaxCpuCount; Index++) {\r
739 PeiCpuMpData->CpuData[Index].StartupApSignal = \r
740 (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);\r
741 }\r
742 }\r
ea0f431c
JF
743 //\r
744 // Backup original data and copy AP reset code in it\r
745 //\r
746 BackupAndPrepareWakeupBuffer(PeiCpuMpData);\r
747\r
748 return PeiCpuMpData;\r
749}\r
750\r
751/**\r
752 Notify function on End Of Pei PPI.\r
753\r
754 On S3 boot, this function will restore wakeup buffer data.\r
755 On normal boot, this function will flag wakeup buffer to be un-used type.\r
756\r
757 @param PeiServices The pointer to the PEI Services Table.\r
758 @param NotifyDescriptor Address of the notification descriptor data structure.\r
759 @param Ppi Address of the PPI that was installed.\r
760\r
761 @retval EFI_SUCCESS When everything is OK.\r
762\r
763**/\r
764EFI_STATUS\r
765EFIAPI\r
766CpuMpEndOfPeiCallback (\r
767 IN EFI_PEI_SERVICES **PeiServices,\r
768 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
769 IN VOID *Ppi\r
770 )\r
771{\r
772 EFI_STATUS Status;\r
773 EFI_BOOT_MODE BootMode;\r
774 PEI_CPU_MP_DATA *PeiCpuMpData;\r
775 EFI_PEI_HOB_POINTERS Hob;\r
776 EFI_HOB_MEMORY_ALLOCATION *MemoryHob;\r
777\r
c972495e 778 DEBUG ((EFI_D_INFO, "CpuMpPei: CpuMpEndOfPeiCallback () invoked\n"));\r
ea0f431c
JF
779\r
780 Status = PeiServicesGetBootMode (&BootMode);\r
781 ASSERT_EFI_ERROR (Status);\r
782\r
783 PeiCpuMpData = GetMpHobData ();\r
784 ASSERT (PeiCpuMpData != NULL);\r
785\r
786 if (BootMode != BOOT_ON_S3_RESUME) {\r
787 //\r
788 // Get the HOB list for processing\r
789 //\r
790 Hob.Raw = GetHobList ();\r
791 //\r
792 // Collect memory ranges\r
793 //\r
794 while (!END_OF_HOB_LIST (Hob)) {\r
795 if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {\r
796 MemoryHob = Hob.MemoryAllocation;\r
797 if(MemoryHob->AllocDescriptor.MemoryBaseAddress == PeiCpuMpData->WakeupBuffer) {\r
798 //\r
799 // Flag this HOB type to un-used\r
800 //\r
801 GET_HOB_TYPE (Hob) = EFI_HOB_TYPE_UNUSED;\r
802 break;\r
803 }\r
804 }\r
805 Hob.Raw = GET_NEXT_HOB (Hob);\r
806 }\r
807 } else {\r
808 RestoreWakeupBuffer (PeiCpuMpData);\r
809 PeiCpuMpData->EndOfPeiFlag = TRUE;\r
810 }\r
811 return EFI_SUCCESS;\r
812}\r
813\r
814/**\r
815 The Entry point of the MP CPU PEIM.\r
816\r
817 This function will wakeup APs and collect CPU AP count and install the\r
818 Mp Service Ppi.\r
819\r
820 @param FileHandle Handle of the file being invoked.\r
821 @param PeiServices Describes the list of possible PEI Services.\r
822\r
823 @retval EFI_SUCCESS MpServicePpi is installed successfully.\r
824\r
825**/\r
826EFI_STATUS\r
827EFIAPI\r
828CpuMpPeimInit (\r
829 IN EFI_PEI_FILE_HANDLE FileHandle,\r
830 IN CONST EFI_PEI_SERVICES **PeiServices\r
831 )\r
832{\r
9bedfb2f
JF
833 EFI_STATUS Status;\r
834 PEI_CPU_MP_DATA *PeiCpuMpData;\r
835 EFI_VECTOR_HANDOFF_INFO *VectorInfo;\r
836 EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi;\r
ea0f431c 837\r
ea0f431c 838 //\r
9bedfb2f
JF
839 // Get Vector Hand-off Info PPI\r
840 //\r
841 VectorInfo = NULL;\r
842 Status = PeiServicesLocatePpi (\r
843 &gEfiVectorHandoffInfoPpiGuid,\r
844 0,\r
845 NULL,\r
846 (VOID **)&VectorHandoffInfoPpi\r
847 );\r
848 if (Status == EFI_SUCCESS) {\r
849 VectorInfo = VectorHandoffInfoPpi->Info;\r
850 }\r
851 Status = InitializeCpuExceptionHandlers (VectorInfo);\r
852 ASSERT_EFI_ERROR (Status);\r
853 //\r
ea0f431c
JF
854 // Get wakeup buffer and copy AP reset code in it\r
855 //\r
856 PeiCpuMpData = PrepareAPStartupVector ();\r
857 //\r
858 // Count processor number and collect processor information\r
859 //\r
6c7f3f1d 860 CountProcessorNumber (PeiCpuMpData);\r
ea0f431c
JF
861 //\r
862 // Build location of PEI CPU MP DATA buffer in HOB\r
863 //\r
864 BuildGuidDataHob (\r
865 &gEfiCallerIdGuid,\r
866 (VOID *)&PeiCpuMpData,\r
867 sizeof(UINT64)\r
868 );\r
869 //\r
870 // Update and publish CPU BIST information\r
871 //\r
872 CollectBistDataFromPpi (PeiServices, PeiCpuMpData);\r
873 //\r
874 // register an event for EndOfPei\r
875 //\r
876 Status = PeiServicesNotifyPpi (&mNotifyList);\r
877 ASSERT_EFI_ERROR (Status);\r
878 //\r
879 // Install CPU MP PPI\r
880 //\r
881 Status = PeiServicesInstallPpi(&mPeiCpuMpPpiDesc);\r
882 ASSERT_EFI_ERROR (Status);\r
883\r
884 return Status;\r
885}\r