VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/UefiCpuPkg/Library/MpInitLib/MpLib.c@ 109019

Last change on this file since 109019 was 108794, checked in by vboxsync, 4 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable202502 from the vendor branch and make it build for the important platforms, bugref:4643

  • Property svn:eol-style set to native
File size: 103.1 KB
Line 
1/** @file
2 CPU MP Initialize Library common functions.
3
4 Copyright (c) 2016 - 2024, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) 2020 - 2024, AMD Inc. All rights reserved.<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9**/
10
11#include "MpLib.h"
12#include <Library/CcExitLib.h>
13#include <Register/Amd/SevSnpMsr.h>
14#include <Register/Amd/Ghcb.h>
15#ifdef VBOX
16# include <Library/IoLib.h>
17# include "../../../../DevEFI.h"
18#endif
19
20EFI_GUID mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID;
21EFI_GUID mMpHandOffGuid = MP_HANDOFF_GUID;
22EFI_GUID mMpHandOffConfigGuid = MP_HANDOFF_CONFIG_GUID;
23
24RELOCATE_AP_LOOP_ENTRY mReservedApLoop;
25UINTN mReservedTopOfApStack;
26volatile UINT32 mNumberToFinish = 0;
27UINTN mApPageTable;
28
29/**
30 Save the volatile registers required to be restored following INIT IPI.
31
32 @param[out] VolatileRegisters Returns buffer saved the volatile resisters
33**/
34VOID
35SaveVolatileRegisters (
36 OUT CPU_VOLATILE_REGISTERS *VolatileRegisters
37 );
38
39/**
40 Restore the volatile registers following INIT IPI.
41
42 @param[in] VolatileRegisters Pointer to volatile resisters
43 @param[in] IsRestoreDr TRUE: Restore DRx if supported
44 FALSE: Do not restore DRx
45**/
46VOID
47RestoreVolatileRegisters (
48 IN CPU_VOLATILE_REGISTERS *VolatileRegisters
49 );
50
51/**
52 The function will check if BSP Execute Disable is enabled.
53
54 DxeIpl may have enabled Execute Disable for BSP, APs need to
55 get the status and sync up the settings.
56 If BSP's CR0.Paging is not set, BSP execute Disble feature is
57 not working actually.
58
59 @retval TRUE BSP Execute Disable is enabled.
60 @retval FALSE BSP Execute Disable is not enabled.
61**/
62BOOLEAN
63IsBspExecuteDisableEnabled (
64 VOID
65 )
66{
67 UINT32 Eax;
68 CPUID_EXTENDED_CPU_SIG_EDX Edx;
69 MSR_IA32_EFER_REGISTER EferMsr;
70 BOOLEAN Enabled;
71 IA32_CR0 Cr0;
72
73 Enabled = FALSE;
74 Cr0.UintN = AsmReadCr0 ();
75 if (Cr0.Bits.PG != 0) {
76 //
77 // If CR0 Paging bit is set
78 //
79 AsmCpuid (CPUID_EXTENDED_FUNCTION, &Eax, NULL, NULL, NULL);
80 if (Eax >= CPUID_EXTENDED_CPU_SIG) {
81 AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &Edx.Uint32);
82 //
83 // CPUID 0x80000001
84 // Bit 20: Execute Disable Bit available.
85 //
86 if (Edx.Bits.NX != 0) {
87 EferMsr.Uint64 = AsmReadMsr64 (MSR_IA32_EFER);
88 //
89 // MSR 0xC0000080
90 // Bit 11: Execute Disable Bit enable.
91 //
92 if (EferMsr.Bits.NXE != 0) {
93 Enabled = TRUE;
94 }
95 }
96 }
97 }
98
99 return Enabled;
100}
101
102/**
103 Worker function for SwitchBSP().
104
105 Worker function for SwitchBSP(), assigned to the AP which is intended
106 to become BSP.
107
108 @param[in] Buffer Pointer to CPU MP Data
109**/
110VOID
111EFIAPI
112FutureBSPProc (
113 IN VOID *Buffer
114 )
115{
116 CPU_MP_DATA *DataInHob;
117
118 DataInHob = (CPU_MP_DATA *)Buffer;
119 //
120 // Save and restore volatile registers when switch BSP
121 //
122 SaveVolatileRegisters (&DataInHob->APInfo.VolatileRegisters);
123 AsmExchangeRole (&DataInHob->APInfo, &DataInHob->BSPInfo);
124 RestoreVolatileRegisters (&DataInHob->APInfo.VolatileRegisters);
125}
126
127/**
128 Get the Application Processors state.
129
130 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
131
132 @return The AP status
133**/
134CPU_STATE
135GetApState (
136 IN CPU_AP_DATA *CpuData
137 )
138{
139 return CpuData->State;
140}
141
142/**
143 Set the Application Processors state.
144
145 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
146 @param[in] State The AP status
147**/
148VOID
149SetApState (
150 IN CPU_AP_DATA *CpuData,
151 IN CPU_STATE State
152 )
153{
154 AcquireSpinLock (&CpuData->ApLock);
155 CpuData->State = State;
156 ReleaseSpinLock (&CpuData->ApLock);
157}
158
159/**
160 Save BSP's local APIC timer setting.
161
162 @param[in] CpuMpData Pointer to CPU MP Data
163**/
164VOID
165SaveLocalApicTimerSetting (
166 IN CPU_MP_DATA *CpuMpData
167 )
168{
169 CpuMpData->InitTimerCount = GetApicTimerInitCount ();
170 if (CpuMpData->InitTimerCount != 0) {
171 //
172 // Record the current local APIC timer setting of BSP
173 //
174 GetApicTimerState (
175 &CpuMpData->DivideValue,
176 &CpuMpData->PeriodicMode,
177 &CpuMpData->Vector
178 );
179
180 CpuMpData->TimerInterruptState = GetApicTimerInterruptState ();
181 }
182}
183
184/**
185 Sync local APIC timer setting from BSP to AP.
186
187 @param[in] CpuMpData Pointer to CPU MP Data
188**/
189VOID
190SyncLocalApicTimerSetting (
191 IN CPU_MP_DATA *CpuMpData
192 )
193{
194 if (CpuMpData->InitTimerCount != 0) {
195 //
196 // Sync local APIC timer setting from BSP to AP
197 //
198 InitializeApicTimer (
199 CpuMpData->DivideValue,
200 CpuMpData->InitTimerCount,
201 CpuMpData->PeriodicMode,
202 CpuMpData->Vector
203 );
204 //
205 // Disable AP's local APIC timer interrupt
206 //
207 DisableApicTimerInterrupt ();
208 }
209}
210
211/**
212 Save the volatile registers required to be restored following INIT IPI.
213
214 @param[out] VolatileRegisters Returns buffer saved the volatile resisters
215**/
216VOID
217SaveVolatileRegisters (
218 OUT CPU_VOLATILE_REGISTERS *VolatileRegisters
219 )
220{
221 CPUID_VERSION_INFO_EDX VersionInfoEdx;
222
223 VolatileRegisters->Cr0 = AsmReadCr0 ();
224 VolatileRegisters->Cr3 = AsmReadCr3 ();
225 VolatileRegisters->Cr4 = AsmReadCr4 ();
226
227 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
228 if (VersionInfoEdx.Bits.DE != 0) {
229 //
230 // If processor supports Debugging Extensions feature
231 // by CPUID.[EAX=01H]:EDX.BIT2
232 //
233 VolatileRegisters->Dr0 = AsmReadDr0 ();
234 VolatileRegisters->Dr1 = AsmReadDr1 ();
235 VolatileRegisters->Dr2 = AsmReadDr2 ();
236 VolatileRegisters->Dr3 = AsmReadDr3 ();
237 VolatileRegisters->Dr6 = AsmReadDr6 ();
238 VolatileRegisters->Dr7 = AsmReadDr7 ();
239 }
240
241 AsmReadGdtr (&VolatileRegisters->Gdtr);
242 AsmReadIdtr (&VolatileRegisters->Idtr);
243 VolatileRegisters->Tr = AsmReadTr ();
244}
245
246/**
247 Restore the volatile registers following INIT IPI.
248
249 @param[in] VolatileRegisters Pointer to volatile resisters
250
251**/
252VOID
253RestoreVolatileRegisters (
254 IN CPU_VOLATILE_REGISTERS *VolatileRegisters
255 )
256{
257 CPUID_VERSION_INFO_EDX VersionInfoEdx;
258 IA32_TSS_DESCRIPTOR *Tss;
259
260 AsmWriteCr3 (VolatileRegisters->Cr3);
261 AsmWriteCr4 (VolatileRegisters->Cr4);
262 AsmWriteCr0 (VolatileRegisters->Cr0);
263
264 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
265 if (VersionInfoEdx.Bits.DE != 0) {
266 //
267 // If processor supports Debugging Extensions feature
268 // by CPUID.[EAX=01H]:EDX.BIT2
269 //
270 AsmWriteDr0 (VolatileRegisters->Dr0);
271 AsmWriteDr1 (VolatileRegisters->Dr1);
272 AsmWriteDr2 (VolatileRegisters->Dr2);
273 AsmWriteDr3 (VolatileRegisters->Dr3);
274 AsmWriteDr6 (VolatileRegisters->Dr6);
275 AsmWriteDr7 (VolatileRegisters->Dr7);
276 }
277
278 AsmWriteGdtr (&VolatileRegisters->Gdtr);
279 AsmWriteIdtr (&VolatileRegisters->Idtr);
280 if ((VolatileRegisters->Tr != 0) &&
281 (VolatileRegisters->Tr < VolatileRegisters->Gdtr.Limit))
282 {
283 Tss = (IA32_TSS_DESCRIPTOR *)(VolatileRegisters->Gdtr.Base +
284 VolatileRegisters->Tr);
285 if (Tss->Bits.P == 1) {
286 Tss->Bits.Type &= 0xD; // 1101 - Clear busy bit just in case
287 AsmWriteTr (VolatileRegisters->Tr);
288 }
289 }
290}
291
292/**
293 Detect whether Mwait-monitor feature is supported.
294
295 @retval TRUE Mwait-monitor feature is supported.
296 @retval FALSE Mwait-monitor feature is not supported.
297**/
298BOOLEAN
299IsMwaitSupport (
300 VOID
301 )
302{
303 CPUID_VERSION_INFO_ECX VersionInfoEcx;
304
305 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &VersionInfoEcx.Uint32, NULL);
306 return (VersionInfoEcx.Bits.MONITOR == 1) ? TRUE : FALSE;
307}
308
309/**
310 Get AP loop mode.
311
312 @param[out] MonitorFilterSize Returns the largest monitor-line size in bytes.
313
314 @return The AP loop mode.
315**/
316UINT8
317GetApLoopMode (
318 OUT UINT32 *MonitorFilterSize
319 )
320{
321 UINT8 ApLoopMode;
322 CPUID_MONITOR_MWAIT_EBX MonitorMwaitEbx;
323
324 ASSERT (MonitorFilterSize != NULL);
325
326 ApLoopMode = PcdGet8 (PcdCpuApLoopMode);
327 ASSERT (ApLoopMode >= ApInHltLoop && ApLoopMode <= ApInRunLoop);
328 if (ApLoopMode == ApInMwaitLoop) {
329 if (!IsMwaitSupport ()) {
330 //
331 // If processor does not support MONITOR/MWAIT feature,
332 // force AP in Hlt-loop mode
333 //
334 ApLoopMode = ApInHltLoop;
335 }
336
337 if (ConfidentialComputingGuestHas (CCAttrAmdSevEs) &&
338 !ConfidentialComputingGuestHas (CCAttrAmdSevSnp))
339 {
340 //
341 // For SEV-ES (SEV-SNP is also considered SEV-ES), force AP in Hlt-loop
342 // mode in order to use the GHCB protocol for starting APs
343 //
344 ApLoopMode = ApInHltLoop;
345 }
346 }
347
348 if (ApLoopMode != ApInMwaitLoop) {
349 *MonitorFilterSize = sizeof (UINT32);
350 } else {
351 //
352 // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes
353 // CPUID.[EAX=05H].EDX: C-states supported using MWAIT
354 //
355 AsmCpuid (CPUID_MONITOR_MWAIT, NULL, &MonitorMwaitEbx.Uint32, NULL, NULL);
356 *MonitorFilterSize = MonitorMwaitEbx.Bits.LargestMonitorLineSize;
357 }
358
359 return ApLoopMode;
360}
361
362/**
363 Sort the APIC ID of all processors.
364
365 This function sorts the APIC ID of all processors so that processor number is
366 assigned in the ascending order of APIC ID which eases MP debugging.
367
368 @param[in] CpuMpData Pointer to PEI CPU MP Data
369**/
370VOID
371SortApicId (
372 IN CPU_MP_DATA *CpuMpData
373 )
374{
375 UINTN Index1;
376 UINTN Index2;
377 UINTN Index3;
378 UINT32 ApicId;
379 CPU_INFO_IN_HOB CpuInfo;
380 CPU_AP_DATA CpuApData;
381 UINT32 ApCount;
382 CPU_INFO_IN_HOB *CpuInfoInHob;
383
384 ApCount = CpuMpData->CpuCount - 1;
385 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
386 if (ApCount != 0) {
387 for (Index1 = 0; Index1 < ApCount; Index1++) {
388 Index3 = Index1;
389 //
390 // Sort key is the hardware default APIC ID
391 //
392 ApicId = CpuInfoInHob[Index1].ApicId;
393 for (Index2 = Index1 + 1; Index2 <= ApCount; Index2++) {
394 if (ApicId > CpuInfoInHob[Index2].ApicId) {
395 Index3 = Index2;
396 ApicId = CpuInfoInHob[Index2].ApicId;
397 }
398 }
399
400 if (Index3 != Index1) {
401 CopyMem (&CpuInfo, &CpuInfoInHob[Index3], sizeof (CPU_INFO_IN_HOB));
402 CopyMem (
403 &CpuInfoInHob[Index3],
404 &CpuInfoInHob[Index1],
405 sizeof (CPU_INFO_IN_HOB)
406 );
407 CopyMem (&CpuInfoInHob[Index1], &CpuInfo, sizeof (CPU_INFO_IN_HOB));
408
409 CopyMem (&CpuApData, &CpuMpData->CpuData[Index3], sizeof (CPU_AP_DATA));
410 CopyMem (
411 &CpuMpData->CpuData[Index3],
412 &CpuMpData->CpuData[Index1],
413 sizeof (CPU_AP_DATA)
414 );
415 CopyMem (&CpuMpData->CpuData[Index1], &CpuApData, sizeof (CPU_AP_DATA));
416 }
417 }
418
419 //
420 // Get the processor number for the BSP
421 //
422 ApicId = GetInitialApicId ();
423 for (Index1 = 0; Index1 < CpuMpData->CpuCount; Index1++) {
424 if (CpuInfoInHob[Index1].ApicId == ApicId) {
425 CpuMpData->BspNumber = (UINT32)Index1;
426 break;
427 }
428 }
429 }
430}
431
432/**
433 Enable x2APIC mode on APs.
434
435 @param[in, out] Buffer Pointer to private data buffer.
436**/
437VOID
438EFIAPI
439ApFuncEnableX2Apic (
440 IN OUT VOID *Buffer
441 )
442{
443 SetApicMode (LOCAL_APIC_MODE_X2APIC);
444}
445
446/**
447 Do sync on APs.
448
449 @param[in, out] Buffer Pointer to private data buffer.
450**/
451VOID
452EFIAPI
453ApInitializeSync (
454 IN OUT VOID *Buffer
455 )
456{
457 CPU_MP_DATA *CpuMpData;
458 UINTN ProcessorNumber;
459 EFI_STATUS Status;
460
461 CpuMpData = (CPU_MP_DATA *)Buffer;
462 Status = GetProcessorNumber (CpuMpData, &ProcessorNumber);
463 ASSERT_EFI_ERROR (Status);
464 //
465 // Load microcode on AP
466 //
467 MicrocodeDetect (CpuMpData, ProcessorNumber);
468 //
469 // Sync BSP's MTRR table to AP
470 //
471 MtrrSetAllMtrrs (&CpuMpData->MtrrTable);
472}
473
474/**
475 Find the current Processor number by APIC ID.
476
477 @param[in] CpuMpData Pointer to PEI CPU MP Data
478 @param[out] ProcessorNumber Return the pocessor number found
479
480 @retval EFI_SUCCESS ProcessorNumber is found and returned.
481 @retval EFI_NOT_FOUND ProcessorNumber is not found.
482**/
483EFI_STATUS
484GetProcessorNumber (
485 IN CPU_MP_DATA *CpuMpData,
486 OUT UINTN *ProcessorNumber
487 )
488{
489 UINTN TotalProcessorNumber;
490 UINTN Index;
491 CPU_INFO_IN_HOB *CpuInfoInHob;
492 UINT32 CurrentApicId;
493
494 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
495
496 TotalProcessorNumber = CpuMpData->CpuCount;
497 CurrentApicId = GetApicId ();
498 for (Index = 0; Index < TotalProcessorNumber; Index++) {
499 if (CpuInfoInHob[Index].ApicId == CurrentApicId) {
500 *ProcessorNumber = Index;
501 return EFI_SUCCESS;
502 }
503 }
504
505 return EFI_NOT_FOUND;
506}
507
508#ifdef VBOX
509/*
510 * @todo move this function to the library.
511 */
512UINT32 VBoxGetVmVariable(UINT32 Variable, CHAR8* Buffer, UINT32 Size)
513{
514 UINT32 VarLen, i;
515
516 IoWrite32(EFI_INFO_PORT, Variable);
517 VarLen = IoRead32(EFI_INFO_PORT);
518
519 for (i = 0; i < VarLen && i < Size; i++)
520 Buffer[i] = IoRead8(EFI_INFO_PORT);
521
522 return VarLen;
523}
524#endif
525
526/**
527 Enable x2APIC mode if
528 1. Number of CPU is greater than 255; or
529 2. There are any logical processors reporting an Initial APIC ID of 255 or greater.
530
531 @param[in] CpuMpData Pointer to PEI CPU MP Data
532**/
533VOID
534AutoEnableX2Apic (
535 IN CPU_MP_DATA *CpuMpData
536 )
537{
538 BOOLEAN X2Apic;
539 UINTN Index;
540 CPU_INFO_IN_HOB *CpuInfoInHob;
541#ifdef VBOX
542 CHAR8 u8ApicMode;
543#endif
544
545 //
546 // Enable x2APIC mode if
547 // 1. Number of CPU is greater than 255; or
548 // 2. There are any logical processors reporting an Initial APIC ID of 255 or greater.
549 //
550 X2Apic = FALSE;
551 if (CpuMpData->CpuCount > 255) {
552 //
553 // If there are more than 255 processor found, force to enable X2APIC
554 //
555 X2Apic = TRUE;
556 } else {
557 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
558 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
559 if (CpuInfoInHob[Index].InitialApicId >= 0xFF) {
560 X2Apic = TRUE;
561 break;
562 }
563 }
564 }
565#ifdef VBOX
566 /* Force x2APIC mode if the VM config forces it. */
567 VBoxGetVmVariable(EFI_INFO_INDEX_APIC_MODE, &u8ApicMode, sizeof(u8ApicMode));
568 if (u8ApicMode == EFI_APIC_MODE_X2APIC)
569 X2Apic = TRUE;
570#endif
571
572 if (X2Apic) {
573 DEBUG ((DEBUG_INFO, "Force x2APIC mode!\n"));
574 //
575 // Wakeup all APs to enable x2APIC mode
576 //
577 WakeUpAP (CpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL, TRUE);
578 //
579 // Wait for all known APs finished
580 //
581 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
582 CpuPause ();
583 }
584
585 //
586 // Enable x2APIC on BSP
587 //
588 SetApicMode (LOCAL_APIC_MODE_X2APIC);
589 //
590 // Set BSP/Aps state to IDLE
591 //
592 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
593 SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);
594 }
595 }
596
597 DEBUG ((DEBUG_INFO, "APIC MODE is %d\n", GetApicMode ()));
598}
599
600/**
601 This function will get CPU count in the system.
602
603 @param[in] CpuMpData Pointer to PEI CPU MP Data
604
605 @return CPU count detected
606**/
607UINTN
608CollectProcessorCount (
609 IN CPU_MP_DATA *CpuMpData
610 )
611{
612 //
613 // Send 1st broadcast IPI to APs to wakeup APs
614 //
615 CpuMpData->InitFlag = ApInitConfig;
616 WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL, TRUE);
617 CpuMpData->InitFlag = ApInitDone;
618 //
619 // When InitFlag == ApInitConfig, WakeUpAP () guarantees all APs are checked in.
620 // FinishedCount is the number of check-in APs.
621 //
622 CpuMpData->CpuCount = CpuMpData->FinishedCount + 1;
623 ASSERT (CpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));
624
625 return CpuMpData->CpuCount;
626}
627
628/**
629 Initialize CPU AP Data when AP is wakeup at the first time.
630
631 @param[in, out] CpuMpData Pointer to PEI CPU MP Data
632 @param[in] ProcessorNumber The handle number of processor
633 @param[in] BistData Processor BIST data
634 @param[in] ApTopOfStack Top of AP stack
635
636**/
637VOID
638InitializeApData (
639 IN OUT CPU_MP_DATA *CpuMpData,
640 IN UINTN ProcessorNumber,
641 IN UINT32 BistData,
642 IN UINT64 ApTopOfStack
643 )
644{
645 CPU_INFO_IN_HOB *CpuInfoInHob;
646 MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr;
647 AP_STACK_DATA *ApStackData;
648
649 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
650 CpuInfoInHob[ProcessorNumber].InitialApicId = GetInitialApicId ();
651 CpuInfoInHob[ProcessorNumber].ApicId = GetApicId ();
652 CpuInfoInHob[ProcessorNumber].Health = BistData;
653 CpuInfoInHob[ProcessorNumber].ApTopOfStack = ApTopOfStack;
654
655 //
656 // AP_STACK_DATA is stored at the top of AP Stack
657 //
658 ApStackData = (AP_STACK_DATA *)((UINTN)ApTopOfStack - sizeof (AP_STACK_DATA));
659 ApStackData->MpData = CpuMpData;
660
661 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
662 CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;
663
664 //
665 // NOTE: PlatformId is not relevant on AMD platforms.
666 //
667 if (!StandardSignatureIsAuthenticAMD ()) {
668 PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID);
669 CpuMpData->CpuData[ProcessorNumber].PlatformId = (UINT8)PlatformIdMsr.Bits.PlatformId;
670 }
671
672 AsmCpuid (
673 CPUID_VERSION_INFO,
674 &CpuMpData->CpuData[ProcessorNumber].ProcessorSignature,
675 NULL,
676 NULL,
677 NULL
678 );
679
680 InitializeSpinLock (&CpuMpData->CpuData[ProcessorNumber].ApLock);
681 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);
682}
683
684/**
685 This function place APs in Halt loop.
686
687 @param[in] CpuMpData Pointer to CPU MP Data
688**/
689VOID
690PlaceAPInHltLoop (
691 IN CPU_MP_DATA *CpuMpData
692 )
693{
694 while (TRUE) {
695 DisableInterrupts ();
696 if (CpuMpData->UseSevEsAPMethod) {
697 SevEsPlaceApHlt (CpuMpData);
698 } else {
699 CpuSleep ();
700 }
701
702 CpuPause ();
703 }
704}
705
706/**
707 This function place APs in Mwait or Run loop.
708
709 @param[in] ApLoopMode Ap Loop Mode
710 @param[in] ApStartupSignalBuffer Pointer to Ap Startup Signal Buffer
711 @param[in] ApTargetCState Ap Target CState
712**/
713VOID
714PlaceAPInMwaitLoopOrRunLoop (
715 IN UINT8 ApLoopMode,
716 IN volatile UINT32 *ApStartupSignalBuffer,
717 IN UINT8 ApTargetCState
718 )
719{
720 while (TRUE) {
721 DisableInterrupts ();
722 if (ApLoopMode == ApInMwaitLoop) {
723 //
724 // Place AP in MWAIT-loop
725 //
726 AsmMonitor ((UINTN)ApStartupSignalBuffer, 0, 0);
727 if ((*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) && (*ApStartupSignalBuffer != MP_HAND_OFF_SIGNAL)) {
728 //
729 // Check AP start-up signal again.
730 // If AP start-up signal is not set, place AP into
731 // the specified C-state
732 //
733 AsmMwait (ApTargetCState << 4, 0);
734 }
735 } else if (ApLoopMode == ApInRunLoop) {
736 //
737 // Place AP in Run-loop
738 //
739 CpuPause ();
740 } else {
741 ASSERT (FALSE);
742 }
743
744 //
745 // If AP start-up signal is written, AP is waken up
746 // otherwise place AP in loop again
747 //
748 if ((*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) || (*ApStartupSignalBuffer == MP_HAND_OFF_SIGNAL)) {
749 break;
750 }
751 }
752}
753
754/**
755 This function will be called from AP reset code if BSP uses WakeUpAP.
756
757 @param[in] CpuMpData Pointer to CPU MP Data
758 @param[in] ApIndex Number of current executing AP
759**/
760VOID
761EFIAPI
762ApWakeupFunction (
763 IN CPU_MP_DATA *CpuMpData,
764 IN UINTN ApIndex
765 )
766{
767 UINTN ProcessorNumber;
768 EFI_AP_PROCEDURE Procedure;
769 VOID *Parameter;
770 UINT32 BistData;
771 volatile UINT32 *ApStartupSignalBuffer;
772 CPU_INFO_IN_HOB *CpuInfoInHob;
773 UINT64 ApTopOfStack;
774 UINTN CurrentApicMode;
775 AP_STACK_DATA *ApStackData;
776 UINT32 OriginalValue;
777
778 //
779 // AP's local APIC settings will be lost after received INIT IPI
780 // We need to re-initialize them at here
781 //
782 ProgramVirtualWireMode ();
783 //
784 // Mask the LINT0 and LINT1 so that AP doesn't enter the system timer interrupt handler.
785 //
786 DisableLvtInterrupts ();
787 SyncLocalApicTimerSetting (CpuMpData);
788
789 CurrentApicMode = GetApicMode ();
790 while (TRUE) {
791 if (CpuMpData->InitFlag == ApInitConfig) {
792 //
793 // Synchronize APIC mode with BSP in the first time AP wakeup ONLY.
794 //
795 SetApicMode (CpuMpData->InitialBspApicMode);
796 CurrentApicMode = CpuMpData->InitialBspApicMode;
797
798 ProcessorNumber = ApIndex;
799 //
800 // This is first time AP wakeup, get BIST information from AP stack
801 //
802 ApTopOfStack = CpuMpData->Buffer + (ProcessorNumber + 1) * CpuMpData->CpuApStackSize;
803 ApStackData = (AP_STACK_DATA *)((UINTN)ApTopOfStack - sizeof (AP_STACK_DATA));
804 BistData = (UINT32)ApStackData->Bist;
805
806 //
807 // CpuMpData->CpuData[ProcessorNumber].VolatileRegisters is initialized based on BSP environment,
808 // to initialize AP in InitConfig path.
809 // NOTE: IDTR.BASE stored in CpuMpData->CpuData[ProcessorNumber].VolatileRegisters points to a different IDT shared by all APs.
810 //
811 RestoreVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters);
812 InitializeApData (CpuMpData, ProcessorNumber, BistData, ApTopOfStack);
813 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
814 } else {
815 //
816 // Execute AP function if AP is ready
817 //
818 GetProcessorNumber (CpuMpData, &ProcessorNumber);
819 //
820 // Clear AP start-up signal when AP waken up
821 //
822 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
823 OriginalValue = InterlockedCompareExchange32 (
824 (UINT32 *)ApStartupSignalBuffer,
825 MP_HAND_OFF_SIGNAL,
826 0
827 );
828 if (OriginalValue == MP_HAND_OFF_SIGNAL) {
829 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateReady);
830 }
831
832 InterlockedCompareExchange32 (
833 (UINT32 *)ApStartupSignalBuffer,
834 WAKEUP_AP_SIGNAL,
835 0
836 );
837
838 RestoreVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters);
839
840 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateReady) {
841 Procedure = (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNumber].ApFunction;
842 Parameter = (VOID *)CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument;
843 if (Procedure != NULL) {
844 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy);
845 //
846 // Enable source debugging on AP function
847 //
848 EnableDebugAgent ();
849 //
850 // Invoke AP function here
851 //
852 Procedure (Parameter);
853 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
854 if (CpuMpData->SwitchBspFlag) {
855 //
856 // Re-get the processor number due to BSP/AP maybe exchange in AP function
857 //
858 GetProcessorNumber (CpuMpData, &ProcessorNumber);
859 CpuMpData->CpuData[ProcessorNumber].ApFunction = 0;
860 CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument = 0;
861 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
862 CpuInfoInHob[ProcessorNumber].ApTopOfStack = CpuInfoInHob[CpuMpData->NewBspNumber].ApTopOfStack;
863 } else {
864 if ((CpuInfoInHob[ProcessorNumber].ApicId != GetApicId ()) ||
865 (CpuInfoInHob[ProcessorNumber].InitialApicId != GetInitialApicId ()))
866 {
867 if (CurrentApicMode != GetApicMode ()) {
868 //
869 // If APIC mode change happened during AP function execution,
870 // we do not support APIC ID value changed.
871 //
872 ASSERT (FALSE);
873 CpuDeadLoop ();
874 } else {
875 //
876 // Re-get the CPU APICID and Initial APICID if they are changed
877 //
878 CpuInfoInHob[ProcessorNumber].ApicId = GetApicId ();
879 CpuInfoInHob[ProcessorNumber].InitialApicId = GetInitialApicId ();
880 }
881 }
882 }
883 }
884
885 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished);
886 }
887 }
888
889 SaveVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters);
890
891 //
892 // AP finished executing C code
893 //
894 InterlockedIncrement ((UINT32 *)&CpuMpData->FinishedCount);
895
896 if (CpuMpData->InitFlag == ApInitConfig) {
897 //
898 // Delay decrementing the APs executing count when SEV-ES is enabled
899 // to allow the APs to issue an AP_RESET_HOLD before the BSP possibly
900 // performs another INIT-SIPI-SIPI sequence.
901 //
902 if (!CpuMpData->UseSevEsAPMethod) {
903 InterlockedDecrement ((UINT32 *)&CpuMpData->MpCpuExchangeInfo->NumApsExecuting);
904 }
905 }
906
907 //
908 // Place AP is specified loop mode
909 //
910 if (CpuMpData->ApLoopMode == ApInHltLoop) {
911 PlaceAPInHltLoop (CpuMpData);
912 //
913 // Never run here
914 //
915 } else {
916 PlaceAPInMwaitLoopOrRunLoop (CpuMpData->ApLoopMode, ApStartupSignalBuffer, CpuMpData->ApTargetCState);
917 }
918 }
919}
920
921/**
922 This function serves as the entry point for APs when
923 they are awakened by the stores in the memory address
924 indicated by the MP_HANDOFF_INFO structure.
925
926 @param[in] CpuMpData Pointer to PEI CPU MP Data
927**/
928VOID
929EFIAPI
930DxeApEntryPoint (
931 CPU_MP_DATA *CpuMpData
932 )
933{
934 UINTN ProcessorNumber;
935 MSR_IA32_EFER_REGISTER EferMsr;
936
937 GetProcessorNumber (CpuMpData, &ProcessorNumber);
938 if (CpuMpData->EnableExecuteDisableForSwitchContext) {
939 EferMsr.Uint64 = AsmReadMsr64 (MSR_IA32_EFER);
940 EferMsr.Bits.NXE = 1;
941 AsmWriteMsr64 (MSR_IA32_EFER, EferMsr.Uint64);
942 }
943
944 RestoreVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters);
945 InterlockedIncrement ((UINT32 *)&CpuMpData->FinishedCount);
946 PlaceAPInMwaitLoopOrRunLoop (
947 CpuMpData->ApLoopMode,
948 CpuMpData->CpuData[ProcessorNumber].StartupApSignal,
949 CpuMpData->ApTargetCState
950 );
951 ApWakeupFunction (CpuMpData, ProcessorNumber);
952}
953
954/**
955 Wait for AP wakeup and write AP start-up signal till AP is waken up.
956
957 @param[in] ApStartupSignalBuffer Pointer to AP wakeup signal
958**/
959VOID
960WaitApWakeup (
961 IN volatile UINT32 *ApStartupSignalBuffer
962 )
963{
964 //
965 // If AP is waken up, StartupApSignal should be cleared.
966 // Otherwise, write StartupApSignal again till AP waken up.
967 //
968 while (InterlockedCompareExchange32 (
969 (UINT32 *)ApStartupSignalBuffer,
970 WAKEUP_AP_SIGNAL,
971 WAKEUP_AP_SIGNAL
972 ) != 0)
973 {
974 CpuPause ();
975 }
976}
977
978/**
979 Calculate the size of the reset vector.
980
981 @param[in] AddressMap The pointer to Address Map structure.
982 @param[out] SizeBelow1Mb Return the size of below 1MB memory for AP reset area.
983 @param[out] SizeAbove1Mb Return the size of abvoe 1MB memory for AP reset area.
984**/
985STATIC
986VOID
987GetApResetVectorSize (
988 IN MP_ASSEMBLY_ADDRESS_MAP *AddressMap,
989 OUT UINTN *SizeBelow1Mb OPTIONAL,
990 OUT UINTN *SizeAbove1Mb OPTIONAL
991 )
992{
993 if (SizeBelow1Mb != NULL) {
994 *SizeBelow1Mb = AddressMap->ModeTransitionOffset + sizeof (MP_CPU_EXCHANGE_INFO);
995 }
996
997 if (SizeAbove1Mb != NULL) {
998 *SizeAbove1Mb = AddressMap->RendezvousFunnelSize - AddressMap->ModeTransitionOffset;
999 }
1000}
1001
1002/**
1003 This function will fill the exchange info structure.
1004
1005 @param[in] CpuMpData Pointer to CPU MP Data
1006
1007**/
1008VOID
1009FillExchangeInfoData (
1010 IN CPU_MP_DATA *CpuMpData
1011 )
1012{
1013 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
1014 UINTN Size;
1015 IA32_SEGMENT_DESCRIPTOR *Selector;
1016 IA32_CR4 Cr4;
1017
1018 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;
1019 ExchangeInfo->StackStart = CpuMpData->Buffer;
1020 ExchangeInfo->StackSize = CpuMpData->CpuApStackSize;
1021 ExchangeInfo->BufferStart = CpuMpData->WakeupBuffer;
1022 ExchangeInfo->ModeOffset = CpuMpData->AddressMap.ModeEntryOffset;
1023
1024 ExchangeInfo->CodeSegment = AsmReadCs ();
1025 ExchangeInfo->DataSegment = AsmReadDs ();
1026
1027 ExchangeInfo->Cr3 = AsmReadCr3 ();
1028
1029 ExchangeInfo->CFunction = (UINTN)ApWakeupFunction;
1030 ExchangeInfo->ApIndex = 0;
1031 ExchangeInfo->NumApsExecuting = 0;
1032 ExchangeInfo->InitFlag = (UINTN)CpuMpData->InitFlag;
1033 ExchangeInfo->CpuInfo = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
1034 ExchangeInfo->CpuMpData = CpuMpData;
1035
1036 ExchangeInfo->EnableExecuteDisable = IsBspExecuteDisableEnabled ();
1037
1038 ExchangeInfo->InitializeFloatingPointUnitsAddress = (UINTN)InitializeFloatingPointUnits;
1039
1040 //
1041 // We can check either CPUID(7).ECX[bit16] or check CR4.LA57[bit12]
1042 // to determin whether 5-Level Paging is enabled.
1043 // CPUID(7).ECX[bit16] shows CPU's capability, CR4.LA57[bit12] shows
1044 // current system setting.
1045 // Using latter way is simpler because it also eliminates the needs to
1046 // check whether platform wants to enable it.
1047 //
1048 Cr4.UintN = AsmReadCr4 ();
1049 ExchangeInfo->Enable5LevelPaging = (BOOLEAN)(Cr4.Bits.LA57 == 1);
1050 DEBUG ((DEBUG_INFO, "%a: 5-Level Paging = %d\n", gEfiCallerBaseName, ExchangeInfo->Enable5LevelPaging));
1051
1052 ExchangeInfo->SevEsIsEnabled = CpuMpData->SevEsIsEnabled;
1053 ExchangeInfo->SevSnpIsEnabled = CpuMpData->SevSnpIsEnabled;
1054 ExchangeInfo->GhcbBase = (UINTN)CpuMpData->GhcbBase;
1055
1056 //
1057 // Populate SEV-ES specific exchange data.
1058 //
1059 if (ExchangeInfo->SevSnpIsEnabled) {
1060 FillExchangeInfoDataSevEs (ExchangeInfo);
1061 }
1062
1063 //
1064 // Get the BSP's data of GDT and IDT
1065 //
1066 AsmReadGdtr ((IA32_DESCRIPTOR *)&ExchangeInfo->GdtrProfile);
1067 AsmReadIdtr ((IA32_DESCRIPTOR *)&ExchangeInfo->IdtrProfile);
1068
1069 //
1070 // Find a 32-bit code segment
1071 //
1072 Selector = (IA32_SEGMENT_DESCRIPTOR *)ExchangeInfo->GdtrProfile.Base;
1073 Size = ExchangeInfo->GdtrProfile.Limit + 1;
1074 while (Size > 0) {
1075 if ((Selector->Bits.L == 0) && (Selector->Bits.Type >= 8)) {
1076 ExchangeInfo->ModeTransitionSegment =
1077 (UINT16)((UINTN)Selector - ExchangeInfo->GdtrProfile.Base);
1078 break;
1079 }
1080
1081 Selector += 1;
1082 Size -= sizeof (IA32_SEGMENT_DESCRIPTOR);
1083 }
1084
1085 ExchangeInfo->ModeTransitionMemory = (UINT32)CpuMpData->WakeupBufferHigh;
1086
1087 ExchangeInfo->ModeHighMemory = ExchangeInfo->ModeTransitionMemory +
1088 (UINT32)ExchangeInfo->ModeOffset -
1089 (UINT32)CpuMpData->AddressMap.ModeTransitionOffset;
1090 ExchangeInfo->ModeHighSegment = (UINT16)ExchangeInfo->CodeSegment;
1091}
1092
1093/**
1094 Helper function that waits until the finished AP count reaches the specified
1095 limit, or the specified timeout elapses (whichever comes first).
1096
1097 @param[in] CpuMpData Pointer to CPU MP Data.
1098 @param[in] FinishedApLimit The number of finished APs to wait for.
1099 @param[in] TimeLimit The number of microseconds to wait for.
1100**/
1101VOID
1102TimedWaitForApFinish (
1103 IN CPU_MP_DATA *CpuMpData,
1104 IN UINT32 FinishedApLimit,
1105 IN UINT32 TimeLimit
1106 );
1107
1108/**
1109 Get available system memory below 1MB by specified size.
1110
1111 @param[in] CpuMpData The pointer to CPU MP Data structure.
1112**/
1113VOID
1114BackupAndPrepareWakeupBuffer (
1115 IN CPU_MP_DATA *CpuMpData
1116 )
1117{
1118 CopyMem (
1119 (VOID *)CpuMpData->BackupBuffer,
1120 (VOID *)CpuMpData->WakeupBuffer,
1121 CpuMpData->BackupBufferSize
1122 );
1123 CopyMem (
1124 (VOID *)CpuMpData->WakeupBuffer,
1125 (VOID *)CpuMpData->AddressMap.RendezvousFunnelAddress,
1126 CpuMpData->BackupBufferSize - sizeof (MP_CPU_EXCHANGE_INFO)
1127 );
1128}
1129
1130/**
1131 Restore wakeup buffer data.
1132
1133 @param[in] CpuMpData The pointer to CPU MP Data structure.
1134**/
1135VOID
1136RestoreWakeupBuffer (
1137 IN CPU_MP_DATA *CpuMpData
1138 )
1139{
1140 CopyMem (
1141 (VOID *)CpuMpData->WakeupBuffer,
1142 (VOID *)CpuMpData->BackupBuffer,
1143 CpuMpData->BackupBufferSize
1144 );
1145}
1146
1147/**
1148 Allocate reset vector buffer.
1149
1150 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
1151**/
1152VOID
1153AllocateResetVectorBelow1Mb (
1154 IN OUT CPU_MP_DATA *CpuMpData
1155 )
1156{
1157 UINTN ApResetStackSize;
1158
1159 if (CpuMpData->WakeupBuffer == (UINTN)-1) {
1160 CpuMpData->WakeupBuffer = GetWakeupBuffer (CpuMpData->BackupBufferSize);
1161 CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *)(UINTN)
1162 (CpuMpData->WakeupBuffer + CpuMpData->BackupBufferSize - sizeof (MP_CPU_EXCHANGE_INFO));
1163 DEBUG ((
1164 DEBUG_INFO,
1165 "AP Vector: 16-bit = %p/%x, ExchangeInfo = %p/%x\n",
1166 CpuMpData->WakeupBuffer,
1167 CpuMpData->BackupBufferSize - sizeof (MP_CPU_EXCHANGE_INFO),
1168 CpuMpData->MpCpuExchangeInfo,
1169 sizeof (MP_CPU_EXCHANGE_INFO)
1170 ));
1171 //
1172 // The AP reset stack is only used by SEV-ES guests. Do not allocate it
1173 // if SEV-ES is not enabled. An SEV-SNP guest is also considered
1174 // an SEV-ES guest, but uses a different method of AP startup, eliminating
1175 // the need for the allocation.
1176 //
1177 if (ConfidentialComputingGuestHas (CCAttrAmdSevEs) &&
1178 !ConfidentialComputingGuestHas (CCAttrAmdSevSnp))
1179 {
1180 //
1181 // Stack location is based on ProcessorNumber, so use the total number
1182 // of processors for calculating the total stack area.
1183 //
1184 ApResetStackSize = (AP_RESET_STACK_SIZE *
1185 PcdGet32 (PcdCpuMaxLogicalProcessorNumber));
1186
1187 //
1188 // Invoke GetWakeupBuffer a second time to allocate the stack area
1189 // below 1MB. The returned buffer will be page aligned and sized and
1190 // below the previously allocated buffer.
1191 //
1192 CpuMpData->SevEsAPResetStackStart = GetWakeupBuffer (ApResetStackSize);
1193
1194 //
1195 // Check to be sure that the "allocate below" behavior hasn't changed.
1196 // This will also catch a failed allocation, as "-1" is returned on
1197 // failure.
1198 //
1199 if (CpuMpData->SevEsAPResetStackStart >= CpuMpData->WakeupBuffer) {
1200 DEBUG ((
1201 DEBUG_ERROR,
1202 "SEV-ES AP reset stack is not below wakeup buffer\n"
1203 ));
1204
1205 ASSERT (FALSE);
1206 CpuDeadLoop ();
1207 }
1208 }
1209 }
1210
1211 BackupAndPrepareWakeupBuffer (CpuMpData);
1212}
1213
1214/**
1215 Free AP reset vector buffer.
1216
1217 @param[in] CpuMpData The pointer to CPU MP Data structure.
1218**/
1219VOID
1220FreeResetVector (
1221 IN CPU_MP_DATA *CpuMpData
1222 )
1223{
1224 //
1225 // If SEV-ES is enabled, the reset area is needed for AP parking and
1226 // and AP startup in the OS, so the reset area is reserved. Do not
1227 // perform the restore as this will overwrite memory which has data
1228 // needed by SEV-ES.
1229 //
1230 if (!CpuMpData->UseSevEsAPMethod) {
1231 RestoreWakeupBuffer (CpuMpData);
1232 }
1233}
1234
1235/**
1236 This function will be called by BSP to wakeup AP.
1237
1238 @param[in] CpuMpData Pointer to CPU MP Data
1239 @param[in] Broadcast TRUE: Send broadcast IPI to all APs
1240 FALSE: Send IPI to AP by ApicId
1241 @param[in] ProcessorNumber The handle number of specified processor
1242 @param[in] Procedure The function to be invoked by AP
1243 @param[in] ProcedureArgument The argument to be passed into AP function
1244 @param[in] WakeUpDisabledAps Whether need to wake up disabled APs in broadcast mode.
1245**/
1246VOID
1247WakeUpAP (
1248 IN CPU_MP_DATA *CpuMpData,
1249 IN BOOLEAN Broadcast,
1250 IN UINTN ProcessorNumber,
1251 IN EFI_AP_PROCEDURE Procedure OPTIONAL,
1252 IN VOID *ProcedureArgument OPTIONAL,
1253 IN BOOLEAN WakeUpDisabledAps
1254 )
1255{
1256 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
1257 UINTN Index;
1258 CPU_AP_DATA *CpuData;
1259 BOOLEAN ResetVectorRequired;
1260 CPU_INFO_IN_HOB *CpuInfoInHob;
1261
1262 CpuMpData->FinishedCount = 0;
1263 ResetVectorRequired = FALSE;
1264
1265 if (CpuMpData->WakeUpByInitSipiSipi ||
1266 (CpuMpData->InitFlag == ApInitConfig))
1267 {
1268 ResetVectorRequired = TRUE;
1269 AllocateResetVectorBelow1Mb (CpuMpData);
1270 AllocateSevEsAPMemory (CpuMpData);
1271 FillExchangeInfoData (CpuMpData);
1272 }
1273
1274 if (CpuMpData->ApLoopMode == ApInMwaitLoop) {
1275 //
1276 // Get AP target C-state each time when waking up AP,
1277 // for it maybe updated by platform again
1278 //
1279 CpuMpData->ApTargetCState = PcdGet8 (PcdCpuApTargetCstate);
1280 }
1281
1282 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;
1283
1284 if (Broadcast) {
1285 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
1286 if (Index != CpuMpData->BspNumber) {
1287 CpuData = &CpuMpData->CpuData[Index];
1288 //
1289 // All AP(include disabled AP) will be woke up by INIT-SIPI-SIPI, but
1290 // the AP procedure will be skipped for disabled AP because AP state
1291 // is not CpuStateReady.
1292 //
1293 if ((GetApState (CpuData) == CpuStateDisabled) && !WakeUpDisabledAps) {
1294 continue;
1295 }
1296
1297 CpuData->ApFunction = (UINTN)Procedure;
1298 CpuData->ApFunctionArgument = (UINTN)ProcedureArgument;
1299 SetApState (CpuData, CpuStateReady);
1300 if (CpuMpData->InitFlag == ApInitDone) {
1301 *(UINT32 *)CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;
1302 }
1303 }
1304 }
1305
1306 if (ResetVectorRequired) {
1307 //
1308 // For SEV-ES and SEV-SNP, the initial AP boot address will be defined by
1309 // PcdSevEsWorkAreaBase. The Segment/Rip must be the jump address
1310 // from the original INIT-SIPI-SIPI.
1311 //
1312 if (CpuMpData->SevEsIsEnabled) {
1313 SetSevEsJumpTable (ExchangeInfo->BufferStart);
1314 }
1315
1316 //
1317 // Wakeup all APs
1318 // Must use the INIT-SIPI-SIPI method for initial configuration in
1319 // order to obtain the APIC ID if not an SEV-SNP guest and the
1320 // list of APIC IDs is not available.
1321 //
1322 if (CanUseSevSnpCreateAP (CpuMpData)) {
1323 SevSnpCreateAP (CpuMpData, -1);
1324 } else {
1325 if ((CpuMpData->InitFlag == ApInitConfig) && FixedPcdGetBool (PcdFirstTimeWakeUpAPsBySipi)) {
1326 //
1327 // SIPI can be used for the first time wake up after reset to reduce boot time.
1328 //
1329 SendStartupIpiAllExcludingSelf ((UINT32)ExchangeInfo->BufferStart);
1330 } else {
1331 SendInitSipiSipiAllExcludingSelf ((UINT32)ExchangeInfo->BufferStart);
1332 }
1333 }
1334 }
1335
1336 if (CpuMpData->InitFlag == ApInitConfig) {
1337 if (PcdGet32 (PcdCpuBootLogicalProcessorNumber) > 0) {
1338 //
1339 // The AP enumeration algorithm below is suitable only when the
1340 // platform can tell us the *exact* boot CPU count in advance.
1341 //
1342 // The wait below finishes only when the detected AP count reaches
1343 // (PcdCpuBootLogicalProcessorNumber - 1), regardless of how long that
1344 // takes. If at least one AP fails to check in (meaning a platform
1345 // hardware bug), the detection hangs forever, by design. If the actual
1346 // boot CPU count in the system is higher than
1347 // PcdCpuBootLogicalProcessorNumber (meaning a platform
1348 // misconfiguration), then some APs may complete initialization after
1349 // the wait finishes, and cause undefined behavior.
1350 //
1351 TimedWaitForApFinish (
1352 CpuMpData,
1353 PcdGet32 (PcdCpuBootLogicalProcessorNumber) - 1,
1354 MAX_UINT32 // approx. 71 minutes
1355 );
1356 } else {
1357 //
1358 // The AP enumeration algorithm below is suitable for two use cases.
1359 //
1360 // (1) The check-in time for an individual AP is bounded, and APs run
1361 // through their initialization routines strongly concurrently. In
1362 // particular, the number of concurrently running APs
1363 // ("NumApsExecuting") is never expected to fall to zero
1364 // *temporarily* -- it is expected to fall to zero only when all
1365 // APs have checked-in.
1366 //
1367 // In this case, the platform is supposed to set
1368 // PcdCpuApInitTimeOutInMicroSeconds to a low-ish value (just long
1369 // enough for one AP to start initialization). The timeout will be
1370 // reached soon, and remaining APs are collected by watching
1371 // NumApsExecuting fall to zero. If NumApsExecuting falls to zero
1372 // mid-process, while some APs have not completed initialization,
1373 // the behavior is undefined.
1374 //
1375 // (2) The check-in time for an individual AP is unbounded, and/or APs
1376 // may complete their initializations widely spread out. In
1377 // particular, some APs may finish initialization before some APs
1378 // even start.
1379 //
1380 // In this case, the platform is supposed to set
1381 // PcdCpuApInitTimeOutInMicroSeconds to a high-ish value. The AP
1382 // enumeration will always take that long (except when the boot CPU
1383 // count happens to be maximal, that is,
1384 // PcdCpuMaxLogicalProcessorNumber). All APs are expected to
1385 // check-in before the timeout, and NumApsExecuting is assumed zero
1386 // at timeout. APs that miss the time-out may cause undefined
1387 // behavior.
1388 //
1389 TimedWaitForApFinish (
1390 CpuMpData,
1391 PcdGet32 (PcdCpuMaxLogicalProcessorNumber) - 1,
1392 PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds)
1393 );
1394
1395 while (CpuMpData->MpCpuExchangeInfo->NumApsExecuting != 0) {
1396 CpuPause ();
1397 }
1398 }
1399 } else {
1400 //
1401 // Wait all APs waken up if this is not the 1st broadcast of SIPI
1402 //
1403 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
1404 CpuData = &CpuMpData->CpuData[Index];
1405 if (Index != CpuMpData->BspNumber) {
1406 WaitApWakeup (CpuData->StartupApSignal);
1407 }
1408 }
1409 }
1410 } else {
1411 CpuData = &CpuMpData->CpuData[ProcessorNumber];
1412 CpuData->ApFunction = (UINTN)Procedure;
1413 CpuData->ApFunctionArgument = (UINTN)ProcedureArgument;
1414 SetApState (CpuData, CpuStateReady);
1415 //
1416 // Wakeup specified AP
1417 //
1418 ASSERT (CpuMpData->InitFlag == ApInitDone);
1419 *(UINT32 *)CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;
1420 if (ResetVectorRequired) {
1421 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
1422
1423 //
1424 // For SEV-ES and SEV-SNP, the initial AP boot address will be defined by
1425 // PcdSevEsWorkAreaBase. The Segment/Rip must be the jump address
1426 // from the original INIT-SIPI-SIPI.
1427 //
1428 if (CpuMpData->SevEsIsEnabled) {
1429 SetSevEsJumpTable (ExchangeInfo->BufferStart);
1430 }
1431
1432 if (CanUseSevSnpCreateAP (CpuMpData)) {
1433 SevSnpCreateAP (CpuMpData, (INTN)ProcessorNumber);
1434 } else {
1435 SendInitSipiSipi (
1436 CpuInfoInHob[ProcessorNumber].ApicId,
1437 (UINT32)ExchangeInfo->BufferStart
1438 );
1439 }
1440 }
1441
1442 //
1443 // Wait specified AP waken up
1444 //
1445 WaitApWakeup (CpuData->StartupApSignal);
1446 }
1447
1448 if (ResetVectorRequired) {
1449 FreeResetVector (CpuMpData);
1450 }
1451
1452 //
1453 // After one round of Wakeup Ap actions, need to re-sync ApLoopMode with
1454 // WakeUpByInitSipiSipi flag. WakeUpByInitSipiSipi flag maybe changed by
1455 // S3SmmInitDone Ppi.
1456 //
1457 CpuMpData->WakeUpByInitSipiSipi = (CpuMpData->ApLoopMode == ApInHltLoop);
1458}
1459
1460/**
1461 Calculate timeout value and return the current performance counter value.
1462
1463 Calculate the number of performance counter ticks required for a timeout.
1464 If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
1465 as infinity.
1466
1467 @param[in] TimeoutInMicroseconds Timeout value in microseconds.
1468 @param[out] CurrentTime Returns the current value of the performance counter.
1469
1470 @return Expected time stamp counter for timeout.
1471 If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
1472 as infinity.
1473
1474**/
1475UINT64
1476CalculateTimeout (
1477 IN UINTN TimeoutInMicroseconds,
1478 OUT UINT64 *CurrentTime
1479 )
1480{
1481 UINT64 TimeoutInSeconds;
1482 UINT64 TimestampCounterFreq;
1483
1484 //
1485 // Read the current value of the performance counter
1486 //
1487 *CurrentTime = GetPerformanceCounter ();
1488
1489 //
1490 // If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
1491 // as infinity.
1492 //
1493 if (TimeoutInMicroseconds == 0) {
1494 return 0;
1495 }
1496
1497 //
1498 // GetPerformanceCounterProperties () returns the timestamp counter's frequency
1499 // in Hz.
1500 //
1501 TimestampCounterFreq = GetPerformanceCounterProperties (NULL, NULL);
1502
1503 //
1504 // Check the potential overflow before calculate the number of ticks for the timeout value.
1505 //
1506 if (DivU64x64Remainder (MAX_UINT64, TimeoutInMicroseconds, NULL) < TimestampCounterFreq) {
1507 //
1508 // Convert microseconds into seconds if direct multiplication overflows
1509 //
1510 TimeoutInSeconds = DivU64x32 (TimeoutInMicroseconds, 1000000);
1511 //
1512 // Assertion if the final tick count exceeds MAX_UINT64
1513 //
1514 ASSERT (DivU64x64Remainder (MAX_UINT64, TimeoutInSeconds, NULL) >= TimestampCounterFreq);
1515 return MultU64x64 (TimestampCounterFreq, TimeoutInSeconds);
1516 } else {
1517 //
1518 // No overflow case, multiply the return value with TimeoutInMicroseconds and then divide
1519 // it by 1,000,000, to get the number of ticks for the timeout value.
1520 //
1521 return DivU64x32 (
1522 MultU64x64 (
1523 TimestampCounterFreq,
1524 TimeoutInMicroseconds
1525 ),
1526 1000000
1527 );
1528 }
1529}
1530
1531/**
1532 Switch Context for each AP.
1533
1534**/
1535VOID
1536EFIAPI
1537SwitchContextPerAp (
1538 VOID
1539 )
1540{
1541 UINTN ProcessorNumber;
1542 CPU_MP_DATA *CpuMpData;
1543 CPU_INFO_IN_HOB *CpuInfoInHob;
1544
1545 CpuMpData = GetCpuMpData ();
1546 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
1547 GetProcessorNumber (CpuMpData, &ProcessorNumber);
1548
1549 SwitchStack (
1550 (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeApEntryPoint,
1551 (VOID *)(UINTN)CpuMpData,
1552 NULL,
1553 (VOID *)((UINTN)CpuInfoInHob[ProcessorNumber].ApTopOfStack)
1554 );
1555}
1556
1557/**
1558 Checks whether timeout expires.
1559
1560 Check whether the number of elapsed performance counter ticks required for
1561 a timeout condition has been reached.
1562 If Timeout is zero, which means infinity, return value is always FALSE.
1563
1564 @param[in, out] PreviousTime On input, the value of the performance counter
1565 when it was last read.
1566 On output, the current value of the performance
1567 counter
1568 @param[in] TotalTime The total amount of elapsed time in performance
1569 counter ticks.
1570 @param[in] Timeout The number of performance counter ticks required
1571 to reach a timeout condition.
1572
1573 @retval TRUE A timeout condition has been reached.
1574 @retval FALSE A timeout condition has not been reached.
1575
1576**/
1577BOOLEAN
1578CheckTimeout (
1579 IN OUT UINT64 *PreviousTime,
1580 IN UINT64 *TotalTime,
1581 IN UINT64 Timeout
1582 )
1583{
1584 UINT64 Start;
1585 UINT64 End;
1586 UINT64 CurrentTime;
1587 INT64 Delta;
1588 INT64 Cycle;
1589
1590 if (Timeout == 0) {
1591 return FALSE;
1592 }
1593
1594 GetPerformanceCounterProperties (&Start, &End);
1595 Cycle = End - Start;
1596 if (Cycle < 0) {
1597 Cycle = -Cycle;
1598 }
1599
1600 Cycle++;
1601 CurrentTime = GetPerformanceCounter ();
1602 Delta = (INT64)(CurrentTime - *PreviousTime);
1603 if (Start > End) {
1604 Delta = -Delta;
1605 }
1606
1607 if (Delta < 0) {
1608 Delta += Cycle;
1609 }
1610
1611 *TotalTime += Delta;
1612 *PreviousTime = CurrentTime;
1613 if (*TotalTime > Timeout) {
1614 return TRUE;
1615 }
1616
1617 return FALSE;
1618}
1619
1620/**
1621 Helper function that waits until the finished AP count reaches the specified
1622 limit, or the specified timeout elapses (whichever comes first).
1623
1624 @param[in] CpuMpData Pointer to CPU MP Data.
1625 @param[in] FinishedApLimit The number of finished APs to wait for.
1626 @param[in] TimeLimit The number of microseconds to wait for.
1627**/
1628VOID
1629TimedWaitForApFinish (
1630 IN CPU_MP_DATA *CpuMpData,
1631 IN UINT32 FinishedApLimit,
1632 IN UINT32 TimeLimit
1633 )
1634{
1635 //
1636 // CalculateTimeout() and CheckTimeout() consider a TimeLimit of 0
1637 // "infinity", so check for (TimeLimit == 0) explicitly.
1638 //
1639 if (TimeLimit == 0) {
1640 return;
1641 }
1642
1643 CpuMpData->TotalTime = 0;
1644 CpuMpData->ExpectedTime = CalculateTimeout (
1645 TimeLimit,
1646 &CpuMpData->CurrentTime
1647 );
1648 while (CpuMpData->FinishedCount < FinishedApLimit &&
1649 !CheckTimeout (
1650 &CpuMpData->CurrentTime,
1651 &CpuMpData->TotalTime,
1652 CpuMpData->ExpectedTime
1653 ))
1654 {
1655 CpuPause ();
1656 }
1657
1658 if (CpuMpData->FinishedCount >= FinishedApLimit) {
1659 DEBUG ((
1660 DEBUG_VERBOSE,
1661 "%a: reached FinishedApLimit=%u in %Lu microseconds\n",
1662 __func__,
1663 FinishedApLimit,
1664 DivU64x64Remainder (
1665 MultU64x32 (CpuMpData->TotalTime, 1000000),
1666 GetPerformanceCounterProperties (NULL, NULL),
1667 NULL
1668 )
1669 ));
1670 }
1671}
1672
1673/**
1674 Reset an AP to Idle state.
1675
1676 Any task being executed by the AP will be aborted and the AP
1677 will be waiting for a new task in Wait-For-SIPI state.
1678
1679 @param[in] ProcessorNumber The handle number of processor.
1680**/
1681VOID
1682ResetProcessorToIdleState (
1683 IN UINTN ProcessorNumber
1684 )
1685{
1686 CPU_MP_DATA *CpuMpData;
1687
1688 CpuMpData = GetCpuMpData ();
1689
1690 CpuMpData->WakeUpByInitSipiSipi = TRUE;
1691 if (CpuMpData == NULL) {
1692 DEBUG ((DEBUG_ERROR, "[%a] - Failed to get CpuMpData. Aborting the AP reset to idle.\n", __func__));
1693 return;
1694 }
1695
1696 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, NULL, NULL, TRUE);
1697 while (CpuMpData->FinishedCount < 1) {
1698 CpuPause ();
1699 }
1700
1701 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);
1702}
1703
1704/**
1705 Searches for the next waiting AP.
1706
1707 Search for the next AP that is put in waiting state by single-threaded StartupAllAPs().
1708
1709 @param[out] NextProcessorNumber Pointer to the processor number of the next waiting AP.
1710
1711 @retval EFI_SUCCESS The next waiting AP has been found.
1712 @retval EFI_NOT_FOUND No waiting AP exists.
1713
1714**/
1715EFI_STATUS
1716GetNextWaitingProcessorNumber (
1717 OUT UINTN *NextProcessorNumber
1718 )
1719{
1720 UINTN ProcessorNumber;
1721 CPU_MP_DATA *CpuMpData;
1722
1723 CpuMpData = GetCpuMpData ();
1724
1725 if (CpuMpData == NULL) {
1726 DEBUG ((DEBUG_ERROR, "[%a] - Failed to get CpuMpData.\n", __func__));
1727 return EFI_LOAD_ERROR;
1728 }
1729
1730 for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
1731 if (CpuMpData->CpuData[ProcessorNumber].Waiting) {
1732 *NextProcessorNumber = ProcessorNumber;
1733 return EFI_SUCCESS;
1734 }
1735 }
1736
1737 return EFI_NOT_FOUND;
1738}
1739
1740/** Checks status of specified AP.
1741
1742 This function checks whether the specified AP has finished the task assigned
1743 by StartupThisAP(), and whether timeout expires.
1744
1745 @param[in] ProcessorNumber The handle number of processor.
1746
1747 @retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs().
1748 @retval EFI_TIMEOUT The timeout expires.
1749 @retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired.
1750**/
1751EFI_STATUS
1752CheckThisAP (
1753 IN UINTN ProcessorNumber
1754 )
1755{
1756 CPU_MP_DATA *CpuMpData;
1757 CPU_AP_DATA *CpuData;
1758
1759 CpuMpData = GetCpuMpData ();
1760
1761 if (CpuMpData == NULL) {
1762 DEBUG ((DEBUG_ERROR, "[%a] - Failed to get CpuMpData.\n", __func__));
1763 return EFI_LOAD_ERROR;
1764 }
1765
1766 CpuData = &CpuMpData->CpuData[ProcessorNumber];
1767
1768 //
1769 // Check the CPU state of AP. If it is CpuStateIdle, then the AP has finished its task.
1770 // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the
1771 // value of state after setting the it to CpuStateIdle, so BSP can safely make use of its value.
1772 //
1773 //
1774 // If the AP finishes for StartupThisAP(), return EFI_SUCCESS.
1775 //
1776 if (GetApState (CpuData) == CpuStateFinished) {
1777 if (CpuData->Finished != NULL) {
1778 *(CpuData->Finished) = TRUE;
1779 }
1780
1781 SetApState (CpuData, CpuStateIdle);
1782 return EFI_SUCCESS;
1783 } else {
1784 //
1785 // If timeout expires for StartupThisAP(), report timeout.
1786 //
1787 if (CheckTimeout (&CpuData->CurrentTime, &CpuData->TotalTime, CpuData->ExpectedTime)) {
1788 if (CpuData->Finished != NULL) {
1789 *(CpuData->Finished) = FALSE;
1790 }
1791
1792 //
1793 // Reset failed AP to idle state
1794 //
1795 ResetProcessorToIdleState (ProcessorNumber);
1796
1797 return EFI_TIMEOUT;
1798 }
1799 }
1800
1801 return EFI_NOT_READY;
1802}
1803
1804/**
1805 Checks status of all APs.
1806
1807 This function checks whether all APs have finished task assigned by StartupAllAPs(),
1808 and whether timeout expires.
1809
1810 @retval EFI_SUCCESS All APs have finished task assigned by StartupAllAPs().
1811 @retval EFI_TIMEOUT The timeout expires.
1812 @retval EFI_NOT_READY APs have not finished task and timeout has not expired.
1813**/
1814EFI_STATUS
1815CheckAllAPs (
1816 VOID
1817 )
1818{
1819 UINTN ProcessorNumber;
1820 UINTN NextProcessorNumber;
1821 UINTN ListIndex;
1822 EFI_STATUS Status;
1823 CPU_MP_DATA *CpuMpData;
1824 CPU_AP_DATA *CpuData;
1825
1826 CpuMpData = GetCpuMpData ();
1827
1828 if (CpuMpData == NULL) {
1829 DEBUG ((DEBUG_ERROR, "[%a] - Failed to get CpuMpData.\n", __func__));
1830 return EFI_LOAD_ERROR;
1831 }
1832
1833 NextProcessorNumber = 0;
1834
1835 //
1836 // Go through all APs that are responsible for the StartupAllAPs().
1837 //
1838 for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
1839 if (!CpuMpData->CpuData[ProcessorNumber].Waiting) {
1840 continue;
1841 }
1842
1843 CpuData = &CpuMpData->CpuData[ProcessorNumber];
1844 //
1845 // Check the CPU state of AP. If it is CpuStateIdle, then the AP has finished its task.
1846 // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the
1847 // value of state after setting the it to CpuStateIdle, so BSP can safely make use of its value.
1848 //
1849 if (GetApState (CpuData) == CpuStateFinished) {
1850 CpuMpData->RunningCount--;
1851 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
1852 SetApState (CpuData, CpuStateIdle);
1853
1854 //
1855 // If in Single Thread mode, then search for the next waiting AP for execution.
1856 //
1857 if (CpuMpData->SingleThread) {
1858 Status = GetNextWaitingProcessorNumber (&NextProcessorNumber);
1859
1860 if (!EFI_ERROR (Status)) {
1861 WakeUpAP (
1862 CpuMpData,
1863 FALSE,
1864 (UINT32)NextProcessorNumber,
1865 CpuMpData->Procedure,
1866 CpuMpData->ProcArguments,
1867 TRUE
1868 );
1869 }
1870 }
1871 }
1872 }
1873
1874 //
1875 // If all APs finish, return EFI_SUCCESS.
1876 //
1877 if (CpuMpData->RunningCount == 0) {
1878 return EFI_SUCCESS;
1879 }
1880
1881 //
1882 // If timeout expires, report timeout.
1883 //
1884 if (CheckTimeout (
1885 &CpuMpData->CurrentTime,
1886 &CpuMpData->TotalTime,
1887 CpuMpData->ExpectedTime
1888 )
1889 )
1890 {
1891 //
1892 // If FailedCpuList is not NULL, record all failed APs in it.
1893 //
1894 if (CpuMpData->FailedCpuList != NULL) {
1895 *CpuMpData->FailedCpuList =
1896 AllocatePool ((CpuMpData->RunningCount + 1) * sizeof (UINTN));
1897 ASSERT (*CpuMpData->FailedCpuList != NULL);
1898 }
1899
1900 ListIndex = 0;
1901
1902 for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
1903 //
1904 // Check whether this processor is responsible for StartupAllAPs().
1905 //
1906 if (CpuMpData->CpuData[ProcessorNumber].Waiting) {
1907 //
1908 // Reset failed APs to idle state
1909 //
1910 ResetProcessorToIdleState (ProcessorNumber);
1911 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
1912 if (CpuMpData->FailedCpuList != NULL) {
1913 (*CpuMpData->FailedCpuList)[ListIndex++] = ProcessorNumber;
1914 }
1915 }
1916 }
1917
1918 if (CpuMpData->FailedCpuList != NULL) {
1919 (*CpuMpData->FailedCpuList)[ListIndex] = END_OF_CPU_LIST;
1920 }
1921
1922 return EFI_TIMEOUT;
1923 }
1924
1925 return EFI_NOT_READY;
1926}
1927
1928/**
1929 This function Get BspNumber.
1930
1931 @param[in] FirstMpHandOff Pointer to first MpHandOff HOB body.
1932 @return BspNumber
1933**/
1934UINT32
1935GetBspNumber (
1936 IN CONST MP_HAND_OFF *FirstMpHandOff
1937 )
1938{
1939 UINT32 ApicId;
1940 UINT32 Index;
1941 CONST MP_HAND_OFF *MpHandOff;
1942
1943 //
1944 // Get the processor number for the BSP
1945 //
1946 ApicId = GetInitialApicId ();
1947
1948 for (MpHandOff = FirstMpHandOff;
1949 MpHandOff != NULL;
1950 MpHandOff = GetNextMpHandOffHob (MpHandOff))
1951 {
1952 for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
1953 if (MpHandOff->Info[Index].ApicId == ApicId) {
1954 return MpHandOff->ProcessorIndex + Index;
1955 }
1956 }
1957 }
1958
1959 ASSERT_EFI_ERROR (EFI_NOT_FOUND);
1960 return 0;
1961}
1962
1963/**
1964 This function is intended to be invoked by the BSP in order
1965 to wake up the AP. The BSP accomplishes this by triggering a
1966 start-up signal, which in turn causes any APs that are
1967 currently in a loop on the PEI-prepared memory to awaken and
1968 begin running the procedure called SwitchContextPerAp.
1969 This procedure allows the AP to switch to another section of
1970 memory and continue its loop there.
1971
1972 @param[in] MpHandOffConfig Pointer to MP hand-off config HOB body.
1973 @param[in] FirstMpHandOff Pointer to first MP hand-off HOB body.
1974**/
1975VOID
1976SwitchApContext (
1977 IN CONST MP_HAND_OFF_CONFIG *MpHandOffConfig,
1978 IN CONST MP_HAND_OFF *FirstMpHandOff
1979 )
1980{
1981 UINTN Index;
1982 UINT32 BspNumber;
1983 CONST MP_HAND_OFF *MpHandOff;
1984
1985 BspNumber = GetBspNumber (FirstMpHandOff);
1986
1987 for (MpHandOff = FirstMpHandOff;
1988 MpHandOff != NULL;
1989 MpHandOff = GetNextMpHandOffHob (MpHandOff))
1990 {
1991 for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
1992 if (MpHandOff->ProcessorIndex + Index != BspNumber) {
1993 *(UINTN *)(UINTN)MpHandOff->Info[Index].StartupProcedureAddress = (UINTN)SwitchContextPerAp;
1994 *(UINT32 *)(UINTN)MpHandOff->Info[Index].StartupSignalAddress = MpHandOffConfig->StartupSignalValue;
1995 }
1996 }
1997 }
1998
1999 //
2000 // Wait all APs waken up if this is not the 1st broadcast of SIPI
2001 //
2002 for (MpHandOff = FirstMpHandOff;
2003 MpHandOff != NULL;
2004 MpHandOff = GetNextMpHandOffHob (MpHandOff))
2005 {
2006 for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
2007 if (MpHandOff->ProcessorIndex + Index != BspNumber) {
2008 WaitApWakeup ((UINT32 *)(UINTN)(MpHandOff->Info[Index].StartupSignalAddress));
2009 }
2010 }
2011 }
2012}
2013
2014/**
2015 Get pointer to MP_HAND_OFF_CONFIG GUIDed HOB body.
2016
2017 @return The pointer to MP_HAND_OFF_CONFIG structure.
2018**/
2019MP_HAND_OFF_CONFIG *
2020GetMpHandOffConfigHob (
2021 VOID
2022 )
2023{
2024 EFI_HOB_GUID_TYPE *GuidHob;
2025
2026 GuidHob = GetFirstGuidHob (&mMpHandOffConfigGuid);
2027 if (GuidHob == NULL) {
2028 return NULL;
2029 }
2030
2031 return (MP_HAND_OFF_CONFIG *)GET_GUID_HOB_DATA (GuidHob);
2032}
2033
2034/**
2035 Get pointer to next MP_HAND_OFF GUIDed HOB body.
2036
2037 @param[in] MpHandOff Previous HOB body. Pass NULL to get the first HOB.
2038
2039 @return The pointer to MP_HAND_OFF structure.
2040**/
2041MP_HAND_OFF *
2042GetNextMpHandOffHob (
2043 IN CONST MP_HAND_OFF *MpHandOff
2044 )
2045{
2046 EFI_HOB_GUID_TYPE *GuidHob;
2047
2048 if (MpHandOff == NULL) {
2049 GuidHob = GetFirstGuidHob (&mMpHandOffGuid);
2050 } else {
2051 GuidHob = (VOID *)(((UINT8 *)MpHandOff) - sizeof (EFI_HOB_GUID_TYPE));
2052 GuidHob = GetNextGuidHob (&mMpHandOffGuid, GET_NEXT_HOB (GuidHob));
2053 }
2054
2055 if (GuidHob == NULL) {
2056 return NULL;
2057 }
2058
2059 return (MP_HAND_OFF *)GET_GUID_HOB_DATA (GuidHob);
2060}
2061
2062/**
2063 MP Initialize Library initialization.
2064
2065 This service will allocate AP reset vector and wakeup all APs to do APs
2066 initialization.
2067
2068 This service must be invoked before all other MP Initialize Library
2069 service are invoked.
2070
2071 @retval EFI_SUCCESS MP initialization succeeds.
2072 @retval Others MP initialization fails.
2073
2074**/
2075EFI_STATUS
2076EFIAPI
2077MpInitLibInitialize (
2078 VOID
2079 )
2080{
2081 MP_HAND_OFF_CONFIG *MpHandOffConfig;
2082 MP_HAND_OFF *FirstMpHandOff;
2083 MP_HAND_OFF *MpHandOff;
2084 CPU_INFO_IN_HOB *CpuInfoInHob;
2085 UINT32 MaxLogicalProcessorNumber;
2086 UINT32 ApStackSize;
2087 MP_ASSEMBLY_ADDRESS_MAP AddressMap;
2088 CPU_VOLATILE_REGISTERS VolatileRegisters;
2089 UINTN BufferSize;
2090 UINT32 MonitorFilterSize;
2091 VOID *MpBuffer;
2092 UINTN Buffer;
2093 CPU_MP_DATA *CpuMpData;
2094 UINT8 ApLoopMode;
2095 UINT8 *MonitorBuffer;
2096 UINT32 Index, HobIndex;
2097 UINTN ApResetVectorSizeBelow1Mb;
2098 UINTN ApResetVectorSizeAbove1Mb;
2099 UINTN BackupBufferAddr;
2100 UINTN ApIdtBase;
2101
2102 FirstMpHandOff = GetNextMpHandOffHob (NULL);
2103 if (FirstMpHandOff != NULL) {
2104 MaxLogicalProcessorNumber = 0;
2105 for (MpHandOff = FirstMpHandOff;
2106 MpHandOff != NULL;
2107 MpHandOff = GetNextMpHandOffHob (MpHandOff))
2108 {
2109 DEBUG ((
2110 DEBUG_INFO,
2111 "%a: ProcessorIndex=%u CpuCount=%u\n",
2112 __func__,
2113 MpHandOff->ProcessorIndex,
2114 MpHandOff->CpuCount
2115 ));
2116 ASSERT (MaxLogicalProcessorNumber == MpHandOff->ProcessorIndex);
2117 MaxLogicalProcessorNumber += MpHandOff->CpuCount;
2118 }
2119 } else {
2120 MaxLogicalProcessorNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
2121 }
2122
2123 ASSERT (MaxLogicalProcessorNumber != 0);
2124
2125 AsmGetAddressMap (&AddressMap);
2126 GetApResetVectorSize (&AddressMap, &ApResetVectorSizeBelow1Mb, &ApResetVectorSizeAbove1Mb);
2127 ApStackSize = PcdGet32 (PcdCpuApStackSize);
2128 //
2129 // ApStackSize must be power of 2
2130 //
2131 ASSERT ((ApStackSize & (ApStackSize - 1)) == 0);
2132 ApLoopMode = GetApLoopMode (&MonitorFilterSize);
2133
2134 //
2135 // Save BSP's Control registers for APs.
2136 //
2137 SaveVolatileRegisters (&VolatileRegisters);
2138
2139 BufferSize = ApStackSize * MaxLogicalProcessorNumber;
2140 //
2141 // Allocate extra ApStackSize to let AP stack align on ApStackSize bounday
2142 //
2143 BufferSize += ApStackSize;
2144 BufferSize += MonitorFilterSize * MaxLogicalProcessorNumber;
2145 BufferSize += ApResetVectorSizeBelow1Mb;
2146 BufferSize = ALIGN_VALUE (BufferSize, 8);
2147 BufferSize += VolatileRegisters.Idtr.Limit + 1;
2148 BufferSize += sizeof (CPU_MP_DATA);
2149 BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber;
2150 MpBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));
2151 ASSERT (MpBuffer != NULL);
2152 if (MpBuffer == NULL) {
2153 return EFI_OUT_OF_RESOURCES;
2154 }
2155
2156 ZeroMem (MpBuffer, BufferSize);
2157 Buffer = ALIGN_VALUE ((UINTN)MpBuffer, ApStackSize);
2158
2159 //
2160 // The layout of the Buffer is as below (lower address on top):
2161 //
2162 // +--------------------+ <-- Buffer (Pointer of CpuMpData is stored in the top of each AP's stack.)
2163 // AP Stacks (N) (StackTop = (RSP + ApStackSize) & ~ApStackSize))
2164 // +--------------------+ <-- MonitorBuffer
2165 // AP Monitor Filters (N)
2166 // +--------------------+ <-- BackupBufferAddr (CpuMpData->BackupBuffer)
2167 // Backup Buffer
2168 // +--------------------+
2169 // Padding
2170 // +--------------------+ <-- ApIdtBase (8-byte boundary)
2171 // AP IDT All APs share one separate IDT.
2172 // +--------------------+ <-- CpuMpData
2173 // CPU_MP_DATA
2174 // +--------------------+ <-- CpuMpData->CpuData
2175 // CPU_AP_DATA (N)
2176 // +--------------------+ <-- CpuMpData->CpuInfoInHob
2177 // CPU_INFO_IN_HOB (N)
2178 // +--------------------+
2179 //
2180 MonitorBuffer = (UINT8 *)(Buffer + ApStackSize * MaxLogicalProcessorNumber);
2181 BackupBufferAddr = (UINTN)MonitorBuffer + MonitorFilterSize * MaxLogicalProcessorNumber;
2182 ApIdtBase = ALIGN_VALUE (BackupBufferAddr + ApResetVectorSizeBelow1Mb, 8);
2183 CpuMpData = (CPU_MP_DATA *)(ApIdtBase + VolatileRegisters.Idtr.Limit + 1);
2184 CpuMpData->Buffer = Buffer;
2185 CpuMpData->CpuApStackSize = ApStackSize;
2186 CpuMpData->BackupBuffer = BackupBufferAddr;
2187 CpuMpData->BackupBufferSize = ApResetVectorSizeBelow1Mb;
2188 CpuMpData->WakeupBuffer = (UINTN)-1;
2189 CpuMpData->CpuCount = 1;
2190 if (FirstMpHandOff == NULL) {
2191 CpuMpData->BspNumber = 0;
2192 } else {
2193 CpuMpData->BspNumber = GetBspNumber (FirstMpHandOff);
2194 }
2195
2196 CpuMpData->WaitEvent = NULL;
2197 CpuMpData->SwitchBspFlag = FALSE;
2198 CpuMpData->CpuData = (CPU_AP_DATA *)(CpuMpData + 1);
2199 CpuMpData->CpuInfoInHob = (UINT64)(UINTN)(CpuMpData->CpuData + MaxLogicalProcessorNumber);
2200 InitializeSpinLock (&CpuMpData->MpLock);
2201 CpuMpData->SevEsIsEnabled = ConfidentialComputingGuestHas (CCAttrAmdSevEs);
2202 CpuMpData->SevSnpIsEnabled = ConfidentialComputingGuestHas (CCAttrAmdSevSnp);
2203 CpuMpData->SevEsAPBuffer = (UINTN)-1;
2204 CpuMpData->GhcbBase = PcdGet64 (PcdGhcbBase);
2205 CpuMpData->UseSevEsAPMethod = CpuMpData->SevEsIsEnabled && !CpuMpData->SevSnpIsEnabled;
2206
2207 if (CpuMpData->SevSnpIsEnabled) {
2208 ASSERT ((PcdGet64 (PcdGhcbHypervisorFeatures) & GHCB_HV_FEATURES_SNP_AP_CREATE) == GHCB_HV_FEATURES_SNP_AP_CREATE);
2209 }
2210
2211 //
2212 // Make sure no memory usage outside of the allocated buffer.
2213 // (ApStackSize - (Buffer - (UINTN)MpBuffer)) is the redundant caused by alignment
2214 //
2215 ASSERT (
2216 (CpuMpData->CpuInfoInHob + sizeof (CPU_INFO_IN_HOB) * MaxLogicalProcessorNumber) ==
2217 (UINTN)MpBuffer + BufferSize - (ApStackSize - Buffer + (UINTN)MpBuffer)
2218 );
2219
2220 //
2221 // Duplicate BSP's IDT to APs.
2222 // All APs share one separate IDT. So AP can get the address of CpuMpData by using IDTR.BASE + IDTR.LIMIT + 1
2223 //
2224 CopyMem ((VOID *)ApIdtBase, (VOID *)VolatileRegisters.Idtr.Base, VolatileRegisters.Idtr.Limit + 1);
2225 VolatileRegisters.Idtr.Base = ApIdtBase;
2226 //
2227 // Don't pass BSP's TR to APs to avoid AP init failure.
2228 //
2229 VolatileRegisters.Tr = 0;
2230 //
2231 // Set DR as 0 since DR is set only for BSP.
2232 //
2233 VolatileRegisters.Dr0 = 0;
2234 VolatileRegisters.Dr1 = 0;
2235 VolatileRegisters.Dr2 = 0;
2236 VolatileRegisters.Dr3 = 0;
2237 VolatileRegisters.Dr6 = 0;
2238 VolatileRegisters.Dr7 = 0;
2239
2240 //
2241 // Copy volatile registers since either APs are the first time to bring up,
2242 // or BSP is in DXE phase but APs are still running in PEI context.
2243 // In both cases, APs need use volatile registers from BSP
2244 //
2245 for (Index = 0; Index < MaxLogicalProcessorNumber; Index++) {
2246 CopyMem (&CpuMpData->CpuData[Index].VolatileRegisters, &VolatileRegisters, sizeof (VolatileRegisters));
2247 }
2248
2249 //
2250 // Set BSP basic information
2251 //
2252 InitializeApData (CpuMpData, CpuMpData->BspNumber, 0, CpuMpData->Buffer + ApStackSize * (CpuMpData->BspNumber + 1));
2253 //
2254 // Save assembly code information
2255 //
2256 CopyMem (&CpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));
2257 //
2258 // Finally set AP loop mode
2259 //
2260 CpuMpData->ApLoopMode = ApLoopMode;
2261 DEBUG ((DEBUG_INFO, "AP Loop Mode is %d\n", CpuMpData->ApLoopMode));
2262
2263 CpuMpData->WakeUpByInitSipiSipi = (CpuMpData->ApLoopMode == ApInHltLoop);
2264
2265 //
2266 // Set up APs wakeup signal buffer
2267 //
2268 for (Index = 0; Index < MaxLogicalProcessorNumber; Index++) {
2269 CpuMpData->CpuData[Index].StartupApSignal =
2270 (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);
2271 }
2272
2273 //
2274 // Copy all 32-bit code and 64-bit code into memory with type of
2275 // EfiBootServicesCode to avoid page fault if NX memory protection is enabled.
2276 //
2277 CpuMpData->WakeupBufferHigh = AllocateCodeBuffer (ApResetVectorSizeAbove1Mb);
2278 CopyMem (
2279 (VOID *)CpuMpData->WakeupBufferHigh,
2280 CpuMpData->AddressMap.RendezvousFunnelAddress +
2281 CpuMpData->AddressMap.ModeTransitionOffset,
2282 ApResetVectorSizeAbove1Mb
2283 );
2284 DEBUG ((DEBUG_INFO, "AP Vector: non-16-bit = %p/%x\n", CpuMpData->WakeupBufferHigh, ApResetVectorSizeAbove1Mb));
2285
2286 //
2287 // Save APIC mode for AP to sync
2288 //
2289 CpuMpData->InitialBspApicMode = GetApicMode ();
2290
2291 //
2292 // Enable the local APIC for Virtual Wire Mode.
2293 //
2294 ProgramVirtualWireMode ();
2295 SaveLocalApicTimerSetting (CpuMpData);
2296
2297 if (FirstMpHandOff == NULL) {
2298 if (MaxLogicalProcessorNumber > 1) {
2299 //
2300 // Wakeup all APs and calculate the processor count in system
2301 //
2302 CollectProcessorCount (CpuMpData);
2303
2304 //
2305 // Enable X2APIC if needed.
2306 //
2307 if (CpuMpData->InitialBspApicMode == LOCAL_APIC_MODE_XAPIC) {
2308 AutoEnableX2Apic (CpuMpData);
2309 }
2310
2311 //
2312 // Sort BSP/Aps by CPU APIC ID in ascending order
2313 //
2314 SortApicId (CpuMpData);
2315
2316 DEBUG ((DEBUG_INFO, "MpInitLib: Find %d processors in system.\n", CpuMpData->CpuCount));
2317 }
2318 } else {
2319 //
2320 // APs have been wakeup before, just get the CPU Information
2321 // from HOB
2322 //
2323 CpuMpData->InitFlag = ApInitDone;
2324 if (CpuMpData->UseSevEsAPMethod) {
2325 AmdSevUpdateCpuMpData (CpuMpData);
2326 }
2327
2328 CpuMpData->CpuCount = MaxLogicalProcessorNumber;
2329 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
2330 for (MpHandOff = FirstMpHandOff;
2331 MpHandOff != NULL;
2332 MpHandOff = GetNextMpHandOffHob (MpHandOff))
2333 {
2334 for (HobIndex = 0; HobIndex < MpHandOff->CpuCount; HobIndex++) {
2335 Index = MpHandOff->ProcessorIndex + HobIndex;
2336 InitializeSpinLock (&CpuMpData->CpuData[Index].ApLock);
2337 CpuMpData->CpuData[Index].CpuHealthy = (MpHandOff->Info[HobIndex].Health == 0) ? TRUE : FALSE;
2338 CpuMpData->CpuData[Index].ApFunction = 0;
2339 CpuInfoInHob[Index].InitialApicId = MpHandOff->Info[HobIndex].ApicId;
2340 CpuInfoInHob[Index].ApTopOfStack = CpuMpData->Buffer + (Index + 1) * CpuMpData->CpuApStackSize;
2341 CpuInfoInHob[Index].ApicId = MpHandOff->Info[HobIndex].ApicId;
2342 CpuInfoInHob[Index].Health = MpHandOff->Info[HobIndex].Health;
2343 }
2344 }
2345
2346 MpHandOffConfig = GetMpHandOffConfigHob ();
2347 if (MpHandOffConfig == NULL) {
2348 DEBUG ((
2349 DEBUG_ERROR,
2350 "%a: at least one MpHandOff HOB, but no MpHandOffConfig HOB\n",
2351 __func__
2352 ));
2353 ASSERT (MpHandOffConfig != NULL);
2354 CpuDeadLoop ();
2355 }
2356
2357 DEBUG ((
2358 DEBUG_INFO,
2359 "FirstMpHandOff->WaitLoopExecutionMode: %04d, sizeof (VOID *): %04d\n",
2360 MpHandOffConfig->WaitLoopExecutionMode,
2361 sizeof (VOID *)
2362 ));
2363 if (MpHandOffConfig->WaitLoopExecutionMode == sizeof (VOID *)) {
2364 ASSERT (CpuMpData->ApLoopMode != ApInHltLoop);
2365
2366 CpuMpData->FinishedCount = 0;
2367 CpuMpData->EnableExecuteDisableForSwitchContext = IsBspExecuteDisableEnabled ();
2368 SaveCpuMpData (CpuMpData);
2369 //
2370 // In scenarios where both the PEI and DXE phases run in the same
2371 // execution mode (32bit or 64bit), the BSP triggers
2372 // a start-up signal during the DXE phase to wake up the APs. This causes any
2373 // APs that are currently in a loop on the memory prepared during the PEI
2374 // phase to awaken and run the SwitchContextPerAp procedure. This procedure
2375 // enables the APs to switch to a different memory section and continue their
2376 // looping process there.
2377 //
2378 SwitchApContext (MpHandOffConfig, FirstMpHandOff);
2379 //
2380 // Wait for all APs finished initialization
2381 //
2382 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
2383 CpuPause ();
2384 }
2385
2386 //
2387 // Set Apstate as Idle, otherwise Aps cannot be waken-up again.
2388 // If any enabled AP is not idle, return EFI_NOT_READY during waken-up.
2389 //
2390 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
2391 SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);
2392 }
2393
2394 //
2395 // Initialize global data for MP support
2396 //
2397 InitMpGlobalData (CpuMpData);
2398 return EFI_SUCCESS;
2399 } else {
2400 //
2401 // PEI and DXE are in different Execution Mode
2402 // Use Init Sipi Sipi for the first AP wake up in DXE phase.
2403 //
2404 CpuMpData->WakeUpByInitSipiSipi = TRUE;
2405 }
2406 }
2407
2408 if (!GetMicrocodePatchInfoFromHob (
2409 &CpuMpData->MicrocodePatchAddress,
2410 &CpuMpData->MicrocodePatchRegionSize
2411 ))
2412 {
2413 //
2414 // The microcode patch information cache HOB does not exist, which means
2415 // the microcode patches data has not been loaded into memory yet
2416 //
2417 ShadowMicrocodeUpdatePatch (CpuMpData);
2418 }
2419
2420 //
2421 // Detect and apply Microcode on BSP
2422 //
2423 MicrocodeDetect (CpuMpData, CpuMpData->BspNumber);
2424 //
2425 // Store BSP's MTRR setting
2426 //
2427 MtrrGetAllMtrrs (&CpuMpData->MtrrTable);
2428
2429 //
2430 // Wakeup APs to do some AP initialize sync (Microcode & MTRR)
2431 //
2432 if (CpuMpData->CpuCount > 1) {
2433 WakeUpAP (CpuMpData, TRUE, 0, ApInitializeSync, CpuMpData, TRUE);
2434 //
2435 // Wait for all APs finished initialization
2436 //
2437 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
2438 CpuPause ();
2439 }
2440
2441 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
2442 SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);
2443 }
2444 }
2445
2446 //
2447 // Dump the microcode revision for each core.
2448 //
2449 DEBUG_CODE_BEGIN ();
2450 UINT32 ThreadId;
2451 UINT32 ExpectedMicrocodeRevision;
2452
2453 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
2454 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
2455 GetProcessorLocationByApicId (CpuInfoInHob[Index].InitialApicId, NULL, NULL, &ThreadId);
2456 if (ThreadId == 0) {
2457 //
2458 // MicrocodeDetect() loads microcode in first thread of each core, so,
2459 // CpuMpData->CpuData[Index].MicrocodeEntryAddr is initialized only for first thread of each core.
2460 //
2461 ExpectedMicrocodeRevision = 0;
2462 if (CpuMpData->CpuData[Index].MicrocodeEntryAddr != 0) {
2463 ExpectedMicrocodeRevision = ((CPU_MICROCODE_HEADER *)(UINTN)CpuMpData->CpuData[Index].MicrocodeEntryAddr)->UpdateRevision;
2464 }
2465
2466 DEBUG ((
2467 DEBUG_INFO,
2468 "CPU[%04d]: Microcode revision = %08x, expected = %08x\n",
2469 Index,
2470 CpuMpData->CpuData[Index].MicrocodeRevision,
2471 ExpectedMicrocodeRevision
2472 ));
2473 }
2474 }
2475
2476 DEBUG_CODE_END ();
2477 //
2478 // Initialize global data for MP support
2479 //
2480 InitMpGlobalData (CpuMpData);
2481
2482 return EFI_SUCCESS;
2483}
2484
2485/**
2486 Gets detailed MP-related information on the requested processor at the
2487 instant this call is made. This service may only be called from the BSP.
2488
2489 @param[in] ProcessorNumber The handle number of processor.
2490 Lower 24 bits contains the actual processor number.
2491 BIT24 indicates if the EXTENDED_PROCESSOR_INFORMATION will be retrived.
2492 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
2493 the requested processor is deposited.
2494 @param[out] HealthData Return processor health data.
2495
2496 @retval EFI_SUCCESS Processor information was returned.
2497 @retval EFI_DEVICE_ERROR The calling processor is an AP.
2498 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
2499 @retval EFI_NOT_FOUND The processor with the handle specified by
2500 ProcessorNumber does not exist in the platform.
2501 @retval EFI_NOT_READY MP Initialize Library is not initialized.
2502
2503**/
2504EFI_STATUS
2505EFIAPI
2506MpInitLibGetProcessorInfo (
2507 IN UINTN ProcessorNumber,
2508 OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,
2509 OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL
2510 )
2511{
2512 CPU_MP_DATA *CpuMpData;
2513 UINTN CallerNumber;
2514 CPU_INFO_IN_HOB *CpuInfoInHob;
2515 UINTN OriginalProcessorNumber;
2516 EFI_STATUS Status;
2517
2518 CpuMpData = GetCpuMpData ();
2519
2520 if (CpuMpData == NULL) {
2521 DEBUG ((DEBUG_ERROR, "[%a] - Failed to get CpuMpData.\n", __func__));
2522 return EFI_LOAD_ERROR;
2523 }
2524
2525 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
2526
2527 //
2528 // Lower 24 bits contains the actual processor number.
2529 //
2530 OriginalProcessorNumber = ProcessorNumber;
2531 ProcessorNumber &= BIT24 - 1;
2532
2533 //
2534 // Check whether caller processor is BSP
2535 //
2536 Status = MpInitLibWhoAmI (&CallerNumber);
2537
2538 if (EFI_ERROR (Status)) {
2539 DEBUG ((DEBUG_ERROR, "[%a] - Failed to get processor number. Failed to get MpInit Processor info.\n", __func__));
2540 return Status;
2541 }
2542
2543 if (CallerNumber != CpuMpData->BspNumber) {
2544 return EFI_DEVICE_ERROR;
2545 }
2546
2547 if (ProcessorInfoBuffer == NULL) {
2548 return EFI_INVALID_PARAMETER;
2549 }
2550
2551 if (ProcessorNumber >= CpuMpData->CpuCount) {
2552 return EFI_NOT_FOUND;
2553 }
2554
2555 ProcessorInfoBuffer->ProcessorId = (UINT64)CpuInfoInHob[ProcessorNumber].ApicId;
2556 ProcessorInfoBuffer->StatusFlag = 0;
2557 if (ProcessorNumber == CpuMpData->BspNumber) {
2558 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT;
2559 }
2560
2561 if (CpuMpData->CpuData[ProcessorNumber].CpuHealthy) {
2562 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_HEALTH_STATUS_BIT;
2563 }
2564
2565 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) {
2566 ProcessorInfoBuffer->StatusFlag &= ~PROCESSOR_ENABLED_BIT;
2567 } else {
2568 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_ENABLED_BIT;
2569 }
2570
2571 //
2572 // Get processor location information
2573 //
2574 GetProcessorLocationByApicId (
2575 CpuInfoInHob[ProcessorNumber].ApicId,
2576 &ProcessorInfoBuffer->Location.Package,
2577 &ProcessorInfoBuffer->Location.Core,
2578 &ProcessorInfoBuffer->Location.Thread
2579 );
2580
2581 if ((OriginalProcessorNumber & CPU_V2_EXTENDED_TOPOLOGY) != 0) {
2582 GetProcessorLocation2ByApicId (
2583 CpuInfoInHob[ProcessorNumber].ApicId,
2584 &ProcessorInfoBuffer->ExtendedInformation.Location2.Package,
2585 &ProcessorInfoBuffer->ExtendedInformation.Location2.Die,
2586 &ProcessorInfoBuffer->ExtendedInformation.Location2.Tile,
2587 &ProcessorInfoBuffer->ExtendedInformation.Location2.Module,
2588 &ProcessorInfoBuffer->ExtendedInformation.Location2.Core,
2589 &ProcessorInfoBuffer->ExtendedInformation.Location2.Thread
2590 );
2591 }
2592
2593 if (HealthData != NULL) {
2594 HealthData->Uint32 = CpuInfoInHob[ProcessorNumber].Health;
2595 }
2596
2597 return EFI_SUCCESS;
2598}
2599
2600/**
2601 Worker function to switch the requested AP to be the BSP from that point onward.
2602
2603 @param[in] ProcessorNumber The handle number of AP that is to become the new BSP.
2604 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
2605 enabled AP. Otherwise, it will be disabled.
2606
2607 @retval EFI_SUCCESS BSP successfully switched.
2608 @retval others Failed to switch BSP.
2609
2610**/
2611EFI_STATUS
2612SwitchBSPWorker (
2613 IN UINTN ProcessorNumber,
2614 IN BOOLEAN EnableOldBSP
2615 )
2616{
2617 CPU_MP_DATA *CpuMpData;
2618 UINTN CallerNumber;
2619 CPU_STATE State;
2620 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
2621 BOOLEAN OldInterruptState;
2622 BOOLEAN OldTimerInterruptState;
2623 EFI_STATUS Status;
2624
2625 //
2626 // Save and Disable Local APIC timer interrupt
2627 //
2628 OldTimerInterruptState = GetApicTimerInterruptState ();
2629 DisableApicTimerInterrupt ();
2630 //
2631 // Before send both BSP and AP to a procedure to exchange their roles,
2632 // interrupt must be disabled. This is because during the exchange role
2633 // process, 2 CPU may use 1 stack. If interrupt happens, the stack will
2634 // be corrupted, since interrupt return address will be pushed to stack
2635 // by hardware.
2636 //
2637 OldInterruptState = SaveAndDisableInterrupts ();
2638
2639 //
2640 // Mask LINT0 & LINT1 for the old BSP
2641 //
2642 DisableLvtInterrupts ();
2643
2644 CpuMpData = GetCpuMpData ();
2645
2646 if (CpuMpData == NULL) {
2647 DEBUG ((DEBUG_ERROR, "[%a] - Failed to get CpuMpData.\n", __func__));
2648 return EFI_LOAD_ERROR;
2649 }
2650
2651 //
2652 // Check whether caller processor is BSP
2653 //
2654 Status = MpInitLibWhoAmI (&CallerNumber);
2655
2656 if (EFI_ERROR (Status)) {
2657 DEBUG ((DEBUG_ERROR, "[%a] - Failed to get processor number. Failed to get MpInit Processor info.\n", __func__));
2658 return Status;
2659 }
2660
2661 if (CallerNumber != CpuMpData->BspNumber) {
2662 return EFI_DEVICE_ERROR;
2663 }
2664
2665 if (ProcessorNumber >= CpuMpData->CpuCount) {
2666 return EFI_NOT_FOUND;
2667 }
2668
2669 //
2670 // Check whether specified AP is disabled
2671 //
2672 State = GetApState (&CpuMpData->CpuData[ProcessorNumber]);
2673 if (State == CpuStateDisabled) {
2674 return EFI_INVALID_PARAMETER;
2675 }
2676
2677 //
2678 // Check whether ProcessorNumber specifies the current BSP
2679 //
2680 if (ProcessorNumber == CpuMpData->BspNumber) {
2681 return EFI_INVALID_PARAMETER;
2682 }
2683
2684 //
2685 // Check whether specified AP is busy
2686 //
2687 if (State == CpuStateBusy) {
2688 return EFI_NOT_READY;
2689 }
2690
2691 CpuMpData->BSPInfo.State = CPU_SWITCH_STATE_IDLE;
2692 CpuMpData->APInfo.State = CPU_SWITCH_STATE_IDLE;
2693 CpuMpData->SwitchBspFlag = TRUE;
2694 CpuMpData->NewBspNumber = ProcessorNumber;
2695
2696 //
2697 // Clear the BSP bit of MSR_IA32_APIC_BASE
2698 //
2699 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
2700 ApicBaseMsr.Bits.BSP = 0;
2701 AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
2702
2703 //
2704 // Save BSP's local APIC timer setting.
2705 //
2706 SaveLocalApicTimerSetting (CpuMpData);
2707
2708 //
2709 // Need to wakeUp AP (future BSP).
2710 //
2711 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, FutureBSPProc, CpuMpData, TRUE);
2712
2713 //
2714 // Save and restore volatile registers when switch BSP
2715 //
2716 SaveVolatileRegisters (&CpuMpData->BSPInfo.VolatileRegisters);
2717 AsmExchangeRole (&CpuMpData->BSPInfo, &CpuMpData->APInfo);
2718 RestoreVolatileRegisters (&CpuMpData->BSPInfo.VolatileRegisters);
2719 //
2720 // Set the BSP bit of MSR_IA32_APIC_BASE on new BSP
2721 //
2722 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
2723 ApicBaseMsr.Bits.BSP = 1;
2724 AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
2725 ProgramVirtualWireMode ();
2726
2727 //
2728 // Wait for old BSP finished AP task
2729 //
2730 while (GetApState (&CpuMpData->CpuData[CallerNumber]) != CpuStateFinished) {
2731 CpuPause ();
2732 }
2733
2734 CpuMpData->SwitchBspFlag = FALSE;
2735 //
2736 // Set old BSP enable state
2737 //
2738 if (!EnableOldBSP) {
2739 SetApState (&CpuMpData->CpuData[CallerNumber], CpuStateDisabled);
2740 } else {
2741 SetApState (&CpuMpData->CpuData[CallerNumber], CpuStateIdle);
2742 }
2743
2744 //
2745 // Save new BSP number
2746 //
2747 CpuMpData->BspNumber = (UINT32)ProcessorNumber;
2748
2749 //
2750 // Restore interrupt state.
2751 //
2752 SetInterruptState (OldInterruptState);
2753
2754 if (OldTimerInterruptState) {
2755 EnableApicTimerInterrupt ();
2756 }
2757
2758 return EFI_SUCCESS;
2759}
2760
2761/**
2762 Worker function to let the caller enable or disable an AP from this point onward.
2763 This service may only be called from the BSP.
2764
2765 @param[in] ProcessorNumber The handle number of AP.
2766 @param[in] EnableAP Specifies the new state for the processor for
2767 enabled, FALSE for disabled.
2768 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
2769 the new health status of the AP.
2770
2771 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
2772 @retval others Failed to Enable/Disable AP.
2773
2774**/
2775EFI_STATUS
2776EnableDisableApWorker (
2777 IN UINTN ProcessorNumber,
2778 IN BOOLEAN EnableAP,
2779 IN UINT32 *HealthFlag OPTIONAL
2780 )
2781{
2782 CPU_MP_DATA *CpuMpData;
2783 UINTN CallerNumber;
2784 EFI_STATUS Status;
2785
2786 CpuMpData = GetCpuMpData ();
2787
2788 if (CpuMpData == NULL) {
2789 DEBUG ((DEBUG_ERROR, "[%a] - Failed to get CpuMpData.\n", __func__));
2790 return EFI_LOAD_ERROR;
2791 }
2792
2793 //
2794 // Check whether caller processor is BSP
2795 //
2796 Status = MpInitLibWhoAmI (&CallerNumber);
2797
2798 if (EFI_ERROR (Status)) {
2799 DEBUG ((DEBUG_ERROR, "[%a] - Failed to get processor number. Failed to get MpInit Processor info.\n", __func__));
2800 return Status;
2801 }
2802
2803 if (CallerNumber != CpuMpData->BspNumber) {
2804 return EFI_DEVICE_ERROR;
2805 }
2806
2807 if (ProcessorNumber == CpuMpData->BspNumber) {
2808 return EFI_INVALID_PARAMETER;
2809 }
2810
2811 if (ProcessorNumber >= CpuMpData->CpuCount) {
2812 return EFI_NOT_FOUND;
2813 }
2814
2815 if (!EnableAP) {
2816 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateDisabled);
2817 } else {
2818 ResetProcessorToIdleState (ProcessorNumber);
2819 }
2820
2821 if (HealthFlag != NULL) {
2822 CpuMpData->CpuData[ProcessorNumber].CpuHealthy =
2823 (BOOLEAN)((*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT) != 0);
2824 }
2825
2826 return EFI_SUCCESS;
2827}
2828
2829/**
2830 This return the handle number for the calling processor. This service may be
2831 called from the BSP and APs.
2832
2833 @param[out] ProcessorNumber Pointer to the handle number of AP.
2834 The range is from 0 to the total number of
2835 logical processors minus 1. The total number of
2836 logical processors can be retrieved by
2837 MpInitLibGetNumberOfProcessors().
2838
2839 @retval EFI_SUCCESS The current processor handle number was returned
2840 in ProcessorNumber.
2841 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
2842 @retval EFI_NOT_READY MP Initialize Library is not initialized.
2843
2844**/
2845EFI_STATUS
2846EFIAPI
2847MpInitLibWhoAmI (
2848 OUT UINTN *ProcessorNumber
2849 )
2850{
2851 CPU_MP_DATA *CpuMpData;
2852
2853 if (ProcessorNumber == NULL) {
2854 return EFI_INVALID_PARAMETER;
2855 }
2856
2857 CpuMpData = GetCpuMpData ();
2858
2859 if (CpuMpData == NULL) {
2860 DEBUG ((DEBUG_ERROR, "[%a] - Failed to get CpuMpData.\n", __func__));
2861 return EFI_LOAD_ERROR;
2862 }
2863
2864 return GetProcessorNumber (CpuMpData, ProcessorNumber);
2865}
2866
2867/**
2868 Retrieves the number of logical processor in the platform and the number of
2869 those logical processors that are enabled on this boot. This service may only
2870 be called from the BSP.
2871
2872 @param[out] NumberOfProcessors Pointer to the total number of logical
2873 processors in the system, including the BSP
2874 and disabled APs.
2875 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
2876 processors that exist in system, including
2877 the BSP.
2878
2879 @retval EFI_SUCCESS The number of logical processors and enabled
2880 logical processors was retrieved.
2881 @retval EFI_DEVICE_ERROR The calling processor is an AP.
2882 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors
2883 is NULL.
2884 @retval EFI_NOT_READY MP Initialize Library is not initialized.
2885
2886**/
2887EFI_STATUS
2888EFIAPI
2889MpInitLibGetNumberOfProcessors (
2890 OUT UINTN *NumberOfProcessors OPTIONAL,
2891 OUT UINTN *NumberOfEnabledProcessors OPTIONAL
2892 )
2893{
2894 CPU_MP_DATA *CpuMpData;
2895 UINTN CallerNumber;
2896 UINTN ProcessorNumber;
2897 UINTN EnabledProcessorNumber;
2898 UINTN Index;
2899 EFI_STATUS Status;
2900
2901 CpuMpData = GetCpuMpData ();
2902
2903 if (CpuMpData == NULL) {
2904 DEBUG ((DEBUG_ERROR, "[%a] - Failed to get CpuMpData.\n", __func__));
2905 return EFI_LOAD_ERROR;
2906 }
2907
2908 if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) {
2909 return EFI_INVALID_PARAMETER;
2910 }
2911
2912 //
2913 // Check whether caller processor is BSP
2914 //
2915 Status = MpInitLibWhoAmI (&CallerNumber);
2916
2917 if (EFI_ERROR (Status)) {
2918 DEBUG ((DEBUG_ERROR, "[%a] - Failed to get processor number. Failed to get MpInit Processor info.\n", __func__));
2919 return Status;
2920 }
2921
2922 if (CallerNumber != CpuMpData->BspNumber) {
2923 return EFI_DEVICE_ERROR;
2924 }
2925
2926 ProcessorNumber = CpuMpData->CpuCount;
2927 EnabledProcessorNumber = 0;
2928 for (Index = 0; Index < ProcessorNumber; Index++) {
2929 if (GetApState (&CpuMpData->CpuData[Index]) != CpuStateDisabled) {
2930 EnabledProcessorNumber++;
2931 }
2932 }
2933
2934 if (NumberOfProcessors != NULL) {
2935 *NumberOfProcessors = ProcessorNumber;
2936 }
2937
2938 if (NumberOfEnabledProcessors != NULL) {
2939 *NumberOfEnabledProcessors = EnabledProcessorNumber;
2940 }
2941
2942 return EFI_SUCCESS;
2943}
2944
2945/**
2946 Worker function to execute a caller provided function on all enabled APs.
2947
2948 @param[in] Procedure A pointer to the function to be run on
2949 enabled APs of the system.
2950 @param[in] SingleThread If TRUE, then all the enabled APs execute
2951 the function specified by Procedure one by
2952 one, in ascending order of processor handle
2953 number. If FALSE, then all the enabled APs
2954 execute the function specified by Procedure
2955 simultaneously.
2956 @param[in] ExcludeBsp Whether let BSP also trig this task.
2957 @param[in] WaitEvent The event created by the caller with CreateEvent()
2958 service.
2959 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
2960 APs to return from Procedure, either for
2961 blocking or non-blocking mode.
2962 @param[in] ProcedureArgument The parameter passed into Procedure for
2963 all APs.
2964 @param[out] FailedCpuList If all APs finish successfully, then its
2965 content is set to NULL. If not all APs
2966 finish before timeout expires, then its
2967 content is set to address of the buffer
2968 holding handle numbers of the failed APs.
2969
2970 @retval EFI_SUCCESS In blocking mode, all APs have finished before
2971 the timeout expired.
2972 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
2973 to all enabled APs.
2974 @retval others Failed to Startup all APs.
2975
2976**/
2977EFI_STATUS
2978StartupAllCPUsWorker (
2979 IN EFI_AP_PROCEDURE Procedure,
2980 IN BOOLEAN SingleThread,
2981 IN BOOLEAN ExcludeBsp,
2982 IN EFI_EVENT WaitEvent OPTIONAL,
2983 IN UINTN TimeoutInMicroseconds,
2984 IN VOID *ProcedureArgument OPTIONAL,
2985 OUT UINTN **FailedCpuList OPTIONAL
2986 )
2987{
2988 EFI_STATUS Status;
2989 CPU_MP_DATA *CpuMpData;
2990 UINTN ProcessorCount;
2991 UINTN ProcessorNumber;
2992 UINTN CallerNumber;
2993 CPU_AP_DATA *CpuData;
2994 BOOLEAN HasEnabledAp;
2995 CPU_STATE ApState;
2996
2997 CpuMpData = GetCpuMpData ();
2998
2999 if (FailedCpuList != NULL) {
3000 *FailedCpuList = NULL;
3001 }
3002
3003 if (CpuMpData == NULL) {
3004 DEBUG ((DEBUG_ERROR, "[%a] - Failed to get CpuMpData.\n", __func__));
3005 return EFI_LOAD_ERROR;
3006 }
3007
3008 if ((CpuMpData->CpuCount == 1) && ExcludeBsp) {
3009 return EFI_NOT_STARTED;
3010 }
3011
3012 if (Procedure == NULL) {
3013 return EFI_INVALID_PARAMETER;
3014 }
3015
3016 //
3017 // Check whether caller processor is BSP
3018 //
3019 Status = MpInitLibWhoAmI (&CallerNumber);
3020
3021 if (EFI_ERROR (Status)) {
3022 DEBUG ((DEBUG_ERROR, "[%a] - Failed to get processor number. Failed to get MpInit Processor info.\n", __func__));
3023 return Status;
3024 }
3025
3026 if (CallerNumber != CpuMpData->BspNumber) {
3027 return EFI_DEVICE_ERROR;
3028 }
3029
3030 //
3031 // Update AP state
3032 //
3033 CheckAndUpdateApsStatus ();
3034
3035 ProcessorCount = CpuMpData->CpuCount;
3036 HasEnabledAp = FALSE;
3037 //
3038 // Check whether all enabled APs are idle.
3039 // If any enabled AP is not idle, return EFI_NOT_READY.
3040 //
3041 for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {
3042 CpuData = &CpuMpData->CpuData[ProcessorNumber];
3043 if (ProcessorNumber != CpuMpData->BspNumber) {
3044 ApState = GetApState (CpuData);
3045 if (ApState != CpuStateDisabled) {
3046 HasEnabledAp = TRUE;
3047 if (ApState != CpuStateIdle) {
3048 //
3049 // If any enabled APs are busy, return EFI_NOT_READY.
3050 //
3051 return EFI_NOT_READY;
3052 }
3053 }
3054 }
3055 }
3056
3057 if (!HasEnabledAp && ExcludeBsp) {
3058 //
3059 // If no enabled AP exists and not include Bsp to do the procedure, return EFI_NOT_STARTED.
3060 //
3061 return EFI_NOT_STARTED;
3062 }
3063
3064 CpuMpData->RunningCount = 0;
3065 for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {
3066 CpuData = &CpuMpData->CpuData[ProcessorNumber];
3067 CpuData->Waiting = FALSE;
3068 if (ProcessorNumber != CpuMpData->BspNumber) {
3069 if (CpuData->State == CpuStateIdle) {
3070 //
3071 // Mark this processor as responsible for current calling.
3072 //
3073 CpuData->Waiting = TRUE;
3074 CpuMpData->RunningCount++;
3075 }
3076 }
3077 }
3078
3079 CpuMpData->Procedure = Procedure;
3080 CpuMpData->ProcArguments = ProcedureArgument;
3081 CpuMpData->SingleThread = SingleThread;
3082 CpuMpData->FinishedCount = 0;
3083 CpuMpData->FailedCpuList = FailedCpuList;
3084 CpuMpData->ExpectedTime = CalculateTimeout (
3085 TimeoutInMicroseconds,
3086 &CpuMpData->CurrentTime
3087 );
3088 CpuMpData->TotalTime = 0;
3089 CpuMpData->WaitEvent = WaitEvent;
3090
3091 if (!SingleThread) {
3092 WakeUpAP (CpuMpData, TRUE, 0, Procedure, ProcedureArgument, FALSE);
3093 } else {
3094 for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {
3095 if (ProcessorNumber == CallerNumber) {
3096 continue;
3097 }
3098
3099 if (CpuMpData->CpuData[ProcessorNumber].Waiting) {
3100 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument, TRUE);
3101 break;
3102 }
3103 }
3104 }
3105
3106 if (!ExcludeBsp) {
3107 //
3108 // Start BSP.
3109 //
3110 Procedure (ProcedureArgument);
3111 }
3112
3113 Status = EFI_SUCCESS;
3114 if (WaitEvent == NULL) {
3115 do {
3116 Status = CheckAllAPs ();
3117 } while (Status == EFI_NOT_READY);
3118 }
3119
3120 return Status;
3121}
3122
3123/**
3124 Worker function to let the caller get one enabled AP to execute a caller-provided
3125 function.
3126
3127 @param[in] Procedure A pointer to the function to be run on
3128 enabled APs of the system.
3129 @param[in] ProcessorNumber The handle number of the AP.
3130 @param[in] WaitEvent The event created by the caller with CreateEvent()
3131 service.
3132 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
3133 APs to return from Procedure, either for
3134 blocking or non-blocking mode.
3135 @param[in] ProcedureArgument The parameter passed into Procedure for
3136 all APs.
3137 @param[out] Finished If AP returns from Procedure before the
3138 timeout expires, its content is set to TRUE.
3139 Otherwise, the value is set to FALSE.
3140
3141 @retval EFI_SUCCESS In blocking mode, specified AP finished before
3142 the timeout expires.
3143 @retval others Failed to Startup AP.
3144
3145**/
3146EFI_STATUS
3147StartupThisAPWorker (
3148 IN EFI_AP_PROCEDURE Procedure,
3149 IN UINTN ProcessorNumber,
3150 IN EFI_EVENT WaitEvent OPTIONAL,
3151 IN UINTN TimeoutInMicroseconds,
3152 IN VOID *ProcedureArgument OPTIONAL,
3153 OUT BOOLEAN *Finished OPTIONAL
3154 )
3155{
3156 EFI_STATUS Status;
3157 CPU_MP_DATA *CpuMpData;
3158 CPU_AP_DATA *CpuData;
3159 UINTN CallerNumber;
3160
3161 CpuMpData = GetCpuMpData ();
3162
3163 if (Finished != NULL) {
3164 *Finished = FALSE;
3165 }
3166
3167 if (CpuMpData == NULL) {
3168 DEBUG ((DEBUG_ERROR, "[%a] - Failed to get CpuMpData.\n", __func__));
3169 return EFI_LOAD_ERROR;
3170 }
3171
3172 //
3173 // Check whether caller processor is BSP
3174 //
3175 Status = MpInitLibWhoAmI (&CallerNumber);
3176
3177 if (EFI_ERROR (Status)) {
3178 DEBUG ((DEBUG_ERROR, "[%a] - Failed to get processor number. Failed to get MpInit Processor info.\n", __func__));
3179 return Status;
3180 }
3181
3182 if (CallerNumber != CpuMpData->BspNumber) {
3183 return EFI_DEVICE_ERROR;
3184 }
3185
3186 //
3187 // Check whether processor with the handle specified by ProcessorNumber exists
3188 //
3189 if (ProcessorNumber >= CpuMpData->CpuCount) {
3190 return EFI_NOT_FOUND;
3191 }
3192
3193 //
3194 // Check whether specified processor is BSP
3195 //
3196 if (ProcessorNumber == CpuMpData->BspNumber) {
3197 return EFI_INVALID_PARAMETER;
3198 }
3199
3200 //
3201 // Check parameter Procedure
3202 //
3203 if (Procedure == NULL) {
3204 return EFI_INVALID_PARAMETER;
3205 }
3206
3207 //
3208 // Update AP state
3209 //
3210 CheckAndUpdateApsStatus ();
3211
3212 //
3213 // Check whether specified AP is disabled
3214 //
3215 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) {
3216 return EFI_INVALID_PARAMETER;
3217 }
3218
3219 //
3220 // If WaitEvent is not NULL, execute in non-blocking mode.
3221 // BSP saves data for CheckAPsStatus(), and returns EFI_SUCCESS.
3222 // CheckAPsStatus() will check completion and timeout periodically.
3223 //
3224 CpuData = &CpuMpData->CpuData[ProcessorNumber];
3225 CpuData->WaitEvent = WaitEvent;
3226 CpuData->Finished = Finished;
3227 CpuData->ExpectedTime = CalculateTimeout (TimeoutInMicroseconds, &CpuData->CurrentTime);
3228 CpuData->TotalTime = 0;
3229
3230 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument, TRUE);
3231
3232 //
3233 // If WaitEvent is NULL, execute in blocking mode.
3234 // BSP checks AP's state until it finishes or TimeoutInMicrosecsond expires.
3235 //
3236 Status = EFI_SUCCESS;
3237 if (WaitEvent == NULL) {
3238 do {
3239 Status = CheckThisAP (ProcessorNumber);
3240 } while (Status == EFI_NOT_READY);
3241 }
3242
3243 return Status;
3244}
3245
3246/**
3247 Get pointer to CPU MP Data structure from GUIDed HOB.
3248
3249 @return The pointer to CPU MP Data structure.
3250**/
3251CPU_MP_DATA *
3252GetCpuMpDataFromGuidedHob (
3253 VOID
3254 )
3255{
3256 EFI_HOB_GUID_TYPE *GuidHob;
3257 VOID *DataInHob;
3258 CPU_MP_DATA *CpuMpData;
3259
3260 CpuMpData = NULL;
3261 GuidHob = GetFirstGuidHob (&mCpuInitMpLibHobGuid);
3262 if (GuidHob != NULL) {
3263 DataInHob = GET_GUID_HOB_DATA (GuidHob);
3264 CpuMpData = (CPU_MP_DATA *)(*(UINTN *)DataInHob);
3265 }
3266
3267 return CpuMpData;
3268}
3269
3270/**
3271 This service executes a caller provided function on all enabled CPUs.
3272
3273 @param[in] Procedure A pointer to the function to be run on
3274 enabled APs of the system. See type
3275 EFI_AP_PROCEDURE.
3276 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
3277 APs to return from Procedure, either for
3278 blocking or non-blocking mode. Zero means
3279 infinity. TimeoutInMicroseconds is ignored
3280 for BSP.
3281 @param[in] ProcedureArgument The parameter passed into Procedure for
3282 all APs.
3283
3284 @retval EFI_SUCCESS In blocking mode, all CPUs have finished before
3285 the timeout expired.
3286 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
3287 to all enabled CPUs.
3288 @retval EFI_DEVICE_ERROR Caller processor is AP.
3289 @retval EFI_NOT_READY Any enabled APs are busy.
3290 @retval EFI_NOT_READY MP Initialize Library is not initialized.
3291 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
3292 all enabled APs have finished.
3293 @retval EFI_INVALID_PARAMETER Procedure is NULL.
3294
3295**/
3296EFI_STATUS
3297EFIAPI
3298MpInitLibStartupAllCPUs (
3299 IN EFI_AP_PROCEDURE Procedure,
3300 IN UINTN TimeoutInMicroseconds,
3301 IN VOID *ProcedureArgument OPTIONAL
3302 )
3303{
3304 return StartupAllCPUsWorker (
3305 Procedure,
3306 FALSE,
3307 FALSE,
3308 NULL,
3309 TimeoutInMicroseconds,
3310 ProcedureArgument,
3311 NULL
3312 );
3313}
3314
3315/**
3316 The function check if the specified Attr is set.
3317
3318 @param[in] CurrentAttr The current attribute.
3319 @param[in] Attr The attribute to check.
3320
3321 @retval TRUE The specified Attr is set.
3322 @retval FALSE The specified Attr is not set.
3323
3324**/
3325STATIC
3326BOOLEAN
3327AmdMemEncryptionAttrCheck (
3328 IN UINT64 CurrentAttr,
3329 IN CONFIDENTIAL_COMPUTING_GUEST_ATTR Attr
3330 )
3331{
3332 UINT64 CurrentLevel;
3333
3334 CurrentLevel = CurrentAttr & CCAttrTypeMask;
3335
3336 switch (Attr) {
3337 case CCAttrAmdSev:
3338 //
3339 // SEV is automatically enabled if SEV-ES or SEV-SNP is active.
3340 //
3341 return CurrentLevel >= CCAttrAmdSev;
3342 case CCAttrAmdSevEs:
3343 //
3344 // SEV-ES is automatically enabled if SEV-SNP is active.
3345 //
3346 return CurrentLevel >= CCAttrAmdSevEs;
3347 case CCAttrAmdSevSnp:
3348 return CurrentLevel == CCAttrAmdSevSnp;
3349 case CCAttrFeatureAmdSevEsDebugVirtualization:
3350 return !!(CurrentAttr & CCAttrFeatureAmdSevEsDebugVirtualization);
3351 default:
3352 return FALSE;
3353 }
3354}
3355
3356/**
3357 Check if the specified confidential computing attribute is active.
3358
3359 @param[in] Attr The attribute to check.
3360
3361 @retval TRUE The specified Attr is active.
3362 @retval FALSE The specified Attr is not active.
3363
3364**/
3365BOOLEAN
3366EFIAPI
3367ConfidentialComputingGuestHas (
3368 IN CONFIDENTIAL_COMPUTING_GUEST_ATTR Attr
3369 )
3370{
3371 UINT64 CurrentAttr;
3372
3373 //
3374 // Get the current CC attribute.
3375 //
3376 CurrentAttr = PcdGet64 (PcdConfidentialComputingGuestAttr);
3377
3378 //
3379 // If attr is for the AMD group then call AMD specific checks.
3380 //
3381 if (((RShiftU64 (CurrentAttr, 8)) & 0xff) == 1) {
3382 return AmdMemEncryptionAttrCheck (CurrentAttr, Attr);
3383 }
3384
3385 return (CurrentAttr == Attr);
3386}
3387
3388/**
3389 Do sync on APs.
3390
3391 @param[in, out] Buffer Pointer to private data buffer.
3392**/
3393VOID
3394EFIAPI
3395RelocateApLoop (
3396 IN OUT VOID *Buffer
3397 )
3398{
3399 CPU_MP_DATA *CpuMpData;
3400 BOOLEAN MwaitSupport;
3401 UINTN ProcessorNumber;
3402 UINTN StackStart;
3403 EFI_STATUS Status;
3404
3405 Status = MpInitLibWhoAmI (&ProcessorNumber);
3406
3407 if (EFI_ERROR (Status)) {
3408 DEBUG ((DEBUG_ERROR, "[%a] - Failed to get processor number. Aborting AP sync.\n", __func__));
3409 return;
3410 }
3411
3412 CpuMpData = GetCpuMpData ();
3413 MwaitSupport = IsMwaitSupport ();
3414 if (CpuMpData->UseSevEsAPMethod) {
3415 //
3416 // 64-bit AMD processors with SEV-ES
3417 //
3418 StackStart = CpuMpData->SevEsAPResetStackStart;
3419 mReservedApLoop.AmdSevEntry (
3420 MwaitSupport,
3421 CpuMpData->ApTargetCState,
3422 CpuMpData->PmCodeSegment,
3423 StackStart - ProcessorNumber * AP_SAFE_STACK_SIZE,
3424 (UINTN)&mNumberToFinish,
3425 CpuMpData->Pm16CodeSegment,
3426 CpuMpData->SevEsAPBuffer,
3427 CpuMpData->WakeupBuffer
3428 );
3429 } else {
3430 //
3431 // Intel processors (32-bit or 64-bit), 32-bit AMD processors, or 64-bit AMD processors without SEV-ES
3432 //
3433 StackStart = mReservedTopOfApStack;
3434 mReservedApLoop.GenericEntry (
3435 MwaitSupport,
3436 CpuMpData->ApTargetCState,
3437 StackStart - ProcessorNumber * AP_SAFE_STACK_SIZE,
3438 (UINTN)&mNumberToFinish,
3439 mApPageTable
3440 );
3441 }
3442
3443 //
3444 // It should never reach here
3445 //
3446 ASSERT (FALSE);
3447}
3448
3449/**
3450 Prepare ApLoopCode.
3451
3452 @param[in] CpuMpData Pointer to CpuMpData.
3453**/
3454VOID
3455PrepareApLoopCode (
3456 IN CPU_MP_DATA *CpuMpData
3457 )
3458{
3459 EFI_PHYSICAL_ADDRESS Address;
3460 MP_ASSEMBLY_ADDRESS_MAP *AddressMap;
3461 UINT8 *ApLoopFunc;
3462 UINTN ApLoopFuncSize;
3463 UINTN StackPages;
3464 UINTN FuncPages;
3465 IA32_CR0 Cr0;
3466
3467 AddressMap = &CpuMpData->AddressMap;
3468 if (CpuMpData->UseSevEsAPMethod) {
3469 //
3470 // 64-bit AMD processors with SEV-ES
3471 //
3472 Address = BASE_4GB - 1;
3473 ApLoopFunc = AddressMap->RelocateApLoopFuncAddressAmdSev;
3474 ApLoopFuncSize = AddressMap->RelocateApLoopFuncSizeAmdSev;
3475 } else {
3476 //
3477 // Intel processors (32-bit or 64-bit), 32-bit AMD processors, or 64-bit AMD processors without SEV-ES
3478 //
3479 Address = MAX_ADDRESS;
3480 ApLoopFunc = AddressMap->RelocateApLoopFuncAddressGeneric;
3481 ApLoopFuncSize = AddressMap->RelocateApLoopFuncSizeGeneric;
3482 }
3483
3484 //
3485 // Avoid APs access invalid buffer data which allocated by BootServices,
3486 // so we will allocate reserved data for AP loop code. We also need to
3487 // allocate this buffer below 4GB due to APs may be transferred to 32bit
3488 // protected mode on long mode DXE.
3489 // Allocating it in advance since memory services are not available in
3490 // Exit Boot Services callback function.
3491 //
3492 // +------------+ (TopOfApStack)
3493 // | Stack * N |
3494 // +------------+ (stack base, 4k aligned)
3495 // | Padding |
3496 // +------------+
3497 // | Ap Loop |
3498 // +------------+ ((low address, 4k-aligned)
3499 //
3500
3501 StackPages = EFI_SIZE_TO_PAGES (CpuMpData->CpuCount * AP_SAFE_STACK_SIZE);
3502 FuncPages = EFI_SIZE_TO_PAGES (ApLoopFuncSize);
3503
3504 AllocateApLoopCodeBuffer (StackPages + FuncPages, &Address);
3505 ASSERT (Address != 0);
3506
3507 Cr0.UintN = AsmReadCr0 ();
3508 if (Cr0.Bits.PG != 0) {
3509 //
3510 // Make sure that the buffer memory is executable if NX protection is enabled
3511 // for EfiReservedMemoryType.
3512 //
3513 RemoveNxprotection (Address, EFI_PAGES_TO_SIZE (FuncPages));
3514 }
3515
3516 mReservedTopOfApStack = (UINTN)Address + EFI_PAGES_TO_SIZE (StackPages+FuncPages);
3517 ASSERT ((mReservedTopOfApStack & (UINTN)(CPU_STACK_ALIGNMENT - 1)) == 0);
3518 mReservedApLoop.Data = (VOID *)(UINTN)Address;
3519 ASSERT (mReservedApLoop.Data != NULL);
3520 CopyMem (mReservedApLoop.Data, ApLoopFunc, ApLoopFuncSize);
3521 if (!CpuMpData->UseSevEsAPMethod) {
3522 //
3523 // processors without SEV-ES and paging is enabled
3524 //
3525 mApPageTable = CreatePageTable (
3526 (UINTN)Address,
3527 EFI_PAGES_TO_SIZE (StackPages+FuncPages)
3528 );
3529 }
3530}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette