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