]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/CpuMpPei/CpuMpPei.c
UefiCpuPkg/CpuMpPei: Do not load new GDT table
[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
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
4de216c0
JF
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
ea0f431c
JF
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
ef1fdb80 192/**\r
5ac96e3a 193 Save the volatile registers required to be restored following INIT IPI.\r
ef1fdb80
JF
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
5ac96e3a 224 Restore the volatile registers following INIT IPI.\r
ef1fdb80
JF
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
ea0f431c
JF
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
c972495e 263 @param NumApsExecuting Number of current executing AP\r
ea0f431c
JF
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
c87e41b4 276 volatile UINT32 *ApStartupSignalBuffer;\r
ea0f431c
JF
277\r
278 PeiCpuMpData = ExchangeInfo->PeiCpuMpData;\r
c87e41b4
JF
279 while (TRUE) {\r
280 if (PeiCpuMpData->InitFlag) {\r
281 ProcessorNumber = NumApsExecuting;\r
282 //\r
283 // Sync BSP's Control registers to APs\r
284 //\r
285 RestoreVolatileRegisters (&PeiCpuMpData->CpuData[0].VolatileRegisters, FALSE);\r
286 //\r
287 // This is first time AP wakeup, get BIST information from AP stack\r
288 //\r
289 BistData = *(UINTN *) (PeiCpuMpData->Buffer + ProcessorNumber * PeiCpuMpData->CpuApStackSize - sizeof (UINTN));\r
290 PeiCpuMpData->CpuData[ProcessorNumber].Health.Uint32 = (UINT32) BistData;\r
291 PeiCpuMpData->CpuData[ProcessorNumber].ApicId = GetInitialApicId ();\r
292 if (PeiCpuMpData->CpuData[ProcessorNumber].ApicId >= 0xFF) {\r
293 //\r
294 // Set x2APIC mode if there are any logical processor reporting\r
295 // an APIC ID of 255 or greater.\r
296 //\r
297 AcquireSpinLock(&PeiCpuMpData->MpLock);\r
298 PeiCpuMpData->X2ApicEnable = TRUE;\r
299 ReleaseSpinLock(&PeiCpuMpData->MpLock);\r
300 }\r
301 //\r
302 // Sync BSP's Mtrr table to all wakeup APs and load microcode on APs.\r
303 //\r
304 MtrrSetAllMtrrs (&PeiCpuMpData->MtrrTable);\r
719ff8cf 305 MicrocodeDetect (PeiCpuMpData);\r
c87e41b4
JF
306 PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle;\r
307 } else {\r
2f0261b7 308 //\r
c87e41b4 309 // Execute AP function if AP is not disabled\r
2f0261b7 310 //\r
c87e41b4
JF
311 GetProcessorNumber (PeiCpuMpData, &ProcessorNumber);\r
312 if (PeiCpuMpData->ApLoopMode == ApInHltLoop) {\r
313 //\r
314 // Restore AP's volatile registers saved\r
315 //\r
316 RestoreVolatileRegisters (&PeiCpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);\r
317 }\r
318\r
319 if ((PeiCpuMpData->CpuData[ProcessorNumber].State != CpuStateDisabled) &&\r
320 (PeiCpuMpData->ApFunction != 0)) {\r
321 PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateBusy;\r
322 Procedure = (EFI_AP_PROCEDURE)(UINTN)PeiCpuMpData->ApFunction;\r
323 //\r
324 // Invoke AP function here\r
325 //\r
326 Procedure ((VOID *)(UINTN)PeiCpuMpData->ApFunctionArgument);\r
327 //\r
328 // Re-get the processor number due to BSP/AP maybe exchange in AP function\r
329 //\r
330 GetProcessorNumber (PeiCpuMpData, &ProcessorNumber);\r
331 PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle;\r
332 }\r
2f0261b7 333 }\r
c87e41b4 334\r
ea0f431c 335 //\r
c87e41b4 336 // AP finished executing C code\r
ea0f431c 337 //\r
c87e41b4
JF
338 InterlockedIncrement ((UINT32 *)&PeiCpuMpData->FinishedCount);\r
339\r
ea0f431c 340 //\r
c87e41b4 341 // Place AP is specified loop mode\r
ea0f431c 342 //\r
c87e41b4
JF
343 if (PeiCpuMpData->ApLoopMode == ApInHltLoop) {\r
344 //\r
345 // Save AP volatile registers\r
346 //\r
347 SaveVolatileRegisters (&PeiCpuMpData->CpuData[ProcessorNumber].VolatileRegisters);\r
348 //\r
349 // Place AP in Hlt-loop\r
350 //\r
351 while (TRUE) {\r
352 DisableInterrupts ();\r
353 CpuSleep ();\r
354 CpuPause ();\r
355 }\r
356 }\r
357 ApStartupSignalBuffer = PeiCpuMpData->CpuData[ProcessorNumber].StartupApSignal;\r
c87e41b4
JF
358 while (TRUE) {\r
359 DisableInterrupts ();\r
360 if (PeiCpuMpData->ApLoopMode == ApInMwaitLoop) {\r
361 //\r
362 // Place AP in Mwait-loop\r
363 //\r
364 AsmMonitor ((UINTN)ApStartupSignalBuffer, 0, 0);\r
365 if (*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) {\r
366 //\r
367 // If AP start-up signal is not set, place AP into\r
368 // the maximum C-state\r
369 //\r
370 AsmMwait (PeiCpuMpData->ApTargetCState << 4, 0);\r
371 }\r
372 } else if (PeiCpuMpData->ApLoopMode == ApInRunLoop) {\r
373 //\r
374 // Place AP in Run-loop\r
375 //\r
376 CpuPause ();\r
377 } else {\r
378 ASSERT (FALSE);\r
379 }\r
f40a7de4 380\r
c972495e 381 //\r
c87e41b4
JF
382 // If AP start-up signal is written, AP is waken up\r
383 // otherwise place AP in loop again\r
c972495e 384 //\r
c87e41b4 385 if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) {\r
4da1ebf3
JF
386 //\r
387 // Clear AP start-up signal when AP waken up\r
388 //\r
389 InterlockedCompareExchange32 (\r
390 (UINT32 *)ApStartupSignalBuffer,\r
391 WAKEUP_AP_SIGNAL,\r
392 0\r
393 );\r
c87e41b4
JF
394 break;\r
395 }\r
ea0f431c
JF
396 }\r
397 }\r
ea0f431c
JF
398}\r
399\r
4da1ebf3
JF
400/**\r
401 Write AP start-up signal to wakeup AP.\r
402\r
403 @param ApStartupSignalBuffer Pointer to AP wakeup signal\r
404**/\r
405VOID\r
406WriteStartupSignal (\r
407 IN volatile UINT32 *ApStartupSignalBuffer\r
408 )\r
409{\r
410 *ApStartupSignalBuffer = WAKEUP_AP_SIGNAL;\r
411 //\r
412 // If AP is waken up, StartupApSignal should be cleared.\r
413 // Otherwise, write StartupApSignal again till AP waken up.\r
414 //\r
415 while (InterlockedCompareExchange32 (\r
416 (UINT32 *)ApStartupSignalBuffer,\r
417 WAKEUP_AP_SIGNAL,\r
418 WAKEUP_AP_SIGNAL\r
419 ) != 0) {\r
420 CpuPause ();\r
421 }\r
422}\r
423\r
ea0f431c
JF
424/**\r
425 This function will be called by BSP to wakeup AP.\r
426\r
427 @param PeiCpuMpData Pointer to PEI CPU MP Data\r
428 @param Broadcast TRUE: Send broadcast IPI to all APs\r
429 FALSE: Send IPI to AP by ApicId\r
a09647f3 430 @param ProcessorNumber The handle number of specified processor\r
ea0f431c
JF
431 @param Procedure The function to be invoked by AP\r
432 @param ProcedureArgument The argument to be passed into AP function\r
433**/\r
434VOID\r
435WakeUpAP (\r
436 IN PEI_CPU_MP_DATA *PeiCpuMpData,\r
437 IN BOOLEAN Broadcast,\r
a09647f3 438 IN UINTN ProcessorNumber,\r
ea0f431c
JF
439 IN EFI_AP_PROCEDURE Procedure, OPTIONAL\r
440 IN VOID *ProcedureArgument OPTIONAL\r
441 )\r
442{\r
443 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;\r
a09647f3 444 UINTN Index;\r
ea0f431c
JF
445\r
446 PeiCpuMpData->ApFunction = (UINTN) Procedure;\r
447 PeiCpuMpData->ApFunctionArgument = (UINTN) ProcedureArgument;\r
448 PeiCpuMpData->FinishedCount = 0;\r
449\r
450 ExchangeInfo = PeiCpuMpData->MpCpuExchangeInfo;\r
451 ExchangeInfo->Lock = 0;\r
452 ExchangeInfo->StackStart = PeiCpuMpData->Buffer;\r
453 ExchangeInfo->StackSize = PeiCpuMpData->CpuApStackSize;\r
454 ExchangeInfo->BufferStart = PeiCpuMpData->WakeupBuffer;\r
455 ExchangeInfo->PmodeOffset = PeiCpuMpData->AddressMap.PModeEntryOffset;\r
456 ExchangeInfo->LmodeOffset = PeiCpuMpData->AddressMap.LModeEntryOffset;\r
457 ExchangeInfo->Cr3 = AsmReadCr3 ();\r
ed04bffe
JF
458 ExchangeInfo->CodeSegment = AsmReadCs ();\r
459 ExchangeInfo->DataSegment = AsmReadDs ();\r
ea0f431c
JF
460 ExchangeInfo->CFunction = (UINTN) ApCFunction;\r
461 ExchangeInfo->NumApsExecuting = 0;\r
462 ExchangeInfo->PeiCpuMpData = PeiCpuMpData;\r
463\r
464 //\r
465 // Get the BSP's data of GDT and IDT\r
466 //\r
9c3d2f9a 467 AsmReadGdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->GdtrProfile);\r
ea0f431c
JF
468 AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);\r
469\r
a09647f3
JF
470 if (PeiCpuMpData->ApLoopMode == ApInMwaitLoop) {\r
471 //\r
472 // Get AP target C-state each time when waking up AP,\r
473 // for it maybe updated by platform again\r
474 //\r
475 PeiCpuMpData->ApTargetCState = PcdGet8 (PcdCpuApTargetCstate);\r
ea0f431c
JF
476 }\r
477\r
a09647f3
JF
478 //\r
479 // Wakeup APs per AP loop state\r
480 //\r
481 if (PeiCpuMpData->ApLoopMode == ApInHltLoop || PeiCpuMpData->InitFlag) {\r
482 if (Broadcast) {\r
483 SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);\r
484 } else {\r
485 SendInitSipiSipi (\r
486 PeiCpuMpData->CpuData[ProcessorNumber].ApicId,\r
487 (UINT32) ExchangeInfo->BufferStart\r
488 );\r
489 }\r
490 } else if ((PeiCpuMpData->ApLoopMode == ApInMwaitLoop) ||\r
491 (PeiCpuMpData->ApLoopMode == ApInRunLoop)) {\r
492 if (Broadcast) {\r
493 for (Index = 0; Index < PeiCpuMpData->CpuCount; Index++) {\r
494 if (Index != PeiCpuMpData->BspNumber) {\r
4da1ebf3 495 WriteStartupSignal (PeiCpuMpData->CpuData[Index].StartupApSignal);\r
a09647f3
JF
496 }\r
497 }\r
498 } else {\r
4da1ebf3 499 WriteStartupSignal (PeiCpuMpData->CpuData[ProcessorNumber].StartupApSignal);\r
a09647f3
JF
500 }\r
501 } else {\r
502 ASSERT (FALSE);\r
503 }\r
ea0f431c
JF
504 return ;\r
505}\r
506\r
507/**\r
508 Get available system memory below 1MB by specified size.\r
509\r
510 @param WakeupBufferSize Wakeup buffer size required\r
511\r
512 @retval other Return wakeup buffer address below 1MB.\r
513 @retval -1 Cannot find free memory below 1MB.\r
514**/\r
515UINTN\r
516GetWakeupBuffer (\r
517 IN UINTN WakeupBufferSize\r
518 )\r
519{\r
520 EFI_PEI_HOB_POINTERS Hob;\r
521 UINTN WakeupBufferStart;\r
522 UINTN WakeupBufferEnd;\r
523\r
524 //\r
525 // Get the HOB list for processing\r
526 //\r
527 Hob.Raw = GetHobList ();\r
528\r
529 //\r
530 // Collect memory ranges\r
531 //\r
532 while (!END_OF_HOB_LIST (Hob)) {\r
533 if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
534 if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) &&\r
535 (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&\r
536 ((Hob.ResourceDescriptor->ResourceAttribute &\r
537 (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |\r
538 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |\r
539 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED\r
540 )) == 0)\r
541 ) {\r
542 //\r
543 // Need memory under 1MB to be collected here\r
544 //\r
545 WakeupBufferEnd = (UINTN) (Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength);\r
546 if (WakeupBufferEnd > BASE_1MB) {\r
547 //\r
548 // Wakeup buffer should be under 1MB\r
549 //\r
550 WakeupBufferEnd = BASE_1MB;\r
551 }\r
552 //\r
553 // Wakeup buffer should be aligned on 4KB\r
554 //\r
555 WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1);\r
556 if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) {\r
557 continue;\r
558 }\r
559 //\r
560 // Create a memory allocation HOB.\r
561 //\r
562 BuildMemoryAllocationHob (\r
563 WakeupBufferStart,\r
564 WakeupBufferSize,\r
565 EfiBootServicesData\r
566 );\r
567 return WakeupBufferStart;\r
568 }\r
569 }\r
570 //\r
571 // Find the next HOB\r
572 //\r
573 Hob.Raw = GET_NEXT_HOB (Hob);\r
574 }\r
575\r
576 return (UINTN) -1;\r
577}\r
578\r
579/**\r
580 Get available system memory below 1MB by specified size.\r
581\r
582 @param PeiCpuMpData Pointer to PEI CPU MP Data\r
583**/\r
584VOID\r
585BackupAndPrepareWakeupBuffer(\r
586 IN PEI_CPU_MP_DATA *PeiCpuMpData\r
587 )\r
588{\r
589 CopyMem (\r
590 (VOID *) PeiCpuMpData->BackupBuffer,\r
591 (VOID *) PeiCpuMpData->WakeupBuffer,\r
592 PeiCpuMpData->BackupBufferSize\r
593 );\r
594 CopyMem (\r
595 (VOID *) PeiCpuMpData->WakeupBuffer,\r
596 (VOID *) PeiCpuMpData->AddressMap.RendezvousFunnelAddress,\r
597 PeiCpuMpData->AddressMap.RendezvousFunnelSize\r
598 );\r
599}\r
600\r
601/**\r
602 Restore wakeup buffer data.\r
603\r
604 @param PeiCpuMpData Pointer to PEI CPU MP Data\r
605**/\r
606VOID\r
607RestoreWakeupBuffer(\r
608 IN PEI_CPU_MP_DATA *PeiCpuMpData\r
609 )\r
610{\r
611 CopyMem ((VOID *) PeiCpuMpData->WakeupBuffer, (VOID *) PeiCpuMpData->BackupBuffer, PeiCpuMpData->BackupBufferSize);\r
612}\r
613\r
614/**\r
615 This function will get CPU count in the system.\r
616\r
617 @param PeiCpuMpData Pointer to PEI CPU MP Data\r
618\r
619 @return AP processor count\r
620**/\r
621UINT32\r
622CountProcessorNumber (\r
623 IN PEI_CPU_MP_DATA *PeiCpuMpData\r
624 )\r
625{\r
626 //\r
627 // Load Microcode on BSP\r
628 //\r
719ff8cf 629 MicrocodeDetect (PeiCpuMpData);\r
ea0f431c
JF
630 //\r
631 // Store BSP's MTRR setting\r
632 //\r
633 MtrrGetAllMtrrs (&PeiCpuMpData->MtrrTable);\r
944f45ae 634\r
ea0f431c 635 //\r
944f45ae 636 // Only perform AP detection if PcdCpuMaxLogicalProcessorNumber is greater than 1\r
ea0f431c 637 //\r
944f45ae
MK
638 if (PcdGet32 (PcdCpuMaxLogicalProcessorNumber) > 1) {\r
639 //\r
2f0261b7 640 // Send 1st broadcast IPI to APs to wakeup APs\r
944f45ae 641 //\r
2f0261b7
JF
642 PeiCpuMpData->InitFlag = TRUE;\r
643 PeiCpuMpData->X2ApicEnable = FALSE;\r
944f45ae
MK
644 WakeUpAP (PeiCpuMpData, TRUE, 0, NULL, NULL);\r
645 //\r
646 // Wait for AP task to complete and then exit.\r
647 //\r
648 MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds));\r
2f0261b7 649 PeiCpuMpData->InitFlag = FALSE;\r
944f45ae
MK
650 PeiCpuMpData->CpuCount += (UINT32)PeiCpuMpData->MpCpuExchangeInfo->NumApsExecuting;\r
651 ASSERT (PeiCpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));\r
652 //\r
c7981a11
JF
653 // Wait for all APs finished the initialization\r
654 //\r
655 while (PeiCpuMpData->FinishedCount < (PeiCpuMpData->CpuCount - 1)) {\r
656 CpuPause ();\r
657 }\r
658\r
659 if (PeiCpuMpData->X2ApicEnable) {\r
660 DEBUG ((EFI_D_INFO, "Force x2APIC mode!\n"));\r
661 //\r
a09647f3 662 // Wakeup all APs to enable x2APIC mode\r
c7981a11
JF
663 //\r
664 WakeUpAP (PeiCpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL);\r
665 //\r
666 // Wait for all known APs finished\r
667 //\r
668 while (PeiCpuMpData->FinishedCount < (PeiCpuMpData->CpuCount - 1)) {\r
669 CpuPause ();\r
670 }\r
671 //\r
672 // Enable x2APIC on BSP\r
673 //\r
674 SetApicMode (LOCAL_APIC_MODE_X2APIC);\r
675 }\r
676 DEBUG ((EFI_D_INFO, "APIC MODE is %d\n", GetApicMode ()));\r
677 //\r
944f45ae
MK
678 // Sort BSP/Aps by CPU APIC ID in ascending order\r
679 //\r
680 SortApicId (PeiCpuMpData);\r
681 }\r
ea0f431c
JF
682\r
683 DEBUG ((EFI_D_INFO, "CpuMpPei: Find %d processors in system.\n", PeiCpuMpData->CpuCount));\r
684 return PeiCpuMpData->CpuCount;\r
685}\r
686\r
687/**\r
688 Prepare for AP wakeup buffer and copy AP reset code into it.\r
689\r
690 Get wakeup buffer below 1MB. Allocate memory for CPU MP Data and APs Stack.\r
691\r
692 @return Pointer to PEI CPU MP Data\r
693**/\r
694PEI_CPU_MP_DATA *\r
695PrepareAPStartupVector (\r
696 VOID\r
697 )\r
698{\r
699 EFI_STATUS Status;\r
700 UINT32 MaxCpuCount;\r
701 PEI_CPU_MP_DATA *PeiCpuMpData;\r
702 EFI_PHYSICAL_ADDRESS Buffer;\r
703 UINTN BufferSize;\r
704 UINTN WakeupBuffer;\r
705 UINTN WakeupBufferSize;\r
706 MP_ASSEMBLY_ADDRESS_MAP AddressMap;\r
e001e11f
JF
707 UINT8 ApLoopMode;\r
708 UINT16 MonitorFilterSize;\r
709 UINT8 *MonitorBuffer;\r
710 UINTN Index;\r
ea0f431c
JF
711\r
712 AsmGetAddressMap (&AddressMap);\r
713 WakeupBufferSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);\r
714 WakeupBuffer = GetWakeupBuffer ((WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1));\r
715 ASSERT (WakeupBuffer != (UINTN) -1);\r
716 DEBUG ((EFI_D_INFO, "CpuMpPei: WakeupBuffer = 0x%x\n", WakeupBuffer));\r
717\r
718 //\r
e001e11f
JF
719 // Allocate Pages for APs stack, CPU MP Data, backup buffer for wakeup buffer,\r
720 // and monitor buffer if required.\r
ea0f431c
JF
721 //\r
722 MaxCpuCount = PcdGet32(PcdCpuMaxLogicalProcessorNumber);\r
723 BufferSize = PcdGet32 (PcdCpuApStackSize) * MaxCpuCount + sizeof (PEI_CPU_MP_DATA)\r
724 + WakeupBufferSize + sizeof (PEI_CPU_DATA) * MaxCpuCount;\r
e001e11f
JF
725 ApLoopMode = GetApLoopMode (&MonitorFilterSize);\r
726 BufferSize += MonitorFilterSize * MaxCpuCount;\r
ea0f431c
JF
727 Status = PeiServicesAllocatePages (\r
728 EfiBootServicesData,\r
729 EFI_SIZE_TO_PAGES (BufferSize),\r
730 &Buffer\r
731 );\r
732 ASSERT_EFI_ERROR (Status);\r
733\r
734 PeiCpuMpData = (PEI_CPU_MP_DATA *) (UINTN) (Buffer + PcdGet32 (PcdCpuApStackSize) * MaxCpuCount);\r
735 PeiCpuMpData->Buffer = (UINTN) Buffer;\r
736 PeiCpuMpData->CpuApStackSize = PcdGet32 (PcdCpuApStackSize);\r
737 PeiCpuMpData->WakeupBuffer = WakeupBuffer;\r
738 PeiCpuMpData->BackupBuffer = (UINTN)PeiCpuMpData + sizeof (PEI_CPU_MP_DATA);\r
739 PeiCpuMpData->BackupBufferSize = WakeupBufferSize;\r
740 PeiCpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeupBuffer + AddressMap.RendezvousFunnelSize);\r
741\r
742 PeiCpuMpData->CpuCount = 1;\r
743 PeiCpuMpData->BspNumber = 0;\r
28f27af6
JF
744 PeiCpuMpData->CpuData = (PEI_CPU_DATA *) (PeiCpuMpData->BackupBuffer +\r
745 PeiCpuMpData->BackupBufferSize);\r
ea0f431c
JF
746 PeiCpuMpData->CpuData[0].ApicId = GetInitialApicId ();\r
747 PeiCpuMpData->CpuData[0].Health.Uint32 = 0;\r
748 PeiCpuMpData->EndOfPeiFlag = FALSE;\r
2f0261b7 749 InitializeSpinLock(&PeiCpuMpData->MpLock);\r
22cfe73a 750 SaveVolatileRegisters (&PeiCpuMpData->CpuData[0].VolatileRegisters);\r
ea0f431c 751 CopyMem (&PeiCpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));\r
e001e11f
JF
752 //\r
753 // Initialize AP loop mode\r
754 //\r
755 PeiCpuMpData->ApLoopMode = ApLoopMode;\r
756 DEBUG ((EFI_D_INFO, "AP Loop Mode is %d\n", PeiCpuMpData->ApLoopMode));\r
757 MonitorBuffer = (UINT8 *)(PeiCpuMpData->CpuData + MaxCpuCount);\r
758 if (PeiCpuMpData->ApLoopMode != ApInHltLoop) {\r
759 //\r
760 // Set up APs wakeup signal buffer\r
761 //\r
762 for (Index = 0; Index < MaxCpuCount; Index++) {\r
763 PeiCpuMpData->CpuData[Index].StartupApSignal = \r
764 (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);\r
765 }\r
766 }\r
ea0f431c
JF
767 //\r
768 // Backup original data and copy AP reset code in it\r
769 //\r
770 BackupAndPrepareWakeupBuffer(PeiCpuMpData);\r
771\r
772 return PeiCpuMpData;\r
773}\r
774\r
775/**\r
776 Notify function on End Of Pei PPI.\r
777\r
778 On S3 boot, this function will restore wakeup buffer data.\r
779 On normal boot, this function will flag wakeup buffer to be un-used type.\r
780\r
781 @param PeiServices The pointer to the PEI Services Table.\r
782 @param NotifyDescriptor Address of the notification descriptor data structure.\r
783 @param Ppi Address of the PPI that was installed.\r
784\r
785 @retval EFI_SUCCESS When everything is OK.\r
786\r
787**/\r
788EFI_STATUS\r
789EFIAPI\r
790CpuMpEndOfPeiCallback (\r
791 IN EFI_PEI_SERVICES **PeiServices,\r
792 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
793 IN VOID *Ppi\r
794 )\r
795{\r
796 EFI_STATUS Status;\r
797 EFI_BOOT_MODE BootMode;\r
798 PEI_CPU_MP_DATA *PeiCpuMpData;\r
799 EFI_PEI_HOB_POINTERS Hob;\r
800 EFI_HOB_MEMORY_ALLOCATION *MemoryHob;\r
801\r
c972495e 802 DEBUG ((EFI_D_INFO, "CpuMpPei: CpuMpEndOfPeiCallback () invoked\n"));\r
ea0f431c
JF
803\r
804 Status = PeiServicesGetBootMode (&BootMode);\r
805 ASSERT_EFI_ERROR (Status);\r
806\r
807 PeiCpuMpData = GetMpHobData ();\r
808 ASSERT (PeiCpuMpData != NULL);\r
809\r
810 if (BootMode != BOOT_ON_S3_RESUME) {\r
811 //\r
812 // Get the HOB list for processing\r
813 //\r
814 Hob.Raw = GetHobList ();\r
815 //\r
816 // Collect memory ranges\r
817 //\r
818 while (!END_OF_HOB_LIST (Hob)) {\r
819 if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {\r
820 MemoryHob = Hob.MemoryAllocation;\r
821 if(MemoryHob->AllocDescriptor.MemoryBaseAddress == PeiCpuMpData->WakeupBuffer) {\r
822 //\r
823 // Flag this HOB type to un-used\r
824 //\r
825 GET_HOB_TYPE (Hob) = EFI_HOB_TYPE_UNUSED;\r
826 break;\r
827 }\r
828 }\r
829 Hob.Raw = GET_NEXT_HOB (Hob);\r
830 }\r
831 } else {\r
832 RestoreWakeupBuffer (PeiCpuMpData);\r
833 PeiCpuMpData->EndOfPeiFlag = TRUE;\r
834 }\r
835 return EFI_SUCCESS;\r
836}\r
837\r
838/**\r
839 The Entry point of the MP CPU PEIM.\r
840\r
841 This function will wakeup APs and collect CPU AP count and install the\r
842 Mp Service Ppi.\r
843\r
844 @param FileHandle Handle of the file being invoked.\r
845 @param PeiServices Describes the list of possible PEI Services.\r
846\r
847 @retval EFI_SUCCESS MpServicePpi is installed successfully.\r
848\r
849**/\r
850EFI_STATUS\r
851EFIAPI\r
852CpuMpPeimInit (\r
853 IN EFI_PEI_FILE_HANDLE FileHandle,\r
854 IN CONST EFI_PEI_SERVICES **PeiServices\r
855 )\r
856{\r
9bedfb2f
JF
857 EFI_STATUS Status;\r
858 PEI_CPU_MP_DATA *PeiCpuMpData;\r
859 EFI_VECTOR_HANDOFF_INFO *VectorInfo;\r
860 EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi;\r
ea0f431c 861\r
ea0f431c 862 //\r
9bedfb2f
JF
863 // Get Vector Hand-off Info PPI\r
864 //\r
865 VectorInfo = NULL;\r
866 Status = PeiServicesLocatePpi (\r
867 &gEfiVectorHandoffInfoPpiGuid,\r
868 0,\r
869 NULL,\r
870 (VOID **)&VectorHandoffInfoPpi\r
871 );\r
872 if (Status == EFI_SUCCESS) {\r
873 VectorInfo = VectorHandoffInfoPpi->Info;\r
874 }\r
875 Status = InitializeCpuExceptionHandlers (VectorInfo);\r
876 ASSERT_EFI_ERROR (Status);\r
877 //\r
ea0f431c
JF
878 // Get wakeup buffer and copy AP reset code in it\r
879 //\r
880 PeiCpuMpData = PrepareAPStartupVector ();\r
881 //\r
882 // Count processor number and collect processor information\r
883 //\r
6c7f3f1d 884 CountProcessorNumber (PeiCpuMpData);\r
ea0f431c
JF
885 //\r
886 // Build location of PEI CPU MP DATA buffer in HOB\r
887 //\r
888 BuildGuidDataHob (\r
889 &gEfiCallerIdGuid,\r
890 (VOID *)&PeiCpuMpData,\r
891 sizeof(UINT64)\r
892 );\r
893 //\r
894 // Update and publish CPU BIST information\r
895 //\r
896 CollectBistDataFromPpi (PeiServices, PeiCpuMpData);\r
897 //\r
898 // register an event for EndOfPei\r
899 //\r
900 Status = PeiServicesNotifyPpi (&mNotifyList);\r
901 ASSERT_EFI_ERROR (Status);\r
902 //\r
903 // Install CPU MP PPI\r
904 //\r
905 Status = PeiServicesInstallPpi(&mPeiCpuMpPpiDesc);\r
906 ASSERT_EFI_ERROR (Status);\r
907\r
908 return Status;\r
909}\r