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/Fam17Msr.h>
|
||||||
#include <Register/Amd/Ghcb.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.
|
Create an SEV-SNP AP save area (VMSA) for use in running the vCPU.
|
||||||
|
|
||||||
|
@ -27,27 +121,33 @@ SevSnpCreateSaveArea (
|
||||||
UINT32 ApicId
|
UINT32 ApicId
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
SEV_ES_SAVE_AREA *SaveArea;
|
SEV_ES_SAVE_AREA *SaveArea;
|
||||||
IA32_CR0 ApCr0;
|
IA32_CR0 ApCr0;
|
||||||
IA32_CR0 ResetCr0;
|
IA32_CR0 ResetCr0;
|
||||||
IA32_CR4 ApCr4;
|
IA32_CR4 ApCr4;
|
||||||
IA32_CR4 ResetCr4;
|
IA32_CR4 ResetCr4;
|
||||||
UINTN StartIp;
|
UINTN StartIp;
|
||||||
UINT8 SipiVector;
|
UINT8 SipiVector;
|
||||||
UINT32 RmpAdjustStatus;
|
|
||||||
UINT64 VmgExitStatus;
|
|
||||||
MSR_SEV_ES_GHCB_REGISTER Msr;
|
|
||||||
GHCB *Ghcb;
|
|
||||||
BOOLEAN InterruptState;
|
|
||||||
UINT64 ExitInfo1;
|
|
||||||
UINT64 ExitInfo2;
|
|
||||||
|
|
||||||
//
|
if (CpuData->SevEsSaveArea == NULL) {
|
||||||
// Allocate a single page for the SEV-ES Save Area and initialize it.
|
//
|
||||||
//
|
// Allocate a single page for the SEV-ES Save Area and initialize it.
|
||||||
SaveArea = AllocateReservedPages (1);
|
//
|
||||||
if (!SaveArea) {
|
SaveArea = AllocateReservedPages (1);
|
||||||
return;
|
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);
|
ZeroMem (SaveArea, EFI_PAGE_SIZE);
|
||||||
|
@ -132,63 +232,7 @@ SevSnpCreateSaveArea (
|
||||||
SaveArea->Vmpl = 0;
|
SaveArea->Vmpl = 0;
|
||||||
SaveArea->SevFeatures = AsmReadMsr64 (MSR_SEV_STATUS) >> 2;
|
SaveArea->SevFeatures = AsmReadMsr64 (MSR_SEV_STATUS) >> 2;
|
||||||
|
|
||||||
//
|
SevSnpPerformApAction (SaveArea, ApicId, 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
|
|
||||||
);
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue