From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by mx.groups.io with SMTP id smtpd.web12.3317.1609841323493113037 for ; Tue, 05 Jan 2021 02:08:43 -0800 Authentication-Results: mx.groups.io; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=Bs/jvUto; spf=pass (domain: redhat.com, ip: 216.205.24.124, mailfrom: lersek@redhat.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1609841322; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=QmMaDMKigZxPlBDSgYVCxn+fAOz+TapNaJYOVjD9kv0=; b=Bs/jvUtowa1aozt3PpLyV5Guhx5dP8VyC4Haz/4/ITU0YjXhtyVLxhFCxSL9+kEXdFMl8K DIWwRRPCO6iZmzgDWCpmNWyST4Rygk6a72JOVxgbTYAvDNcvbD5UdofTI8wBAtCcXWHV4y Vw5OnGoIystaKN/1hdEUUx36lnDXbEo= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-347-W13cRJCWMO6sduEuboJqfA-1; Tue, 05 Jan 2021 05:08:40 -0500 X-MC-Unique: W13cRJCWMO6sduEuboJqfA-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 4498A18C89DD; Tue, 5 Jan 2021 10:08:39 +0000 (UTC) Received: from lacos-laptop-7.usersys.redhat.com (ovpn-112-233.ams2.redhat.com [10.36.112.233]) by smtp.corp.redhat.com (Postfix) with ESMTP id D1CA01002382; Tue, 5 Jan 2021 10:08:36 +0000 (UTC) Subject: Re: [edk2-devel] [PATCH 10/12] OvmfPkg/VmgExitLib: Support nested #VCs To: devel@edk2.groups.io, thomas.lendacky@amd.com Cc: Brijesh Singh , James Bottomley , Jordan Justen , Ard Biesheuvel References: <8d981134522af3a1efa222b12f36d5e831f88f2e.1608065471.git.thomas.lendacky@amd.com> From: "Laszlo Ersek" Message-ID: <714c5653-b500-1ba5-36aa-f75246b034e4@redhat.com> Date: Tue, 5 Jan 2021 11:08:35 +0100 MIME-Version: 1.0 In-Reply-To: <8d981134522af3a1efa222b12f36d5e831f88f2e.1608065471.git.thomas.lendacky@amd.com> X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=lersek@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit On 12/15/20 21:51, Lendacky, Thomas wrote: > From: Tom Lendacky > > BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3108 > > In order to be able to issue messages or make interface calls that cause > another #VC (e.g. GetLocalApicBaseAddress () issues RDMSR), add support > for nested #VCs. > > In order to support nested #VCs, GHCB backup pages are required. If a #VC > is received while currently processing a #VC, a backup of the current GHCB > content is made. This allows the #VC handler to continue processing the > new #VC. Upon completion of the new #VC, the GHCB is restored from the > backup page. The #VC recursion level is tracked in the per-vCPU variable > area. > > Support is added to handle up to one nested #VC (or two #VCs total). If > a second nested #VC is encountered, an ASSERT will be issued and the vCPU > will enter CpuDeadLoop (). > > For SEC, the GHCB backup pages are reserved in the OvmfPkgX64.fdf memory > layout, with two new fixed PCDs to provide the address and size of the > backup area. > > For PEI/DXE, the GHCB backup pages are allocated as boot services pages > using the memory allocation library. > > Cc: Jordan Justen > Cc: Laszlo Ersek > Cc: Ard Biesheuvel > Cc: Brijesh Singh > Signed-off-by: Tom Lendacky > --- > OvmfPkg/OvmfPkg.dec | 2 + > OvmfPkg/AmdSev/AmdSevX64.dsc | 1 + > OvmfPkg/OvmfPkgX64.dsc | 1 + > OvmfPkg/AmdSev/AmdSevX64.fdf | 3 + > OvmfPkg/OvmfPkgX64.fdf | 3 + > OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf | 43 +++++++ > OvmfPkg/Library/VmgExitLib/VmgExitLib.inf | 4 +- > OvmfPkg/Include/Library/MemEncryptSevLib.h | 23 ++++ > OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.h | 53 +++++++++ > .../VmgExitLib/PeiDxeVmgExitVcHandler.c | 103 +++++++++++++++++ > .../Library/VmgExitLib/SecVmgExitVcHandler.c | 109 ++++++++++++++++++ > OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c | 48 ++++---- > OvmfPkg/PlatformPei/AmdSev.c | 38 +++++- > 13 files changed, 404 insertions(+), 27 deletions(-) > create mode 100644 OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf > create mode 100644 OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.h > create mode 100644 OvmfPkg/Library/VmgExitLib/PeiDxeVmgExitVcHandler.c > create mode 100644 OvmfPkg/Library/VmgExitLib/SecVmgExitVcHandler.c I've reviewed the higher-level structure of this patch; it seems OK. Acked-by: Laszlo Ersek Thanks Laszlo > diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec > index 8a294116efaa..9731f09381a9 100644 > --- a/OvmfPkg/OvmfPkg.dec > +++ b/OvmfPkg/OvmfPkg.dec > @@ -304,6 +304,8 @@ [PcdsFixedAtBuild] > ## The base address of the SEC GHCB page used by SEV-ES. > gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|0|UINT32|0x40 > gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize|0|UINT32|0x41 > + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase|0|UINT32|0x44 > + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize|0|UINT32|0x45 > > ## The base address and size of the SEV Launch Secret Area provisioned > # after remote attestation. If this is set in the .fdf, the platform > diff --git a/OvmfPkg/AmdSev/AmdSevX64.dsc b/OvmfPkg/AmdSev/AmdSevX64.dsc > index c742ec54cb57..3e5a3f648ad5 100644 > --- a/OvmfPkg/AmdSev/AmdSevX64.dsc > +++ b/OvmfPkg/AmdSev/AmdSevX64.dsc > @@ -236,6 +236,7 @@ [LibraryClasses.common.SEC] > !else > CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf > !endif > + VmgExitLib|OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf > > [LibraryClasses.common.PEI_CORE] > HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf > diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc > index 3e008855fbc1..226b576545a9 100644 > --- a/OvmfPkg/OvmfPkgX64.dsc > +++ b/OvmfPkg/OvmfPkgX64.dsc > @@ -264,6 +264,7 @@ [LibraryClasses.common.SEC] > !else > CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf > !endif > + VmgExitLib|OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf > > [LibraryClasses.common.PEI_CORE] > HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf > diff --git a/OvmfPkg/AmdSev/AmdSevX64.fdf b/OvmfPkg/AmdSev/AmdSevX64.fdf > index e8fd4b8c7b89..c0098502aa90 100644 > --- a/OvmfPkg/AmdSev/AmdSevX64.fdf > +++ b/OvmfPkg/AmdSev/AmdSevX64.fdf > @@ -62,6 +62,9 @@ [FD.MEMFD] > 0x00C000|0x001000 > gUefiOvmfPkgTokenSpaceGuid.PcdSevLaunchSecretBase|gUefiOvmfPkgTokenSpaceGuid.PcdSevLaunchSecretSize > > +0x00D000|0x001000 > +gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize > + > 0x010000|0x010000 > gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize > > diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf > index 17ba9e177ac3..31fe58566bb5 100644 > --- a/OvmfPkg/OvmfPkgX64.fdf > +++ b/OvmfPkg/OvmfPkgX64.fdf > @@ -85,6 +85,9 @@ [FD.MEMFD] > 0x00B000|0x001000 > gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase|gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaSize > > +0x00C000|0x001000 > +gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize > + > 0x010000|0x010000 > gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize > > diff --git a/OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf b/OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf > new file mode 100644 > index 000000000000..df14de3c21bc > --- /dev/null > +++ b/OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf > @@ -0,0 +1,43 @@ > +## @file > +# VMGEXIT Support Library. > +# > +# Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.
> +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + INF_VERSION = 0x00010005 > + BASE_NAME = SecVmgExitLib > + FILE_GUID = dafff819-f86c-4cff-a70e-83161e5bcf9a > + MODULE_TYPE = BASE > + VERSION_STRING = 1.0 > + LIBRARY_CLASS = VmgExitLib|SEC > + > +# > +# The following information is for reference only and not required by the build tools. > +# > +# VALID_ARCHITECTURES = X64 > +# > + > +[Sources.common] > + VmgExitLib.c > + VmgExitVcHandler.c > + VmgExitVcHandler.h > + SecVmgExitVcHandler.c > + > +[Packages] > + MdePkg/MdePkg.dec > + OvmfPkg/OvmfPkg.dec > + UefiCpuPkg/UefiCpuPkg.dec > + > +[LibraryClasses] > + BaseLib > + BaseMemoryLib > + DebugLib > + PcdLib > + > +[FixedPcd] > + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase > + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize > + > diff --git a/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf b/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf > index d003ac63173e..b3c3e56ecff8 100644 > --- a/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf > +++ b/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf > @@ -12,7 +12,7 @@ [Defines] > FILE_GUID = 0e923c25-13cd-430b-8714-ffe85652a97b > MODULE_TYPE = BASE > VERSION_STRING = 1.0 > - LIBRARY_CLASS = VmgExitLib > + LIBRARY_CLASS = VmgExitLib|PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_DRIVER > > # > # The following information is for reference only and not required by the build tools. > @@ -23,6 +23,8 @@ [Defines] > [Sources.common] > VmgExitLib.c > VmgExitVcHandler.c > + VmgExitVcHandler.h > + PeiDxeVmgExitVcHandler.c > > [Packages] > MdePkg/MdePkg.dec > diff --git a/OvmfPkg/Include/Library/MemEncryptSevLib.h b/OvmfPkg/Include/Library/MemEncryptSevLib.h > index 421b2e2c2c1e..eb400387e8e2 100644 > --- a/OvmfPkg/Include/Library/MemEncryptSevLib.h > +++ b/OvmfPkg/Include/Library/MemEncryptSevLib.h > @@ -13,6 +13,29 @@ > > #include > > +// > +// Define the maximum number of #VCs allowed (e.g. the level of nesting > +// that is allowed => 2 allows for 1 nested #VCs). I this value is changed, > +// be sure to increase the size of > +// gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize > +// in any FDF file using this PCD. > +// > +#define VMGEXIT_MAXIMUM_VC_COUNT 2 > + > +// > +// Per-CPU data mapping structure > +// Use UINT32 for cached indicators and compare to a specific value > +// so that the hypervisor can't indicate a value is cached by just > +// writing random data to that area. > +// > +typedef struct { > + UINT32 Dr7Cached; > + UINT64 Dr7; > + > + UINTN VcCount; > + VOID *GhcbBackupPages; > +} SEV_ES_PER_CPU_DATA; > + > // > // Internal structure for holding SEV-ES information needed during SEC phase > // and valid only during SEC phase and early PEI during platform > diff --git a/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.h b/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.h > new file mode 100644 > index 000000000000..3a37cb04f616 > --- /dev/null > +++ b/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.h > @@ -0,0 +1,53 @@ > +/** @file > + X64 #VC Exception Handler functon header file. > + > + Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef __VMG_EXIT_VC_HANDLER_H__ > +#define __VMG_EXIT_VC_HANDLER_H__ > + > +#include > +#include > +#include > + > +/** > + Handle a #VC exception. > + > + Performs the necessary processing to handle a #VC exception. > + > + @param[in, out] Ghcb Pointer to the GHCB > + @param[in, out] ExceptionType Pointer to an EFI_EXCEPTION_TYPE to be set > + as value to use on error. > + @param[in, out] SystemContext Pointer to EFI_SYSTEM_CONTEXT > + > + @retval EFI_SUCCESS Exception handled > + @retval EFI_UNSUPPORTED #VC not supported, (new) exception value to > + propagate provided > + @retval EFI_PROTOCOL_ERROR #VC handling failed, (new) exception value to > + propagate provided > + > +**/ > +EFI_STATUS > +EFIAPI > +InternalVmgExitHandleVc ( > + IN OUT GHCB *Ghcb, > + IN OUT EFI_EXCEPTION_TYPE *ExceptionType, > + IN OUT EFI_SYSTEM_CONTEXT SystemContext > + ); > + > +/** > + Routine to allow ASSERT from within #VC. > + > + @param[in, out] SevEsData Pointer to the per-CPU data > + > +**/ > +VOID > +EFIAPI > +VmgExitIssueAssert ( > + IN OUT SEV_ES_PER_CPU_DATA *SevEsData > + ); > + > +#endif > diff --git a/OvmfPkg/Library/VmgExitLib/PeiDxeVmgExitVcHandler.c b/OvmfPkg/Library/VmgExitLib/PeiDxeVmgExitVcHandler.c > new file mode 100644 > index 000000000000..fb4942df37ca > --- /dev/null > +++ b/OvmfPkg/Library/VmgExitLib/PeiDxeVmgExitVcHandler.c > @@ -0,0 +1,103 @@ > +/** @file > + X64 #VC Exception Handler functon. > + > + Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "VmgExitVcHandler.h" > + > +/** > + Handle a #VC exception. > + > + Performs the necessary processing to handle a #VC exception. > + > + @param[in, out] ExceptionType Pointer to an EFI_EXCEPTION_TYPE to be set > + as value to use on error. > + @param[in, out] SystemContext Pointer to EFI_SYSTEM_CONTEXT > + > + @retval EFI_SUCCESS Exception handled > + @retval EFI_UNSUPPORTED #VC not supported, (new) exception value to > + propagate provided > + @retval EFI_PROTOCOL_ERROR #VC handling failed, (new) exception value to > + propagate provided > + > +**/ > +EFI_STATUS > +EFIAPI > +VmgExitHandleVc ( > + IN OUT EFI_EXCEPTION_TYPE *ExceptionType, > + IN OUT EFI_SYSTEM_CONTEXT SystemContext > + ) > +{ > + MSR_SEV_ES_GHCB_REGISTER Msr; > + GHCB *Ghcb; > + GHCB *GhcbBackup; > + EFI_STATUS VcRet; > + BOOLEAN InterruptState; > + SEV_ES_PER_CPU_DATA *SevEsData; > + > + InterruptState = GetInterruptState (); > + if (InterruptState) { > + DisableInterrupts (); > + } > + > + Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB); > + ASSERT (Msr.GhcbInfo.Function == 0); > + ASSERT (Msr.Ghcb != 0); > + > + Ghcb = Msr.Ghcb; > + GhcbBackup = NULL; > + > + SevEsData = (SEV_ES_PER_CPU_DATA *) (Ghcb + 1); > + SevEsData->VcCount++; > + > + // > + // Check for maximum PEI/DXE #VC nesting. > + // > + if (SevEsData->VcCount > VMGEXIT_MAXIMUM_VC_COUNT) { > + VmgExitIssueAssert (SevEsData); > + } else if (SevEsData->VcCount > 1) { > + // > + // Nested #VC > + // > + if (SevEsData->GhcbBackupPages == NULL) { > + VmgExitIssueAssert (SevEsData); > + } > + > + // > + // Save the active GHCB to a backup page. > + // To access the correct backup page, increment the backup page pointer > + // based on the current VcCount. > + // > + GhcbBackup = (GHCB *) SevEsData->GhcbBackupPages; > + GhcbBackup += (SevEsData->VcCount - 2); > + > + CopyMem (GhcbBackup, Ghcb, sizeof (*Ghcb)); > + } > + > + VcRet = InternalVmgExitHandleVc (Ghcb, ExceptionType, SystemContext); > + > + if (GhcbBackup != NULL) { > + // > + // Restore the active GHCB from the backup page. > + // > + CopyMem (Ghcb, GhcbBackup, sizeof (*Ghcb)); > + } > + > + SevEsData->VcCount--; > + > + if (InterruptState) { > + EnableInterrupts (); > + } > + > + return VcRet; > +} > diff --git a/OvmfPkg/Library/VmgExitLib/SecVmgExitVcHandler.c b/OvmfPkg/Library/VmgExitLib/SecVmgExitVcHandler.c > new file mode 100644 > index 000000000000..85853d334b35 > --- /dev/null > +++ b/OvmfPkg/Library/VmgExitLib/SecVmgExitVcHandler.c > @@ -0,0 +1,109 @@ > +/** @file > + X64 #VC Exception Handler functon. > + > + Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "VmgExitVcHandler.h" > + > +/** > + Handle a #VC exception. > + > + Performs the necessary processing to handle a #VC exception. > + > + @param[in, out] ExceptionType Pointer to an EFI_EXCEPTION_TYPE to be set > + as value to use on error. > + @param[in, out] SystemContext Pointer to EFI_SYSTEM_CONTEXT > + > + @retval EFI_SUCCESS Exception handled > + @retval EFI_UNSUPPORTED #VC not supported, (new) exception value to > + propagate provided > + @retval EFI_PROTOCOL_ERROR #VC handling failed, (new) exception value to > + propagate provided > + > +**/ > +EFI_STATUS > +EFIAPI > +VmgExitHandleVc ( > + IN OUT EFI_EXCEPTION_TYPE *ExceptionType, > + IN OUT EFI_SYSTEM_CONTEXT SystemContext > + ) > +{ > + MSR_SEV_ES_GHCB_REGISTER Msr; > + GHCB *Ghcb; > + GHCB *GhcbBackup; > + EFI_STATUS VcRet; > + BOOLEAN InterruptState; > + SEV_ES_PER_CPU_DATA *SevEsData; > + > + InterruptState = GetInterruptState (); > + if (InterruptState) { > + DisableInterrupts (); > + } > + > + Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB); > + ASSERT (Msr.GhcbInfo.Function == 0); > + ASSERT (Msr.Ghcb != 0); > + > + Ghcb = Msr.Ghcb; > + GhcbBackup = NULL; > + > + SevEsData = (SEV_ES_PER_CPU_DATA *) (Ghcb + 1); > + SevEsData->VcCount++; > + > + // > + // Check for maximum SEC #VC nesting. > + // > + if (SevEsData->VcCount > VMGEXIT_MAXIMUM_VC_COUNT) { > + VmgExitIssueAssert (SevEsData); > + } else if (SevEsData->VcCount > 1) { > + UINTN GhcbBackupSize; > + > + // > + // Be sure that the proper amount of pages are allocated > + // > + GhcbBackupSize = (VMGEXIT_MAXIMUM_VC_COUNT - 1) * sizeof (*Ghcb); > + if (GhcbBackupSize > FixedPcdGet32 (PcdOvmfSecGhcbBackupSize)) { > + // > + // Not enough SEC backup pages allocated. > + // > + VmgExitIssueAssert (SevEsData); > + } > + > + // > + // Save the active GHCB to a backup page. > + // To access the correct backup page, increment the backup page pointer > + // based on the current VcCount. > + // > + GhcbBackup = (GHCB *) FixedPcdGet32 (PcdOvmfSecGhcbBackupBase); > + GhcbBackup += (SevEsData->VcCount - 2); > + > + CopyMem (GhcbBackup, Ghcb, sizeof (*Ghcb)); > + } > + > + VcRet = InternalVmgExitHandleVc (Ghcb, ExceptionType, SystemContext); > + > + if (GhcbBackup != NULL) { > + // > + // Restore the active GHCB from the backup page. > + // > + CopyMem (Ghcb, GhcbBackup, sizeof (*Ghcb)); > + } > + > + SevEsData->VcCount--; > + > + if (InterruptState) { > + EnableInterrupts (); > + } > + > + return VcRet; > +} > diff --git a/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c b/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c > index 5149ab2bc989..ce577e4677eb 100644 > --- a/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c > +++ b/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c > @@ -9,11 +9,14 @@ > #include > #include > #include > +#include > #include > #include > #include > #include > > +#include "VmgExitVcHandler.h" > + > // > // Instruction execution mode definition > // > @@ -126,18 +129,6 @@ UINT64 > SEV_ES_INSTRUCTION_DATA *InstructionData > ); > > -// > -// Per-CPU data mapping structure > -// Use UINT32 for cached indicators and compare to a specific value > -// so that the hypervisor can't indicate a value is cached by just > -// writing random data to that area. > -// > -typedef struct { > - UINT32 Dr7Cached; > - UINT64 Dr7; > -} SEV_ES_PER_CPU_DATA; > - > - > /** > Return a pointer to the contents of the specified register. > > @@ -1546,6 +1537,7 @@ Dr7ReadExit ( > > Performs the necessary processing to handle a #VC exception. > > + @param[in, out] Ghcb Pointer to the GHCB > @param[in, out] ExceptionType Pointer to an EFI_EXCEPTION_TYPE to be set > as value to use on error. > @param[in, out] SystemContext Pointer to EFI_SYSTEM_CONTEXT > @@ -1559,14 +1551,13 @@ Dr7ReadExit ( > **/ > EFI_STATUS > EFIAPI > -VmgExitHandleVc ( > +InternalVmgExitHandleVc ( > + IN OUT GHCB *Ghcb, > IN OUT EFI_EXCEPTION_TYPE *ExceptionType, > IN OUT EFI_SYSTEM_CONTEXT SystemContext > ) > { > - MSR_SEV_ES_GHCB_REGISTER Msr; > EFI_SYSTEM_CONTEXT_X64 *Regs; > - GHCB *Ghcb; > NAE_EXIT NaeExit; > SEV_ES_INSTRUCTION_DATA InstructionData; > UINT64 ExitCode, Status; > @@ -1575,12 +1566,7 @@ VmgExitHandleVc ( > > VcRet = EFI_SUCCESS; > > - Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB); > - ASSERT (Msr.GhcbInfo.Function == 0); > - ASSERT (Msr.Ghcb != 0); > - > Regs = SystemContext.SystemContextX64; > - Ghcb = Msr.Ghcb; > > VmgInit (Ghcb, &InterruptState); > > @@ -1670,3 +1656,25 @@ VmgExitHandleVc ( > > return VcRet; > } > + > +/** > + Routine to allow ASSERT from within #VC. > + > + @param[in, out] SevEsData Pointer to the per-CPU data > + > +**/ > +VOID > +EFIAPI > +VmgExitIssueAssert ( > + IN OUT SEV_ES_PER_CPU_DATA *SevEsData > + ) > +{ > + // > + // Progress will be halted, so set VcCount to allow for ASSERT output > + // to be seen. > + // > + SevEsData->VcCount = 0; > + > + ASSERT (FALSE); > + CpuDeadLoop (); > +} > diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c > index 954d53eba4e8..dddffdebda4b 100644 > --- a/OvmfPkg/PlatformPei/AmdSev.c > +++ b/OvmfPkg/PlatformPei/AmdSev.c > @@ -33,12 +33,17 @@ AmdSevEsInitialize ( > VOID > ) > { > - VOID *GhcbBase; > - PHYSICAL_ADDRESS GhcbBasePa; > - UINTN GhcbPageCount, PageCount; > - RETURN_STATUS PcdStatus, DecryptStatus; > - IA32_DESCRIPTOR Gdtr; > - VOID *Gdt; > + UINT8 *GhcbBase; > + PHYSICAL_ADDRESS GhcbBasePa; > + UINTN GhcbPageCount; > + UINT8 *GhcbBackupBase; > + UINT8 *GhcbBackupPages; > + UINTN GhcbBackupPageCount; > + SEV_ES_PER_CPU_DATA *SevEsData; > + UINTN PageCount; > + RETURN_STATUS PcdStatus, DecryptStatus; > + IA32_DESCRIPTOR Gdtr; > + VOID *Gdt; > > if (!MemEncryptSevEsIsEnabled ()) { > return; > @@ -84,6 +89,27 @@ AmdSevEsInitialize ( > "SEV-ES is enabled, %lu GHCB pages allocated starting at 0x%p\n", > (UINT64)GhcbPageCount, GhcbBase)); > > + // > + // Allocate #VC recursion backup pages. The number of backup pages needed is > + // one less than the maximum VC count. > + // > + GhcbBackupPageCount = mMaxCpuCount * (VMGEXIT_MAXIMUM_VC_COUNT - 1); > + GhcbBackupBase = AllocatePages (GhcbBackupPageCount); > + ASSERT (GhcbBackupBase != NULL); > + > + GhcbBackupPages = GhcbBackupBase; > + for (PageCount = 1; PageCount < GhcbPageCount; PageCount += 2) { > + SevEsData = > + (SEV_ES_PER_CPU_DATA *)(GhcbBase + EFI_PAGES_TO_SIZE (PageCount)); > + SevEsData->GhcbBackupPages = GhcbBackupPages; > + > + GhcbBackupPages += EFI_PAGE_SIZE * (VMGEXIT_MAXIMUM_VC_COUNT - 1); > + } > + > + DEBUG ((DEBUG_INFO, > + "SEV-ES is enabled, %lu GHCB backup pages allocated starting at 0x%p\n", > + (UINT64)GhcbBackupPageCount, GhcbBackupBase)); > + > AsmWriteMsr64 (MSR_SEV_ES_GHCB, GhcbBasePa); > > // >