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