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