]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/CpuMpPei/CpuMpPei.c
UefiCpuPkg/CpuMpPei: Prepare for monitor buffer
[mirror_edk2.git] / UefiCpuPkg / CpuMpPei / CpuMpPei.c
CommitLineData
ea0f431c
JF
1/** @file\r
2 CPU PEI Module installs CPU Multiple Processor PPI.\r
3\r
4 Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "CpuMpPei.h"\r
16\r
17//\r
18// Global Descriptor Table (GDT)\r
19//\r
20GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT mGdtEntries[] = {\r
21/* selector { Global Segment Descriptor } */\r
22/* 0x00 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //null descriptor\r
23/* 0x08 */ {{0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear data segment descriptor\r
24/* 0x10 */ {{0xffff, 0, 0, 0xf, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear code segment descriptor\r
25/* 0x18 */ {{0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor\r
26/* 0x20 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system code segment descriptor\r
27/* 0x28 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor\r
28/* 0x30 */ {{0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor\r
29/* 0x38 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 1, 0, 1, 0}}, //system code segment descriptor\r
30/* 0x40 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor\r
31};\r
32\r
33//\r
34// IA32 Gdt register\r
35//\r
36GLOBAL_REMOVE_IF_UNREFERENCED IA32_DESCRIPTOR mGdt = {\r
37 sizeof (mGdtEntries) - 1,\r
38 (UINTN) mGdtEntries\r
39 };\r
40\r
41GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = {\r
42 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
43 &gEfiEndOfPeiSignalPpiGuid,\r
44 CpuMpEndOfPeiCallback\r
45};\r
46\r
47/**\r
48 Sort the APIC ID of all processors.\r
49\r
50 This function sorts the APIC ID of all processors so that processor number is\r
51 assigned in the ascending order of APIC ID which eases MP debugging.\r
52\r
53 @param PeiCpuMpData Pointer to PEI CPU MP Data\r
54**/\r
55VOID\r
56SortApicId (\r
57 IN PEI_CPU_MP_DATA *PeiCpuMpData\r
58 )\r
59{\r
60 UINTN Index1;\r
61 UINTN Index2;\r
62 UINTN Index3;\r
63 UINT32 ApicId;\r
24930b56 64 PEI_CPU_DATA CpuData;\r
ea0f431c
JF
65 UINT32 ApCount;\r
66\r
67 ApCount = PeiCpuMpData->CpuCount - 1;\r
68\r
69 if (ApCount != 0) {\r
70 for (Index1 = 0; Index1 < ApCount; Index1++) {\r
71 Index3 = Index1;\r
72 //\r
73 // Sort key is the hardware default APIC ID\r
74 //\r
75 ApicId = PeiCpuMpData->CpuData[Index1].ApicId;\r
76 for (Index2 = Index1 + 1; Index2 <= ApCount; Index2++) {\r
77 if (ApicId > PeiCpuMpData->CpuData[Index2].ApicId) {\r
78 Index3 = Index2;\r
79 ApicId = PeiCpuMpData->CpuData[Index2].ApicId;\r
80 }\r
81 }\r
82 if (Index3 != Index1) {\r
24930b56
JF
83 CopyMem (&CpuData, &PeiCpuMpData->CpuData[Index3], sizeof (PEI_CPU_DATA));\r
84 CopyMem (\r
85 &PeiCpuMpData->CpuData[Index3],\r
86 &PeiCpuMpData->CpuData[Index1],\r
87 sizeof (PEI_CPU_DATA)\r
88 );\r
89 CopyMem (&PeiCpuMpData->CpuData[Index1], &CpuData, sizeof (PEI_CPU_DATA));\r
ea0f431c
JF
90 }\r
91 }\r
92\r
93 //\r
94 // Get the processor number for the BSP\r
95 //\r
96 ApicId = GetInitialApicId ();\r
97 for (Index1 = 0; Index1 < PeiCpuMpData->CpuCount; Index1++) {\r
98 if (PeiCpuMpData->CpuData[Index1].ApicId == ApicId) {\r
99 PeiCpuMpData->BspNumber = (UINT32) Index1;\r
100 break;\r
101 }\r
102 }\r
103 }\r
104}\r
105\r
c7981a11
JF
106/**\r
107 Enable x2APIC mode on APs.\r
108\r
109 @param Buffer Pointer to private data buffer.\r
110**/\r
111VOID\r
112EFIAPI\r
113ApFuncEnableX2Apic (\r
114 IN OUT VOID *Buffer\r
115 )\r
116{\r
117 SetApicMode (LOCAL_APIC_MODE_X2APIC);\r
118}\r
119\r
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
276\r
277 PeiCpuMpData = ExchangeInfo->PeiCpuMpData;\r
278 if (PeiCpuMpData->InitFlag) {\r
10c6c206 279 ProcessorNumber = NumApsExecuting;\r
ea0f431c 280 //\r
22cfe73a
JF
281 // Sync BSP's Control registers to APs\r
282 //\r
283 RestoreVolatileRegisters (&PeiCpuMpData->CpuData[0].VolatileRegisters, FALSE);\r
284 //\r
2f0261b7 285 // This is first time AP wakeup, get BIST information from AP stack\r
ea0f431c 286 //\r
10c6c206
JF
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
2f0261b7
JF
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
ea0f431c
JF
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
10c6c206 304 PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle;\r
ea0f431c
JF
305 } else {\r
306 //\r
307 // Execute AP function if AP is not disabled\r
308 //\r
309 GetProcessorNumber (PeiCpuMpData, &ProcessorNumber);\r
f40a7de4
JF
310 //\r
311 // Restore AP's volatile registers saved\r
312 //\r
313 RestoreVolatileRegisters (&PeiCpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);\r
314\r
ea0f431c
JF
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
c972495e
JF
319 //\r
320 // Invoke AP function here\r
321 //\r
ea0f431c
JF
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
f40a7de4
JF
332 //\r
333 // Save AP volatile registers\r
334 //\r
335 SaveVolatileRegisters (&PeiCpuMpData->CpuData[ProcessorNumber].VolatileRegisters);\r
336\r
ea0f431c
JF
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
944f45ae 519\r
ea0f431c 520 //\r
944f45ae 521 // Only perform AP detection if PcdCpuMaxLogicalProcessorNumber is greater than 1\r
ea0f431c 522 //\r
944f45ae
MK
523 if (PcdGet32 (PcdCpuMaxLogicalProcessorNumber) > 1) {\r
524 //\r
2f0261b7 525 // Send 1st broadcast IPI to APs to wakeup APs\r
944f45ae 526 //\r
2f0261b7
JF
527 PeiCpuMpData->InitFlag = TRUE;\r
528 PeiCpuMpData->X2ApicEnable = FALSE;\r
944f45ae
MK
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
2f0261b7 534 PeiCpuMpData->InitFlag = FALSE;\r
944f45ae
MK
535 PeiCpuMpData->CpuCount += (UINT32)PeiCpuMpData->MpCpuExchangeInfo->NumApsExecuting;\r
536 ASSERT (PeiCpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));\r
537 //\r
c7981a11
JF
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
944f45ae
MK
563 // Sort BSP/Aps by CPU APIC ID in ascending order\r
564 //\r
565 SortApicId (PeiCpuMpData);\r
566 }\r
ea0f431c
JF
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
e001e11f
JF
592 UINT8 ApLoopMode;\r
593 UINT16 MonitorFilterSize;\r
594 UINT8 *MonitorBuffer;\r
595 UINTN Index;\r
ea0f431c
JF
596\r
597 AsmGetAddressMap (&AddressMap);\r
598 WakeupBufferSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);\r
599 WakeupBuffer = GetWakeupBuffer ((WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1));\r
600 ASSERT (WakeupBuffer != (UINTN) -1);\r
601 DEBUG ((EFI_D_INFO, "CpuMpPei: WakeupBuffer = 0x%x\n", WakeupBuffer));\r
602\r
603 //\r
e001e11f
JF
604 // Allocate Pages for APs stack, CPU MP Data, backup buffer for wakeup buffer,\r
605 // and monitor buffer if required.\r
ea0f431c
JF
606 //\r
607 MaxCpuCount = PcdGet32(PcdCpuMaxLogicalProcessorNumber);\r
608 BufferSize = PcdGet32 (PcdCpuApStackSize) * MaxCpuCount + sizeof (PEI_CPU_MP_DATA)\r
609 + WakeupBufferSize + sizeof (PEI_CPU_DATA) * MaxCpuCount;\r
e001e11f
JF
610 ApLoopMode = GetApLoopMode (&MonitorFilterSize);\r
611 BufferSize += MonitorFilterSize * MaxCpuCount;\r
ea0f431c
JF
612 Status = PeiServicesAllocatePages (\r
613 EfiBootServicesData,\r
614 EFI_SIZE_TO_PAGES (BufferSize),\r
615 &Buffer\r
616 );\r
617 ASSERT_EFI_ERROR (Status);\r
618\r
619 PeiCpuMpData = (PEI_CPU_MP_DATA *) (UINTN) (Buffer + PcdGet32 (PcdCpuApStackSize) * MaxCpuCount);\r
620 PeiCpuMpData->Buffer = (UINTN) Buffer;\r
621 PeiCpuMpData->CpuApStackSize = PcdGet32 (PcdCpuApStackSize);\r
622 PeiCpuMpData->WakeupBuffer = WakeupBuffer;\r
623 PeiCpuMpData->BackupBuffer = (UINTN)PeiCpuMpData + sizeof (PEI_CPU_MP_DATA);\r
624 PeiCpuMpData->BackupBufferSize = WakeupBufferSize;\r
625 PeiCpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeupBuffer + AddressMap.RendezvousFunnelSize);\r
626\r
627 PeiCpuMpData->CpuCount = 1;\r
628 PeiCpuMpData->BspNumber = 0;\r
28f27af6
JF
629 PeiCpuMpData->CpuData = (PEI_CPU_DATA *) (PeiCpuMpData->BackupBuffer +\r
630 PeiCpuMpData->BackupBufferSize);\r
ea0f431c
JF
631 PeiCpuMpData->CpuData[0].ApicId = GetInitialApicId ();\r
632 PeiCpuMpData->CpuData[0].Health.Uint32 = 0;\r
633 PeiCpuMpData->EndOfPeiFlag = FALSE;\r
2f0261b7 634 InitializeSpinLock(&PeiCpuMpData->MpLock);\r
22cfe73a 635 SaveVolatileRegisters (&PeiCpuMpData->CpuData[0].VolatileRegisters);\r
ea0f431c 636 CopyMem (&PeiCpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));\r
e001e11f
JF
637 //\r
638 // Initialize AP loop mode\r
639 //\r
640 PeiCpuMpData->ApLoopMode = ApLoopMode;\r
641 DEBUG ((EFI_D_INFO, "AP Loop Mode is %d\n", PeiCpuMpData->ApLoopMode));\r
642 MonitorBuffer = (UINT8 *)(PeiCpuMpData->CpuData + MaxCpuCount);\r
643 if (PeiCpuMpData->ApLoopMode != ApInHltLoop) {\r
644 //\r
645 // Set up APs wakeup signal buffer\r
646 //\r
647 for (Index = 0; Index < MaxCpuCount; Index++) {\r
648 PeiCpuMpData->CpuData[Index].StartupApSignal = \r
649 (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);\r
650 }\r
651 }\r
ea0f431c
JF
652 //\r
653 // Backup original data and copy AP reset code in it\r
654 //\r
655 BackupAndPrepareWakeupBuffer(PeiCpuMpData);\r
656\r
657 return PeiCpuMpData;\r
658}\r
659\r
660/**\r
661 Notify function on End Of Pei PPI.\r
662\r
663 On S3 boot, this function will restore wakeup buffer data.\r
664 On normal boot, this function will flag wakeup buffer to be un-used type.\r
665\r
666 @param PeiServices The pointer to the PEI Services Table.\r
667 @param NotifyDescriptor Address of the notification descriptor data structure.\r
668 @param Ppi Address of the PPI that was installed.\r
669\r
670 @retval EFI_SUCCESS When everything is OK.\r
671\r
672**/\r
673EFI_STATUS\r
674EFIAPI\r
675CpuMpEndOfPeiCallback (\r
676 IN EFI_PEI_SERVICES **PeiServices,\r
677 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
678 IN VOID *Ppi\r
679 )\r
680{\r
681 EFI_STATUS Status;\r
682 EFI_BOOT_MODE BootMode;\r
683 PEI_CPU_MP_DATA *PeiCpuMpData;\r
684 EFI_PEI_HOB_POINTERS Hob;\r
685 EFI_HOB_MEMORY_ALLOCATION *MemoryHob;\r
686\r
c972495e 687 DEBUG ((EFI_D_INFO, "CpuMpPei: CpuMpEndOfPeiCallback () invoked\n"));\r
ea0f431c
JF
688\r
689 Status = PeiServicesGetBootMode (&BootMode);\r
690 ASSERT_EFI_ERROR (Status);\r
691\r
692 PeiCpuMpData = GetMpHobData ();\r
693 ASSERT (PeiCpuMpData != NULL);\r
694\r
695 if (BootMode != BOOT_ON_S3_RESUME) {\r
696 //\r
697 // Get the HOB list for processing\r
698 //\r
699 Hob.Raw = GetHobList ();\r
700 //\r
701 // Collect memory ranges\r
702 //\r
703 while (!END_OF_HOB_LIST (Hob)) {\r
704 if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {\r
705 MemoryHob = Hob.MemoryAllocation;\r
706 if(MemoryHob->AllocDescriptor.MemoryBaseAddress == PeiCpuMpData->WakeupBuffer) {\r
707 //\r
708 // Flag this HOB type to un-used\r
709 //\r
710 GET_HOB_TYPE (Hob) = EFI_HOB_TYPE_UNUSED;\r
711 break;\r
712 }\r
713 }\r
714 Hob.Raw = GET_NEXT_HOB (Hob);\r
715 }\r
716 } else {\r
717 RestoreWakeupBuffer (PeiCpuMpData);\r
718 PeiCpuMpData->EndOfPeiFlag = TRUE;\r
719 }\r
720 return EFI_SUCCESS;\r
721}\r
722\r
723/**\r
724 The Entry point of the MP CPU PEIM.\r
725\r
726 This function will wakeup APs and collect CPU AP count and install the\r
727 Mp Service Ppi.\r
728\r
729 @param FileHandle Handle of the file being invoked.\r
730 @param PeiServices Describes the list of possible PEI Services.\r
731\r
732 @retval EFI_SUCCESS MpServicePpi is installed successfully.\r
733\r
734**/\r
735EFI_STATUS\r
736EFIAPI\r
737CpuMpPeimInit (\r
738 IN EFI_PEI_FILE_HANDLE FileHandle,\r
739 IN CONST EFI_PEI_SERVICES **PeiServices\r
740 )\r
741{\r
742 EFI_STATUS Status;\r
743 PEI_CPU_MP_DATA *PeiCpuMpData;\r
744 UINT32 ProcessorCount;\r
745\r
746 //\r
747 // Load new GDT table on BSP\r
748 //\r
749 AsmInitializeGdt (&mGdt);\r
750 //\r
751 // Get wakeup buffer and copy AP reset code in it\r
752 //\r
753 PeiCpuMpData = PrepareAPStartupVector ();\r
754 //\r
755 // Count processor number and collect processor information\r
756 //\r
757 ProcessorCount = CountProcessorNumber (PeiCpuMpData);\r
758 //\r
759 // Build location of PEI CPU MP DATA buffer in HOB\r
760 //\r
761 BuildGuidDataHob (\r
762 &gEfiCallerIdGuid,\r
763 (VOID *)&PeiCpuMpData,\r
764 sizeof(UINT64)\r
765 );\r
766 //\r
767 // Update and publish CPU BIST information\r
768 //\r
769 CollectBistDataFromPpi (PeiServices, PeiCpuMpData);\r
770 //\r
771 // register an event for EndOfPei\r
772 //\r
773 Status = PeiServicesNotifyPpi (&mNotifyList);\r
774 ASSERT_EFI_ERROR (Status);\r
775 //\r
776 // Install CPU MP PPI\r
777 //\r
778 Status = PeiServicesInstallPpi(&mPeiCpuMpPpiDesc);\r
779 ASSERT_EFI_ERROR (Status);\r
780\r
781 return Status;\r
782}\r