VirtualBox

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

Last change on this file since 101291 was 101291, checked in by vboxsync, 17 months ago

EFI/FirmwareNew: Make edk2-stable202308 build on all supported platforms (using gcc at least, msvc not tested yet), bugref:4643

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

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