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