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