]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/CpuMpPei/CpuMpPei.c
UefiCpuPkg/CpuMpPei: Remove un-used variables and functions
[mirror_edk2.git] / UefiCpuPkg / CpuMpPei / CpuMpPei.c
1 /** @file
2 CPU PEI Module installs CPU Multiple Processor PPI.
3
4 Copyright (c) 2015 - 2016, 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 GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = {
18 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
19 &gEfiEndOfPeiSignalPpiGuid,
20 CpuMpEndOfPeiCallback
21 };
22
23 /**
24 Sort the APIC ID of all processors.
25
26 This function sorts the APIC ID of all processors so that processor number is
27 assigned in the ascending order of APIC ID which eases MP debugging.
28
29 @param PeiCpuMpData Pointer to PEI CPU MP Data
30 **/
31 VOID
32 SortApicId (
33 IN PEI_CPU_MP_DATA *PeiCpuMpData
34 )
35 {
36 UINTN Index1;
37 UINTN Index2;
38 UINTN Index3;
39 UINT32 ApicId;
40 PEI_CPU_DATA CpuData;
41 UINT32 ApCount;
42
43 ApCount = PeiCpuMpData->CpuCount - 1;
44
45 if (ApCount != 0) {
46 for (Index1 = 0; Index1 < ApCount; Index1++) {
47 Index3 = Index1;
48 //
49 // Sort key is the hardware default APIC ID
50 //
51 ApicId = PeiCpuMpData->CpuData[Index1].ApicId;
52 for (Index2 = Index1 + 1; Index2 <= ApCount; Index2++) {
53 if (ApicId > PeiCpuMpData->CpuData[Index2].ApicId) {
54 Index3 = Index2;
55 ApicId = PeiCpuMpData->CpuData[Index2].ApicId;
56 }
57 }
58 if (Index3 != Index1) {
59 CopyMem (&CpuData, &PeiCpuMpData->CpuData[Index3], sizeof (PEI_CPU_DATA));
60 CopyMem (
61 &PeiCpuMpData->CpuData[Index3],
62 &PeiCpuMpData->CpuData[Index1],
63 sizeof (PEI_CPU_DATA)
64 );
65 CopyMem (&PeiCpuMpData->CpuData[Index1], &CpuData, sizeof (PEI_CPU_DATA));
66 }
67 }
68
69 //
70 // Get the processor number for the BSP
71 //
72 ApicId = GetInitialApicId ();
73 for (Index1 = 0; Index1 < PeiCpuMpData->CpuCount; Index1++) {
74 if (PeiCpuMpData->CpuData[Index1].ApicId == ApicId) {
75 PeiCpuMpData->BspNumber = (UINT32) Index1;
76 break;
77 }
78 }
79 }
80 }
81
82 /**
83 Enable x2APIC mode on APs.
84
85 @param Buffer Pointer to private data buffer.
86 **/
87 VOID
88 EFIAPI
89 ApFuncEnableX2Apic (
90 IN OUT VOID *Buffer
91 )
92 {
93 SetApicMode (LOCAL_APIC_MODE_X2APIC);
94 }
95
96 /**
97 Get AP loop mode.
98
99 @param MonitorFilterSize Returns the largest monitor-line size in bytes.
100
101 @return The AP loop mode.
102 **/
103 UINT8
104 GetApLoopMode (
105 OUT UINT16 *MonitorFilterSize
106 )
107 {
108 UINT8 ApLoopMode;
109 UINT32 RegEbx;
110 UINT32 RegEcx;
111 UINT32 RegEdx;
112
113 ASSERT (MonitorFilterSize != NULL);
114
115 ApLoopMode = PcdGet8 (PcdCpuApLoopMode);
116 ASSERT (ApLoopMode >= ApInHltLoop && ApLoopMode <= ApInRunLoop);
117 if (ApLoopMode == ApInMwaitLoop) {
118 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &RegEcx, NULL);
119 if ((RegEcx & BIT3) == 0) {
120 //
121 // If processor does not support MONITOR/MWAIT feature
122 // by CPUID.[EAX=01H]:ECX.BIT3, force AP in Hlt-loop mode
123 //
124 ApLoopMode = ApInHltLoop;
125 }
126 }
127
128 if (ApLoopMode == ApInHltLoop) {
129 *MonitorFilterSize = 0;
130 } else if (ApLoopMode == ApInRunLoop) {
131 *MonitorFilterSize = sizeof (UINT32);
132 } else if (ApLoopMode == ApInMwaitLoop) {
133 //
134 // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes
135 // CPUID.[EAX=05H].EDX: C-states supported using MWAIT
136 //
137 AsmCpuid (CPUID_MONITOR_MWAIT, NULL, &RegEbx, NULL, &RegEdx);
138 *MonitorFilterSize = RegEbx & 0xFFFF;
139 }
140
141 return ApLoopMode;
142 }
143
144 /**
145 Get CPU MP Data pointer from the Guided HOB.
146
147 @return Pointer to Pointer to PEI CPU MP Data
148 **/
149 PEI_CPU_MP_DATA *
150 GetMpHobData (
151 VOID
152 )
153 {
154 EFI_HOB_GUID_TYPE *GuidHob;
155 VOID *DataInHob;
156 PEI_CPU_MP_DATA *CpuMpData;
157
158 CpuMpData = NULL;
159 GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
160 if (GuidHob != NULL) {
161 DataInHob = GET_GUID_HOB_DATA (GuidHob);
162 CpuMpData = (PEI_CPU_MP_DATA *)(*(UINTN *)DataInHob);
163 }
164 ASSERT (CpuMpData != NULL);
165 return CpuMpData;
166 }
167
168 /**
169 Save the volatile registers required to be restored following INIT IPI.
170
171 @param VolatileRegisters Returns buffer saved the volatile resisters
172 **/
173 VOID
174 SaveVolatileRegisters (
175 OUT CPU_VOLATILE_REGISTERS *VolatileRegisters
176 )
177 {
178 UINT32 RegEdx;
179
180 VolatileRegisters->Cr0 = AsmReadCr0 ();
181 VolatileRegisters->Cr3 = AsmReadCr3 ();
182 VolatileRegisters->Cr4 = AsmReadCr4 ();
183
184 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx);
185 if ((RegEdx & BIT2) != 0) {
186 //
187 // If processor supports Debugging Extensions feature
188 // by CPUID.[EAX=01H]:EDX.BIT2
189 //
190 VolatileRegisters->Dr0 = AsmReadDr0 ();
191 VolatileRegisters->Dr1 = AsmReadDr1 ();
192 VolatileRegisters->Dr2 = AsmReadDr2 ();
193 VolatileRegisters->Dr3 = AsmReadDr3 ();
194 VolatileRegisters->Dr6 = AsmReadDr6 ();
195 VolatileRegisters->Dr7 = AsmReadDr7 ();
196 }
197 }
198
199 /**
200 Restore the volatile registers following INIT IPI.
201
202 @param VolatileRegisters Pointer to volatile resisters
203 @param IsRestoreDr TRUE: Restore DRx if supported
204 FALSE: Do not restore DRx
205 **/
206 VOID
207 RestoreVolatileRegisters (
208 IN CPU_VOLATILE_REGISTERS *VolatileRegisters,
209 IN BOOLEAN IsRestoreDr
210 )
211 {
212 UINT32 RegEdx;
213
214 AsmWriteCr0 (VolatileRegisters->Cr0);
215 AsmWriteCr3 (VolatileRegisters->Cr3);
216 AsmWriteCr4 (VolatileRegisters->Cr4);
217
218 if (IsRestoreDr) {
219 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx);
220 if ((RegEdx & BIT2) != 0) {
221 //
222 // If processor supports Debugging Extensions feature
223 // by CPUID.[EAX=01H]:EDX.BIT2
224 //
225 AsmWriteDr0 (VolatileRegisters->Dr0);
226 AsmWriteDr1 (VolatileRegisters->Dr1);
227 AsmWriteDr2 (VolatileRegisters->Dr2);
228 AsmWriteDr3 (VolatileRegisters->Dr3);
229 AsmWriteDr6 (VolatileRegisters->Dr6);
230 AsmWriteDr7 (VolatileRegisters->Dr7);
231 }
232 }
233 }
234
235 /**
236 This function will be called from AP reset code if BSP uses WakeUpAP.
237
238 @param ExchangeInfo Pointer to the MP exchange info buffer
239 @param NumApsExecuting Number of current executing AP
240 **/
241 VOID
242 EFIAPI
243 ApCFunction (
244 IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,
245 IN UINTN NumApsExecuting
246 )
247 {
248 PEI_CPU_MP_DATA *PeiCpuMpData;
249 UINTN ProcessorNumber;
250 EFI_AP_PROCEDURE Procedure;
251 UINTN BistData;
252 volatile UINT32 *ApStartupSignalBuffer;
253
254 PeiCpuMpData = ExchangeInfo->PeiCpuMpData;
255 while (TRUE) {
256 if (PeiCpuMpData->InitFlag) {
257 ProcessorNumber = NumApsExecuting;
258 //
259 // Sync BSP's Control registers to APs
260 //
261 RestoreVolatileRegisters (&PeiCpuMpData->CpuData[0].VolatileRegisters, FALSE);
262 //
263 // This is first time AP wakeup, get BIST information from AP stack
264 //
265 BistData = *(UINTN *) (PeiCpuMpData->Buffer + ProcessorNumber * PeiCpuMpData->CpuApStackSize - sizeof (UINTN));
266 PeiCpuMpData->CpuData[ProcessorNumber].Health.Uint32 = (UINT32) BistData;
267 PeiCpuMpData->CpuData[ProcessorNumber].ApicId = GetInitialApicId ();
268 if (PeiCpuMpData->CpuData[ProcessorNumber].ApicId >= 0xFF) {
269 //
270 // Set x2APIC mode if there are any logical processor reporting
271 // an APIC ID of 255 or greater.
272 //
273 AcquireSpinLock(&PeiCpuMpData->MpLock);
274 PeiCpuMpData->X2ApicEnable = TRUE;
275 ReleaseSpinLock(&PeiCpuMpData->MpLock);
276 }
277 //
278 // Sync BSP's Mtrr table to all wakeup APs and load microcode on APs.
279 //
280 MtrrSetAllMtrrs (&PeiCpuMpData->MtrrTable);
281 MicrocodeDetect (PeiCpuMpData);
282 PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle;
283 } else {
284 //
285 // Execute AP function if AP is not disabled
286 //
287 GetProcessorNumber (PeiCpuMpData, &ProcessorNumber);
288 if (PeiCpuMpData->ApLoopMode == ApInHltLoop) {
289 //
290 // Restore AP's volatile registers saved
291 //
292 RestoreVolatileRegisters (&PeiCpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);
293 }
294
295 if ((PeiCpuMpData->CpuData[ProcessorNumber].State != CpuStateDisabled) &&
296 (PeiCpuMpData->ApFunction != 0)) {
297 PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateBusy;
298 Procedure = (EFI_AP_PROCEDURE)(UINTN)PeiCpuMpData->ApFunction;
299 //
300 // Invoke AP function here
301 //
302 Procedure ((VOID *)(UINTN)PeiCpuMpData->ApFunctionArgument);
303 //
304 // Re-get the processor number due to BSP/AP maybe exchange in AP function
305 //
306 GetProcessorNumber (PeiCpuMpData, &ProcessorNumber);
307 PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle;
308 }
309 }
310
311 //
312 // AP finished executing C code
313 //
314 InterlockedIncrement ((UINT32 *)&PeiCpuMpData->FinishedCount);
315
316 //
317 // Place AP is specified loop mode
318 //
319 if (PeiCpuMpData->ApLoopMode == ApInHltLoop) {
320 //
321 // Save AP volatile registers
322 //
323 SaveVolatileRegisters (&PeiCpuMpData->CpuData[ProcessorNumber].VolatileRegisters);
324 //
325 // Place AP in Hlt-loop
326 //
327 while (TRUE) {
328 DisableInterrupts ();
329 CpuSleep ();
330 CpuPause ();
331 }
332 }
333 ApStartupSignalBuffer = PeiCpuMpData->CpuData[ProcessorNumber].StartupApSignal;
334 while (TRUE) {
335 DisableInterrupts ();
336 if (PeiCpuMpData->ApLoopMode == ApInMwaitLoop) {
337 //
338 // Place AP in Mwait-loop
339 //
340 AsmMonitor ((UINTN)ApStartupSignalBuffer, 0, 0);
341 if (*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) {
342 //
343 // If AP start-up signal is not set, place AP into
344 // the maximum C-state
345 //
346 AsmMwait (PeiCpuMpData->ApTargetCState << 4, 0);
347 }
348 } else if (PeiCpuMpData->ApLoopMode == ApInRunLoop) {
349 //
350 // Place AP in Run-loop
351 //
352 CpuPause ();
353 } else {
354 ASSERT (FALSE);
355 }
356
357 //
358 // If AP start-up signal is written, AP is waken up
359 // otherwise place AP in loop again
360 //
361 if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) {
362 //
363 // Clear AP start-up signal when AP waken up
364 //
365 InterlockedCompareExchange32 (
366 (UINT32 *)ApStartupSignalBuffer,
367 WAKEUP_AP_SIGNAL,
368 0
369 );
370 break;
371 }
372 }
373 }
374 }
375
376 /**
377 Write AP start-up signal to wakeup AP.
378
379 @param ApStartupSignalBuffer Pointer to AP wakeup signal
380 **/
381 VOID
382 WriteStartupSignal (
383 IN volatile UINT32 *ApStartupSignalBuffer
384 )
385 {
386 *ApStartupSignalBuffer = WAKEUP_AP_SIGNAL;
387 //
388 // If AP is waken up, StartupApSignal should be cleared.
389 // Otherwise, write StartupApSignal again till AP waken up.
390 //
391 while (InterlockedCompareExchange32 (
392 (UINT32 *)ApStartupSignalBuffer,
393 WAKEUP_AP_SIGNAL,
394 WAKEUP_AP_SIGNAL
395 ) != 0) {
396 CpuPause ();
397 }
398 }
399
400 /**
401 This function will be called by BSP to wakeup AP.
402
403 @param PeiCpuMpData Pointer to PEI CPU MP Data
404 @param Broadcast TRUE: Send broadcast IPI to all APs
405 FALSE: Send IPI to AP by ApicId
406 @param ProcessorNumber The handle number of specified processor
407 @param Procedure The function to be invoked by AP
408 @param ProcedureArgument The argument to be passed into AP function
409 **/
410 VOID
411 WakeUpAP (
412 IN PEI_CPU_MP_DATA *PeiCpuMpData,
413 IN BOOLEAN Broadcast,
414 IN UINTN ProcessorNumber,
415 IN EFI_AP_PROCEDURE Procedure, OPTIONAL
416 IN VOID *ProcedureArgument OPTIONAL
417 )
418 {
419 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
420 UINTN Index;
421
422 PeiCpuMpData->ApFunction = (UINTN) Procedure;
423 PeiCpuMpData->ApFunctionArgument = (UINTN) ProcedureArgument;
424 PeiCpuMpData->FinishedCount = 0;
425
426 ExchangeInfo = PeiCpuMpData->MpCpuExchangeInfo;
427 ExchangeInfo->Lock = 0;
428 ExchangeInfo->StackStart = PeiCpuMpData->Buffer;
429 ExchangeInfo->StackSize = PeiCpuMpData->CpuApStackSize;
430 ExchangeInfo->BufferStart = PeiCpuMpData->WakeupBuffer;
431 ExchangeInfo->PmodeOffset = PeiCpuMpData->AddressMap.PModeEntryOffset;
432 ExchangeInfo->LmodeOffset = PeiCpuMpData->AddressMap.LModeEntryOffset;
433 ExchangeInfo->Cr3 = AsmReadCr3 ();
434 ExchangeInfo->CodeSegment = AsmReadCs ();
435 ExchangeInfo->DataSegment = AsmReadDs ();
436 ExchangeInfo->CFunction = (UINTN) ApCFunction;
437 ExchangeInfo->NumApsExecuting = 0;
438 ExchangeInfo->PeiCpuMpData = PeiCpuMpData;
439
440 //
441 // Get the BSP's data of GDT and IDT
442 //
443 AsmReadGdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->GdtrProfile);
444 AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);
445
446 if (PeiCpuMpData->ApLoopMode == ApInMwaitLoop) {
447 //
448 // Get AP target C-state each time when waking up AP,
449 // for it maybe updated by platform again
450 //
451 PeiCpuMpData->ApTargetCState = PcdGet8 (PcdCpuApTargetCstate);
452 }
453
454 //
455 // Wakeup APs per AP loop state
456 //
457 if (PeiCpuMpData->ApLoopMode == ApInHltLoop || PeiCpuMpData->InitFlag) {
458 if (Broadcast) {
459 SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);
460 } else {
461 SendInitSipiSipi (
462 PeiCpuMpData->CpuData[ProcessorNumber].ApicId,
463 (UINT32) ExchangeInfo->BufferStart
464 );
465 }
466 } else if ((PeiCpuMpData->ApLoopMode == ApInMwaitLoop) ||
467 (PeiCpuMpData->ApLoopMode == ApInRunLoop)) {
468 if (Broadcast) {
469 for (Index = 0; Index < PeiCpuMpData->CpuCount; Index++) {
470 if (Index != PeiCpuMpData->BspNumber) {
471 WriteStartupSignal (PeiCpuMpData->CpuData[Index].StartupApSignal);
472 }
473 }
474 } else {
475 WriteStartupSignal (PeiCpuMpData->CpuData[ProcessorNumber].StartupApSignal);
476 }
477 } else {
478 ASSERT (FALSE);
479 }
480 return ;
481 }
482
483 /**
484 Get available system memory below 1MB by specified size.
485
486 @param WakeupBufferSize Wakeup buffer size required
487
488 @retval other Return wakeup buffer address below 1MB.
489 @retval -1 Cannot find free memory below 1MB.
490 **/
491 UINTN
492 GetWakeupBuffer (
493 IN UINTN WakeupBufferSize
494 )
495 {
496 EFI_PEI_HOB_POINTERS Hob;
497 UINTN WakeupBufferStart;
498 UINTN WakeupBufferEnd;
499
500 //
501 // Get the HOB list for processing
502 //
503 Hob.Raw = GetHobList ();
504
505 //
506 // Collect memory ranges
507 //
508 while (!END_OF_HOB_LIST (Hob)) {
509 if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
510 if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) &&
511 (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&
512 ((Hob.ResourceDescriptor->ResourceAttribute &
513 (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |
514 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |
515 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
516 )) == 0)
517 ) {
518 //
519 // Need memory under 1MB to be collected here
520 //
521 WakeupBufferEnd = (UINTN) (Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength);
522 if (WakeupBufferEnd > BASE_1MB) {
523 //
524 // Wakeup buffer should be under 1MB
525 //
526 WakeupBufferEnd = BASE_1MB;
527 }
528 //
529 // Wakeup buffer should be aligned on 4KB
530 //
531 WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1);
532 if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) {
533 continue;
534 }
535 //
536 // Create a memory allocation HOB.
537 //
538 BuildMemoryAllocationHob (
539 WakeupBufferStart,
540 WakeupBufferSize,
541 EfiBootServicesData
542 );
543 return WakeupBufferStart;
544 }
545 }
546 //
547 // Find the next HOB
548 //
549 Hob.Raw = GET_NEXT_HOB (Hob);
550 }
551
552 return (UINTN) -1;
553 }
554
555 /**
556 Get available system memory below 1MB by specified size.
557
558 @param PeiCpuMpData Pointer to PEI CPU MP Data
559 **/
560 VOID
561 BackupAndPrepareWakeupBuffer(
562 IN PEI_CPU_MP_DATA *PeiCpuMpData
563 )
564 {
565 CopyMem (
566 (VOID *) PeiCpuMpData->BackupBuffer,
567 (VOID *) PeiCpuMpData->WakeupBuffer,
568 PeiCpuMpData->BackupBufferSize
569 );
570 CopyMem (
571 (VOID *) PeiCpuMpData->WakeupBuffer,
572 (VOID *) PeiCpuMpData->AddressMap.RendezvousFunnelAddress,
573 PeiCpuMpData->AddressMap.RendezvousFunnelSize
574 );
575 }
576
577 /**
578 Restore wakeup buffer data.
579
580 @param PeiCpuMpData Pointer to PEI CPU MP Data
581 **/
582 VOID
583 RestoreWakeupBuffer(
584 IN PEI_CPU_MP_DATA *PeiCpuMpData
585 )
586 {
587 CopyMem ((VOID *) PeiCpuMpData->WakeupBuffer, (VOID *) PeiCpuMpData->BackupBuffer, PeiCpuMpData->BackupBufferSize);
588 }
589
590 /**
591 This function will get CPU count in the system.
592
593 @param PeiCpuMpData Pointer to PEI CPU MP Data
594
595 @return AP processor count
596 **/
597 UINT32
598 CountProcessorNumber (
599 IN PEI_CPU_MP_DATA *PeiCpuMpData
600 )
601 {
602 //
603 // Load Microcode on BSP
604 //
605 MicrocodeDetect (PeiCpuMpData);
606 //
607 // Store BSP's MTRR setting
608 //
609 MtrrGetAllMtrrs (&PeiCpuMpData->MtrrTable);
610
611 //
612 // Only perform AP detection if PcdCpuMaxLogicalProcessorNumber is greater than 1
613 //
614 if (PcdGet32 (PcdCpuMaxLogicalProcessorNumber) > 1) {
615 //
616 // Send 1st broadcast IPI to APs to wakeup APs
617 //
618 PeiCpuMpData->InitFlag = TRUE;
619 PeiCpuMpData->X2ApicEnable = FALSE;
620 WakeUpAP (PeiCpuMpData, TRUE, 0, NULL, NULL);
621 //
622 // Wait for AP task to complete and then exit.
623 //
624 MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds));
625 PeiCpuMpData->InitFlag = FALSE;
626 PeiCpuMpData->CpuCount += (UINT32)PeiCpuMpData->MpCpuExchangeInfo->NumApsExecuting;
627 ASSERT (PeiCpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));
628 //
629 // Wait for all APs finished the initialization
630 //
631 while (PeiCpuMpData->FinishedCount < (PeiCpuMpData->CpuCount - 1)) {
632 CpuPause ();
633 }
634
635 if (PeiCpuMpData->X2ApicEnable) {
636 DEBUG ((EFI_D_INFO, "Force x2APIC mode!\n"));
637 //
638 // Wakeup all APs to enable x2APIC mode
639 //
640 WakeUpAP (PeiCpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL);
641 //
642 // Wait for all known APs finished
643 //
644 while (PeiCpuMpData->FinishedCount < (PeiCpuMpData->CpuCount - 1)) {
645 CpuPause ();
646 }
647 //
648 // Enable x2APIC on BSP
649 //
650 SetApicMode (LOCAL_APIC_MODE_X2APIC);
651 }
652 DEBUG ((EFI_D_INFO, "APIC MODE is %d\n", GetApicMode ()));
653 //
654 // Sort BSP/Aps by CPU APIC ID in ascending order
655 //
656 SortApicId (PeiCpuMpData);
657 }
658
659 DEBUG ((EFI_D_INFO, "CpuMpPei: Find %d processors in system.\n", PeiCpuMpData->CpuCount));
660 return PeiCpuMpData->CpuCount;
661 }
662
663 /**
664 Prepare for AP wakeup buffer and copy AP reset code into it.
665
666 Get wakeup buffer below 1MB. Allocate memory for CPU MP Data and APs Stack.
667
668 @return Pointer to PEI CPU MP Data
669 **/
670 PEI_CPU_MP_DATA *
671 PrepareAPStartupVector (
672 VOID
673 )
674 {
675 EFI_STATUS Status;
676 UINT32 MaxCpuCount;
677 PEI_CPU_MP_DATA *PeiCpuMpData;
678 EFI_PHYSICAL_ADDRESS Buffer;
679 UINTN BufferSize;
680 UINTN WakeupBuffer;
681 UINTN WakeupBufferSize;
682 MP_ASSEMBLY_ADDRESS_MAP AddressMap;
683 UINT8 ApLoopMode;
684 UINT16 MonitorFilterSize;
685 UINT8 *MonitorBuffer;
686 UINTN Index;
687
688 AsmGetAddressMap (&AddressMap);
689 WakeupBufferSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);
690 WakeupBuffer = GetWakeupBuffer ((WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1));
691 ASSERT (WakeupBuffer != (UINTN) -1);
692 DEBUG ((EFI_D_INFO, "CpuMpPei: WakeupBuffer = 0x%x\n", WakeupBuffer));
693
694 //
695 // Allocate Pages for APs stack, CPU MP Data, backup buffer for wakeup buffer,
696 // and monitor buffer if required.
697 //
698 MaxCpuCount = PcdGet32(PcdCpuMaxLogicalProcessorNumber);
699 BufferSize = PcdGet32 (PcdCpuApStackSize) * MaxCpuCount + sizeof (PEI_CPU_MP_DATA)
700 + WakeupBufferSize + sizeof (PEI_CPU_DATA) * MaxCpuCount;
701 ApLoopMode = GetApLoopMode (&MonitorFilterSize);
702 BufferSize += MonitorFilterSize * MaxCpuCount;
703 Status = PeiServicesAllocatePages (
704 EfiBootServicesData,
705 EFI_SIZE_TO_PAGES (BufferSize),
706 &Buffer
707 );
708 ASSERT_EFI_ERROR (Status);
709
710 PeiCpuMpData = (PEI_CPU_MP_DATA *) (UINTN) (Buffer + PcdGet32 (PcdCpuApStackSize) * MaxCpuCount);
711 PeiCpuMpData->Buffer = (UINTN) Buffer;
712 PeiCpuMpData->CpuApStackSize = PcdGet32 (PcdCpuApStackSize);
713 PeiCpuMpData->WakeupBuffer = WakeupBuffer;
714 PeiCpuMpData->BackupBuffer = (UINTN)PeiCpuMpData + sizeof (PEI_CPU_MP_DATA);
715 PeiCpuMpData->BackupBufferSize = WakeupBufferSize;
716 PeiCpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeupBuffer + AddressMap.RendezvousFunnelSize);
717
718 PeiCpuMpData->CpuCount = 1;
719 PeiCpuMpData->BspNumber = 0;
720 PeiCpuMpData->CpuData = (PEI_CPU_DATA *) (PeiCpuMpData->BackupBuffer +
721 PeiCpuMpData->BackupBufferSize);
722 PeiCpuMpData->CpuData[0].ApicId = GetInitialApicId ();
723 PeiCpuMpData->CpuData[0].Health.Uint32 = 0;
724 PeiCpuMpData->EndOfPeiFlag = FALSE;
725 InitializeSpinLock(&PeiCpuMpData->MpLock);
726 SaveVolatileRegisters (&PeiCpuMpData->CpuData[0].VolatileRegisters);
727 CopyMem (&PeiCpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));
728 //
729 // Initialize AP loop mode
730 //
731 PeiCpuMpData->ApLoopMode = ApLoopMode;
732 DEBUG ((EFI_D_INFO, "AP Loop Mode is %d\n", PeiCpuMpData->ApLoopMode));
733 MonitorBuffer = (UINT8 *)(PeiCpuMpData->CpuData + MaxCpuCount);
734 if (PeiCpuMpData->ApLoopMode != ApInHltLoop) {
735 //
736 // Set up APs wakeup signal buffer
737 //
738 for (Index = 0; Index < MaxCpuCount; Index++) {
739 PeiCpuMpData->CpuData[Index].StartupApSignal =
740 (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);
741 }
742 }
743 //
744 // Backup original data and copy AP reset code in it
745 //
746 BackupAndPrepareWakeupBuffer(PeiCpuMpData);
747
748 return PeiCpuMpData;
749 }
750
751 /**
752 Notify function on End Of Pei PPI.
753
754 On S3 boot, this function will restore wakeup buffer data.
755 On normal boot, this function will flag wakeup buffer to be un-used type.
756
757 @param PeiServices The pointer to the PEI Services Table.
758 @param NotifyDescriptor Address of the notification descriptor data structure.
759 @param Ppi Address of the PPI that was installed.
760
761 @retval EFI_SUCCESS When everything is OK.
762
763 **/
764 EFI_STATUS
765 EFIAPI
766 CpuMpEndOfPeiCallback (
767 IN EFI_PEI_SERVICES **PeiServices,
768 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
769 IN VOID *Ppi
770 )
771 {
772 EFI_STATUS Status;
773 EFI_BOOT_MODE BootMode;
774 PEI_CPU_MP_DATA *PeiCpuMpData;
775 EFI_PEI_HOB_POINTERS Hob;
776 EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
777
778 DEBUG ((EFI_D_INFO, "CpuMpPei: CpuMpEndOfPeiCallback () invoked\n"));
779
780 Status = PeiServicesGetBootMode (&BootMode);
781 ASSERT_EFI_ERROR (Status);
782
783 PeiCpuMpData = GetMpHobData ();
784 ASSERT (PeiCpuMpData != NULL);
785
786 if (BootMode != BOOT_ON_S3_RESUME) {
787 //
788 // Get the HOB list for processing
789 //
790 Hob.Raw = GetHobList ();
791 //
792 // Collect memory ranges
793 //
794 while (!END_OF_HOB_LIST (Hob)) {
795 if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
796 MemoryHob = Hob.MemoryAllocation;
797 if(MemoryHob->AllocDescriptor.MemoryBaseAddress == PeiCpuMpData->WakeupBuffer) {
798 //
799 // Flag this HOB type to un-used
800 //
801 GET_HOB_TYPE (Hob) = EFI_HOB_TYPE_UNUSED;
802 break;
803 }
804 }
805 Hob.Raw = GET_NEXT_HOB (Hob);
806 }
807 } else {
808 RestoreWakeupBuffer (PeiCpuMpData);
809 PeiCpuMpData->EndOfPeiFlag = TRUE;
810 }
811 return EFI_SUCCESS;
812 }
813
814 /**
815 The Entry point of the MP CPU PEIM.
816
817 This function will wakeup APs and collect CPU AP count and install the
818 Mp Service Ppi.
819
820 @param FileHandle Handle of the file being invoked.
821 @param PeiServices Describes the list of possible PEI Services.
822
823 @retval EFI_SUCCESS MpServicePpi is installed successfully.
824
825 **/
826 EFI_STATUS
827 EFIAPI
828 CpuMpPeimInit (
829 IN EFI_PEI_FILE_HANDLE FileHandle,
830 IN CONST EFI_PEI_SERVICES **PeiServices
831 )
832 {
833 EFI_STATUS Status;
834 PEI_CPU_MP_DATA *PeiCpuMpData;
835 EFI_VECTOR_HANDOFF_INFO *VectorInfo;
836 EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi;
837
838 //
839 // Get Vector Hand-off Info PPI
840 //
841 VectorInfo = NULL;
842 Status = PeiServicesLocatePpi (
843 &gEfiVectorHandoffInfoPpiGuid,
844 0,
845 NULL,
846 (VOID **)&VectorHandoffInfoPpi
847 );
848 if (Status == EFI_SUCCESS) {
849 VectorInfo = VectorHandoffInfoPpi->Info;
850 }
851 Status = InitializeCpuExceptionHandlers (VectorInfo);
852 ASSERT_EFI_ERROR (Status);
853 //
854 // Get wakeup buffer and copy AP reset code in it
855 //
856 PeiCpuMpData = PrepareAPStartupVector ();
857 //
858 // Count processor number and collect processor information
859 //
860 CountProcessorNumber (PeiCpuMpData);
861 //
862 // Build location of PEI CPU MP DATA buffer in HOB
863 //
864 BuildGuidDataHob (
865 &gEfiCallerIdGuid,
866 (VOID *)&PeiCpuMpData,
867 sizeof(UINT64)
868 );
869 //
870 // Update and publish CPU BIST information
871 //
872 CollectBistDataFromPpi (PeiServices, PeiCpuMpData);
873 //
874 // register an event for EndOfPei
875 //
876 Status = PeiServicesNotifyPpi (&mNotifyList);
877 ASSERT_EFI_ERROR (Status);
878 //
879 // Install CPU MP PPI
880 //
881 Status = PeiServicesInstallPpi(&mPeiCpuMpPpiDesc);
882 ASSERT_EFI_ERROR (Status);
883
884 return Status;
885 }