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