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