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