summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLendacky, Thomas via groups.io <thomas.lendacky=amd.com@groups.io>2023-03-29 02:09:23 +0800
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2023-04-01 03:15:51 +0000
commit3323359a811a597b8ee045638c5addd10444402c (patch)
tree87edc58c4b8f1e8272982872d456d0f28e412179
parent54051768cdf69e2b46dc4fe1a85455d631aa2634 (diff)
downloadedk2-3323359a811a597b8ee045638c5addd10444402c.tar.gz
edk2-3323359a811a597b8ee045638c5addd10444402c.tar.bz2
edk2-3323359a811a597b8ee045638c5addd10444402c.zip
UefiCpuPkg/MpInitLib: Reuse VMSA allocation to avoid unreserved allocation
https://bugzilla.tianocore.org/show_bug.cgi?id=4353 When parking the APs on exiting from UEFI, a new page allocation is made. This allocation, however, does not end up being marked reserved in the memory map supplied to the OS. To avoid this, re-use the VMSA by clearing the VMSA RMP flag, updating the page contents and re-setting the VMSA RMP flag. Fixes: 06544455d0d4 ("UefiCpuPkg/MpInitLib: Use SEV-SNP AP Creation ...") Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com> Acked-by: Gerd Hoffmann <kraxel@redhat.com> Acked-by: Ray Ni <ray.ni@intel.com>
-rw-r--r--UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c198
1 files changed, 121 insertions, 77 deletions
diff --git a/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c b/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c
index bfda1e1903..509be9b417 100644
--- a/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c
+++ b/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c
@@ -14,6 +14,100 @@
#include <Register/Amd/Ghcb.h>
/**
+ Perform the requested AP Creation action.
+
+ @param[in] SaveArea Pointer to VM save area (VMSA)
+ @param[in] ApicId APIC ID of the vCPU
+ @param[in] Action AP action to perform
+
+ @retval TRUE Action completed successfully
+ @retval FALSE Action did not complete successfully
+**/
+STATIC
+BOOLEAN
+SevSnpPerformApAction (
+ IN SEV_ES_SAVE_AREA *SaveArea,
+ IN UINT32 ApicId,
+ IN UINTN Action
+ )
+{
+ MSR_SEV_ES_GHCB_REGISTER Msr;
+ GHCB *Ghcb;
+ BOOLEAN InterruptState;
+ UINT64 ExitInfo1;
+ UINT64 ExitInfo2;
+ UINT32 RmpAdjustStatus;
+ UINT64 VmgExitStatus;
+
+ if (Action == SVM_VMGEXIT_SNP_AP_CREATE) {
+ //
+ // 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
+ );
+ if (RmpAdjustStatus != 0) {
+ DEBUG ((DEBUG_INFO, "SEV-SNP: RMPADJUST failed for VMSA creation\n"));
+ ASSERT (FALSE);
+
+ return FALSE;
+ }
+ }
+
+ ExitInfo1 = (UINT64)ApicId << 32;
+ ExitInfo1 |= Action;
+ ExitInfo2 = (UINT64)(UINTN)SaveArea;
+
+ Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+ Ghcb = Msr.Ghcb;
+
+ CcExitVmgInit (Ghcb, &InterruptState);
+
+ if (Action == SVM_VMGEXIT_SNP_AP_CREATE) {
+ Ghcb->SaveArea.Rax = SaveArea->SevFeatures;
+ CcExitVmgSetOffsetValid (Ghcb, GhcbRax);
+ }
+
+ VmgExitStatus = CcExitVmgExit (
+ Ghcb,
+ SVM_EXIT_SNP_AP_CREATION,
+ ExitInfo1,
+ ExitInfo2
+ );
+
+ CcExitVmgDone (Ghcb, InterruptState);
+
+ if (VmgExitStatus != 0) {
+ DEBUG ((DEBUG_INFO, "SEV-SNP: AP Destroy failed\n"));
+ ASSERT (FALSE);
+
+ return FALSE;
+ }
+
+ if (Action == SVM_VMGEXIT_SNP_AP_DESTROY) {
+ //
+ // Make the current VMSA not runnable and accessible to be
+ // reprogrammed.
+ //
+ RmpAdjustStatus = SevSnpRmpAdjust (
+ (EFI_PHYSICAL_ADDRESS)(UINTN)SaveArea,
+ FALSE
+ );
+ if (RmpAdjustStatus != 0) {
+ DEBUG ((DEBUG_INFO, "SEV-SNP: RMPADJUST failed for VMSA reset\n"));
+ ASSERT (FALSE);
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
Create an SEV-SNP AP save area (VMSA) for use in running the vCPU.
@param[in] CpuMpData Pointer to CPU MP Data
@@ -27,27 +121,33 @@ SevSnpCreateSaveArea (
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;
+ SEV_ES_SAVE_AREA *SaveArea;
+ IA32_CR0 ApCr0;
+ IA32_CR0 ResetCr0;
+ IA32_CR4 ApCr4;
+ IA32_CR4 ResetCr4;
+ UINTN StartIp;
+ UINT8 SipiVector;
+
+ if (CpuData->SevEsSaveArea == NULL) {
+ //
+ // Allocate a single page for the SEV-ES Save Area and initialize it.
+ //
+ SaveArea = AllocateReservedPages (1);
+ if (!SaveArea) {
+ return;
+ }
- //
- // Allocate a single page for the SEV-ES Save Area and initialize it.
- //
- SaveArea = AllocateReservedPages (1);
- if (!SaveArea) {
- return;
+ CpuData->SevEsSaveArea = SaveArea;
+ } else {
+ SaveArea = CpuData->SevEsSaveArea;
+
+ //
+ // Tell the hypervisor to not use the current VMSA
+ //
+ if (!SevSnpPerformApAction (SaveArea, ApicId, SVM_VMGEXIT_SNP_AP_DESTROY)) {
+ return;
+ }
}
ZeroMem (SaveArea, EFI_PAGE_SIZE);
@@ -132,63 +232,7 @@ SevSnpCreateSaveArea (
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;
-
- CcExitVmgInit (Ghcb, &InterruptState);
- Ghcb->SaveArea.Rax = SaveArea->SevFeatures;
- CcExitVmgSetOffsetValid (Ghcb, GhcbRax);
- VmgExitStatus = CcExitVmgExit (
- Ghcb,
- SVM_EXIT_SNP_AP_CREATION,
- ExitInfo1,
- ExitInfo2
- );
- CcExitVmgDone (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;
+ SevSnpPerformApAction (SaveArea, ApicId, SVM_VMGEXIT_SNP_AP_CREATE);
}
/**