From: Tom Lendacky <thomas.lenda...@amd.com> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275
Use the SEV-SNP AP Creation NAE event to create and launch APs under SEV-SNP. This capability will be advertised in the SEV Hypervisor Feature Support PCD (PcdSevEsHypervisorFeatures). Cc: Michael Roth <michael.r...@amd.com> Cc: Eric Dong <eric.d...@intel.com> Cc: Ray Ni <ray...@intel.com> Cc: Rahul Kumar <rahul1.ku...@intel.com> Cc: James Bottomley <j...@linux.ibm.com> Cc: Min Xu <min.m...@intel.com> Cc: Jiewen Yao <jiewen....@intel.com> Cc: Tom Lendacky <thomas.lenda...@amd.com> Cc: Jordan Justen <jordan.l.jus...@intel.com> Cc: Ard Biesheuvel <ardb+tianoc...@kernel.org> Cc: Erdem Aktas <erdemak...@google.com> Cc: Gerd Hoffmann <kra...@redhat.com> Acked-by: Gerd Hoffmann <kra...@redhat.com> Signed-off-by: Tom Lendacky <thomas.lenda...@amd.com> Signed-off-by: Brijesh Singh <brijesh.si...@amd.com> --- UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf | 3 + UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf | 3 + UefiCpuPkg/Library/MpInitLib/MpLib.h | 44 +++ UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 12 +- UefiCpuPkg/Library/MpInitLib/Ia32/AmdSev.c | 70 +++++ UefiCpuPkg/Library/MpInitLib/MpLib.c | 51 ++-- UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c | 261 ++++++++++++++++++ 7 files changed, 425 insertions(+), 19 deletions(-) create mode 100644 UefiCpuPkg/Library/MpInitLib/Ia32/AmdSev.c create mode 100644 UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf index de705bc54bb4..e1cd0b350008 100644 --- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf +++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf @@ -22,9 +22,11 @@ [Defines] # [Sources.IA32] + Ia32/AmdSev.c Ia32/MpFuncs.nasm [Sources.X64] + X64/AmdSev.c X64/MpFuncs.nasm [Sources.common] @@ -73,6 +75,7 @@ [Pcd] gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode ## CONSUMES gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate ## SOMETIMES_CONSUMES gUefiCpuPkgTokenSpaceGuid.PcdCpuApStatusCheckIntervalInMicroSeconds ## CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdGhcbHypervisorFeatures ## CONSUMES gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase ## SOMETIMES_CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase ## CONSUMES diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf index b7e15ee023f0..5facf4db9499 100644 --- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf +++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf @@ -22,9 +22,11 @@ [Defines] # [Sources.IA32] + Ia32/AmdSev.c Ia32/MpFuncs.nasm [Sources.X64] + X64/AmdSev.c X64/MpFuncs.nasm [Sources.common] @@ -64,6 +66,7 @@ [Pcd] gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode ## CONSUMES gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate ## SOMETIMES_CONSUMES gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase ## SOMETIMES_CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdGhcbHypervisorFeatures ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase ## CONSUMES gEfiMdePkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr ## CONSUMES diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h index c52b6157429b..48f6e933bb36 100644 --- a/UefiCpuPkg/Library/MpInitLib/MpLib.h +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h @@ -15,6 +15,7 @@ #include <Register/Intel/Cpuid.h> #include <Register/Amd/Cpuid.h> +#include <Register/Amd/Ghcb.h> #include <Register/Intel/Msr.h> #include <Register/Intel/LocalApic.h> #include <Register/Intel/Microcode.h> @@ -150,6 +151,7 @@ typedef struct { UINT8 PlatformId; UINT64 MicrocodeEntryAddr; UINT32 MicrocodeRevision; + SEV_ES_SAVE_AREA *SevEsSaveArea; } CPU_AP_DATA; // @@ -294,6 +296,7 @@ struct _CPU_MP_DATA { BOOLEAN SevEsIsEnabled; BOOLEAN SevSnpIsEnabled; + BOOLEAN UseSevEsAPMethod; UINTN SevEsAPBuffer; UINTN SevEsAPResetStackStart; CPU_MP_DATA *NewCpuMpData; @@ -790,5 +793,46 @@ ConfidentialComputingGuestHas ( CONFIDENTIAL_COMPUTING_GUEST_ATTR Attr ); +/** + Issue RMPADJUST to adjust the VMSA attribute of an SEV-SNP page. + + @param[in] PageAddress + @param[in] VmsaPage + + @return RMPADJUST return value +**/ +UINT32 +SevSnpRmpAdjust ( + IN EFI_PHYSICAL_ADDRESS PageAddress, + IN BOOLEAN VmsaPage + ); + +/** + Create an SEV-SNP AP save area (VMSA) for use in running the vCPU. + + @param[in] CpuMpData Pointer to CPU MP Data + @param[in] CpuData Pointer to CPU AP Data + @param[in] ApicId APIC ID of the vCPU +**/ +VOID +SevSnpCreateSaveArea ( + IN CPU_MP_DATA *CpuMpData, + IN CPU_AP_DATA *CpuData, + UINT32 ApicId + ); + +/** + Create SEV-SNP APs. + + @param[in] CpuMpData Pointer to CPU MP Data + @param[in] ProcessorNumber The handle number of specified processor + (-1 for all APs) +**/ +VOID +SevSnpCreateAP ( + IN CPU_MP_DATA *CpuMpData, + IN INTN ProcessorNumber + ); + #endif diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c index 657a73dca05e..7a3ef0015a31 100644 --- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c @@ -93,7 +93,13 @@ GetWakeupBuffer ( EFI_PHYSICAL_ADDRESS StartAddress; EFI_MEMORY_TYPE MemoryType; - if (ConfidentialComputingGuestHas (CCAttrAmdSevEs)) { + if (ConfidentialComputingGuestHas (CCAttrAmdSevEs) && + !ConfidentialComputingGuestHas (CCAttrAmdSevSnp)) { + // + // An SEV-ES-only guest requires the memory to be reserved. SEV-SNP, which + // is also considered SEV-ES, uses a different AP startup method, though, + // which does not have the same requirement. + // MemoryType = EfiReservedMemoryType; } else { MemoryType = EfiBootServicesData; @@ -373,7 +379,7 @@ RelocateApLoop ( MpInitLibWhoAmI (&ProcessorNumber); CpuMpData = GetCpuMpData (); MwaitSupport = IsMwaitSupport (); - if (CpuMpData->SevEsIsEnabled) { + if (CpuMpData->UseSevEsAPMethod) { StackStart = CpuMpData->SevEsAPResetStackStart; } else { StackStart = mReservedTopOfApStack; @@ -422,7 +428,7 @@ MpInitChangeApLoopCallback ( CpuPause (); } - if (CpuMpData->SevEsIsEnabled && (CpuMpData->WakeupBuffer != (UINTN) -1)) { + if (CpuMpData->UseSevEsAPMethod && (CpuMpData->WakeupBuffer != (UINTN) -1)) { // // There are APs present. Re-use reserved memory area below 1MB from // WakeupBuffer as the area to be used for transitioning to 16-bit mode diff --git a/UefiCpuPkg/Library/MpInitLib/Ia32/AmdSev.c b/UefiCpuPkg/Library/MpInitLib/Ia32/AmdSev.c new file mode 100644 index 000000000000..a4702e298d98 --- /dev/null +++ b/UefiCpuPkg/Library/MpInitLib/Ia32/AmdSev.c @@ -0,0 +1,70 @@ +/** @file + + AMD SEV helper function. + + Copyright (c) 2021, AMD Incorporated. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "MpLib.h" + +/** + Create an SEV-SNP AP save area (VMSA) for use in running the vCPU. + + @param[in] CpuMpData Pointer to CPU MP Data + @param[in] CpuData Pointer to CPU AP Data + @param[in] ApicId APIC ID of the vCPU +**/ +VOID +SevSnpCreateSaveArea ( + IN CPU_MP_DATA *CpuMpData, + IN CPU_AP_DATA *CpuData, + UINT32 ApicId + ) +{ + // + // SEV-SNP is not support on 32-bit build. + // + ASSERT (FALSE); +} + +/** + Create SEV-SNP APs. + + @param[in] CpuMpData Pointer to CPU MP Data + @param[in] ProcessorNumber The handle number of specified processor + (-1 for all APs) +**/ +VOID +SevSnpCreateAP ( + IN CPU_MP_DATA *CpuMpData, + IN INTN ProcessorNumber + ) +{ + // + // SEV-SNP is not support on 32-bit build. + // + ASSERT (FALSE); +} + +/** + Issue RMPADJUST to adjust the VMSA attribute of an SEV-SNP page. + + @param[in] PageAddress + @param[in] VmsaPage + + @return RMPADJUST return value +**/ +UINT32 +SevSnpRmpAdjust ( + IN EFI_PHYSICAL_ADDRESS PageAddress, + IN BOOLEAN VmsaPage + ) +{ + // + // RMPADJUST is not supported in 32-bit mode + // + return RETURN_UNSUPPORTED; +} diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c index d8372ffa9d5a..d134dc1326e8 100644 --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c @@ -295,10 +295,11 @@ GetApLoopMode ( ApLoopMode = ApInHltLoop; } - if (ConfidentialComputingGuestHas (CCAttrAmdSevEs)) { + if (ConfidentialComputingGuestHas (CCAttrAmdSevEs) && + !ConfidentialComputingGuestHas (CCAttrAmdSevSnp)) { // - // For SEV-ES, force AP in Hlt-loop mode in order to use the GHCB - // protocol for starting APs + // For SEV-ES (SEV-SNP is also considered SEV-ES), force AP in Hlt-loop + // mode in order to use the GHCB protocol for starting APs // ApLoopMode = ApInHltLoop; } @@ -758,7 +759,7 @@ ApWakeupFunction ( // to allow the APs to issue an AP_RESET_HOLD before the BSP possibly // performs another INIT-SIPI-SIPI sequence. // - if (!CpuMpData->SevEsIsEnabled) { + if (!CpuMpData->UseSevEsAPMethod) { InterlockedDecrement ((UINT32 *) &CpuMpData->MpCpuExchangeInfo->NumApsExecuting); } } @@ -772,7 +773,7 @@ ApWakeupFunction ( // while (TRUE) { DisableInterrupts (); - if (CpuMpData->SevEsIsEnabled) { + if (CpuMpData->UseSevEsAPMethod) { SevEsPlaceApHlt (CpuMpData); } else { CpuSleep (); @@ -1056,9 +1057,12 @@ AllocateResetVector ( ); // // The AP reset stack is only used by SEV-ES guests. Do not allocate it - // if SEV-ES is not enabled. + // if SEV-ES is not enabled. An SEV-SNP guest is also considered + // an SEV-ES guest, but uses a different method of AP startup, eliminating + // the need for the allocation. // - if (ConfidentialComputingGuestHas (CCAttrAmdSevEs)) { + if (ConfidentialComputingGuestHas (CCAttrAmdSevEs) && + !ConfidentialComputingGuestHas (CCAttrAmdSevSnp)) { // // Stack location is based on ProcessorNumber, so use the total number // of processors for calculating the total stack area. @@ -1108,7 +1112,7 @@ FreeResetVector ( // perform the restore as this will overwrite memory which has data // needed by SEV-ES. // - if (!CpuMpData->SevEsIsEnabled) { + if (!CpuMpData->UseSevEsAPMethod) { RestoreWakeupBuffer (CpuMpData); } } @@ -1144,7 +1148,7 @@ WakeUpAP ( ResetVectorRequired = FALSE; if (CpuMpData->WakeUpByInitSipiSipi || - CpuMpData->InitFlag != ApInitDone) { + CpuMpData->InitFlag != ApInitDone) { ResetVectorRequired = TRUE; AllocateResetVector (CpuMpData); AllocateSevEsAPMemory (CpuMpData); @@ -1185,7 +1189,7 @@ WakeUpAP ( } if (ResetVectorRequired) { // - // For SEV-ES, the initial AP boot address will be defined by + // For SEV-ES and SEV-SNP, the initial AP boot address will be defined by // PcdSevEsWorkAreaBase. The Segment/Rip must be the jump address // from the original INIT-SIPI-SIPI. // @@ -1195,8 +1199,14 @@ WakeUpAP ( // // Wakeup all APs + // Must use the INIT-SIPI-SIPI method for initial configuration in + // order to obtain the APIC ID. // - SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart); + if (CpuMpData->SevSnpIsEnabled && CpuMpData->InitFlag != ApInitConfig) { + SevSnpCreateAP (CpuMpData, -1); + } else { + SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart); + } } if (CpuMpData->InitFlag == ApInitConfig) { if (PcdGet32 (PcdCpuBootLogicalProcessorNumber) > 0) { @@ -1286,7 +1296,7 @@ WakeUpAP ( CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob; // - // For SEV-ES, the initial AP boot address will be defined by + // For SEV-ES and SEV-SNP, the initial AP boot address will be defined by // PcdSevEsWorkAreaBase. The Segment/Rip must be the jump address // from the original INIT-SIPI-SIPI. // @@ -1294,10 +1304,14 @@ WakeUpAP ( SetSevEsJumpTable (ExchangeInfo->BufferStart); } - SendInitSipiSipi ( - CpuInfoInHob[ProcessorNumber].ApicId, - (UINT32) ExchangeInfo->BufferStart - ); + if (CpuMpData->SevSnpIsEnabled && CpuMpData->InitFlag != ApInitConfig) { + SevSnpCreateAP (CpuMpData, (INTN) ProcessorNumber); + } else { + SendInitSipiSipi ( + CpuInfoInHob[ProcessorNumber].ApicId, + (UINT32) ExchangeInfo->BufferStart + ); + } } // // Wait specified AP waken up @@ -1832,6 +1846,11 @@ MpInitLibInitialize ( CpuMpData->SevSnpIsEnabled = ConfidentialComputingGuestHas (CCAttrAmdSevSnp); CpuMpData->SevEsAPBuffer = (UINTN) -1; CpuMpData->GhcbBase = PcdGet64 (PcdGhcbBase); + CpuMpData->UseSevEsAPMethod = CpuMpData->SevEsIsEnabled && !CpuMpData->SevSnpIsEnabled; + + if (CpuMpData->SevSnpIsEnabled) { + ASSERT ((PcdGet64 (PcdGhcbHypervisorFeatures) & GHCB_HV_FEATURES_SNP_AP_CREATE) == GHCB_HV_FEATURES_SNP_AP_CREATE); + } // // Make sure no memory usage outside of the allocated buffer. diff --git a/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c b/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c new file mode 100644 index 000000000000..303271abdaad --- /dev/null +++ b/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c @@ -0,0 +1,261 @@ +/** @file + + AMD SEV helper function. + + Copyright (c) 2021, AMD Incorporated. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "MpLib.h" +#include <Library/VmgExitLib.h> +#include <Register/Amd/Fam17Msr.h> +#include <Register/Amd/Ghcb.h> + +/** + Create an SEV-SNP AP save area (VMSA) for use in running the vCPU. + + @param[in] CpuMpData Pointer to CPU MP Data + @param[in] CpuData Pointer to CPU AP Data + @param[in] ApicId APIC ID of the vCPU +**/ +VOID +SevSnpCreateSaveArea ( + IN CPU_MP_DATA *CpuMpData, + IN CPU_AP_DATA *CpuData, + UINT32 ApicId + ) +{ + SEV_ES_SAVE_AREA *SaveArea; + IA32_CR0 ApCr0; + IA32_CR0 ResetCr0; + IA32_CR4 ApCr4; + IA32_CR4 ResetCr4; + UINTN StartIp; + UINT8 SipiVector; + UINT32 RmpAdjustStatus; + UINT64 VmgExitStatus; + MSR_SEV_ES_GHCB_REGISTER Msr; + GHCB *Ghcb; + BOOLEAN InterruptState; + UINT64 ExitInfo1; + UINT64 ExitInfo2; + + // + // Allocate a single page for the SEV-ES Save Area and initialize it. + // + SaveArea = AllocateReservedPages (1); + if (!SaveArea) { + return; + } + ZeroMem (SaveArea, EFI_PAGE_SIZE); + + // + // Propogate the CR0.NW and CR0.CD setting to the AP + // + ResetCr0.UintN = 0x00000010; + ApCr0.UintN = CpuData->VolatileRegisters.Cr0; + if (ApCr0.Bits.NW) { + ResetCr0.Bits.NW = 1; + } + if (ApCr0.Bits.CD) { + ResetCr0.Bits.CD = 1; + } + + // + // Propagate the CR4.MCE setting to the AP + // + ResetCr4.UintN = 0; + ApCr4.UintN = CpuData->VolatileRegisters.Cr4; + if (ApCr4.Bits.MCE) { + ResetCr4.Bits.MCE = 1; + } + + // + // Convert the start IP into a SIPI Vector + // + StartIp = CpuMpData->MpCpuExchangeInfo->BufferStart; + SipiVector = (UINT8) (StartIp >> 12); + + // + // Set the CS:RIP value based on the start IP + // + SaveArea->Cs.Base = SipiVector << 12; + SaveArea->Cs.Selector = SipiVector << 8; + SaveArea->Cs.Limit = 0xFFFF; + SaveArea->Cs.Attributes.Bits.Present = 1; + SaveArea->Cs.Attributes.Bits.Sbit = 1; + SaveArea->Cs.Attributes.Bits.Type = SEV_ES_RESET_CODE_SEGMENT_TYPE; + SaveArea->Rip = StartIp & 0xFFF; + + // + // Set the remaining values as defined in APM for INIT + // + SaveArea->Ds.Limit = 0xFFFF; + SaveArea->Ds.Attributes.Bits.Present = 1; + SaveArea->Ds.Attributes.Bits.Sbit = 1; + SaveArea->Ds.Attributes.Bits.Type = SEV_ES_RESET_DATA_SEGMENT_TYPE; + SaveArea->Es = SaveArea->Ds; + SaveArea->Fs = SaveArea->Ds; + SaveArea->Gs = SaveArea->Ds; + SaveArea->Ss = SaveArea->Ds; + + SaveArea->Gdtr.Limit = 0xFFFF; + SaveArea->Ldtr.Limit = 0xFFFF; + SaveArea->Ldtr.Attributes.Bits.Present = 1; + SaveArea->Ldtr.Attributes.Bits.Type = SEV_ES_RESET_LDT_TYPE; + SaveArea->Idtr.Limit = 0xFFFF; + SaveArea->Tr.Limit = 0xFFFF; + SaveArea->Ldtr.Attributes.Bits.Present = 1; + SaveArea->Ldtr.Attributes.Bits.Type = SEV_ES_RESET_TSS_TYPE; + + SaveArea->Efer = 0x1000; + SaveArea->Cr4 = ResetCr4.UintN; + SaveArea->Cr0 = ResetCr0.UintN; + SaveArea->Dr7 = 0x0400; + SaveArea->Dr6 = 0xFFFF0FF0; + SaveArea->Rflags = 0x0002; + SaveArea->GPat = 0x0007040600070406ULL; + SaveArea->XCr0 = 0x0001; + SaveArea->Mxcsr = 0x1F80; + SaveArea->X87Ftw = 0x5555; + SaveArea->X87Fcw = 0x0040; + + // + // Set the SEV-SNP specific fields for the save area: + // VMPL - always VMPL0 + // SEV_FEATURES - equivalent to the SEV_STATUS MSR right shifted 2 bits + // + SaveArea->Vmpl = 0; + SaveArea->SevFeatures = AsmReadMsr64 (MSR_SEV_STATUS) >> 2; + + // + // To turn the page into a recognized VMSA page, issue RMPADJUST: + // Target VMPL but numerically higher than current VMPL + // Target PermissionMask is not used + // + RmpAdjustStatus = SevSnpRmpAdjust ( + (EFI_PHYSICAL_ADDRESS) (UINTN) SaveArea, + TRUE + ); + ASSERT (RmpAdjustStatus == 0); + + ExitInfo1 = (UINT64) ApicId << 32; + ExitInfo1 |= SVM_VMGEXIT_SNP_AP_CREATE; + ExitInfo2 = (UINT64) (UINTN) SaveArea; + + Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB); + Ghcb = Msr.Ghcb; + + VmgInit (Ghcb, &InterruptState); + Ghcb->SaveArea.Rax = SaveArea->SevFeatures; + VmgSetOffsetValid (Ghcb, GhcbRax); + VmgExitStatus = VmgExit ( + Ghcb, + SVM_EXIT_SNP_AP_CREATION, + ExitInfo1, + ExitInfo2 + ); + VmgDone (Ghcb, InterruptState); + + ASSERT (VmgExitStatus == 0); + if (VmgExitStatus != 0) { + RmpAdjustStatus = SevSnpRmpAdjust ( + (EFI_PHYSICAL_ADDRESS) (UINTN) SaveArea, + FALSE + ); + if (RmpAdjustStatus == 0) { + FreePages (SaveArea, 1); + } else { + DEBUG ((DEBUG_INFO, "SEV-SNP: RMPADJUST failed, leaking VMSA page\n")); + } + + SaveArea = NULL; + } + + if (CpuData->SevEsSaveArea) { + RmpAdjustStatus = SevSnpRmpAdjust ( + (EFI_PHYSICAL_ADDRESS) (UINTN) CpuData->SevEsSaveArea, + FALSE + ); + if (RmpAdjustStatus == 0) { + FreePages (CpuData->SevEsSaveArea, 1); + } else { + DEBUG ((DEBUG_INFO, "SEV-SNP: RMPADJUST failed, leaking VMSA page\n")); + } + } + + CpuData->SevEsSaveArea = SaveArea; +} + +/** + Create SEV-SNP APs. + + @param[in] CpuMpData Pointer to CPU MP Data + @param[in] ProcessorNumber The handle number of specified processor + (-1 for all APs) +**/ +VOID +SevSnpCreateAP ( + IN CPU_MP_DATA *CpuMpData, + IN INTN ProcessorNumber + ) +{ + CPU_INFO_IN_HOB *CpuInfoInHob; + CPU_AP_DATA *CpuData; + UINTN Index; + UINT32 ApicId; + + ASSERT (CpuMpData->MpCpuExchangeInfo->BufferStart < 0x100000); + + CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob; + + if (ProcessorNumber < 0) { + for (Index = 0; Index < CpuMpData->CpuCount; Index++) { + if (Index != CpuMpData->BspNumber) { + CpuData = &CpuMpData->CpuData[Index]; + ApicId = CpuInfoInHob[Index].ApicId, + SevSnpCreateSaveArea (CpuMpData, CpuData, ApicId); + } + } + } else { + Index = (UINTN) ProcessorNumber; + CpuData = &CpuMpData->CpuData[Index]; + ApicId = CpuInfoInHob[ProcessorNumber].ApicId, + SevSnpCreateSaveArea (CpuMpData, CpuData, ApicId); + } +} + +/** + Issue RMPADJUST to adjust the VMSA attribute of an SEV-SNP page. + + @param[in] PageAddress + @param[in] VmsaPage + + @return RMPADJUST return value +**/ +UINT32 +SevSnpRmpAdjust ( + IN EFI_PHYSICAL_ADDRESS PageAddress, + IN BOOLEAN VmsaPage + ) +{ + UINT64 Rdx; + + // + // The RMPADJUST instruction is used to set or clear the VMSA bit for a + // page. The VMSA change is only made when running at VMPL0 and is ignored + // otherwise. If too low a target VMPL is specified, the instruction can + // succeed without changing the VMSA bit when not running at VMPL0. Using a + // target VMPL level of 1, RMPADJUST will return a FAIL_PERMISSION error if + // not running at VMPL0, thus ensuring that the VMSA bit is set appropriately + // when no error is returned. + // + Rdx = 1; + if (VmsaPage) { + Rdx |= RMPADJUST_VMSA_PAGE_BIT; + } + + return AsmRmpAdjust ((UINT64) PageAddress, 0, Rdx); +} -- 2.25.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#83607): https://edk2.groups.io/g/devel/message/83607 Mute This Topic: https://groups.io/mt/86969158/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-