mirror of https://github.com/acidanthera/audk.git
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: 06544455d0
("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>
This commit is contained in:
parent
54051768cd
commit
3323359a81
|
@ -13,6 +13,100 @@
|
|||
#include <Register/Amd/Fam17Msr.h>
|
||||
#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.
|
||||
|
||||
|
@ -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;
|
||||
|
||||
//
|
||||
// Allocate a single page for the SEV-ES Save Area and initialize it.
|
||||
//
|
||||
SaveArea = AllocateReservedPages (1);
|
||||
if (!SaveArea) {
|
||||
return;
|
||||
if (CpuData->SevEsSaveArea == NULL) {
|
||||
//
|
||||
// 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue