From a010681f74c9110a9e8e1753a98c13743b60f7f7 Mon Sep 17 00:00:00 2001 From: Tom Lendacky Date: Fri, 8 Mar 2024 07:32:44 -0800 Subject: UefiCpuPkg/MpInitLib: AP creation support under an SVSM BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4654 When running under an SVSM, the VMPL level of the APs that are started must match the VMPL level provided by the SVSM. Additionally, each AP must have a Calling Area for use with the SVSM protocol. Update the AP creation to properly support running under an SVSM. Cc: Gerd Hoffmann Cc: Laszlo Ersek Cc: Rahul Kumar Cc: Ray Ni Acked-by: Ray Ni Acked-by: Gerd Hoffmann Signed-off-by: Tom Lendacky --- UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c b/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c index 9811356213..bbdc47b5a3 100644 --- a/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c +++ b/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c @@ -44,7 +44,8 @@ SevSnpPerformApAction ( if (Action == SVM_VMGEXIT_SNP_AP_CREATE) { // - // Turn the page into a recognized VMSA page. + // Turn the page into a recognized VMSA page. When an SVSM is present + // the page following the VMSA is the Calling Area page. // VmsaStatus = AmdSvsmSnpVmsaRmpAdjust (SaveArea, ApicId, TRUE); if (EFI_ERROR (VmsaStatus)) { @@ -56,6 +57,7 @@ SevSnpPerformApAction ( } ExitInfo1 = (UINT64)ApicId << 32; + ExitInfo1 |= (UINT64)SaveArea->Vmpl << 16; ExitInfo1 |= Action; ExitInfo2 = (UINT64)(UINTN)SaveArea; @@ -87,8 +89,9 @@ SevSnpPerformApAction ( if (Action == SVM_VMGEXIT_SNP_AP_DESTROY) { // - // Make the current VMSA not runnable and accessible to be - // reprogrammed. + // Make the current VMSA not runnable and accessible to be reprogrammed. + // When an SVSM is present the page following the VMSA is the Calling Area + // page. // VmsaStatus = AmdSvsmSnpVmsaRmpAdjust (SaveArea, ApicId, FALSE); if (EFI_ERROR (VmsaStatus)) { @@ -116,6 +119,7 @@ SevSnpCreateSaveArea ( UINT32 ApicId ) { + UINTN PageCount; UINT8 *Pages; SEV_ES_SAVE_AREA *SaveArea; IA32_CR0 ApCr0; @@ -125,13 +129,19 @@ SevSnpCreateSaveArea ( UINTN StartIp; UINT8 SipiVector; + // + // When running under an SVSM, a Calling Area page is also needed and is + // always the page following the VMSA. + // + PageCount = AmdSvsmIsSvsmPresent () ? 2 : 1; + if (CpuData->SevEsSaveArea == NULL) { // // Allocate a page for the SEV-ES Save Area and initialize it. Due to AMD // erratum #1467 (VMSA cannot be on a 2MB boundary), allocate an extra page // to choose from to work around the issue. // - Pages = AllocateReservedPages (2); + Pages = AllocateReservedPages (PageCount + 1); if (!Pages) { return; } @@ -140,12 +150,12 @@ SevSnpCreateSaveArea ( // Since page allocation works by allocating downward in the address space, // try to always free the first (lower address) page to limit possible holes // in the memory map. So, if the address of the second page is 2MB aligned, - // then use the first page and free the second page. Otherwise, free the + // then use the first page and free the last page. Otherwise, free the // first page and use the second page. // if (_IS_ALIGNED (Pages + EFI_PAGE_SIZE, SIZE_2MB)) { SaveArea = (SEV_ES_SAVE_AREA *)Pages; - FreePages (Pages + EFI_PAGE_SIZE, 1); + FreePages (Pages + (EFI_PAGE_SIZE * PageCount), 1); } else { SaveArea = (SEV_ES_SAVE_AREA *)(Pages + EFI_PAGE_SIZE); FreePages (Pages, 1); @@ -163,7 +173,7 @@ SevSnpCreateSaveArea ( } } - ZeroMem (SaveArea, EFI_PAGE_SIZE); + ZeroMem (SaveArea, EFI_PAGE_SIZE * PageCount); // // Propogate the CR0.NW and CR0.CD setting to the AP @@ -239,10 +249,10 @@ SevSnpCreateSaveArea ( // // Set the SEV-SNP specific fields for the save area: - // VMPL - always VMPL0 + // VMPL - based on current mode // SEV_FEATURES - equivalent to the SEV_STATUS MSR right shifted 2 bits // - SaveArea->Vmpl = 0; + SaveArea->Vmpl = AmdSvsmSnpGetVmpl (); SaveArea->SevFeatures = AsmReadMsr64 (MSR_SEV_STATUS) >> 2; SevSnpPerformApAction (SaveArea, ApicId, SVM_VMGEXIT_SNP_AP_CREATE); -- cgit