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