From a89f558d3c56d9c16e5f5b7d395c1aa36ccd38f2 Mon Sep 17 00:00:00 2001 From: Min M Xu Date: Mon, 7 Nov 2022 14:30:26 +0800 Subject: OvmfPkg/UefiCpuPkg/UefiPayloadPkg: Rename VmgExitLib to CcExitLib BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4123 VmgExitLib once was designed to provide interfaces to support #VC handler and issue VMGEXIT instruction. After TDVF (enable TDX feature in OVMF) is introduced, this library is updated to support #VE as well. Now the name of VmgExitLib cannot reflect what the lib does. This patch renames VmgExitLib to CcExitLib (Cc means Confidential Computing). This is a simple renaming and there is no logic changes. After renaming all the VmgExitLib related codes are updated with CcExitLib. These changes are in OvmfPkg/UefiCpuPkg/UefiPayloadPkg. Cc: Guo Dong Cc: Sean Rhodes Cc: James Lu Cc: Gua Guo Cc: Eric Dong Cc: Ray Ni Cc: Brijesh Singh Cc: Erdem Aktas Cc: Gerd Hoffmann Cc: James Bottomley Cc: Jiewen Yao Cc: Tom Lendacky Reviewed-by: James Lu Reviewed-by: Gua Guo Reviewed-by: Jiewen Yao Reviewed-by: Ray Ni Signed-off-by: Min Xu --- OvmfPkg/AmdSev/AmdSevX64.dsc | 4 +- OvmfPkg/Bhyve/BhyveX64.dsc | 2 +- OvmfPkg/CloudHv/CloudHvX64.dsc | 6 +- OvmfPkg/IntelTdx/IntelTdxX64.dsc | 4 +- .../BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf | 2 +- .../BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf | 2 +- .../BaseMemEncryptSevLib/SecMemEncryptSevLib.inf | 2 +- .../X64/SnpPageStateChangeInternal.c | 2 +- OvmfPkg/Library/CcExitLib/CcExitLib.c | 239 ++ OvmfPkg/Library/CcExitLib/CcExitLib.inf | 46 + OvmfPkg/Library/CcExitLib/CcExitTd.h | 32 + OvmfPkg/Library/CcExitLib/CcExitVcHandler.c | 2355 +++++++++++++++++++ OvmfPkg/Library/CcExitLib/CcExitVcHandler.h | 53 + OvmfPkg/Library/CcExitLib/CcExitVeHandler.c | 577 +++++ OvmfPkg/Library/CcExitLib/PeiDxeCcExitVcHandler.c | 103 + OvmfPkg/Library/CcExitLib/SecCcExitLib.inf | 48 + OvmfPkg/Library/CcExitLib/SecCcExitVcHandler.c | 109 + OvmfPkg/Library/CcExitLib/X64/TdVmcallCpuid.nasm | 146 ++ .../Library/VmgExitLib/PeiDxeVmgExitVcHandler.c | 103 - OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf | 48 - OvmfPkg/Library/VmgExitLib/SecVmgExitVcHandler.c | 109 - OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h | 32 - OvmfPkg/Library/VmgExitLib/VmTdExitVeHandler.c | 577 ----- OvmfPkg/Library/VmgExitLib/VmgExitLib.c | 238 -- OvmfPkg/Library/VmgExitLib/VmgExitLib.inf | 45 - OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c | 2356 -------------------- OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.h | 53 - OvmfPkg/Library/VmgExitLib/X64/TdVmcallCpuid.nasm | 146 -- OvmfPkg/Microvm/MicrovmX64.dsc | 4 +- OvmfPkg/OvmfPkgIa32.dsc | 4 +- OvmfPkg/OvmfPkgIa32X64.dsc | 4 +- OvmfPkg/OvmfPkgX64.dsc | 6 +- OvmfPkg/OvmfXen.dsc | 2 +- OvmfPkg/PlatformPei/AmdSev.c | 2 +- OvmfPkg/PlatformPei/PlatformPei.inf | 2 +- .../FvbServicesRuntimeDxe.inf | 2 +- .../QemuFlashFvbServicesRuntimeDxe/QemuFlashDxe.c | 2 +- UefiCpuPkg/Include/Library/CcExitLib.h | 176 ++ UefiCpuPkg/Include/Library/VmgExitLib.h | 173 -- UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.c | 194 ++ UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf | 28 + UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.uni | 14 + .../DxeCpuExceptionHandlerLib.inf | 2 +- .../PeiCpuExceptionHandlerLib.inf | 2 +- .../CpuExceptionHandlerLib/PeiDxeSmmCpuException.c | 2 +- .../CpuExceptionHandlerLib/SecPeiCpuException.c | 2 +- .../SecPeiCpuExceptionHandlerLib.inf | 2 +- .../SmmCpuExceptionHandlerLib.inf | 2 +- .../Xcode5SecPeiCpuExceptionHandlerLib.inf | 2 +- UefiCpuPkg/Library/MpInitLib/AmdSev.c | 2 +- UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf | 2 +- UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 2 +- UefiCpuPkg/Library/MpInitLib/MpLib.c | 2 +- UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf | 2 +- UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c | 2 +- UefiCpuPkg/Library/VmgExitLibNull/VmTdExitNull.c | 38 - UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.c | 165 -- .../Library/VmgExitLibNull/VmgExitLibNull.inf | 28 - .../Library/VmgExitLibNull/VmgExitLibNull.uni | 15 - UefiCpuPkg/UefiCpuPkg.dec | 4 +- UefiCpuPkg/UefiCpuPkg.dsc | 4 +- UefiPayloadPkg/UefiPayloadPkg.dsc | 2 +- 62 files changed, 4164 insertions(+), 4170 deletions(-) create mode 100644 OvmfPkg/Library/CcExitLib/CcExitLib.c create mode 100644 OvmfPkg/Library/CcExitLib/CcExitLib.inf create mode 100644 OvmfPkg/Library/CcExitLib/CcExitTd.h create mode 100644 OvmfPkg/Library/CcExitLib/CcExitVcHandler.c create mode 100644 OvmfPkg/Library/CcExitLib/CcExitVcHandler.h create mode 100644 OvmfPkg/Library/CcExitLib/CcExitVeHandler.c create mode 100644 OvmfPkg/Library/CcExitLib/PeiDxeCcExitVcHandler.c create mode 100644 OvmfPkg/Library/CcExitLib/SecCcExitLib.inf create mode 100644 OvmfPkg/Library/CcExitLib/SecCcExitVcHandler.c create mode 100644 OvmfPkg/Library/CcExitLib/X64/TdVmcallCpuid.nasm delete mode 100644 OvmfPkg/Library/VmgExitLib/PeiDxeVmgExitVcHandler.c delete mode 100644 OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf delete mode 100644 OvmfPkg/Library/VmgExitLib/SecVmgExitVcHandler.c delete mode 100644 OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h delete mode 100644 OvmfPkg/Library/VmgExitLib/VmTdExitVeHandler.c delete mode 100644 OvmfPkg/Library/VmgExitLib/VmgExitLib.c delete mode 100644 OvmfPkg/Library/VmgExitLib/VmgExitLib.inf delete mode 100644 OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c delete mode 100644 OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.h delete mode 100644 OvmfPkg/Library/VmgExitLib/X64/TdVmcallCpuid.nasm create mode 100644 UefiCpuPkg/Include/Library/CcExitLib.h delete mode 100644 UefiCpuPkg/Include/Library/VmgExitLib.h create mode 100644 UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.c create mode 100644 UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf create mode 100644 UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.uni delete mode 100644 UefiCpuPkg/Library/VmgExitLibNull/VmTdExitNull.c delete mode 100644 UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.c delete mode 100644 UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf delete mode 100644 UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.uni diff --git a/OvmfPkg/AmdSev/AmdSevX64.dsc b/OvmfPkg/AmdSev/AmdSevX64.dsc index 90e8a213ef..8f7cae787e 100644 --- a/OvmfPkg/AmdSev/AmdSevX64.dsc +++ b/OvmfPkg/AmdSev/AmdSevX64.dsc @@ -204,7 +204,7 @@ [LibraryClasses.common] BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf - VmgExitLib|OvmfPkg/Library/VmgExitLib/VmgExitLib.inf + CcExitLib|OvmfPkg/Library/CcExitLib/CcExitLib.inf TdxLib|MdePkg/Library/TdxLib/TdxLib.inf [LibraryClasses.common.SEC] @@ -229,7 +229,7 @@ !else CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf !endif - VmgExitLib|OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf + CcExitLib|OvmfPkg/Library/CcExitLib/SecCcExitLib.inf MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf [LibraryClasses.common.PEI_CORE] diff --git a/OvmfPkg/Bhyve/BhyveX64.dsc b/OvmfPkg/Bhyve/BhyveX64.dsc index 475b88b21a..e3bb367b6b 100644 --- a/OvmfPkg/Bhyve/BhyveX64.dsc +++ b/OvmfPkg/Bhyve/BhyveX64.dsc @@ -232,7 +232,7 @@ [LibraryClasses.common] BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf - VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf + CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf TdxLib|MdePkg/Library/TdxLib/TdxLib.inf [LibraryClasses.common.SEC] diff --git a/OvmfPkg/CloudHv/CloudHvX64.dsc b/OvmfPkg/CloudHv/CloudHvX64.dsc index 10b16104ac..ce277cb239 100644 --- a/OvmfPkg/CloudHv/CloudHvX64.dsc +++ b/OvmfPkg/CloudHv/CloudHvX64.dsc @@ -251,7 +251,7 @@ [LibraryClasses.common] BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf - VmgExitLib|OvmfPkg/Library/VmgExitLib/VmgExitLib.inf + CcExitLib|OvmfPkg/Library/CcExitLib/CcExitLib.inf TdxLib|MdePkg/Library/TdxLib/TdxLib.inf [LibraryClasses.common.SEC] @@ -275,7 +275,7 @@ !else CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf !endif - VmgExitLib|OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf + CcExitLib|OvmfPkg/Library/CcExitLib/SecCcExitLib.inf MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf [LibraryClasses.common.PEI_CORE] @@ -915,7 +915,7 @@ # OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf { - VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf + CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf } MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf { diff --git a/OvmfPkg/IntelTdx/IntelTdxX64.dsc b/OvmfPkg/IntelTdx/IntelTdxX64.dsc index c0c1a15b09..3458926515 100644 --- a/OvmfPkg/IntelTdx/IntelTdxX64.dsc +++ b/OvmfPkg/IntelTdx/IntelTdxX64.dsc @@ -215,7 +215,7 @@ [LibraryClasses.common] BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf - VmgExitLib|OvmfPkg/Library/VmgExitLib/VmgExitLib.inf + CcExitLib|OvmfPkg/Library/CcExitLib/CcExitLib.inf TdxLib|MdePkg/Library/TdxLib/TdxLib.inf TdxMailboxLib|OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf PlatformInitLib|OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf @@ -237,7 +237,7 @@ !else CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf !endif - VmgExitLib|OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf + CcExitLib|OvmfPkg/Library/CcExitLib/SecCcExitLib.inf MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf PrePiHobListPointerLib|OvmfPkg/IntelTdx/PrePiHobListPointerLibTdx/PrePiHobListPointerLibTdx.inf HobLib|EmbeddedPkg/Library/PrePiHobLib/PrePiHobLib.inf diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf b/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf index 35b7d519d9..cc24961c92 100644 --- a/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf @@ -51,7 +51,7 @@ DebugLib MemoryAllocationLib PcdLib - VmgExitLib + CcExitLib [FeaturePcd] gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf index 714da33237..8f56783da5 100644 --- a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf @@ -51,7 +51,7 @@ DebugLib MemoryAllocationLib PcdLib - VmgExitLib + CcExitLib [FeaturePcd] gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf b/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf index 284e5acc11..b6d76e7e63 100644 --- a/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf @@ -48,7 +48,7 @@ CpuLib DebugLib PcdLib - VmgExitLib + CcExitLib [FixedPcd] gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeInternal.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeInternal.c index d11aafae84..73698a7b9d 100644 --- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeInternal.c +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeInternal.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include diff --git a/OvmfPkg/Library/CcExitLib/CcExitLib.c b/OvmfPkg/Library/CcExitLib/CcExitLib.c new file mode 100644 index 0000000000..477064cde2 --- /dev/null +++ b/OvmfPkg/Library/CcExitLib/CcExitLib.c @@ -0,0 +1,239 @@ +/** @file + CcExitLib Support Library. + + Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.
+ Copyright (C) 2020 - 2022, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include + +/** + Check for VMGEXIT error + + Check if the hypervisor has returned an error after completion of the VMGEXIT + by examining the SwExitInfo1 field of the GHCB. + + @param[in] Ghcb A pointer to the GHCB + + @retval 0 VMGEXIT succeeded. + @return Exception number to be propagated, VMGEXIT processing + did not succeed. + +**/ +STATIC +UINT64 +VmgExitErrorCheck ( + IN GHCB *Ghcb + ) +{ + GHCB_EVENT_INJECTION Event; + GHCB_EXIT_INFO ExitInfo; + UINT64 Status; + + ExitInfo.Uint64 = Ghcb->SaveArea.SwExitInfo1; + ASSERT ( + (ExitInfo.Elements.Lower32Bits == 0) || + (ExitInfo.Elements.Lower32Bits == 1) + ); + + Status = 0; + if (ExitInfo.Elements.Lower32Bits == 0) { + return Status; + } + + if (ExitInfo.Elements.Lower32Bits == 1) { + ASSERT (Ghcb->SaveArea.SwExitInfo2 != 0); + + // + // Check that the return event is valid + // + Event.Uint64 = Ghcb->SaveArea.SwExitInfo2; + if (Event.Elements.Valid && + (Event.Elements.Type == GHCB_EVENT_INJECTION_TYPE_EXCEPTION)) + { + switch (Event.Elements.Vector) { + case GP_EXCEPTION: + case UD_EXCEPTION: + // + // Use returned event as return code + // + Status = Event.Uint64; + } + } + } + + if (Status == 0) { + GHCB_EVENT_INJECTION GpEvent; + + GpEvent.Uint64 = 0; + GpEvent.Elements.Vector = GP_EXCEPTION; + GpEvent.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION; + GpEvent.Elements.Valid = 1; + + Status = GpEvent.Uint64; + } + + return Status; +} + +/** + Perform VMGEXIT. + + Sets the necessary fields of the GHCB, invokes the VMGEXIT instruction and + then handles the return actions. + + @param[in, out] Ghcb A pointer to the GHCB + @param[in] ExitCode VMGEXIT code to be assigned to the SwExitCode + field of the GHCB. + @param[in] ExitInfo1 VMGEXIT information to be assigned to the + SwExitInfo1 field of the GHCB. + @param[in] ExitInfo2 VMGEXIT information to be assigned to the + SwExitInfo2 field of the GHCB. + + @retval 0 VMGEXIT succeeded. + @return Exception number to be propagated, VMGEXIT + processing did not succeed. + +**/ +UINT64 +EFIAPI +VmgExit ( + IN OUT GHCB *Ghcb, + IN UINT64 ExitCode, + IN UINT64 ExitInfo1, + IN UINT64 ExitInfo2 + ) +{ + Ghcb->SaveArea.SwExitCode = ExitCode; + Ghcb->SaveArea.SwExitInfo1 = ExitInfo1; + Ghcb->SaveArea.SwExitInfo2 = ExitInfo2; + + VmgSetOffsetValid (Ghcb, GhcbSwExitCode); + VmgSetOffsetValid (Ghcb, GhcbSwExitInfo1); + VmgSetOffsetValid (Ghcb, GhcbSwExitInfo2); + + // + // Guest memory is used for the guest-hypervisor communication, so fence + // the invocation of the VMGEXIT instruction to ensure GHCB accesses are + // synchronized properly. + // + MemoryFence (); + AsmVmgExit (); + MemoryFence (); + + return VmgExitErrorCheck (Ghcb); +} + +/** + Perform pre-VMGEXIT initialization/preparation. + + Performs the necessary steps in preparation for invoking VMGEXIT. Must be + called before setting any fields within the GHCB. + + @param[in, out] Ghcb A pointer to the GHCB + @param[in, out] InterruptState A pointer to hold the current interrupt + state, used for restoring in VmgDone () + +**/ +VOID +EFIAPI +VmgInit ( + IN OUT GHCB *Ghcb, + IN OUT BOOLEAN *InterruptState + ) +{ + // + // Be sure that an interrupt can't cause a #VC while the GHCB is + // being used. + // + *InterruptState = GetInterruptState (); + if (*InterruptState) { + DisableInterrupts (); + } + + SetMem (&Ghcb->SaveArea, sizeof (Ghcb->SaveArea), 0); +} + +/** + Perform post-VMGEXIT cleanup. + + Performs the necessary steps to cleanup after invoking VMGEXIT. Must be + called after obtaining needed fields within the GHCB. + + @param[in, out] Ghcb A pointer to the GHCB + @param[in] InterruptState An indicator to conditionally (re)enable + interrupts + +**/ +VOID +EFIAPI +VmgDone ( + IN OUT GHCB *Ghcb, + IN BOOLEAN InterruptState + ) +{ + if (InterruptState) { + EnableInterrupts (); + } +} + +/** + Marks a field at the specified offset as valid in the GHCB. + + The ValidBitmap area represents the areas of the GHCB that have been marked + valid. Set the bit in ValidBitmap for the input offset. + + @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication Block + @param[in] Offset Qword offset in the GHCB to mark valid + +**/ +VOID +EFIAPI +VmgSetOffsetValid ( + IN OUT GHCB *Ghcb, + IN GHCB_REGISTER Offset + ) +{ + UINT32 OffsetIndex; + UINT32 OffsetBit; + + OffsetIndex = Offset / 8; + OffsetBit = Offset % 8; + + Ghcb->SaveArea.ValidBitmap[OffsetIndex] |= (1 << OffsetBit); +} + +/** + Checks if a specified offset is valid in the GHCB. + + The ValidBitmap area represents the areas of the GHCB that have been marked + valid. Return whether the bit in the ValidBitmap is set for the input offset. + + @param[in] Ghcb A pointer to the GHCB + @param[in] Offset Qword offset in the GHCB to mark valid + + @retval TRUE Offset is marked valid in the GHCB + @retval FALSE Offset is not marked valid in the GHCB + +**/ +BOOLEAN +EFIAPI +VmgIsOffsetValid ( + IN GHCB *Ghcb, + IN GHCB_REGISTER Offset + ) +{ + UINT32 OffsetIndex; + UINT32 OffsetBit; + + OffsetIndex = Offset / 8; + OffsetBit = Offset % 8; + + return ((Ghcb->SaveArea.ValidBitmap[OffsetIndex] & (1 << OffsetBit)) != 0); +} diff --git a/OvmfPkg/Library/CcExitLib/CcExitLib.inf b/OvmfPkg/Library/CcExitLib/CcExitLib.inf new file mode 100644 index 0000000000..131fa62675 --- /dev/null +++ b/OvmfPkg/Library/CcExitLib/CcExitLib.inf @@ -0,0 +1,46 @@ +## @file +# CcExitLib Library. +# +# Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.
+# Copyright (C) 2020 - 2022, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = CcExitLib + FILE_GUID = 0e923c25-13cd-430b-8714-ffe85652a97b + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = CcExitLib|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. +# +# VALID_ARCHITECTURES = X64 +# + +[Sources.common] + CcExitLib.c + CcExitVcHandler.c + CcExitVcHandler.h + PeiDxeCcExitVcHandler.c + CcExitVeHandler.c + X64/TdVmcallCpuid.nasm + +[Packages] + MdePkg/MdePkg.dec + OvmfPkg/OvmfPkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + LocalApicLib + MemEncryptSevLib + +[Pcd] + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidSize diff --git a/OvmfPkg/Library/CcExitLib/CcExitTd.h b/OvmfPkg/Library/CcExitLib/CcExitTd.h new file mode 100644 index 0000000000..013a55e207 --- /dev/null +++ b/OvmfPkg/Library/CcExitLib/CcExitTd.h @@ -0,0 +1,32 @@ +/** @file + + Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef CC_EXIT_TD_H_ +#define CC_EXIT_TD_H_ + +#include +#include + +/** + This function enable the TD guest to request the VMM to emulate CPUID + operation, especially for non-architectural, CPUID leaves. + + @param[in] Eax Main leaf of the CPUID + @param[in] Ecx Sub-leaf of the CPUID + @param[out] Results Returned result of CPUID operation + + @return EFI_SUCCESS +**/ +EFI_STATUS +EFIAPI +TdVmCallCpuid ( + IN UINT64 Eax, + IN UINT64 Ecx, + OUT VOID *Results + ); + +#endif diff --git a/OvmfPkg/Library/CcExitLib/CcExitVcHandler.c b/OvmfPkg/Library/CcExitLib/CcExitVcHandler.c new file mode 100644 index 0000000000..ad2a922c9f --- /dev/null +++ b/OvmfPkg/Library/CcExitLib/CcExitVcHandler.c @@ -0,0 +1,2355 @@ +/** @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 +#include +#include + +#include "CcExitVcHandler.h" + +// +// Instruction execution mode definition +// +typedef enum { + LongMode64Bit = 0, + LongModeCompat32Bit, + LongModeCompat16Bit, +} SEV_ES_INSTRUCTION_MODE; + +// +// Instruction size definition (for operand and address) +// +typedef enum { + Size8Bits = 0, + Size16Bits, + Size32Bits, + Size64Bits, +} SEV_ES_INSTRUCTION_SIZE; + +// +// Intruction segment definition +// +typedef enum { + SegmentEs = 0, + SegmentCs, + SegmentSs, + SegmentDs, + SegmentFs, + SegmentGs, +} SEV_ES_INSTRUCTION_SEGMENT; + +// +// Instruction rep function definition +// +typedef enum { + RepNone = 0, + RepZ, + RepNZ, +} SEV_ES_INSTRUCTION_REP; + +typedef struct { + UINT8 Rm; + UINT8 Reg; + UINT8 Mod; +} SEV_ES_INSTRUCTION_MODRM_EXT; + +typedef struct { + UINT8 Base; + UINT8 Index; + UINT8 Scale; +} SEV_ES_INSTRUCTION_SIB_EXT; + +// +// Instruction opcode definition +// +typedef struct { + SEV_ES_INSTRUCTION_MODRM_EXT ModRm; + + SEV_ES_INSTRUCTION_SIB_EXT Sib; + + UINTN RegData; + UINTN RmData; +} SEV_ES_INSTRUCTION_OPCODE_EXT; + +// +// Instruction parsing context definition +// +typedef struct { + GHCB *Ghcb; + + SEV_ES_INSTRUCTION_MODE Mode; + SEV_ES_INSTRUCTION_SIZE DataSize; + SEV_ES_INSTRUCTION_SIZE AddrSize; + BOOLEAN SegmentSpecified; + SEV_ES_INSTRUCTION_SEGMENT Segment; + SEV_ES_INSTRUCTION_REP RepMode; + + UINT8 *Begin; + UINT8 *End; + + UINT8 *Prefixes; + UINT8 *OpCodes; + UINT8 *Displacement; + UINT8 *Immediate; + + INSTRUCTION_REX_PREFIX RexPrefix; + + BOOLEAN ModRmPresent; + INSTRUCTION_MODRM ModRm; + + BOOLEAN SibPresent; + INSTRUCTION_SIB Sib; + + UINTN PrefixSize; + UINTN OpCodeSize; + UINTN DisplacementSize; + UINTN ImmediateSize; + + SEV_ES_INSTRUCTION_OPCODE_EXT Ext; +} SEV_ES_INSTRUCTION_DATA; + +// +// Non-automatic Exit function prototype +// +typedef +UINT64 +(*NAE_EXIT) ( + GHCB *Ghcb, + EFI_SYSTEM_CONTEXT_X64 *Regs, + SEV_ES_INSTRUCTION_DATA *InstructionData + ); + +// +// SEV-SNP Cpuid table entry/function +// +typedef PACKED struct { + UINT32 EaxIn; + UINT32 EcxIn; + UINT64 Unused; + UINT64 Unused2; + UINT32 Eax; + UINT32 Ebx; + UINT32 Ecx; + UINT32 Edx; + UINT64 Reserved; +} SEV_SNP_CPUID_FUNCTION; + +// +// SEV-SNP Cpuid page format +// +typedef PACKED struct { + UINT32 Count; + UINT32 Reserved1; + UINT64 Reserved2; + SEV_SNP_CPUID_FUNCTION function[0]; +} SEV_SNP_CPUID_INFO; + +/** + Return a pointer to the contents of the specified register. + + Based upon the input register, return a pointer to the registers contents + in the x86 processor context. + + @param[in] Regs x64 processor context + @param[in] Register Register to obtain pointer for + + @return Pointer to the contents of the requested register + +**/ +STATIC +UINT64 * +GetRegisterPointer ( + IN EFI_SYSTEM_CONTEXT_X64 *Regs, + IN UINT8 Register + ) +{ + UINT64 *Reg; + + switch (Register) { + case 0: + Reg = &Regs->Rax; + break; + case 1: + Reg = &Regs->Rcx; + break; + case 2: + Reg = &Regs->Rdx; + break; + case 3: + Reg = &Regs->Rbx; + break; + case 4: + Reg = &Regs->Rsp; + break; + case 5: + Reg = &Regs->Rbp; + break; + case 6: + Reg = &Regs->Rsi; + break; + case 7: + Reg = &Regs->Rdi; + break; + case 8: + Reg = &Regs->R8; + break; + case 9: + Reg = &Regs->R9; + break; + case 10: + Reg = &Regs->R10; + break; + case 11: + Reg = &Regs->R11; + break; + case 12: + Reg = &Regs->R12; + break; + case 13: + Reg = &Regs->R13; + break; + case 14: + Reg = &Regs->R14; + break; + case 15: + Reg = &Regs->R15; + break; + default: + Reg = NULL; + } + + ASSERT (Reg != NULL); + + return Reg; +} + +/** + Update the instruction parsing context for displacement bytes. + + @param[in, out] InstructionData Instruction parsing context + @param[in] Size The instruction displacement size + +**/ +STATIC +VOID +UpdateForDisplacement ( + IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData, + IN UINTN Size + ) +{ + InstructionData->DisplacementSize = Size; + InstructionData->Immediate += Size; + InstructionData->End += Size; +} + +/** + Determine if an instruction address if RIP relative. + + Examine the instruction parsing context to determine if the address offset + is relative to the instruction pointer. + + @param[in] InstructionData Instruction parsing context + + @retval TRUE Instruction addressing is RIP relative + @retval FALSE Instruction addressing is not RIP relative + +**/ +STATIC +BOOLEAN +IsRipRelative ( + IN SEV_ES_INSTRUCTION_DATA *InstructionData + ) +{ + SEV_ES_INSTRUCTION_OPCODE_EXT *Ext; + + Ext = &InstructionData->Ext; + + return ((InstructionData->Mode == LongMode64Bit) && + (Ext->ModRm.Mod == 0) && + (Ext->ModRm.Rm == 5) && + (InstructionData->SibPresent == FALSE)); +} + +/** + Return the effective address of a memory operand. + + Examine the instruction parsing context to obtain the effective memory + address of a memory operand. + + @param[in] Regs x64 processor context + @param[in] InstructionData Instruction parsing context + + @return The memory operand effective address + +**/ +STATIC +UINT64 +GetEffectiveMemoryAddress ( + IN EFI_SYSTEM_CONTEXT_X64 *Regs, + IN SEV_ES_INSTRUCTION_DATA *InstructionData + ) +{ + SEV_ES_INSTRUCTION_OPCODE_EXT *Ext; + UINT64 EffectiveAddress; + + Ext = &InstructionData->Ext; + EffectiveAddress = 0; + + if (IsRipRelative (InstructionData)) { + // + // RIP-relative displacement is a 32-bit signed value + // + INT32 RipRelative; + + RipRelative = *(INT32 *)InstructionData->Displacement; + + UpdateForDisplacement (InstructionData, 4); + + // + // Negative displacement is handled by standard UINT64 wrap-around. + // + return Regs->Rip + (UINT64)RipRelative; + } + + switch (Ext->ModRm.Mod) { + case 1: + UpdateForDisplacement (InstructionData, 1); + EffectiveAddress += (UINT64)(*(INT8 *)(InstructionData->Displacement)); + break; + case 2: + switch (InstructionData->AddrSize) { + case Size16Bits: + UpdateForDisplacement (InstructionData, 2); + EffectiveAddress += (UINT64)(*(INT16 *)(InstructionData->Displacement)); + break; + default: + UpdateForDisplacement (InstructionData, 4); + EffectiveAddress += (UINT64)(*(INT32 *)(InstructionData->Displacement)); + break; + } + + break; + } + + if (InstructionData->SibPresent) { + INT64 Displacement; + + if (Ext->Sib.Index != 4) { + CopyMem ( + &Displacement, + GetRegisterPointer (Regs, Ext->Sib.Index), + sizeof (Displacement) + ); + Displacement *= (INT64)(1 << Ext->Sib.Scale); + + // + // Negative displacement is handled by standard UINT64 wrap-around. + // + EffectiveAddress += (UINT64)Displacement; + } + + if ((Ext->Sib.Base != 5) || Ext->ModRm.Mod) { + EffectiveAddress += *GetRegisterPointer (Regs, Ext->Sib.Base); + } else { + UpdateForDisplacement (InstructionData, 4); + EffectiveAddress += (UINT64)(*(INT32 *)(InstructionData->Displacement)); + } + } else { + EffectiveAddress += *GetRegisterPointer (Regs, Ext->ModRm.Rm); + } + + return EffectiveAddress; +} + +/** + Decode a ModRM byte. + + Examine the instruction parsing context to decode a ModRM byte and the SIB + byte, if present. + + @param[in] Regs x64 processor context + @param[in, out] InstructionData Instruction parsing context + +**/ +STATIC +VOID +DecodeModRm ( + IN EFI_SYSTEM_CONTEXT_X64 *Regs, + IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData + ) +{ + SEV_ES_INSTRUCTION_OPCODE_EXT *Ext; + INSTRUCTION_REX_PREFIX *RexPrefix; + INSTRUCTION_MODRM *ModRm; + INSTRUCTION_SIB *Sib; + + RexPrefix = &InstructionData->RexPrefix; + Ext = &InstructionData->Ext; + ModRm = &InstructionData->ModRm; + Sib = &InstructionData->Sib; + + InstructionData->ModRmPresent = TRUE; + ModRm->Uint8 = *(InstructionData->End); + + InstructionData->Displacement++; + InstructionData->Immediate++; + InstructionData->End++; + + Ext->ModRm.Mod = ModRm->Bits.Mod; + Ext->ModRm.Reg = (RexPrefix->Bits.BitR << 3) | ModRm->Bits.Reg; + Ext->ModRm.Rm = (RexPrefix->Bits.BitB << 3) | ModRm->Bits.Rm; + + Ext->RegData = *GetRegisterPointer (Regs, Ext->ModRm.Reg); + + if (Ext->ModRm.Mod == 3) { + Ext->RmData = *GetRegisterPointer (Regs, Ext->ModRm.Rm); + } else { + if (ModRm->Bits.Rm == 4) { + InstructionData->SibPresent = TRUE; + Sib->Uint8 = *(InstructionData->End); + + InstructionData->Displacement++; + InstructionData->Immediate++; + InstructionData->End++; + + Ext->Sib.Scale = Sib->Bits.Scale; + Ext->Sib.Index = (RexPrefix->Bits.BitX << 3) | Sib->Bits.Index; + Ext->Sib.Base = (RexPrefix->Bits.BitB << 3) | Sib->Bits.Base; + } + + Ext->RmData = GetEffectiveMemoryAddress (Regs, InstructionData); + } +} + +/** + Decode instruction prefixes. + + Parse the instruction data to track the instruction prefixes that have + been used. + + @param[in] Regs x64 processor context + @param[in, out] InstructionData Instruction parsing context + +**/ +STATIC +VOID +DecodePrefixes ( + IN EFI_SYSTEM_CONTEXT_X64 *Regs, + IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData + ) +{ + SEV_ES_INSTRUCTION_MODE Mode; + SEV_ES_INSTRUCTION_SIZE ModeDataSize; + SEV_ES_INSTRUCTION_SIZE ModeAddrSize; + UINT8 *Byte; + + // + // Always in 64-bit mode + // + Mode = LongMode64Bit; + ModeDataSize = Size32Bits; + ModeAddrSize = Size64Bits; + + InstructionData->Mode = Mode; + InstructionData->DataSize = ModeDataSize; + InstructionData->AddrSize = ModeAddrSize; + + InstructionData->Prefixes = InstructionData->Begin; + + Byte = InstructionData->Prefixes; + for ( ; ; Byte++, InstructionData->PrefixSize++) { + // + // Check the 0x40 to 0x4F range using an if statement here since some + // compilers don't like the "case 0x40 ... 0x4F:" syntax. This avoids + // 16 case statements below. + // + if ((*Byte >= REX_PREFIX_START) && (*Byte <= REX_PREFIX_STOP)) { + InstructionData->RexPrefix.Uint8 = *Byte; + if ((*Byte & REX_64BIT_OPERAND_SIZE_MASK) != 0) { + InstructionData->DataSize = Size64Bits; + } + + continue; + } + + switch (*Byte) { + case OVERRIDE_SEGMENT_CS: + case OVERRIDE_SEGMENT_DS: + case OVERRIDE_SEGMENT_ES: + case OVERRIDE_SEGMENT_SS: + if (Mode != LongMode64Bit) { + InstructionData->SegmentSpecified = TRUE; + InstructionData->Segment = (*Byte >> 3) & 3; + } + + break; + + case OVERRIDE_SEGMENT_FS: + case OVERRIDE_SEGMENT_GS: + InstructionData->SegmentSpecified = TRUE; + InstructionData->Segment = *Byte & 7; + break; + + case OVERRIDE_OPERAND_SIZE: + if (InstructionData->RexPrefix.Uint8 == 0) { + InstructionData->DataSize = + (Mode == LongMode64Bit) ? Size16Bits : + (Mode == LongModeCompat32Bit) ? Size16Bits : + (Mode == LongModeCompat16Bit) ? Size32Bits : 0; + } + + break; + + case OVERRIDE_ADDRESS_SIZE: + InstructionData->AddrSize = + (Mode == LongMode64Bit) ? Size32Bits : + (Mode == LongModeCompat32Bit) ? Size16Bits : + (Mode == LongModeCompat16Bit) ? Size32Bits : 0; + break; + + case LOCK_PREFIX: + break; + + case REPZ_PREFIX: + InstructionData->RepMode = RepZ; + break; + + case REPNZ_PREFIX: + InstructionData->RepMode = RepNZ; + break; + + default: + InstructionData->OpCodes = Byte; + InstructionData->OpCodeSize = (*Byte == TWO_BYTE_OPCODE_ESCAPE) ? 2 : 1; + + InstructionData->End = Byte + InstructionData->OpCodeSize; + InstructionData->Displacement = InstructionData->End; + InstructionData->Immediate = InstructionData->End; + return; + } + } +} + +/** + Determine instruction length + + Return the total length of the parsed instruction. + + @param[in] InstructionData Instruction parsing context + + @return Length of parsed instruction + +**/ +STATIC +UINT64 +InstructionLength ( + IN SEV_ES_INSTRUCTION_DATA *InstructionData + ) +{ + return (UINT64)(InstructionData->End - InstructionData->Begin); +} + +/** + Initialize the instruction parsing context. + + Initialize the instruction parsing context, which includes decoding the + instruction prefixes. + + @param[in, out] InstructionData Instruction parsing context + @param[in] Ghcb Pointer to the Guest-Hypervisor Communication + Block + @param[in] Regs x64 processor context + +**/ +STATIC +VOID +InitInstructionData ( + IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData, + IN GHCB *Ghcb, + IN EFI_SYSTEM_CONTEXT_X64 *Regs + ) +{ + SetMem (InstructionData, sizeof (*InstructionData), 0); + InstructionData->Ghcb = Ghcb; + InstructionData->Begin = (UINT8 *)Regs->Rip; + InstructionData->End = (UINT8 *)Regs->Rip; + + DecodePrefixes (Regs, InstructionData); +} + +/** + Report an unsupported event to the hypervisor + + Use the VMGEXIT support to report an unsupported event to the hypervisor. + + @param[in] Ghcb Pointer to the Guest-Hypervisor Communication + Block + @param[in] Regs x64 processor context + @param[in] InstructionData Instruction parsing context + + @return New exception value to propagate + +**/ +STATIC +UINT64 +UnsupportedExit ( + IN GHCB *Ghcb, + IN EFI_SYSTEM_CONTEXT_X64 *Regs, + IN SEV_ES_INSTRUCTION_DATA *InstructionData + ) +{ + UINT64 Status; + + Status = VmgExit (Ghcb, SVM_EXIT_UNSUPPORTED, Regs->ExceptionData, 0); + if (Status == 0) { + GHCB_EVENT_INJECTION Event; + + Event.Uint64 = 0; + Event.Elements.Vector = GP_EXCEPTION; + Event.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION; + Event.Elements.Valid = 1; + + Status = Event.Uint64; + } + + return Status; +} + +/** + Validate that the MMIO memory access is not to encrypted memory. + + Examine the pagetable entry for the memory specified. MMIO should not be + performed against encrypted memory. MMIO to the APIC page is always allowed. + + @param[in] Ghcb Pointer to the Guest-Hypervisor Communication Block + @param[in] MemoryAddress Memory address to validate + @param[in] MemoryLength Memory length to validate + + @retval 0 Memory is not encrypted + @return New exception value to propogate + +**/ +STATIC +UINT64 +ValidateMmioMemory ( + IN GHCB *Ghcb, + IN UINTN MemoryAddress, + IN UINTN MemoryLength + ) +{ + MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE State; + GHCB_EVENT_INJECTION GpEvent; + UINTN Address; + + // + // Allow APIC accesses (which will have the encryption bit set during + // SEC and PEI phases). + // + Address = MemoryAddress & ~(SIZE_4KB - 1); + if (Address == GetLocalApicBaseAddress ()) { + return 0; + } + + State = MemEncryptSevGetAddressRangeState ( + 0, + MemoryAddress, + MemoryLength + ); + if (State == MemEncryptSevAddressRangeUnencrypted) { + return 0; + } + + // + // Any state other than unencrypted is an error, issue a #GP. + // + DEBUG (( + DEBUG_ERROR, + "MMIO using encrypted memory: %lx\n", + (UINT64)MemoryAddress + )); + GpEvent.Uint64 = 0; + GpEvent.Elements.Vector = GP_EXCEPTION; + GpEvent.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION; + GpEvent.Elements.Valid = 1; + + return GpEvent.Uint64; +} + +/** + Handle an MMIO event. + + Use the VMGEXIT instruction to handle either an MMIO read or an MMIO write. + + @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication + Block + @param[in, out] Regs x64 processor context + @param[in, out] InstructionData Instruction parsing context + + @retval 0 Event handled successfully + @return New exception value to propagate + +**/ +STATIC +UINT64 +MmioExit ( + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData + ) +{ + UINT64 ExitInfo1, ExitInfo2, Status; + UINTN Bytes; + UINT64 *Register; + UINT8 OpCode, SignByte; + UINTN Address; + + Bytes = 0; + + OpCode = *(InstructionData->OpCodes); + if (OpCode == TWO_BYTE_OPCODE_ESCAPE) { + OpCode = *(InstructionData->OpCodes + 1); + } + + switch (OpCode) { + // + // MMIO write (MOV reg/memX, regX) + // + case 0x88: + Bytes = 1; + // + // fall through + // + case 0x89: + DecodeModRm (Regs, InstructionData); + Bytes = ((Bytes != 0) ? Bytes : + (InstructionData->DataSize == Size16Bits) ? 2 : + (InstructionData->DataSize == Size32Bits) ? 4 : + (InstructionData->DataSize == Size64Bits) ? 8 : + 0); + + if (InstructionData->Ext.ModRm.Mod == 3) { + // + // NPF on two register operands??? + // + return UnsupportedExit (Ghcb, Regs, InstructionData); + } + + Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes); + if (Status != 0) { + return Status; + } + + ExitInfo1 = InstructionData->Ext.RmData; + ExitInfo2 = Bytes; + CopyMem (Ghcb->SharedBuffer, &InstructionData->Ext.RegData, Bytes); + + Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer; + VmgSetOffsetValid (Ghcb, GhcbSwScratch); + Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2); + if (Status != 0) { + return Status; + } + + break; + + // + // MMIO write (MOV moffsetX, aX) + // + case 0xA2: + Bytes = 1; + // + // fall through + // + case 0xA3: + Bytes = ((Bytes != 0) ? Bytes : + (InstructionData->DataSize == Size16Bits) ? 2 : + (InstructionData->DataSize == Size32Bits) ? 4 : + (InstructionData->DataSize == Size64Bits) ? 8 : + 0); + + InstructionData->ImmediateSize = (UINTN)(1 << InstructionData->AddrSize); + InstructionData->End += InstructionData->ImmediateSize; + + // + // This code is X64 only, so a possible 8-byte copy to a UINTN is ok. + // Use a STATIC_ASSERT to be certain the code is being built as X64. + // + STATIC_ASSERT ( + sizeof (UINTN) == sizeof (UINT64), + "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64" + ); + + Address = 0; + CopyMem ( + &Address, + InstructionData->Immediate, + InstructionData->ImmediateSize + ); + + Status = ValidateMmioMemory (Ghcb, Address, Bytes); + if (Status != 0) { + return Status; + } + + ExitInfo1 = Address; + ExitInfo2 = Bytes; + CopyMem (Ghcb->SharedBuffer, &Regs->Rax, Bytes); + + Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer; + VmgSetOffsetValid (Ghcb, GhcbSwScratch); + Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2); + if (Status != 0) { + return Status; + } + + break; + + // + // MMIO write (MOV reg/memX, immX) + // + case 0xC6: + Bytes = 1; + // + // fall through + // + case 0xC7: + DecodeModRm (Regs, InstructionData); + Bytes = ((Bytes != 0) ? Bytes : + (InstructionData->DataSize == Size16Bits) ? 2 : + (InstructionData->DataSize == Size32Bits) ? 4 : + 0); + + InstructionData->ImmediateSize = Bytes; + InstructionData->End += Bytes; + + Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes); + if (Status != 0) { + return Status; + } + + ExitInfo1 = InstructionData->Ext.RmData; + ExitInfo2 = Bytes; + CopyMem (Ghcb->SharedBuffer, InstructionData->Immediate, Bytes); + + Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer; + VmgSetOffsetValid (Ghcb, GhcbSwScratch); + Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2); + if (Status != 0) { + return Status; + } + + break; + + // + // MMIO read (MOV regX, reg/memX) + // + case 0x8A: + Bytes = 1; + // + // fall through + // + case 0x8B: + DecodeModRm (Regs, InstructionData); + Bytes = ((Bytes != 0) ? Bytes : + (InstructionData->DataSize == Size16Bits) ? 2 : + (InstructionData->DataSize == Size32Bits) ? 4 : + (InstructionData->DataSize == Size64Bits) ? 8 : + 0); + if (InstructionData->Ext.ModRm.Mod == 3) { + // + // NPF on two register operands??? + // + return UnsupportedExit (Ghcb, Regs, InstructionData); + } + + Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes); + if (Status != 0) { + return Status; + } + + ExitInfo1 = InstructionData->Ext.RmData; + ExitInfo2 = Bytes; + + Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer; + VmgSetOffsetValid (Ghcb, GhcbSwScratch); + Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2); + if (Status != 0) { + return Status; + } + + Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg); + if (Bytes == 4) { + // + // Zero-extend for 32-bit operation + // + *Register = 0; + } + + CopyMem (Register, Ghcb->SharedBuffer, Bytes); + break; + + // + // MMIO read (MOV aX, moffsetX) + // + case 0xA0: + Bytes = 1; + // + // fall through + // + case 0xA1: + Bytes = ((Bytes != 0) ? Bytes : + (InstructionData->DataSize == Size16Bits) ? 2 : + (InstructionData->DataSize == Size32Bits) ? 4 : + (InstructionData->DataSize == Size64Bits) ? 8 : + 0); + + InstructionData->ImmediateSize = (UINTN)(1 << InstructionData->AddrSize); + InstructionData->End += InstructionData->ImmediateSize; + + // + // This code is X64 only, so a possible 8-byte copy to a UINTN is ok. + // Use a STATIC_ASSERT to be certain the code is being built as X64. + // + STATIC_ASSERT ( + sizeof (UINTN) == sizeof (UINT64), + "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64" + ); + + Address = 0; + CopyMem ( + &Address, + InstructionData->Immediate, + InstructionData->ImmediateSize + ); + + Status = ValidateMmioMemory (Ghcb, Address, Bytes); + if (Status != 0) { + return Status; + } + + ExitInfo1 = Address; + ExitInfo2 = Bytes; + + Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer; + VmgSetOffsetValid (Ghcb, GhcbSwScratch); + Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2); + if (Status != 0) { + return Status; + } + + if (Bytes == 4) { + // + // Zero-extend for 32-bit operation + // + Regs->Rax = 0; + } + + CopyMem (&Regs->Rax, Ghcb->SharedBuffer, Bytes); + break; + + // + // MMIO read w/ zero-extension ((MOVZX regX, reg/memX) + // + case 0xB6: + Bytes = 1; + // + // fall through + // + case 0xB7: + DecodeModRm (Regs, InstructionData); + Bytes = (Bytes != 0) ? Bytes : 2; + + Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes); + if (Status != 0) { + return Status; + } + + ExitInfo1 = InstructionData->Ext.RmData; + ExitInfo2 = Bytes; + + Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer; + VmgSetOffsetValid (Ghcb, GhcbSwScratch); + Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2); + if (Status != 0) { + return Status; + } + + Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg); + SetMem (Register, (UINTN)(1 << InstructionData->DataSize), 0); + CopyMem (Register, Ghcb->SharedBuffer, Bytes); + break; + + // + // MMIO read w/ sign-extension (MOVSX regX, reg/memX) + // + case 0xBE: + Bytes = 1; + // + // fall through + // + case 0xBF: + DecodeModRm (Regs, InstructionData); + Bytes = (Bytes != 0) ? Bytes : 2; + + Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes); + if (Status != 0) { + return Status; + } + + ExitInfo1 = InstructionData->Ext.RmData; + ExitInfo2 = Bytes; + + Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer; + VmgSetOffsetValid (Ghcb, GhcbSwScratch); + Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2); + if (Status != 0) { + return Status; + } + + if (Bytes == 1) { + UINT8 *Data; + + Data = (UINT8 *)Ghcb->SharedBuffer; + SignByte = ((*Data & BIT7) != 0) ? 0xFF : 0x00; + } else { + UINT16 *Data; + + Data = (UINT16 *)Ghcb->SharedBuffer; + SignByte = ((*Data & BIT15) != 0) ? 0xFF : 0x00; + } + + Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg); + SetMem (Register, (UINTN)(1 << InstructionData->DataSize), SignByte); + CopyMem (Register, Ghcb->SharedBuffer, Bytes); + break; + + default: + DEBUG ((DEBUG_ERROR, "Invalid MMIO opcode (%x)\n", OpCode)); + Status = GP_EXCEPTION; + ASSERT (FALSE); + } + + return Status; +} + +/** + Handle a MWAIT event. + + Use the VMGEXIT instruction to handle a MWAIT event. + + @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication + Block + @param[in, out] Regs x64 processor context + @param[in] InstructionData Instruction parsing context + + @retval 0 Event handled successfully + @return New exception value to propagate + +**/ +STATIC +UINT64 +MwaitExit ( + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN SEV_ES_INSTRUCTION_DATA *InstructionData + ) +{ + DecodeModRm (Regs, InstructionData); + + Ghcb->SaveArea.Rax = Regs->Rax; + VmgSetOffsetValid (Ghcb, GhcbRax); + Ghcb->SaveArea.Rcx = Regs->Rcx; + VmgSetOffsetValid (Ghcb, GhcbRcx); + + return VmgExit (Ghcb, SVM_EXIT_MWAIT, 0, 0); +} + +/** + Handle a MONITOR event. + + Use the VMGEXIT instruction to handle a MONITOR event. + + @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication + Block + @param[in, out] Regs x64 processor context + @param[in] InstructionData Instruction parsing context + + @retval 0 Event handled successfully + @return New exception value to propagate + +**/ +STATIC +UINT64 +MonitorExit ( + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN SEV_ES_INSTRUCTION_DATA *InstructionData + ) +{ + DecodeModRm (Regs, InstructionData); + + Ghcb->SaveArea.Rax = Regs->Rax; // Identity mapped, so VA = PA + VmgSetOffsetValid (Ghcb, GhcbRax); + Ghcb->SaveArea.Rcx = Regs->Rcx; + VmgSetOffsetValid (Ghcb, GhcbRcx); + Ghcb->SaveArea.Rdx = Regs->Rdx; + VmgSetOffsetValid (Ghcb, GhcbRdx); + + return VmgExit (Ghcb, SVM_EXIT_MONITOR, 0, 0); +} + +/** + Handle a WBINVD event. + + Use the VMGEXIT instruction to handle a WBINVD event. + + @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication + Block + @param[in, out] Regs x64 processor context + @param[in] InstructionData Instruction parsing context + + @retval 0 Event handled successfully + @return New exception value to propagate + +**/ +STATIC +UINT64 +WbinvdExit ( + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN SEV_ES_INSTRUCTION_DATA *InstructionData + ) +{ + return VmgExit (Ghcb, SVM_EXIT_WBINVD, 0, 0); +} + +/** + Handle a RDTSCP event. + + Use the VMGEXIT instruction to handle a RDTSCP event. + + @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication + Block + @param[in, out] Regs x64 processor context + @param[in] InstructionData Instruction parsing context + + @retval 0 Event handled successfully + @return New exception value to propagate + +**/ +STATIC +UINT64 +RdtscpExit ( + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN SEV_ES_INSTRUCTION_DATA *InstructionData + ) +{ + UINT64 Status; + + DecodeModRm (Regs, InstructionData); + + Status = VmgExit (Ghcb, SVM_EXIT_RDTSCP, 0, 0); + if (Status != 0) { + return Status; + } + + if (!VmgIsOffsetValid (Ghcb, GhcbRax) || + !VmgIsOffsetValid (Ghcb, GhcbRcx) || + !VmgIsOffsetValid (Ghcb, GhcbRdx)) + { + return UnsupportedExit (Ghcb, Regs, InstructionData); + } + + Regs->Rax = Ghcb->SaveArea.Rax; + Regs->Rcx = Ghcb->SaveArea.Rcx; + Regs->Rdx = Ghcb->SaveArea.Rdx; + + return 0; +} + +/** + Handle a VMMCALL event. + + Use the VMGEXIT instruction to handle a VMMCALL event. + + @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication + Block + @param[in, out] Regs x64 processor context + @param[in] InstructionData Instruction parsing context + + @retval 0 Event handled successfully + @return New exception value to propagate + +**/ +STATIC +UINT64 +VmmCallExit ( + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN SEV_ES_INSTRUCTION_DATA *InstructionData + ) +{ + UINT64 Status; + + DecodeModRm (Regs, InstructionData); + + Ghcb->SaveArea.Rax = Regs->Rax; + VmgSetOffsetValid (Ghcb, GhcbRax); + Ghcb->SaveArea.Cpl = (UINT8)(Regs->Cs & 0x3); + VmgSetOffsetValid (Ghcb, GhcbCpl); + + Status = VmgExit (Ghcb, SVM_EXIT_VMMCALL, 0, 0); + if (Status != 0) { + return Status; + } + + if (!VmgIsOffsetValid (Ghcb, GhcbRax)) { + return UnsupportedExit (Ghcb, Regs, InstructionData); + } + + Regs->Rax = Ghcb->SaveArea.Rax; + + return 0; +} + +/** + Handle an MSR event. + + Use the VMGEXIT instruction to handle either a RDMSR or WRMSR event. + + @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication + Block + @param[in, out] Regs x64 processor context + @param[in] InstructionData Instruction parsing context + + @retval 0 Event handled successfully + @return New exception value to propagate + +**/ +STATIC +UINT64 +MsrExit ( + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN SEV_ES_INSTRUCTION_DATA *InstructionData + ) +{ + UINT64 ExitInfo1, Status; + + ExitInfo1 = 0; + + switch (*(InstructionData->OpCodes + 1)) { + case 0x30: // WRMSR + ExitInfo1 = 1; + Ghcb->SaveArea.Rax = Regs->Rax; + VmgSetOffsetValid (Ghcb, GhcbRax); + Ghcb->SaveArea.Rdx = Regs->Rdx; + VmgSetOffsetValid (Ghcb, GhcbRdx); + // + // fall through + // + case 0x32: // RDMSR + Ghcb->SaveArea.Rcx = Regs->Rcx; + VmgSetOffsetValid (Ghcb, GhcbRcx); + break; + default: + return UnsupportedExit (Ghcb, Regs, InstructionData); + } + + Status = VmgExit (Ghcb, SVM_EXIT_MSR, ExitInfo1, 0); + if (Status != 0) { + return Status; + } + + if (ExitInfo1 == 0) { + if (!VmgIsOffsetValid (Ghcb, GhcbRax) || + !VmgIsOffsetValid (Ghcb, GhcbRdx)) + { + return UnsupportedExit (Ghcb, Regs, InstructionData); + } + + Regs->Rax = Ghcb->SaveArea.Rax; + Regs->Rdx = Ghcb->SaveArea.Rdx; + } + + return 0; +} + +/** + Build the IOIO event information. + + The IOIO event information identifies the type of IO operation to be performed + by the hypervisor. Build this information based on the instruction data. + + @param[in] Regs x64 processor context + @param[in, out] InstructionData Instruction parsing context + + @return IOIO event information value + +**/ +STATIC +UINT64 +IoioExitInfo ( + IN EFI_SYSTEM_CONTEXT_X64 *Regs, + IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData + ) +{ + UINT64 ExitInfo; + + ExitInfo = 0; + + switch (*(InstructionData->OpCodes)) { + // + // INS opcodes + // + case 0x6C: + case 0x6D: + ExitInfo |= IOIO_TYPE_INS; + ExitInfo |= IOIO_SEG_ES; + ExitInfo |= ((Regs->Rdx & 0xffff) << 16); + break; + + // + // OUTS opcodes + // + case 0x6E: + case 0x6F: + ExitInfo |= IOIO_TYPE_OUTS; + ExitInfo |= IOIO_SEG_DS; + ExitInfo |= ((Regs->Rdx & 0xffff) << 16); + break; + + // + // IN immediate opcodes + // + case 0xE4: + case 0xE5: + InstructionData->ImmediateSize = 1; + InstructionData->End++; + ExitInfo |= IOIO_TYPE_IN; + ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16); + break; + + // + // OUT immediate opcodes + // + case 0xE6: + case 0xE7: + InstructionData->ImmediateSize = 1; + InstructionData->End++; + ExitInfo |= IOIO_TYPE_OUT; + ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16) | IOIO_TYPE_OUT; + break; + + // + // IN register opcodes + // + case 0xEC: + case 0xED: + ExitInfo |= IOIO_TYPE_IN; + ExitInfo |= ((Regs->Rdx & 0xffff) << 16); + break; + + // + // OUT register opcodes + // + case 0xEE: + case 0xEF: + ExitInfo |= IOIO_TYPE_OUT; + ExitInfo |= ((Regs->Rdx & 0xffff) << 16); + break; + + default: + return 0; + } + + switch (*(InstructionData->OpCodes)) { + // + // Single-byte opcodes + // + case 0x6C: + case 0x6E: + case 0xE4: + case 0xE6: + case 0xEC: + case 0xEE: + ExitInfo |= IOIO_DATA_8; + break; + + // + // Length determined by instruction parsing + // + default: + ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16 + : IOIO_DATA_32; + } + + switch (InstructionData->AddrSize) { + case Size16Bits: + ExitInfo |= IOIO_ADDR_16; + break; + + case Size32Bits: + ExitInfo |= IOIO_ADDR_32; + break; + + case Size64Bits: + ExitInfo |= IOIO_ADDR_64; + break; + + default: + break; + } + + if (InstructionData->RepMode != 0) { + ExitInfo |= IOIO_REP; + } + + return ExitInfo; +} + +/** + Handle an IOIO event. + + Use the VMGEXIT instruction to handle an IOIO event. + + @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication + Block + @param[in, out] Regs x64 processor context + @param[in] InstructionData Instruction parsing context + + @retval 0 Event handled successfully + @return New exception value to propagate + +**/ +STATIC +UINT64 +IoioExit ( + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN SEV_ES_INSTRUCTION_DATA *InstructionData + ) +{ + UINT64 ExitInfo1, ExitInfo2, Status; + BOOLEAN IsString; + + ExitInfo1 = IoioExitInfo (Regs, InstructionData); + if (ExitInfo1 == 0) { + return UnsupportedExit (Ghcb, Regs, InstructionData); + } + + IsString = ((ExitInfo1 & IOIO_TYPE_STR) != 0) ? TRUE : FALSE; + if (IsString) { + UINTN IoBytes, VmgExitBytes; + UINTN GhcbCount, OpCount; + + Status = 0; + + IoBytes = IOIO_DATA_BYTES (ExitInfo1); + GhcbCount = sizeof (Ghcb->SharedBuffer) / IoBytes; + + OpCount = ((ExitInfo1 & IOIO_REP) != 0) ? Regs->Rcx : 1; + while (OpCount != 0) { + ExitInfo2 = MIN (OpCount, GhcbCount); + VmgExitBytes = ExitInfo2 * IoBytes; + + if ((ExitInfo1 & IOIO_TYPE_IN) == 0) { + CopyMem (Ghcb->SharedBuffer, (VOID *)Regs->Rsi, VmgExitBytes); + Regs->Rsi += VmgExitBytes; + } + + Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer; + VmgSetOffsetValid (Ghcb, GhcbSwScratch); + Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, ExitInfo2); + if (Status != 0) { + return Status; + } + + if ((ExitInfo1 & IOIO_TYPE_IN) != 0) { + CopyMem ((VOID *)Regs->Rdi, Ghcb->SharedBuffer, VmgExitBytes); + Regs->Rdi += VmgExitBytes; + } + + if ((ExitInfo1 & IOIO_REP) != 0) { + Regs->Rcx -= ExitInfo2; + } + + OpCount -= ExitInfo2; + } + } else { + if ((ExitInfo1 & IOIO_TYPE_IN) != 0) { + Ghcb->SaveArea.Rax = 0; + } else { + CopyMem (&Ghcb->SaveArea.Rax, &Regs->Rax, IOIO_DATA_BYTES (ExitInfo1)); + } + + VmgSetOffsetValid (Ghcb, GhcbRax); + + Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, 0); + if (Status != 0) { + return Status; + } + + if ((ExitInfo1 & IOIO_TYPE_IN) != 0) { + if (!VmgIsOffsetValid (Ghcb, GhcbRax)) { + return UnsupportedExit (Ghcb, Regs, InstructionData); + } + + CopyMem (&Regs->Rax, &Ghcb->SaveArea.Rax, IOIO_DATA_BYTES (ExitInfo1)); + } + } + + return 0; +} + +/** + Handle a INVD event. + + Use the VMGEXIT instruction to handle a INVD event. + + @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication + Block + @param[in, out] Regs x64 processor context + @param[in] InstructionData Instruction parsing context + + @retval 0 Event handled successfully + @return New exception value to propagate + +**/ +STATIC +UINT64 +InvdExit ( + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN SEV_ES_INSTRUCTION_DATA *InstructionData + ) +{ + return VmgExit (Ghcb, SVM_EXIT_INVD, 0, 0); +} + +/** + Fetch CPUID leaf/function via hypervisor/VMGEXIT. + + @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication + Block + @param[in] EaxIn EAX input for cpuid instruction + @param[in] EcxIn ECX input for cpuid instruction + @param[in] Xcr0In XCR0 at time of cpuid instruction + @param[in, out] Eax Pointer to store leaf's EAX value + @param[in, out] Ebx Pointer to store leaf's EBX value + @param[in, out] Ecx Pointer to store leaf's ECX value + @param[in, out] Edx Pointer to store leaf's EDX value + @param[in, out] Status Pointer to store status from VMGEXIT (always 0 + unless return value indicates failure) + @param[in, out] Unsupported Pointer to store indication of unsupported + VMGEXIT (always false unless return value + indicates failure) + + @retval TRUE CPUID leaf fetch successfully. + @retval FALSE Error occurred while fetching CPUID leaf. Callers + should Status and Unsupported and handle + accordingly if they indicate a more precise + error condition. + +**/ +STATIC +BOOLEAN +GetCpuidHyp ( + IN OUT GHCB *Ghcb, + IN UINT32 EaxIn, + IN UINT32 EcxIn, + IN UINT64 XCr0, + IN OUT UINT32 *Eax, + IN OUT UINT32 *Ebx, + IN OUT UINT32 *Ecx, + IN OUT UINT32 *Edx, + IN OUT UINT64 *Status, + IN OUT BOOLEAN *UnsupportedExit + ) +{ + *UnsupportedExit = FALSE; + Ghcb->SaveArea.Rax = EaxIn; + VmgSetOffsetValid (Ghcb, GhcbRax); + Ghcb->SaveArea.Rcx = EcxIn; + VmgSetOffsetValid (Ghcb, GhcbRcx); + if (EaxIn == CPUID_EXTENDED_STATE) { + Ghcb->SaveArea.XCr0 = XCr0; + VmgSetOffsetValid (Ghcb, GhcbXCr0); + } + + *Status = VmgExit (Ghcb, SVM_EXIT_CPUID, 0, 0); + if (*Status != 0) { + return FALSE; + } + + if (!VmgIsOffsetValid (Ghcb, GhcbRax) || + !VmgIsOffsetValid (Ghcb, GhcbRbx) || + !VmgIsOffsetValid (Ghcb, GhcbRcx) || + !VmgIsOffsetValid (Ghcb, GhcbRdx)) + { + *UnsupportedExit = TRUE; + return FALSE; + } + + if (Eax) { + *Eax = (UINT32)(UINTN)Ghcb->SaveArea.Rax; + } + + if (Ebx) { + *Ebx = (UINT32)(UINTN)Ghcb->SaveArea.Rbx; + } + + if (Ecx) { + *Ecx = (UINT32)(UINTN)Ghcb->SaveArea.Rcx; + } + + if (Edx) { + *Edx = (UINT32)(UINTN)Ghcb->SaveArea.Rdx; + } + + return TRUE; +} + +/** + Check if SEV-SNP enabled. + + @retval TRUE SEV-SNP is enabled. + @retval FALSE SEV-SNP is disabled. + +**/ +STATIC +BOOLEAN +SnpEnabled ( + VOID + ) +{ + MSR_SEV_STATUS_REGISTER Msr; + + Msr.Uint32 = AsmReadMsr32 (MSR_SEV_STATUS); + + return !!Msr.Bits.SevSnpBit; +} + +/** + Calculate the total XSAVE area size for enabled XSAVE areas + + @param[in] XFeaturesEnabled Bit-mask of enabled XSAVE features/areas as + indicated by XCR0/MSR_IA32_XSS bits + @param[in] XSaveBaseSize Base/legacy XSAVE area size (e.g. when + XCR0 is 1) + @param[in, out] XSaveSize Pointer to storage for calculated XSAVE area + size + @param[in] Compacted Whether or not the calculation is for the + normal XSAVE area size (leaf 0xD,0x0,EBX) or + compacted XSAVE area size (leaf 0xD,0x1,EBX) + + + @retval TRUE XSAVE size calculation was successful. + @retval FALSE XSAVE size calculation was unsuccessful. +**/ +STATIC +BOOLEAN +GetCpuidXSaveSize ( + IN UINT64 XFeaturesEnabled, + IN UINT32 XSaveBaseSize, + IN OUT UINT32 *XSaveSize, + IN BOOLEAN Compacted + ) +{ + SEV_SNP_CPUID_INFO *CpuidInfo; + UINT64 XFeaturesFound = 0; + UINT32 Idx; + + *XSaveSize = XSaveBaseSize; + CpuidInfo = (SEV_SNP_CPUID_INFO *)(UINT64)PcdGet32 (PcdOvmfCpuidBase); + + for (Idx = 0; Idx < CpuidInfo->Count; Idx++) { + SEV_SNP_CPUID_FUNCTION *CpuidFn = &CpuidInfo->function[Idx]; + + if (!((CpuidFn->EaxIn == 0xD) && + ((CpuidFn->EcxIn == 0) || (CpuidFn->EcxIn == 1)))) + { + continue; + } + + if (XFeaturesFound & (1ULL << CpuidFn->EcxIn) || + !(XFeaturesEnabled & (1ULL << CpuidFn->EcxIn))) + { + continue; + } + + XFeaturesFound |= (1ULL << CpuidFn->EcxIn); + if (Compacted) { + *XSaveSize += CpuidFn->Eax; + } else { + *XSaveSize = MAX (*XSaveSize, CpuidFn->Eax + CpuidFn->Ebx); + } + } + + /* + * Either the guest set unsupported XCR0/XSS bits, or the corresponding + * entries in the CPUID table were not present. This is an invalid state. + */ + if (XFeaturesFound != (XFeaturesEnabled & ~3UL)) { + return FALSE; + } + + return TRUE; +} + +/** + Check if a CPUID leaf/function is indexed via ECX sub-leaf/sub-function + + @param[in] EaxIn EAX input for cpuid instruction + + @retval FALSE cpuid leaf/function is not indexed by ECX input + @retval TRUE cpuid leaf/function is indexed by ECX input + +**/ +STATIC +BOOLEAN +IsFunctionIndexed ( + IN UINT32 EaxIn + ) +{ + switch (EaxIn) { + case CPUID_CACHE_PARAMS: + case CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS: + case CPUID_EXTENDED_TOPOLOGY: + case CPUID_EXTENDED_STATE: + case CPUID_INTEL_RDT_MONITORING: + case CPUID_INTEL_RDT_ALLOCATION: + case CPUID_INTEL_SGX: + case CPUID_INTEL_PROCESSOR_TRACE: + case CPUID_DETERMINISTIC_ADDRESS_TRANSLATION_PARAMETERS: + case CPUID_V2_EXTENDED_TOPOLOGY: + case 0x8000001D: /* Cache Topology Information */ + return TRUE; + } + + return FALSE; +} + +/** + Fetch CPUID leaf/function via SEV-SNP CPUID table. + + @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication + Block + @param[in] EaxIn EAX input for cpuid instruction + @param[in] EcxIn ECX input for cpuid instruction + @param[in] Xcr0In XCR0 at time of cpuid instruction + @param[in, out] Eax Pointer to store leaf's EAX value + @param[in, out] Ebx Pointer to store leaf's EBX value + @param[in, out] Ecx Pointer to store leaf's ECX value + @param[in, out] Edx Pointer to store leaf's EDX value + @param[in, out] Status Pointer to store status from VMGEXIT (always 0 + unless return value indicates failure) + @param[in, out] Unsupported Pointer to store indication of unsupported + VMGEXIT (always false unless return value + indicates failure) + + @retval TRUE CPUID leaf fetch successfully. + @retval FALSE Error occurred while fetching CPUID leaf. Callers + should Status and Unsupported and handle + accordingly if they indicate a more precise + error condition. + +**/ +STATIC +BOOLEAN +GetCpuidFw ( + IN OUT GHCB *Ghcb, + IN UINT32 EaxIn, + IN UINT32 EcxIn, + IN UINT64 XCr0, + IN OUT UINT32 *Eax, + IN OUT UINT32 *Ebx, + IN OUT UINT32 *Ecx, + IN OUT UINT32 *Edx, + IN OUT UINT64 *Status, + IN OUT BOOLEAN *Unsupported + ) +{ + SEV_SNP_CPUID_INFO *CpuidInfo; + BOOLEAN Found; + UINT32 Idx; + + CpuidInfo = (SEV_SNP_CPUID_INFO *)(UINT64)PcdGet32 (PcdOvmfCpuidBase); + Found = FALSE; + + for (Idx = 0; Idx < CpuidInfo->Count; Idx++) { + SEV_SNP_CPUID_FUNCTION *CpuidFn = &CpuidInfo->function[Idx]; + + if (CpuidFn->EaxIn != EaxIn) { + continue; + } + + if (IsFunctionIndexed (CpuidFn->EaxIn) && (CpuidFn->EcxIn != EcxIn)) { + continue; + } + + *Eax = CpuidFn->Eax; + *Ebx = CpuidFn->Ebx; + *Ecx = CpuidFn->Ecx; + *Edx = CpuidFn->Edx; + + Found = TRUE; + break; + } + + if (!Found) { + *Eax = *Ebx = *Ecx = *Edx = 0; + goto Out; + } + + if (EaxIn == CPUID_VERSION_INFO) { + IA32_CR4 Cr4; + UINT32 Ebx2; + UINT32 Edx2; + + if (!GetCpuidHyp ( + Ghcb, + EaxIn, + EcxIn, + XCr0, + NULL, + &Ebx2, + NULL, + &Edx2, + Status, + Unsupported + )) + { + return FALSE; + } + + /* initial APIC ID */ + *Ebx = (*Ebx & 0x00FFFFFF) | (Ebx2 & 0xFF000000); + /* APIC enabled bit */ + *Edx = (*Edx & ~BIT9) | (Edx2 & BIT9); + /* OSXSAVE enabled bit */ + Cr4.UintN = AsmReadCr4 (); + *Ecx = (Cr4.Bits.OSXSAVE) ? (*Ecx & ~BIT27) | (*Ecx & BIT27) + : (*Ecx & ~BIT27); + } else if (EaxIn == CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS) { + IA32_CR4 Cr4; + + Cr4.UintN = AsmReadCr4 (); + /* OSPKE enabled bit */ + *Ecx = (Cr4.Bits.PKE) ? (*Ecx | BIT4) : (*Ecx & ~BIT4); + } else if (EaxIn == CPUID_EXTENDED_TOPOLOGY) { + if (!GetCpuidHyp ( + Ghcb, + EaxIn, + EcxIn, + XCr0, + NULL, + NULL, + NULL, + Edx, + Status, + Unsupported + )) + { + return FALSE; + } + } else if ((EaxIn == CPUID_EXTENDED_STATE) && ((EcxIn == 0) || (EcxIn == 1))) { + MSR_IA32_XSS_REGISTER XssMsr; + BOOLEAN Compacted; + UINT32 XSaveSize; + + XssMsr.Uint64 = 0; + Compacted = FALSE; + if (EcxIn == 1) { + /* + * The PPR and APM aren't clear on what size should be encoded in + * 0xD:0x1:EBX when compaction is not enabled by either XSAVEC or + * XSAVES, as these are generally fixed to 1 on real CPUs. Report + * this undefined case as an error. + */ + if (!(*Eax & (BIT3 | BIT1))) { + /* (XSAVES | XSAVEC) */ + return FALSE; + } + + Compacted = TRUE; + XssMsr.Uint64 = AsmReadMsr64 (MSR_IA32_XSS); + } + + if (!GetCpuidXSaveSize ( + XCr0 | XssMsr.Uint64, + *Ebx, + &XSaveSize, + Compacted + )) + { + return FALSE; + } + + *Ebx = XSaveSize; + } else if (EaxIn == 0x8000001E) { + UINT32 Ebx2; + UINT32 Ecx2; + + /* extended APIC ID */ + if (!GetCpuidHyp ( + Ghcb, + EaxIn, + EcxIn, + XCr0, + Eax, + &Ebx2, + &Ecx2, + NULL, + Status, + Unsupported + )) + { + return FALSE; + } + + /* compute ID */ + *Ebx = (*Ebx & 0xFFFFFF00) | (Ebx2 & 0x000000FF); + /* node ID */ + *Ecx = (*Ecx & 0xFFFFFF00) | (Ecx2 & 0x000000FF); + } + +Out: + *Status = 0; + *Unsupported = FALSE; + return TRUE; +} + +/** + Handle a CPUID event. + + Use VMGEXIT instruction or CPUID table to handle a CPUID event. + + @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication + Block + @param[in, out] Regs x64 processor context + @param[in] InstructionData Instruction parsing context + + @retval 0 Event handled successfully + @return New exception value to propagate + +**/ +STATIC +UINT64 +CpuidExit ( + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN SEV_ES_INSTRUCTION_DATA *InstructionData + ) +{ + BOOLEAN Unsupported; + UINT64 Status; + UINT32 EaxIn; + UINT32 EcxIn; + UINT64 XCr0; + UINT32 Eax; + UINT32 Ebx; + UINT32 Ecx; + UINT32 Edx; + + EaxIn = (UINT32)(UINTN)Regs->Rax; + EcxIn = (UINT32)(UINTN)Regs->Rcx; + + if (EaxIn == CPUID_EXTENDED_STATE) { + IA32_CR4 Cr4; + + Cr4.UintN = AsmReadCr4 (); + Ghcb->SaveArea.XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1; + XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1; + } + + if (SnpEnabled ()) { + if (!GetCpuidFw ( + Ghcb, + EaxIn, + EcxIn, + XCr0, + &Eax, + &Ebx, + &Ecx, + &Edx, + &Status, + &Unsupported + )) + { + goto CpuidFail; + } + } else { + if (!GetCpuidHyp ( + Ghcb, + EaxIn, + EcxIn, + XCr0, + &Eax, + &Ebx, + &Ecx, + &Edx, + &Status, + &Unsupported + )) + { + goto CpuidFail; + } + } + + Regs->Rax = Eax; + Regs->Rbx = Ebx; + Regs->Rcx = Ecx; + Regs->Rdx = Edx; + + return 0; + +CpuidFail: + if (Unsupported) { + return UnsupportedExit (Ghcb, Regs, InstructionData); + } + + return Status; +} + +/** + Handle a RDPMC event. + + Use the VMGEXIT instruction to handle a RDPMC event. + + @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication + Block + @param[in, out] Regs x64 processor context + @param[in] InstructionData Instruction parsing context + + @retval 0 Event handled successfully + @return New exception value to propagate + +**/ +STATIC +UINT64 +RdpmcExit ( + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN SEV_ES_INSTRUCTION_DATA *InstructionData + ) +{ + UINT64 Status; + + Ghcb->SaveArea.Rcx = Regs->Rcx; + VmgSetOffsetValid (Ghcb, GhcbRcx); + + Status = VmgExit (Ghcb, SVM_EXIT_RDPMC, 0, 0); + if (Status != 0) { + return Status; + } + + if (!VmgIsOffsetValid (Ghcb, GhcbRax) || + !VmgIsOffsetValid (Ghcb, GhcbRdx)) + { + return UnsupportedExit (Ghcb, Regs, InstructionData); + } + + Regs->Rax = Ghcb->SaveArea.Rax; + Regs->Rdx = Ghcb->SaveArea.Rdx; + + return 0; +} + +/** + Handle a RDTSC event. + + Use the VMGEXIT instruction to handle a RDTSC event. + + @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication + Block + @param[in, out] Regs x64 processor context + @param[in] InstructionData Instruction parsing context + + @retval 0 Event handled successfully + @return New exception value to propagate + +**/ +STATIC +UINT64 +RdtscExit ( + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN SEV_ES_INSTRUCTION_DATA *InstructionData + ) +{ + UINT64 Status; + + Status = VmgExit (Ghcb, SVM_EXIT_RDTSC, 0, 0); + if (Status != 0) { + return Status; + } + + if (!VmgIsOffsetValid (Ghcb, GhcbRax) || + !VmgIsOffsetValid (Ghcb, GhcbRdx)) + { + return UnsupportedExit (Ghcb, Regs, InstructionData); + } + + Regs->Rax = Ghcb->SaveArea.Rax; + Regs->Rdx = Ghcb->SaveArea.Rdx; + + return 0; +} + +/** + Handle a DR7 register write event. + + Use the VMGEXIT instruction to handle a DR7 write event. + + @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication + Block + @param[in, out] Regs x64 processor context + @param[in] InstructionData Instruction parsing context + + @retval 0 Event handled successfully + @return New exception value to propagate + +**/ +STATIC +UINT64 +Dr7WriteExit ( + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN SEV_ES_INSTRUCTION_DATA *InstructionData + ) +{ + SEV_ES_INSTRUCTION_OPCODE_EXT *Ext; + SEV_ES_PER_CPU_DATA *SevEsData; + UINT64 *Register; + UINT64 Status; + + Ext = &InstructionData->Ext; + SevEsData = (SEV_ES_PER_CPU_DATA *)(Ghcb + 1); + + DecodeModRm (Regs, InstructionData); + + // + // MOV DRn always treats MOD == 3 no matter how encoded + // + Register = GetRegisterPointer (Regs, Ext->ModRm.Rm); + + // + // Using a value of 0 for ExitInfo1 means RAX holds the value + // + Ghcb->SaveArea.Rax = *Register; + VmgSetOffsetValid (Ghcb, GhcbRax); + + Status = VmgExit (Ghcb, SVM_EXIT_DR7_WRITE, 0, 0); + if (Status != 0) { + return Status; + } + + SevEsData->Dr7 = *Register; + SevEsData->Dr7Cached = 1; + + return 0; +} + +/** + Handle a DR7 register read event. + + Use the VMGEXIT instruction to handle a DR7 read event. + + @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication + Block + @param[in, out] Regs x64 processor context + @param[in] InstructionData Instruction parsing context + + @retval 0 Event handled successfully + +**/ +STATIC +UINT64 +Dr7ReadExit ( + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN SEV_ES_INSTRUCTION_DATA *InstructionData + ) +{ + SEV_ES_INSTRUCTION_OPCODE_EXT *Ext; + SEV_ES_PER_CPU_DATA *SevEsData; + UINT64 *Register; + + Ext = &InstructionData->Ext; + SevEsData = (SEV_ES_PER_CPU_DATA *)(Ghcb + 1); + + DecodeModRm (Regs, InstructionData); + + // + // MOV DRn always treats MOD == 3 no matter how encoded + // + Register = GetRegisterPointer (Regs, Ext->ModRm.Rm); + + // + // If there is a cached valued for DR7, return that. Otherwise return the + // DR7 standard reset value of 0x400 (no debug breakpoints set). + // + *Register = (SevEsData->Dr7Cached == 1) ? SevEsData->Dr7 : 0x400; + + return 0; +} + +/** + 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 + ) +{ + EFI_SYSTEM_CONTEXT_X64 *Regs; + NAE_EXIT NaeExit; + SEV_ES_INSTRUCTION_DATA InstructionData; + UINT64 ExitCode, Status; + EFI_STATUS VcRet; + BOOLEAN InterruptState; + + VcRet = EFI_SUCCESS; + + Regs = SystemContext.SystemContextX64; + + VmgInit (Ghcb, &InterruptState); + + ExitCode = Regs->ExceptionData; + switch (ExitCode) { + case SVM_EXIT_DR7_READ: + NaeExit = Dr7ReadExit; + break; + + case SVM_EXIT_DR7_WRITE: + NaeExit = Dr7WriteExit; + break; + + case SVM_EXIT_RDTSC: + NaeExit = RdtscExit; + break; + + case SVM_EXIT_RDPMC: + NaeExit = RdpmcExit; + break; + + case SVM_EXIT_CPUID: + NaeExit = CpuidExit; + break; + + case SVM_EXIT_INVD: + NaeExit = InvdExit; + break; + + case SVM_EXIT_IOIO_PROT: + NaeExit = IoioExit; + break; + + case SVM_EXIT_MSR: + NaeExit = MsrExit; + break; + + case SVM_EXIT_VMMCALL: + NaeExit = VmmCallExit; + break; + + case SVM_EXIT_RDTSCP: + NaeExit = RdtscpExit; + break; + + case SVM_EXIT_WBINVD: + NaeExit = WbinvdExit; + break; + + case SVM_EXIT_MONITOR: + NaeExit = MonitorExit; + break; + + case SVM_EXIT_MWAIT: + NaeExit = MwaitExit; + break; + + case SVM_EXIT_NPF: + NaeExit = MmioExit; + break; + + default: + NaeExit = UnsupportedExit; + } + + InitInstructionData (&InstructionData, Ghcb, Regs); + + Status = NaeExit (Ghcb, Regs, &InstructionData); + if (Status == 0) { + Regs->Rip += InstructionLength (&InstructionData); + } else { + GHCB_EVENT_INJECTION Event; + + Event.Uint64 = Status; + if (Event.Elements.ErrorCodeValid != 0) { + Regs->ExceptionData = Event.Elements.ErrorCode; + } else { + Regs->ExceptionData = 0; + } + + *ExceptionType = Event.Elements.Vector; + + VcRet = EFI_PROTOCOL_ERROR; + } + + VmgDone (Ghcb, InterruptState); + + 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/Library/CcExitLib/CcExitVcHandler.h b/OvmfPkg/Library/CcExitLib/CcExitVcHandler.h new file mode 100644 index 0000000000..464591fcb7 --- /dev/null +++ b/OvmfPkg/Library/CcExitLib/CcExitVcHandler.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 CC_EXIT_VC_HANDLER_H_ +#define CC_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/CcExitLib/CcExitVeHandler.c b/OvmfPkg/Library/CcExitLib/CcExitVeHandler.c new file mode 100644 index 0000000000..08e92c66ce --- /dev/null +++ b/OvmfPkg/Library/CcExitLib/CcExitVeHandler.c @@ -0,0 +1,577 @@ +/** @file + + Copyright (c) 2021, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include "CcExitTd.h" +#include +#include +#include +#include + +typedef union { + struct { + UINT32 Eax; + UINT32 Edx; + } Regs; + UINT64 Val; +} MSR_DATA; + +typedef union { + UINT8 Val; + struct { + UINT8 B : 1; + UINT8 X : 1; + UINT8 R : 1; + UINT8 W : 1; + } Bits; +} REX; + +typedef union { + UINT8 Val; + struct { + UINT8 Rm : 3; + UINT8 Reg : 3; + UINT8 Mod : 2; + } Bits; +} MODRM; + +typedef struct { + UINT64 Regs[4]; +} CPUID_DATA; + +/** + Handle an CPUID event. + + Use the TDVMCALL instruction to handle cpuid #ve + + @param[in, out] Regs x64 processor context + @param[in] Veinfo VE Info + + @retval 0 Event handled successfully + @return New exception value to propagate +**/ +STATIC +UINT64 +EFIAPI +CpuIdExit ( + IN EFI_SYSTEM_CONTEXT_X64 *Regs, + IN TDCALL_VEINFO_RETURN_DATA *Veinfo + ) +{ + CPUID_DATA CpuIdData; + UINT64 Status; + + Status = TdVmCallCpuid (Regs->Rax, Regs->Rcx, &CpuIdData); + + if (Status == 0) { + Regs->Rax = CpuIdData.Regs[0]; + Regs->Rbx = CpuIdData.Regs[1]; + Regs->Rcx = CpuIdData.Regs[2]; + Regs->Rdx = CpuIdData.Regs[3]; + } + + return Status; +} + +/** + Handle an IO event. + + Use the TDVMCALL instruction to handle either an IO read or an IO write. + + @param[in, out] Regs x64 processor context + @param[in] Veinfo VE Info + + @retval 0 Event handled successfully + @return New exception value to propagate +**/ +STATIC +UINT64 +EFIAPI +IoExit ( + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN TDCALL_VEINFO_RETURN_DATA *Veinfo + ) +{ + BOOLEAN Write; + UINTN Size; + UINTN Port; + UINT64 Val; + UINT64 RepCnt; + UINT64 Status; + + Val = 0; + Write = Veinfo->ExitQualification.Io.Direction ? FALSE : TRUE; + Size = Veinfo->ExitQualification.Io.Size + 1; + Port = Veinfo->ExitQualification.Io.Port; + + if (Veinfo->ExitQualification.Io.String) { + // + // If REP is set, get rep-cnt from Rcx + // + RepCnt = Veinfo->ExitQualification.Io.Rep ? Regs->Rcx : 1; + + while (RepCnt) { + Val = 0; + if (Write == TRUE) { + CopyMem (&Val, (VOID *)Regs->Rsi, Size); + Regs->Rsi += Size; + } + + Status = TdVmCall (EXIT_REASON_IO_INSTRUCTION, Size, Write, Port, Val, (Write ? NULL : &Val)); + if (Status != 0) { + break; + } + + if (Write == FALSE) { + CopyMem ((VOID *)Regs->Rdi, &Val, Size); + Regs->Rdi += Size; + } + + if (Veinfo->ExitQualification.Io.Rep) { + Regs->Rcx -= 1; + } + + RepCnt -= 1; + } + } else { + if (Write == TRUE) { + CopyMem (&Val, (VOID *)&Regs->Rax, Size); + } + + Status = TdVmCall (EXIT_REASON_IO_INSTRUCTION, Size, Write, Port, Val, (Write ? NULL : &Val)); + if ((Status == 0) && (Write == FALSE)) { + CopyMem ((VOID *)&Regs->Rax, &Val, Size); + } + } + + return Status; +} + +/** + Handle an READ MSR event. + + Use the TDVMCALL instruction to handle msr read + + @param[in, out] Regs x64 processor context + @param[in] Veinfo VE Info + + @retval 0 Event handled successfully + @return New exception value to propagate +**/ +STATIC +UINT64 +ReadMsrExit ( + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN TDCALL_VEINFO_RETURN_DATA *Veinfo + ) +{ + MSR_DATA Data; + UINT64 Status; + + Status = TdVmCall (EXIT_REASON_MSR_READ, Regs->Rcx, 0, 0, 0, &Data); + if (Status == 0) { + Regs->Rax = Data.Regs.Eax; + Regs->Rdx = Data.Regs.Edx; + } + + return Status; +} + +/** + Handle an WRITE MSR event. + + Use the TDVMCALL instruction to handle msr write + + @param[in, out] Regs x64 processor context + @param[in] Veinfo VE Info + + @retval 0 Event handled successfully + @return New exception value to propagate +**/ +STATIC +UINT64 +WriteMsrExit ( + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN TDCALL_VEINFO_RETURN_DATA *Veinfo + ) +{ + UINT64 Status; + MSR_DATA Data; + + Data.Regs.Eax = (UINT32)Regs->Rax; + Data.Regs.Edx = (UINT32)Regs->Rdx; + + Status = TdVmCall (EXIT_REASON_MSR_WRITE, Regs->Rcx, Data.Val, 0, 0, NULL); + + return Status; +} + +STATIC +VOID +EFIAPI +TdxDecodeInstruction ( + IN UINT8 *Rip + ) +{ + UINTN i; + + DEBUG ((DEBUG_INFO, "TDX: #TD[EPT] instruction (%p):", Rip)); + for (i = 0; i < 15; i++) { + DEBUG ((DEBUG_INFO, "%02x:", Rip[i])); + } + + DEBUG ((DEBUG_INFO, "\n")); +} + +#define TDX_DECODER_BUG_ON(x) \ + if ((x)) { \ + TdxDecodeInstruction(Rip); \ + TdVmCall(TDVMCALL_HALT, 0, 0, 0, 0, 0); \ + } + +STATIC +UINT64 * +EFIAPI +GetRegFromContext ( + IN EFI_SYSTEM_CONTEXT_X64 *Regs, + IN UINTN RegIndex + ) +{ + switch (RegIndex) { + case 0: return &Regs->Rax; + break; + case 1: return &Regs->Rcx; + break; + case 2: return &Regs->Rdx; + break; + case 3: return &Regs->Rbx; + break; + case 4: return &Regs->Rsp; + break; + case 5: return &Regs->Rbp; + break; + case 6: return &Regs->Rsi; + break; + case 7: return &Regs->Rdi; + break; + case 8: return &Regs->R8; + break; + case 9: return &Regs->R9; + break; + case 10: return &Regs->R10; + break; + case 11: return &Regs->R11; + break; + case 12: return &Regs->R12; + break; + case 13: return &Regs->R13; + break; + case 14: return &Regs->R14; + break; + case 15: return &Regs->R15; + break; + } + + return NULL; +} + +/** + Handle an MMIO event. + + Use the TDVMCALL instruction to handle either an mmio read or an mmio write. + + @param[in, out] Regs x64 processor context + @param[in] Veinfo VE Info + + @retval 0 Event handled successfully + @return New exception value to propagate +**/ +STATIC +INTN +EFIAPI +MmioExit ( + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN TDCALL_VEINFO_RETURN_DATA *Veinfo + ) +{ + UINT64 Status; + UINT32 MmioSize; + UINT32 RegSize; + UINT8 OpCode; + BOOLEAN SeenRex; + UINT64 *Reg; + UINT8 *Rip; + UINT64 Val; + UINT32 OpSize; + MODRM ModRm; + REX Rex; + TD_RETURN_DATA TdReturnData; + UINT8 Gpaw; + UINT64 TdSharedPageMask; + + Rip = (UINT8 *)Regs->Rip; + Val = 0; + Rex.Val = 0; + SeenRex = FALSE; + + Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData); + if (Status == TDX_EXIT_REASON_SUCCESS) { + Gpaw = (UINT8)(TdReturnData.TdInfo.Gpaw & 0x3f); + TdSharedPageMask = 1ULL << (Gpaw - 1); + } else { + DEBUG ((DEBUG_ERROR, "TDCALL failed with status=%llx\n", Status)); + return Status; + } + + if ((Veinfo->GuestPA & TdSharedPageMask) == 0) { + DEBUG ((DEBUG_ERROR, "EPT-violation #VE on private memory is not allowed!")); + TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0); + CpuDeadLoop (); + } + + // + // Default to 32bit transfer + // + OpSize = 4; + + do { + OpCode = *Rip++; + if (OpCode == 0x66) { + OpSize = 2; + } else if ((OpCode == 0x64) || (OpCode == 0x65) || (OpCode == 0x67)) { + continue; + } else if ((OpCode >= 0x40) && (OpCode <= 0x4f)) { + SeenRex = TRUE; + Rex.Val = OpCode; + } else { + break; + } + } while (TRUE); + + // + // We need to have at least 2 more bytes for this instruction + // + TDX_DECODER_BUG_ON (((UINT64)Rip - Regs->Rip) > 13); + + OpCode = *Rip++; + // + // Two-byte opecode, get next byte + // + if (OpCode == 0x0F) { + OpCode = *Rip++; + } + + switch (OpCode) { + case 0x88: + case 0x8A: + case 0xB6: + MmioSize = 1; + break; + case 0xB7: + MmioSize = 2; + break; + default: + MmioSize = Rex.Bits.W ? 8 : OpSize; + break; + } + + /* Punt on AH/BH/CH/DH unless it shows up. */ + ModRm.Val = *Rip++; + TDX_DECODER_BUG_ON (MmioSize == 1 && ModRm.Bits.Reg > 4 && !SeenRex && OpCode != 0xB6); + Reg = GetRegFromContext (Regs, ModRm.Bits.Reg | ((int)Rex.Bits.R << 3)); + TDX_DECODER_BUG_ON (!Reg); + + if (ModRm.Bits.Rm == 4) { + ++Rip; /* SIB byte */ + } + + if ((ModRm.Bits.Mod == 2) || ((ModRm.Bits.Mod == 0) && (ModRm.Bits.Rm == 5))) { + Rip += 4; /* DISP32 */ + } else if (ModRm.Bits.Mod == 1) { + ++Rip; /* DISP8 */ + } + + switch (OpCode) { + case 0x88: + case 0x89: + CopyMem ((void *)&Val, Reg, MmioSize); + Status = TdVmCall (TDVMCALL_MMIO, MmioSize, 1, Veinfo->GuestPA, Val, 0); + break; + case 0xC7: + CopyMem ((void *)&Val, Rip, OpSize); + Status = TdVmCall (TDVMCALL_MMIO, MmioSize, 1, Veinfo->GuestPA, Val, 0); + Rip += OpSize; + default: + // + // 32-bit write registers are zero extended to the full register + // Hence 'MOVZX r[32/64], r/m16' is + // hardcoded to reg size 8, and the straight MOV case has a reg + // size of 8 in the 32-bit read case. + // + switch (OpCode) { + case 0xB6: + RegSize = Rex.Bits.W ? 8 : OpSize; + break; + case 0xB7: + RegSize = 8; + break; + default: + RegSize = MmioSize == 4 ? 8 : MmioSize; + break; + } + + Status = TdVmCall (TDVMCALL_MMIO, MmioSize, 0, Veinfo->GuestPA, 0, &Val); + if (Status == 0) { + ZeroMem (Reg, RegSize); + CopyMem (Reg, (void *)&Val, MmioSize); + } + } + + if (Status == 0) { + TDX_DECODER_BUG_ON (((UINT64)Rip - Regs->Rip) > 15); + + // + // We change instruction length to reflect true size so handler can + // bump rip + // + Veinfo->ExitInstructionLength = (UINT32)((UINT64)Rip - Regs->Rip); + } + + return Status; +} + +/** + Handle a #VE exception. + + Performs the necessary processing to handle a #VE 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 #VE not supported, (new) exception value to + propagate provided + @retval EFI_PROTOCOL_ERROR #VE handling failed, (new) exception value to + propagate provided + +**/ +EFI_STATUS +EFIAPI +VmTdExitHandleVe ( + IN OUT EFI_EXCEPTION_TYPE *ExceptionType, + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ) +{ + UINT64 Status; + TD_RETURN_DATA ReturnData; + EFI_SYSTEM_CONTEXT_X64 *Regs; + + Regs = SystemContext.SystemContextX64; + Status = TdCall (TDCALL_TDGETVEINFO, 0, 0, 0, &ReturnData); + ASSERT (Status == 0); + if (Status != 0) { + DEBUG ((DEBUG_ERROR, "#VE happened. TDGETVEINFO failed with Status = 0x%llx\n", Status)); + TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0); + } + + switch (ReturnData.VeInfo.ExitReason) { + case EXIT_REASON_CPUID: + Status = CpuIdExit (Regs, &ReturnData.VeInfo); + DEBUG (( + DEBUG_VERBOSE, + "CPUID #VE happened, ExitReasion is %d, ExitQualification = 0x%x.\n", + ReturnData.VeInfo.ExitReason, + ReturnData.VeInfo.ExitQualification.Val + )); + break; + + case EXIT_REASON_HLT: + Status = TdVmCall (EXIT_REASON_HLT, 0, 0, 0, 0, 0); + break; + + case EXIT_REASON_IO_INSTRUCTION: + Status = IoExit (Regs, &ReturnData.VeInfo); + DEBUG (( + DEBUG_VERBOSE, + "IO_Instruction #VE happened, ExitReasion is %d, ExitQualification = 0x%x.\n", + ReturnData.VeInfo.ExitReason, + ReturnData.VeInfo.ExitQualification.Val + )); + break; + + case EXIT_REASON_MSR_READ: + Status = ReadMsrExit (Regs, &ReturnData.VeInfo); + DEBUG (( + DEBUG_VERBOSE, + "RDMSR #VE happened, ExitReasion is %d, ExitQualification = 0x%x. Regs->Rcx=0x%llx, Status = 0x%llx\n", + ReturnData.VeInfo.ExitReason, + ReturnData.VeInfo.ExitQualification.Val, + Regs->Rcx, + Status + )); + break; + + case EXIT_REASON_MSR_WRITE: + Status = WriteMsrExit (Regs, &ReturnData.VeInfo); + DEBUG (( + DEBUG_VERBOSE, + "WRMSR #VE happened, ExitReasion is %d, ExitQualification = 0x%x. Regs->Rcx=0x%llx, Status = 0x%llx\n", + ReturnData.VeInfo.ExitReason, + ReturnData.VeInfo.ExitQualification.Val, + Regs->Rcx, + Status + )); + break; + + case EXIT_REASON_EPT_VIOLATION: + Status = MmioExit (Regs, &ReturnData.VeInfo); + DEBUG (( + DEBUG_VERBOSE, + "MMIO #VE happened, ExitReasion is %d, ExitQualification = 0x%x.\n", + ReturnData.VeInfo.ExitReason, + ReturnData.VeInfo.ExitQualification.Val + )); + break; + + case EXIT_REASON_VMCALL: + case EXIT_REASON_MWAIT_INSTRUCTION: + case EXIT_REASON_MONITOR_INSTRUCTION: + case EXIT_REASON_WBINVD: + case EXIT_REASON_RDPMC: + /* Handle as nops. */ + break; + + default: + DEBUG (( + DEBUG_ERROR, + "Unsupported #VE happened, ExitReason is %d, ExitQualification = 0x%x.\n", + ReturnData.VeInfo.ExitReason, + ReturnData.VeInfo.ExitQualification.Val + )); + + ASSERT (FALSE); + CpuDeadLoop (); + } + + if (Status) { + DEBUG (( + DEBUG_ERROR, + "#VE Error (0x%llx) returned from host, ExitReason is %d, ExitQualification = 0x%x.\n", + Status, + ReturnData.VeInfo.ExitReason, + ReturnData.VeInfo.ExitQualification.Val + )); + + TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0); + } + + SystemContext.SystemContextX64->Rip += ReturnData.VeInfo.ExitInstructionLength; + return EFI_SUCCESS; +} diff --git a/OvmfPkg/Library/CcExitLib/PeiDxeCcExitVcHandler.c b/OvmfPkg/Library/CcExitLib/PeiDxeCcExitVcHandler.c new file mode 100644 index 0000000000..bb718161f5 --- /dev/null +++ b/OvmfPkg/Library/CcExitLib/PeiDxeCcExitVcHandler.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 "CcExitVcHandler.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/CcExitLib/SecCcExitLib.inf b/OvmfPkg/Library/CcExitLib/SecCcExitLib.inf new file mode 100644 index 0000000000..1ee22ce0ae --- /dev/null +++ b/OvmfPkg/Library/CcExitLib/SecCcExitLib.inf @@ -0,0 +1,48 @@ +## @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 = SecCcExitLib + FILE_GUID = dafff819-f86c-4cff-a70e-83161e5bcf9a + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = CcExitLib|SEC + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = X64 +# + +[Sources.common] + CcExitLib.c + CcExitVcHandler.c + CcExitVcHandler.h + SecCcExitVcHandler.c + CcExitVeHandler.c + X64/TdVmcallCpuid.nasm + +[Packages] + MdePkg/MdePkg.dec + OvmfPkg/OvmfPkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + LocalApicLib + MemEncryptSevLib + PcdLib + +[FixedPcd] + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidSize diff --git a/OvmfPkg/Library/CcExitLib/SecCcExitVcHandler.c b/OvmfPkg/Library/CcExitLib/SecCcExitVcHandler.c new file mode 100644 index 0000000000..769e0b5b74 --- /dev/null +++ b/OvmfPkg/Library/CcExitLib/SecCcExitVcHandler.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 "CcExitVcHandler.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/CcExitLib/X64/TdVmcallCpuid.nasm b/OvmfPkg/Library/CcExitLib/X64/TdVmcallCpuid.nasm new file mode 100644 index 0000000000..fa86440904 --- /dev/null +++ b/OvmfPkg/Library/CcExitLib/X64/TdVmcallCpuid.nasm @@ -0,0 +1,146 @@ +;------------------------------------------------------------------------------ +;* +;* Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
+;* SPDX-License-Identifier: BSD-2-Clause-Patent +;* +;* +;------------------------------------------------------------------------------ + +DEFAULT REL +SECTION .text + +%define TDVMCALL_EXPOSE_REGS_MASK 0xffec +%define TDVMCALL 0x0 +%define EXIT_REASON_CPUID 0xa + +%macro tdcall 0 + db 0x66,0x0f,0x01,0xcc +%endmacro + +%macro tdcall_push_regs 0 + push rbp + mov rbp, rsp + push r15 + push r14 + push r13 + push r12 + push rbx + push rsi + push rdi +%endmacro + +%macro tdcall_pop_regs 0 + pop rdi + pop rsi + pop rbx + pop r12 + pop r13 + pop r14 + pop r15 + pop rbp +%endmacro + +%define number_of_regs_pushed 8 +%define number_of_parameters 4 + +; +; Keep these in sync for push_regs/pop_regs, code below +; uses them to find 5th or greater parameters +; +%define first_variable_on_stack_offset \ + ((number_of_regs_pushed * 8) + (number_of_parameters * 8) + 8) +%define second_variable_on_stack_offset \ + ((first_variable_on_stack_offset) + 8) + +%macro tdcall_regs_preamble 2 + mov rax, %1 + + xor rcx, rcx + mov ecx, %2 + + ; R10 = 0 (standard TDVMCALL) + + xor r10d, r10d + + ; Zero out unused (for standard TDVMCALL) registers to avoid leaking + ; secrets to the VMM. + + xor ebx, ebx + xor esi, esi + xor edi, edi + + xor edx, edx + xor ebp, ebp + xor r8d, r8d + xor r9d, r9d + xor r14, r14 + xor r15, r15 +%endmacro + +%macro tdcall_regs_postamble 0 + xor ebx, ebx + xor esi, esi + xor edi, edi + + xor ecx, ecx + xor edx, edx + xor r8d, r8d + xor r9d, r9d + xor r10d, r10d + xor r11d, r11d +%endmacro + +;------------------------------------------------------------------------------ +; 0 => RAX = TDCALL leaf / TDVMCALL +; M => RCX = TDVMCALL register behavior +; 0xa => R11 = TDVMCALL function / CPUID +; RCX => R12 = p1 +; RDX => R13 = p2 +; +; UINT64 +; EFIAPI +; TdVmCallCpuid ( +; UINT64 EaxIn, // Rcx +; UINT64 EcxIn, // Rdx +; UINT64 *Results // R8 +; ) +global ASM_PFX(TdVmCallCpuid) +ASM_PFX(TdVmCallCpuid): + tdcall_push_regs + + mov r11, EXIT_REASON_CPUID + mov r12, rcx + mov r13, rdx + + ; Save *results pointers + push r8 + + tdcall_regs_preamble TDVMCALL, TDVMCALL_EXPOSE_REGS_MASK + + tdcall + + ; ignore return data if TDCALL reports failure. + test rax, rax + jnz .no_return_data + + ; Propagate TDVMCALL success/failure to return value. + mov rax, r10 + test rax, rax + jnz .no_return_data + + ; Retrieve *Results + pop r8 + test r8, r8 + jz .no_return_data + ; Caller pass in buffer so store results r12-r15 contains eax-edx + mov [r8 + 0], r12 + mov [r8 + 8], r13 + mov [r8 + 16], r14 + mov [r8 + 24], r15 + +.no_return_data: + tdcall_regs_postamble + + tdcall_pop_regs + + ret diff --git a/OvmfPkg/Library/VmgExitLib/PeiDxeVmgExitVcHandler.c b/OvmfPkg/Library/VmgExitLib/PeiDxeVmgExitVcHandler.c deleted file mode 100644 index e3d0715837..0000000000 --- a/OvmfPkg/Library/VmgExitLib/PeiDxeVmgExitVcHandler.c +++ /dev/null @@ -1,103 +0,0 @@ -/** @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/SecVmgExitLib.inf b/OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf deleted file mode 100644 index f9bd4974f6..0000000000 --- a/OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf +++ /dev/null @@ -1,48 +0,0 @@ -## @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 - VmTdExitVeHandler.c - X64/TdVmcallCpuid.nasm - -[Packages] - MdePkg/MdePkg.dec - OvmfPkg/OvmfPkg.dec - UefiCpuPkg/UefiCpuPkg.dec - -[LibraryClasses] - BaseLib - BaseMemoryLib - DebugLib - LocalApicLib - MemEncryptSevLib - PcdLib - -[FixedPcd] - gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase - gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize - gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase - gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidSize diff --git a/OvmfPkg/Library/VmgExitLib/SecVmgExitVcHandler.c b/OvmfPkg/Library/VmgExitLib/SecVmgExitVcHandler.c deleted file mode 100644 index fe8680f831..0000000000 --- a/OvmfPkg/Library/VmgExitLib/SecVmgExitVcHandler.c +++ /dev/null @@ -1,109 +0,0 @@ -/** @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/VmTdExitHandler.h b/OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h deleted file mode 100644 index 7eacd0872f..0000000000 --- a/OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h +++ /dev/null @@ -1,32 +0,0 @@ -/** @file - - Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
- SPDX-License-Identifier: BSD-2-Clause-Patent - -**/ - -#ifndef VMTD_EXIT_HANDLER_H_ -#define VMTD_EXIT_HANDLER_H_ - -#include -#include - -/** - This function enable the TD guest to request the VMM to emulate CPUID - operation, especially for non-architectural, CPUID leaves. - - @param[in] Eax Main leaf of the CPUID - @param[in] Ecx Sub-leaf of the CPUID - @param[out] Results Returned result of CPUID operation - - @return EFI_SUCCESS -**/ -EFI_STATUS -EFIAPI -TdVmCallCpuid ( - IN UINT64 Eax, - IN UINT64 Ecx, - OUT VOID *Results - ); - -#endif diff --git a/OvmfPkg/Library/VmgExitLib/VmTdExitVeHandler.c b/OvmfPkg/Library/VmgExitLib/VmTdExitVeHandler.c deleted file mode 100644 index c89268c5d8..0000000000 --- a/OvmfPkg/Library/VmgExitLib/VmTdExitVeHandler.c +++ /dev/null @@ -1,577 +0,0 @@ -/** @file - - Copyright (c) 2021, Intel Corporation. All rights reserved.
- - SPDX-License-Identifier: BSD-2-Clause-Patent - -**/ - -#include -#include -#include "VmTdExitHandler.h" -#include -#include -#include -#include - -typedef union { - struct { - UINT32 Eax; - UINT32 Edx; - } Regs; - UINT64 Val; -} MSR_DATA; - -typedef union { - UINT8 Val; - struct { - UINT8 B : 1; - UINT8 X : 1; - UINT8 R : 1; - UINT8 W : 1; - } Bits; -} REX; - -typedef union { - UINT8 Val; - struct { - UINT8 Rm : 3; - UINT8 Reg : 3; - UINT8 Mod : 2; - } Bits; -} MODRM; - -typedef struct { - UINT64 Regs[4]; -} CPUID_DATA; - -/** - Handle an CPUID event. - - Use the TDVMCALL instruction to handle cpuid #ve - - @param[in, out] Regs x64 processor context - @param[in] Veinfo VE Info - - @retval 0 Event handled successfully - @return New exception value to propagate -**/ -STATIC -UINT64 -EFIAPI -CpuIdExit ( - IN EFI_SYSTEM_CONTEXT_X64 *Regs, - IN TDCALL_VEINFO_RETURN_DATA *Veinfo - ) -{ - CPUID_DATA CpuIdData; - UINT64 Status; - - Status = TdVmCallCpuid (Regs->Rax, Regs->Rcx, &CpuIdData); - - if (Status == 0) { - Regs->Rax = CpuIdData.Regs[0]; - Regs->Rbx = CpuIdData.Regs[1]; - Regs->Rcx = CpuIdData.Regs[2]; - Regs->Rdx = CpuIdData.Regs[3]; - } - - return Status; -} - -/** - Handle an IO event. - - Use the TDVMCALL instruction to handle either an IO read or an IO write. - - @param[in, out] Regs x64 processor context - @param[in] Veinfo VE Info - - @retval 0 Event handled successfully - @return New exception value to propagate -**/ -STATIC -UINT64 -EFIAPI -IoExit ( - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN TDCALL_VEINFO_RETURN_DATA *Veinfo - ) -{ - BOOLEAN Write; - UINTN Size; - UINTN Port; - UINT64 Val; - UINT64 RepCnt; - UINT64 Status; - - Val = 0; - Write = Veinfo->ExitQualification.Io.Direction ? FALSE : TRUE; - Size = Veinfo->ExitQualification.Io.Size + 1; - Port = Veinfo->ExitQualification.Io.Port; - - if (Veinfo->ExitQualification.Io.String) { - // - // If REP is set, get rep-cnt from Rcx - // - RepCnt = Veinfo->ExitQualification.Io.Rep ? Regs->Rcx : 1; - - while (RepCnt) { - Val = 0; - if (Write == TRUE) { - CopyMem (&Val, (VOID *)Regs->Rsi, Size); - Regs->Rsi += Size; - } - - Status = TdVmCall (EXIT_REASON_IO_INSTRUCTION, Size, Write, Port, Val, (Write ? NULL : &Val)); - if (Status != 0) { - break; - } - - if (Write == FALSE) { - CopyMem ((VOID *)Regs->Rdi, &Val, Size); - Regs->Rdi += Size; - } - - if (Veinfo->ExitQualification.Io.Rep) { - Regs->Rcx -= 1; - } - - RepCnt -= 1; - } - } else { - if (Write == TRUE) { - CopyMem (&Val, (VOID *)&Regs->Rax, Size); - } - - Status = TdVmCall (EXIT_REASON_IO_INSTRUCTION, Size, Write, Port, Val, (Write ? NULL : &Val)); - if ((Status == 0) && (Write == FALSE)) { - CopyMem ((VOID *)&Regs->Rax, &Val, Size); - } - } - - return Status; -} - -/** - Handle an READ MSR event. - - Use the TDVMCALL instruction to handle msr read - - @param[in, out] Regs x64 processor context - @param[in] Veinfo VE Info - - @retval 0 Event handled successfully - @return New exception value to propagate -**/ -STATIC -UINT64 -ReadMsrExit ( - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN TDCALL_VEINFO_RETURN_DATA *Veinfo - ) -{ - MSR_DATA Data; - UINT64 Status; - - Status = TdVmCall (EXIT_REASON_MSR_READ, Regs->Rcx, 0, 0, 0, &Data); - if (Status == 0) { - Regs->Rax = Data.Regs.Eax; - Regs->Rdx = Data.Regs.Edx; - } - - return Status; -} - -/** - Handle an WRITE MSR event. - - Use the TDVMCALL instruction to handle msr write - - @param[in, out] Regs x64 processor context - @param[in] Veinfo VE Info - - @retval 0 Event handled successfully - @return New exception value to propagate -**/ -STATIC -UINT64 -WriteMsrExit ( - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN TDCALL_VEINFO_RETURN_DATA *Veinfo - ) -{ - UINT64 Status; - MSR_DATA Data; - - Data.Regs.Eax = (UINT32)Regs->Rax; - Data.Regs.Edx = (UINT32)Regs->Rdx; - - Status = TdVmCall (EXIT_REASON_MSR_WRITE, Regs->Rcx, Data.Val, 0, 0, NULL); - - return Status; -} - -STATIC -VOID -EFIAPI -TdxDecodeInstruction ( - IN UINT8 *Rip - ) -{ - UINTN i; - - DEBUG ((DEBUG_INFO, "TDX: #TD[EPT] instruction (%p):", Rip)); - for (i = 0; i < 15; i++) { - DEBUG ((DEBUG_INFO, "%02x:", Rip[i])); - } - - DEBUG ((DEBUG_INFO, "\n")); -} - -#define TDX_DECODER_BUG_ON(x) \ - if ((x)) { \ - TdxDecodeInstruction(Rip); \ - TdVmCall(TDVMCALL_HALT, 0, 0, 0, 0, 0); \ - } - -STATIC -UINT64 * -EFIAPI -GetRegFromContext ( - IN EFI_SYSTEM_CONTEXT_X64 *Regs, - IN UINTN RegIndex - ) -{ - switch (RegIndex) { - case 0: return &Regs->Rax; - break; - case 1: return &Regs->Rcx; - break; - case 2: return &Regs->Rdx; - break; - case 3: return &Regs->Rbx; - break; - case 4: return &Regs->Rsp; - break; - case 5: return &Regs->Rbp; - break; - case 6: return &Regs->Rsi; - break; - case 7: return &Regs->Rdi; - break; - case 8: return &Regs->R8; - break; - case 9: return &Regs->R9; - break; - case 10: return &Regs->R10; - break; - case 11: return &Regs->R11; - break; - case 12: return &Regs->R12; - break; - case 13: return &Regs->R13; - break; - case 14: return &Regs->R14; - break; - case 15: return &Regs->R15; - break; - } - - return NULL; -} - -/** - Handle an MMIO event. - - Use the TDVMCALL instruction to handle either an mmio read or an mmio write. - - @param[in, out] Regs x64 processor context - @param[in] Veinfo VE Info - - @retval 0 Event handled successfully - @return New exception value to propagate -**/ -STATIC -INTN -EFIAPI -MmioExit ( - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN TDCALL_VEINFO_RETURN_DATA *Veinfo - ) -{ - UINT64 Status; - UINT32 MmioSize; - UINT32 RegSize; - UINT8 OpCode; - BOOLEAN SeenRex; - UINT64 *Reg; - UINT8 *Rip; - UINT64 Val; - UINT32 OpSize; - MODRM ModRm; - REX Rex; - TD_RETURN_DATA TdReturnData; - UINT8 Gpaw; - UINT64 TdSharedPageMask; - - Rip = (UINT8 *)Regs->Rip; - Val = 0; - Rex.Val = 0; - SeenRex = FALSE; - - Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData); - if (Status == TDX_EXIT_REASON_SUCCESS) { - Gpaw = (UINT8)(TdReturnData.TdInfo.Gpaw & 0x3f); - TdSharedPageMask = 1ULL << (Gpaw - 1); - } else { - DEBUG ((DEBUG_ERROR, "TDCALL failed with status=%llx\n", Status)); - return Status; - } - - if ((Veinfo->GuestPA & TdSharedPageMask) == 0) { - DEBUG ((DEBUG_ERROR, "EPT-violation #VE on private memory is not allowed!")); - TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0); - CpuDeadLoop (); - } - - // - // Default to 32bit transfer - // - OpSize = 4; - - do { - OpCode = *Rip++; - if (OpCode == 0x66) { - OpSize = 2; - } else if ((OpCode == 0x64) || (OpCode == 0x65) || (OpCode == 0x67)) { - continue; - } else if ((OpCode >= 0x40) && (OpCode <= 0x4f)) { - SeenRex = TRUE; - Rex.Val = OpCode; - } else { - break; - } - } while (TRUE); - - // - // We need to have at least 2 more bytes for this instruction - // - TDX_DECODER_BUG_ON (((UINT64)Rip - Regs->Rip) > 13); - - OpCode = *Rip++; - // - // Two-byte opecode, get next byte - // - if (OpCode == 0x0F) { - OpCode = *Rip++; - } - - switch (OpCode) { - case 0x88: - case 0x8A: - case 0xB6: - MmioSize = 1; - break; - case 0xB7: - MmioSize = 2; - break; - default: - MmioSize = Rex.Bits.W ? 8 : OpSize; - break; - } - - /* Punt on AH/BH/CH/DH unless it shows up. */ - ModRm.Val = *Rip++; - TDX_DECODER_BUG_ON (MmioSize == 1 && ModRm.Bits.Reg > 4 && !SeenRex && OpCode != 0xB6); - Reg = GetRegFromContext (Regs, ModRm.Bits.Reg | ((int)Rex.Bits.R << 3)); - TDX_DECODER_BUG_ON (!Reg); - - if (ModRm.Bits.Rm == 4) { - ++Rip; /* SIB byte */ - } - - if ((ModRm.Bits.Mod == 2) || ((ModRm.Bits.Mod == 0) && (ModRm.Bits.Rm == 5))) { - Rip += 4; /* DISP32 */ - } else if (ModRm.Bits.Mod == 1) { - ++Rip; /* DISP8 */ - } - - switch (OpCode) { - case 0x88: - case 0x89: - CopyMem ((void *)&Val, Reg, MmioSize); - Status = TdVmCall (TDVMCALL_MMIO, MmioSize, 1, Veinfo->GuestPA, Val, 0); - break; - case 0xC7: - CopyMem ((void *)&Val, Rip, OpSize); - Status = TdVmCall (TDVMCALL_MMIO, MmioSize, 1, Veinfo->GuestPA, Val, 0); - Rip += OpSize; - default: - // - // 32-bit write registers are zero extended to the full register - // Hence 'MOVZX r[32/64], r/m16' is - // hardcoded to reg size 8, and the straight MOV case has a reg - // size of 8 in the 32-bit read case. - // - switch (OpCode) { - case 0xB6: - RegSize = Rex.Bits.W ? 8 : OpSize; - break; - case 0xB7: - RegSize = 8; - break; - default: - RegSize = MmioSize == 4 ? 8 : MmioSize; - break; - } - - Status = TdVmCall (TDVMCALL_MMIO, MmioSize, 0, Veinfo->GuestPA, 0, &Val); - if (Status == 0) { - ZeroMem (Reg, RegSize); - CopyMem (Reg, (void *)&Val, MmioSize); - } - } - - if (Status == 0) { - TDX_DECODER_BUG_ON (((UINT64)Rip - Regs->Rip) > 15); - - // - // We change instruction length to reflect true size so handler can - // bump rip - // - Veinfo->ExitInstructionLength = (UINT32)((UINT64)Rip - Regs->Rip); - } - - return Status; -} - -/** - Handle a #VE exception. - - Performs the necessary processing to handle a #VE 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 #VE not supported, (new) exception value to - propagate provided - @retval EFI_PROTOCOL_ERROR #VE handling failed, (new) exception value to - propagate provided - -**/ -EFI_STATUS -EFIAPI -VmTdExitHandleVe ( - IN OUT EFI_EXCEPTION_TYPE *ExceptionType, - IN OUT EFI_SYSTEM_CONTEXT SystemContext - ) -{ - UINT64 Status; - TD_RETURN_DATA ReturnData; - EFI_SYSTEM_CONTEXT_X64 *Regs; - - Regs = SystemContext.SystemContextX64; - Status = TdCall (TDCALL_TDGETVEINFO, 0, 0, 0, &ReturnData); - ASSERT (Status == 0); - if (Status != 0) { - DEBUG ((DEBUG_ERROR, "#VE happened. TDGETVEINFO failed with Status = 0x%llx\n", Status)); - TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0); - } - - switch (ReturnData.VeInfo.ExitReason) { - case EXIT_REASON_CPUID: - Status = CpuIdExit (Regs, &ReturnData.VeInfo); - DEBUG (( - DEBUG_VERBOSE, - "CPUID #VE happened, ExitReasion is %d, ExitQualification = 0x%x.\n", - ReturnData.VeInfo.ExitReason, - ReturnData.VeInfo.ExitQualification.Val - )); - break; - - case EXIT_REASON_HLT: - Status = TdVmCall (EXIT_REASON_HLT, 0, 0, 0, 0, 0); - break; - - case EXIT_REASON_IO_INSTRUCTION: - Status = IoExit (Regs, &ReturnData.VeInfo); - DEBUG (( - DEBUG_VERBOSE, - "IO_Instruction #VE happened, ExitReasion is %d, ExitQualification = 0x%x.\n", - ReturnData.VeInfo.ExitReason, - ReturnData.VeInfo.ExitQualification.Val - )); - break; - - case EXIT_REASON_MSR_READ: - Status = ReadMsrExit (Regs, &ReturnData.VeInfo); - DEBUG (( - DEBUG_VERBOSE, - "RDMSR #VE happened, ExitReasion is %d, ExitQualification = 0x%x. Regs->Rcx=0x%llx, Status = 0x%llx\n", - ReturnData.VeInfo.ExitReason, - ReturnData.VeInfo.ExitQualification.Val, - Regs->Rcx, - Status - )); - break; - - case EXIT_REASON_MSR_WRITE: - Status = WriteMsrExit (Regs, &ReturnData.VeInfo); - DEBUG (( - DEBUG_VERBOSE, - "WRMSR #VE happened, ExitReasion is %d, ExitQualification = 0x%x. Regs->Rcx=0x%llx, Status = 0x%llx\n", - ReturnData.VeInfo.ExitReason, - ReturnData.VeInfo.ExitQualification.Val, - Regs->Rcx, - Status - )); - break; - - case EXIT_REASON_EPT_VIOLATION: - Status = MmioExit (Regs, &ReturnData.VeInfo); - DEBUG (( - DEBUG_VERBOSE, - "MMIO #VE happened, ExitReasion is %d, ExitQualification = 0x%x.\n", - ReturnData.VeInfo.ExitReason, - ReturnData.VeInfo.ExitQualification.Val - )); - break; - - case EXIT_REASON_VMCALL: - case EXIT_REASON_MWAIT_INSTRUCTION: - case EXIT_REASON_MONITOR_INSTRUCTION: - case EXIT_REASON_WBINVD: - case EXIT_REASON_RDPMC: - /* Handle as nops. */ - break; - - default: - DEBUG (( - DEBUG_ERROR, - "Unsupported #VE happened, ExitReason is %d, ExitQualification = 0x%x.\n", - ReturnData.VeInfo.ExitReason, - ReturnData.VeInfo.ExitQualification.Val - )); - - ASSERT (FALSE); - CpuDeadLoop (); - } - - if (Status) { - DEBUG (( - DEBUG_ERROR, - "#VE Error (0x%llx) returned from host, ExitReason is %d, ExitQualification = 0x%x.\n", - Status, - ReturnData.VeInfo.ExitReason, - ReturnData.VeInfo.ExitQualification.Val - )); - - TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0); - } - - SystemContext.SystemContextX64->Rip += ReturnData.VeInfo.ExitInstructionLength; - return EFI_SUCCESS; -} diff --git a/OvmfPkg/Library/VmgExitLib/VmgExitLib.c b/OvmfPkg/Library/VmgExitLib/VmgExitLib.c deleted file mode 100644 index c205521870..0000000000 --- a/OvmfPkg/Library/VmgExitLib/VmgExitLib.c +++ /dev/null @@ -1,238 +0,0 @@ -/** @file - VMGEXIT Support Library. - - Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.
- SPDX-License-Identifier: BSD-2-Clause-Patent - -**/ - -#include -#include -#include -#include -#include - -/** - Check for VMGEXIT error - - Check if the hypervisor has returned an error after completion of the VMGEXIT - by examining the SwExitInfo1 field of the GHCB. - - @param[in] Ghcb A pointer to the GHCB - - @retval 0 VMGEXIT succeeded. - @return Exception number to be propagated, VMGEXIT processing - did not succeed. - -**/ -STATIC -UINT64 -VmgExitErrorCheck ( - IN GHCB *Ghcb - ) -{ - GHCB_EVENT_INJECTION Event; - GHCB_EXIT_INFO ExitInfo; - UINT64 Status; - - ExitInfo.Uint64 = Ghcb->SaveArea.SwExitInfo1; - ASSERT ( - (ExitInfo.Elements.Lower32Bits == 0) || - (ExitInfo.Elements.Lower32Bits == 1) - ); - - Status = 0; - if (ExitInfo.Elements.Lower32Bits == 0) { - return Status; - } - - if (ExitInfo.Elements.Lower32Bits == 1) { - ASSERT (Ghcb->SaveArea.SwExitInfo2 != 0); - - // - // Check that the return event is valid - // - Event.Uint64 = Ghcb->SaveArea.SwExitInfo2; - if (Event.Elements.Valid && - (Event.Elements.Type == GHCB_EVENT_INJECTION_TYPE_EXCEPTION)) - { - switch (Event.Elements.Vector) { - case GP_EXCEPTION: - case UD_EXCEPTION: - // - // Use returned event as return code - // - Status = Event.Uint64; - } - } - } - - if (Status == 0) { - GHCB_EVENT_INJECTION GpEvent; - - GpEvent.Uint64 = 0; - GpEvent.Elements.Vector = GP_EXCEPTION; - GpEvent.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION; - GpEvent.Elements.Valid = 1; - - Status = GpEvent.Uint64; - } - - return Status; -} - -/** - Perform VMGEXIT. - - Sets the necessary fields of the GHCB, invokes the VMGEXIT instruction and - then handles the return actions. - - @param[in, out] Ghcb A pointer to the GHCB - @param[in] ExitCode VMGEXIT code to be assigned to the SwExitCode - field of the GHCB. - @param[in] ExitInfo1 VMGEXIT information to be assigned to the - SwExitInfo1 field of the GHCB. - @param[in] ExitInfo2 VMGEXIT information to be assigned to the - SwExitInfo2 field of the GHCB. - - @retval 0 VMGEXIT succeeded. - @return Exception number to be propagated, VMGEXIT - processing did not succeed. - -**/ -UINT64 -EFIAPI -VmgExit ( - IN OUT GHCB *Ghcb, - IN UINT64 ExitCode, - IN UINT64 ExitInfo1, - IN UINT64 ExitInfo2 - ) -{ - Ghcb->SaveArea.SwExitCode = ExitCode; - Ghcb->SaveArea.SwExitInfo1 = ExitInfo1; - Ghcb->SaveArea.SwExitInfo2 = ExitInfo2; - - VmgSetOffsetValid (Ghcb, GhcbSwExitCode); - VmgSetOffsetValid (Ghcb, GhcbSwExitInfo1); - VmgSetOffsetValid (Ghcb, GhcbSwExitInfo2); - - // - // Guest memory is used for the guest-hypervisor communication, so fence - // the invocation of the VMGEXIT instruction to ensure GHCB accesses are - // synchronized properly. - // - MemoryFence (); - AsmVmgExit (); - MemoryFence (); - - return VmgExitErrorCheck (Ghcb); -} - -/** - Perform pre-VMGEXIT initialization/preparation. - - Performs the necessary steps in preparation for invoking VMGEXIT. Must be - called before setting any fields within the GHCB. - - @param[in, out] Ghcb A pointer to the GHCB - @param[in, out] InterruptState A pointer to hold the current interrupt - state, used for restoring in VmgDone () - -**/ -VOID -EFIAPI -VmgInit ( - IN OUT GHCB *Ghcb, - IN OUT BOOLEAN *InterruptState - ) -{ - // - // Be sure that an interrupt can't cause a #VC while the GHCB is - // being used. - // - *InterruptState = GetInterruptState (); - if (*InterruptState) { - DisableInterrupts (); - } - - SetMem (&Ghcb->SaveArea, sizeof (Ghcb->SaveArea), 0); -} - -/** - Perform post-VMGEXIT cleanup. - - Performs the necessary steps to cleanup after invoking VMGEXIT. Must be - called after obtaining needed fields within the GHCB. - - @param[in, out] Ghcb A pointer to the GHCB - @param[in] InterruptState An indicator to conditionally (re)enable - interrupts - -**/ -VOID -EFIAPI -VmgDone ( - IN OUT GHCB *Ghcb, - IN BOOLEAN InterruptState - ) -{ - if (InterruptState) { - EnableInterrupts (); - } -} - -/** - Marks a field at the specified offset as valid in the GHCB. - - The ValidBitmap area represents the areas of the GHCB that have been marked - valid. Set the bit in ValidBitmap for the input offset. - - @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication Block - @param[in] Offset Qword offset in the GHCB to mark valid - -**/ -VOID -EFIAPI -VmgSetOffsetValid ( - IN OUT GHCB *Ghcb, - IN GHCB_REGISTER Offset - ) -{ - UINT32 OffsetIndex; - UINT32 OffsetBit; - - OffsetIndex = Offset / 8; - OffsetBit = Offset % 8; - - Ghcb->SaveArea.ValidBitmap[OffsetIndex] |= (1 << OffsetBit); -} - -/** - Checks if a specified offset is valid in the GHCB. - - The ValidBitmap area represents the areas of the GHCB that have been marked - valid. Return whether the bit in the ValidBitmap is set for the input offset. - - @param[in] Ghcb A pointer to the GHCB - @param[in] Offset Qword offset in the GHCB to mark valid - - @retval TRUE Offset is marked valid in the GHCB - @retval FALSE Offset is not marked valid in the GHCB - -**/ -BOOLEAN -EFIAPI -VmgIsOffsetValid ( - IN GHCB *Ghcb, - IN GHCB_REGISTER Offset - ) -{ - UINT32 OffsetIndex; - UINT32 OffsetBit; - - OffsetIndex = Offset / 8; - OffsetBit = Offset % 8; - - return ((Ghcb->SaveArea.ValidBitmap[OffsetIndex] & (1 << OffsetBit)) != 0); -} diff --git a/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf b/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf deleted file mode 100644 index 255b0c1a2f..0000000000 --- a/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf +++ /dev/null @@ -1,45 +0,0 @@ -## @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 = VmgExitLib - FILE_GUID = 0e923c25-13cd-430b-8714-ffe85652a97b - MODULE_TYPE = BASE - VERSION_STRING = 1.0 - 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. -# -# VALID_ARCHITECTURES = X64 -# - -[Sources.common] - VmgExitLib.c - VmgExitVcHandler.c - VmgExitVcHandler.h - PeiDxeVmgExitVcHandler.c - VmTdExitVeHandler.c - X64/TdVmcallCpuid.nasm - -[Packages] - MdePkg/MdePkg.dec - OvmfPkg/OvmfPkg.dec - UefiCpuPkg/UefiCpuPkg.dec - -[LibraryClasses] - BaseLib - BaseMemoryLib - DebugLib - LocalApicLib - MemEncryptSevLib - -[Pcd] - gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase - gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidSize diff --git a/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c b/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c deleted file mode 100644 index a4393dffbd..0000000000 --- a/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c +++ /dev/null @@ -1,2356 +0,0 @@ -/** @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 -#include -#include - -#include "VmgExitVcHandler.h" -// #include - -// -// Instruction execution mode definition -// -typedef enum { - LongMode64Bit = 0, - LongModeCompat32Bit, - LongModeCompat16Bit, -} SEV_ES_INSTRUCTION_MODE; - -// -// Instruction size definition (for operand and address) -// -typedef enum { - Size8Bits = 0, - Size16Bits, - Size32Bits, - Size64Bits, -} SEV_ES_INSTRUCTION_SIZE; - -// -// Intruction segment definition -// -typedef enum { - SegmentEs = 0, - SegmentCs, - SegmentSs, - SegmentDs, - SegmentFs, - SegmentGs, -} SEV_ES_INSTRUCTION_SEGMENT; - -// -// Instruction rep function definition -// -typedef enum { - RepNone = 0, - RepZ, - RepNZ, -} SEV_ES_INSTRUCTION_REP; - -typedef struct { - UINT8 Rm; - UINT8 Reg; - UINT8 Mod; -} SEV_ES_INSTRUCTION_MODRM_EXT; - -typedef struct { - UINT8 Base; - UINT8 Index; - UINT8 Scale; -} SEV_ES_INSTRUCTION_SIB_EXT; - -// -// Instruction opcode definition -// -typedef struct { - SEV_ES_INSTRUCTION_MODRM_EXT ModRm; - - SEV_ES_INSTRUCTION_SIB_EXT Sib; - - UINTN RegData; - UINTN RmData; -} SEV_ES_INSTRUCTION_OPCODE_EXT; - -// -// Instruction parsing context definition -// -typedef struct { - GHCB *Ghcb; - - SEV_ES_INSTRUCTION_MODE Mode; - SEV_ES_INSTRUCTION_SIZE DataSize; - SEV_ES_INSTRUCTION_SIZE AddrSize; - BOOLEAN SegmentSpecified; - SEV_ES_INSTRUCTION_SEGMENT Segment; - SEV_ES_INSTRUCTION_REP RepMode; - - UINT8 *Begin; - UINT8 *End; - - UINT8 *Prefixes; - UINT8 *OpCodes; - UINT8 *Displacement; - UINT8 *Immediate; - - INSTRUCTION_REX_PREFIX RexPrefix; - - BOOLEAN ModRmPresent; - INSTRUCTION_MODRM ModRm; - - BOOLEAN SibPresent; - INSTRUCTION_SIB Sib; - - UINTN PrefixSize; - UINTN OpCodeSize; - UINTN DisplacementSize; - UINTN ImmediateSize; - - SEV_ES_INSTRUCTION_OPCODE_EXT Ext; -} SEV_ES_INSTRUCTION_DATA; - -// -// Non-automatic Exit function prototype -// -typedef -UINT64 -(*NAE_EXIT) ( - GHCB *Ghcb, - EFI_SYSTEM_CONTEXT_X64 *Regs, - SEV_ES_INSTRUCTION_DATA *InstructionData - ); - -// -// SEV-SNP Cpuid table entry/function -// -typedef PACKED struct { - UINT32 EaxIn; - UINT32 EcxIn; - UINT64 Unused; - UINT64 Unused2; - UINT32 Eax; - UINT32 Ebx; - UINT32 Ecx; - UINT32 Edx; - UINT64 Reserved; -} SEV_SNP_CPUID_FUNCTION; - -// -// SEV-SNP Cpuid page format -// -typedef PACKED struct { - UINT32 Count; - UINT32 Reserved1; - UINT64 Reserved2; - SEV_SNP_CPUID_FUNCTION function[0]; -} SEV_SNP_CPUID_INFO; - -/** - Return a pointer to the contents of the specified register. - - Based upon the input register, return a pointer to the registers contents - in the x86 processor context. - - @param[in] Regs x64 processor context - @param[in] Register Register to obtain pointer for - - @return Pointer to the contents of the requested register - -**/ -STATIC -UINT64 * -GetRegisterPointer ( - IN EFI_SYSTEM_CONTEXT_X64 *Regs, - IN UINT8 Register - ) -{ - UINT64 *Reg; - - switch (Register) { - case 0: - Reg = &Regs->Rax; - break; - case 1: - Reg = &Regs->Rcx; - break; - case 2: - Reg = &Regs->Rdx; - break; - case 3: - Reg = &Regs->Rbx; - break; - case 4: - Reg = &Regs->Rsp; - break; - case 5: - Reg = &Regs->Rbp; - break; - case 6: - Reg = &Regs->Rsi; - break; - case 7: - Reg = &Regs->Rdi; - break; - case 8: - Reg = &Regs->R8; - break; - case 9: - Reg = &Regs->R9; - break; - case 10: - Reg = &Regs->R10; - break; - case 11: - Reg = &Regs->R11; - break; - case 12: - Reg = &Regs->R12; - break; - case 13: - Reg = &Regs->R13; - break; - case 14: - Reg = &Regs->R14; - break; - case 15: - Reg = &Regs->R15; - break; - default: - Reg = NULL; - } - - ASSERT (Reg != NULL); - - return Reg; -} - -/** - Update the instruction parsing context for displacement bytes. - - @param[in, out] InstructionData Instruction parsing context - @param[in] Size The instruction displacement size - -**/ -STATIC -VOID -UpdateForDisplacement ( - IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData, - IN UINTN Size - ) -{ - InstructionData->DisplacementSize = Size; - InstructionData->Immediate += Size; - InstructionData->End += Size; -} - -/** - Determine if an instruction address if RIP relative. - - Examine the instruction parsing context to determine if the address offset - is relative to the instruction pointer. - - @param[in] InstructionData Instruction parsing context - - @retval TRUE Instruction addressing is RIP relative - @retval FALSE Instruction addressing is not RIP relative - -**/ -STATIC -BOOLEAN -IsRipRelative ( - IN SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - SEV_ES_INSTRUCTION_OPCODE_EXT *Ext; - - Ext = &InstructionData->Ext; - - return ((InstructionData->Mode == LongMode64Bit) && - (Ext->ModRm.Mod == 0) && - (Ext->ModRm.Rm == 5) && - (InstructionData->SibPresent == FALSE)); -} - -/** - Return the effective address of a memory operand. - - Examine the instruction parsing context to obtain the effective memory - address of a memory operand. - - @param[in] Regs x64 processor context - @param[in] InstructionData Instruction parsing context - - @return The memory operand effective address - -**/ -STATIC -UINT64 -GetEffectiveMemoryAddress ( - IN EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - SEV_ES_INSTRUCTION_OPCODE_EXT *Ext; - UINT64 EffectiveAddress; - - Ext = &InstructionData->Ext; - EffectiveAddress = 0; - - if (IsRipRelative (InstructionData)) { - // - // RIP-relative displacement is a 32-bit signed value - // - INT32 RipRelative; - - RipRelative = *(INT32 *)InstructionData->Displacement; - - UpdateForDisplacement (InstructionData, 4); - - // - // Negative displacement is handled by standard UINT64 wrap-around. - // - return Regs->Rip + (UINT64)RipRelative; - } - - switch (Ext->ModRm.Mod) { - case 1: - UpdateForDisplacement (InstructionData, 1); - EffectiveAddress += (UINT64)(*(INT8 *)(InstructionData->Displacement)); - break; - case 2: - switch (InstructionData->AddrSize) { - case Size16Bits: - UpdateForDisplacement (InstructionData, 2); - EffectiveAddress += (UINT64)(*(INT16 *)(InstructionData->Displacement)); - break; - default: - UpdateForDisplacement (InstructionData, 4); - EffectiveAddress += (UINT64)(*(INT32 *)(InstructionData->Displacement)); - break; - } - - break; - } - - if (InstructionData->SibPresent) { - INT64 Displacement; - - if (Ext->Sib.Index != 4) { - CopyMem ( - &Displacement, - GetRegisterPointer (Regs, Ext->Sib.Index), - sizeof (Displacement) - ); - Displacement *= (INT64)(1 << Ext->Sib.Scale); - - // - // Negative displacement is handled by standard UINT64 wrap-around. - // - EffectiveAddress += (UINT64)Displacement; - } - - if ((Ext->Sib.Base != 5) || Ext->ModRm.Mod) { - EffectiveAddress += *GetRegisterPointer (Regs, Ext->Sib.Base); - } else { - UpdateForDisplacement (InstructionData, 4); - EffectiveAddress += (UINT64)(*(INT32 *)(InstructionData->Displacement)); - } - } else { - EffectiveAddress += *GetRegisterPointer (Regs, Ext->ModRm.Rm); - } - - return EffectiveAddress; -} - -/** - Decode a ModRM byte. - - Examine the instruction parsing context to decode a ModRM byte and the SIB - byte, if present. - - @param[in] Regs x64 processor context - @param[in, out] InstructionData Instruction parsing context - -**/ -STATIC -VOID -DecodeModRm ( - IN EFI_SYSTEM_CONTEXT_X64 *Regs, - IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - SEV_ES_INSTRUCTION_OPCODE_EXT *Ext; - INSTRUCTION_REX_PREFIX *RexPrefix; - INSTRUCTION_MODRM *ModRm; - INSTRUCTION_SIB *Sib; - - RexPrefix = &InstructionData->RexPrefix; - Ext = &InstructionData->Ext; - ModRm = &InstructionData->ModRm; - Sib = &InstructionData->Sib; - - InstructionData->ModRmPresent = TRUE; - ModRm->Uint8 = *(InstructionData->End); - - InstructionData->Displacement++; - InstructionData->Immediate++; - InstructionData->End++; - - Ext->ModRm.Mod = ModRm->Bits.Mod; - Ext->ModRm.Reg = (RexPrefix->Bits.BitR << 3) | ModRm->Bits.Reg; - Ext->ModRm.Rm = (RexPrefix->Bits.BitB << 3) | ModRm->Bits.Rm; - - Ext->RegData = *GetRegisterPointer (Regs, Ext->ModRm.Reg); - - if (Ext->ModRm.Mod == 3) { - Ext->RmData = *GetRegisterPointer (Regs, Ext->ModRm.Rm); - } else { - if (ModRm->Bits.Rm == 4) { - InstructionData->SibPresent = TRUE; - Sib->Uint8 = *(InstructionData->End); - - InstructionData->Displacement++; - InstructionData->Immediate++; - InstructionData->End++; - - Ext->Sib.Scale = Sib->Bits.Scale; - Ext->Sib.Index = (RexPrefix->Bits.BitX << 3) | Sib->Bits.Index; - Ext->Sib.Base = (RexPrefix->Bits.BitB << 3) | Sib->Bits.Base; - } - - Ext->RmData = GetEffectiveMemoryAddress (Regs, InstructionData); - } -} - -/** - Decode instruction prefixes. - - Parse the instruction data to track the instruction prefixes that have - been used. - - @param[in] Regs x64 processor context - @param[in, out] InstructionData Instruction parsing context - -**/ -STATIC -VOID -DecodePrefixes ( - IN EFI_SYSTEM_CONTEXT_X64 *Regs, - IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - SEV_ES_INSTRUCTION_MODE Mode; - SEV_ES_INSTRUCTION_SIZE ModeDataSize; - SEV_ES_INSTRUCTION_SIZE ModeAddrSize; - UINT8 *Byte; - - // - // Always in 64-bit mode - // - Mode = LongMode64Bit; - ModeDataSize = Size32Bits; - ModeAddrSize = Size64Bits; - - InstructionData->Mode = Mode; - InstructionData->DataSize = ModeDataSize; - InstructionData->AddrSize = ModeAddrSize; - - InstructionData->Prefixes = InstructionData->Begin; - - Byte = InstructionData->Prefixes; - for ( ; ; Byte++, InstructionData->PrefixSize++) { - // - // Check the 0x40 to 0x4F range using an if statement here since some - // compilers don't like the "case 0x40 ... 0x4F:" syntax. This avoids - // 16 case statements below. - // - if ((*Byte >= REX_PREFIX_START) && (*Byte <= REX_PREFIX_STOP)) { - InstructionData->RexPrefix.Uint8 = *Byte; - if ((*Byte & REX_64BIT_OPERAND_SIZE_MASK) != 0) { - InstructionData->DataSize = Size64Bits; - } - - continue; - } - - switch (*Byte) { - case OVERRIDE_SEGMENT_CS: - case OVERRIDE_SEGMENT_DS: - case OVERRIDE_SEGMENT_ES: - case OVERRIDE_SEGMENT_SS: - if (Mode != LongMode64Bit) { - InstructionData->SegmentSpecified = TRUE; - InstructionData->Segment = (*Byte >> 3) & 3; - } - - break; - - case OVERRIDE_SEGMENT_FS: - case OVERRIDE_SEGMENT_GS: - InstructionData->SegmentSpecified = TRUE; - InstructionData->Segment = *Byte & 7; - break; - - case OVERRIDE_OPERAND_SIZE: - if (InstructionData->RexPrefix.Uint8 == 0) { - InstructionData->DataSize = - (Mode == LongMode64Bit) ? Size16Bits : - (Mode == LongModeCompat32Bit) ? Size16Bits : - (Mode == LongModeCompat16Bit) ? Size32Bits : 0; - } - - break; - - case OVERRIDE_ADDRESS_SIZE: - InstructionData->AddrSize = - (Mode == LongMode64Bit) ? Size32Bits : - (Mode == LongModeCompat32Bit) ? Size16Bits : - (Mode == LongModeCompat16Bit) ? Size32Bits : 0; - break; - - case LOCK_PREFIX: - break; - - case REPZ_PREFIX: - InstructionData->RepMode = RepZ; - break; - - case REPNZ_PREFIX: - InstructionData->RepMode = RepNZ; - break; - - default: - InstructionData->OpCodes = Byte; - InstructionData->OpCodeSize = (*Byte == TWO_BYTE_OPCODE_ESCAPE) ? 2 : 1; - - InstructionData->End = Byte + InstructionData->OpCodeSize; - InstructionData->Displacement = InstructionData->End; - InstructionData->Immediate = InstructionData->End; - return; - } - } -} - -/** - Determine instruction length - - Return the total length of the parsed instruction. - - @param[in] InstructionData Instruction parsing context - - @return Length of parsed instruction - -**/ -STATIC -UINT64 -InstructionLength ( - IN SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - return (UINT64)(InstructionData->End - InstructionData->Begin); -} - -/** - Initialize the instruction parsing context. - - Initialize the instruction parsing context, which includes decoding the - instruction prefixes. - - @param[in, out] InstructionData Instruction parsing context - @param[in] Ghcb Pointer to the Guest-Hypervisor Communication - Block - @param[in] Regs x64 processor context - -**/ -STATIC -VOID -InitInstructionData ( - IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData, - IN GHCB *Ghcb, - IN EFI_SYSTEM_CONTEXT_X64 *Regs - ) -{ - SetMem (InstructionData, sizeof (*InstructionData), 0); - InstructionData->Ghcb = Ghcb; - InstructionData->Begin = (UINT8 *)Regs->Rip; - InstructionData->End = (UINT8 *)Regs->Rip; - - DecodePrefixes (Regs, InstructionData); -} - -/** - Report an unsupported event to the hypervisor - - Use the VMGEXIT support to report an unsupported event to the hypervisor. - - @param[in] Ghcb Pointer to the Guest-Hypervisor Communication - Block - @param[in] Regs x64 processor context - @param[in] InstructionData Instruction parsing context - - @return New exception value to propagate - -**/ -STATIC -UINT64 -UnsupportedExit ( - IN GHCB *Ghcb, - IN EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - UINT64 Status; - - Status = VmgExit (Ghcb, SVM_EXIT_UNSUPPORTED, Regs->ExceptionData, 0); - if (Status == 0) { - GHCB_EVENT_INJECTION Event; - - Event.Uint64 = 0; - Event.Elements.Vector = GP_EXCEPTION; - Event.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION; - Event.Elements.Valid = 1; - - Status = Event.Uint64; - } - - return Status; -} - -/** - Validate that the MMIO memory access is not to encrypted memory. - - Examine the pagetable entry for the memory specified. MMIO should not be - performed against encrypted memory. MMIO to the APIC page is always allowed. - - @param[in] Ghcb Pointer to the Guest-Hypervisor Communication Block - @param[in] MemoryAddress Memory address to validate - @param[in] MemoryLength Memory length to validate - - @retval 0 Memory is not encrypted - @return New exception value to propogate - -**/ -STATIC -UINT64 -ValidateMmioMemory ( - IN GHCB *Ghcb, - IN UINTN MemoryAddress, - IN UINTN MemoryLength - ) -{ - MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE State; - GHCB_EVENT_INJECTION GpEvent; - UINTN Address; - - // - // Allow APIC accesses (which will have the encryption bit set during - // SEC and PEI phases). - // - Address = MemoryAddress & ~(SIZE_4KB - 1); - if (Address == GetLocalApicBaseAddress ()) { - return 0; - } - - State = MemEncryptSevGetAddressRangeState ( - 0, - MemoryAddress, - MemoryLength - ); - if (State == MemEncryptSevAddressRangeUnencrypted) { - return 0; - } - - // - // Any state other than unencrypted is an error, issue a #GP. - // - DEBUG (( - DEBUG_ERROR, - "MMIO using encrypted memory: %lx\n", - (UINT64)MemoryAddress - )); - GpEvent.Uint64 = 0; - GpEvent.Elements.Vector = GP_EXCEPTION; - GpEvent.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION; - GpEvent.Elements.Valid = 1; - - return GpEvent.Uint64; -} - -/** - Handle an MMIO event. - - Use the VMGEXIT instruction to handle either an MMIO read or an MMIO write. - - @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication - Block - @param[in, out] Regs x64 processor context - @param[in, out] InstructionData Instruction parsing context - - @retval 0 Event handled successfully - @return New exception value to propagate - -**/ -STATIC -UINT64 -MmioExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - UINT64 ExitInfo1, ExitInfo2, Status; - UINTN Bytes; - UINT64 *Register; - UINT8 OpCode, SignByte; - UINTN Address; - - Bytes = 0; - - OpCode = *(InstructionData->OpCodes); - if (OpCode == TWO_BYTE_OPCODE_ESCAPE) { - OpCode = *(InstructionData->OpCodes + 1); - } - - switch (OpCode) { - // - // MMIO write (MOV reg/memX, regX) - // - case 0x88: - Bytes = 1; - // - // fall through - // - case 0x89: - DecodeModRm (Regs, InstructionData); - Bytes = ((Bytes != 0) ? Bytes : - (InstructionData->DataSize == Size16Bits) ? 2 : - (InstructionData->DataSize == Size32Bits) ? 4 : - (InstructionData->DataSize == Size64Bits) ? 8 : - 0); - - if (InstructionData->Ext.ModRm.Mod == 3) { - // - // NPF on two register operands??? - // - return UnsupportedExit (Ghcb, Regs, InstructionData); - } - - Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes); - if (Status != 0) { - return Status; - } - - ExitInfo1 = InstructionData->Ext.RmData; - ExitInfo2 = Bytes; - CopyMem (Ghcb->SharedBuffer, &InstructionData->Ext.RegData, Bytes); - - Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer; - VmgSetOffsetValid (Ghcb, GhcbSwScratch); - Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2); - if (Status != 0) { - return Status; - } - - break; - - // - // MMIO write (MOV moffsetX, aX) - // - case 0xA2: - Bytes = 1; - // - // fall through - // - case 0xA3: - Bytes = ((Bytes != 0) ? Bytes : - (InstructionData->DataSize == Size16Bits) ? 2 : - (InstructionData->DataSize == Size32Bits) ? 4 : - (InstructionData->DataSize == Size64Bits) ? 8 : - 0); - - InstructionData->ImmediateSize = (UINTN)(1 << InstructionData->AddrSize); - InstructionData->End += InstructionData->ImmediateSize; - - // - // This code is X64 only, so a possible 8-byte copy to a UINTN is ok. - // Use a STATIC_ASSERT to be certain the code is being built as X64. - // - STATIC_ASSERT ( - sizeof (UINTN) == sizeof (UINT64), - "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64" - ); - - Address = 0; - CopyMem ( - &Address, - InstructionData->Immediate, - InstructionData->ImmediateSize - ); - - Status = ValidateMmioMemory (Ghcb, Address, Bytes); - if (Status != 0) { - return Status; - } - - ExitInfo1 = Address; - ExitInfo2 = Bytes; - CopyMem (Ghcb->SharedBuffer, &Regs->Rax, Bytes); - - Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer; - VmgSetOffsetValid (Ghcb, GhcbSwScratch); - Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2); - if (Status != 0) { - return Status; - } - - break; - - // - // MMIO write (MOV reg/memX, immX) - // - case 0xC6: - Bytes = 1; - // - // fall through - // - case 0xC7: - DecodeModRm (Regs, InstructionData); - Bytes = ((Bytes != 0) ? Bytes : - (InstructionData->DataSize == Size16Bits) ? 2 : - (InstructionData->DataSize == Size32Bits) ? 4 : - 0); - - InstructionData->ImmediateSize = Bytes; - InstructionData->End += Bytes; - - Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes); - if (Status != 0) { - return Status; - } - - ExitInfo1 = InstructionData->Ext.RmData; - ExitInfo2 = Bytes; - CopyMem (Ghcb->SharedBuffer, InstructionData->Immediate, Bytes); - - Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer; - VmgSetOffsetValid (Ghcb, GhcbSwScratch); - Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2); - if (Status != 0) { - return Status; - } - - break; - - // - // MMIO read (MOV regX, reg/memX) - // - case 0x8A: - Bytes = 1; - // - // fall through - // - case 0x8B: - DecodeModRm (Regs, InstructionData); - Bytes = ((Bytes != 0) ? Bytes : - (InstructionData->DataSize == Size16Bits) ? 2 : - (InstructionData->DataSize == Size32Bits) ? 4 : - (InstructionData->DataSize == Size64Bits) ? 8 : - 0); - if (InstructionData->Ext.ModRm.Mod == 3) { - // - // NPF on two register operands??? - // - return UnsupportedExit (Ghcb, Regs, InstructionData); - } - - Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes); - if (Status != 0) { - return Status; - } - - ExitInfo1 = InstructionData->Ext.RmData; - ExitInfo2 = Bytes; - - Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer; - VmgSetOffsetValid (Ghcb, GhcbSwScratch); - Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2); - if (Status != 0) { - return Status; - } - - Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg); - if (Bytes == 4) { - // - // Zero-extend for 32-bit operation - // - *Register = 0; - } - - CopyMem (Register, Ghcb->SharedBuffer, Bytes); - break; - - // - // MMIO read (MOV aX, moffsetX) - // - case 0xA0: - Bytes = 1; - // - // fall through - // - case 0xA1: - Bytes = ((Bytes != 0) ? Bytes : - (InstructionData->DataSize == Size16Bits) ? 2 : - (InstructionData->DataSize == Size32Bits) ? 4 : - (InstructionData->DataSize == Size64Bits) ? 8 : - 0); - - InstructionData->ImmediateSize = (UINTN)(1 << InstructionData->AddrSize); - InstructionData->End += InstructionData->ImmediateSize; - - // - // This code is X64 only, so a possible 8-byte copy to a UINTN is ok. - // Use a STATIC_ASSERT to be certain the code is being built as X64. - // - STATIC_ASSERT ( - sizeof (UINTN) == sizeof (UINT64), - "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64" - ); - - Address = 0; - CopyMem ( - &Address, - InstructionData->Immediate, - InstructionData->ImmediateSize - ); - - Status = ValidateMmioMemory (Ghcb, Address, Bytes); - if (Status != 0) { - return Status; - } - - ExitInfo1 = Address; - ExitInfo2 = Bytes; - - Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer; - VmgSetOffsetValid (Ghcb, GhcbSwScratch); - Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2); - if (Status != 0) { - return Status; - } - - if (Bytes == 4) { - // - // Zero-extend for 32-bit operation - // - Regs->Rax = 0; - } - - CopyMem (&Regs->Rax, Ghcb->SharedBuffer, Bytes); - break; - - // - // MMIO read w/ zero-extension ((MOVZX regX, reg/memX) - // - case 0xB6: - Bytes = 1; - // - // fall through - // - case 0xB7: - DecodeModRm (Regs, InstructionData); - Bytes = (Bytes != 0) ? Bytes : 2; - - Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes); - if (Status != 0) { - return Status; - } - - ExitInfo1 = InstructionData->Ext.RmData; - ExitInfo2 = Bytes; - - Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer; - VmgSetOffsetValid (Ghcb, GhcbSwScratch); - Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2); - if (Status != 0) { - return Status; - } - - Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg); - SetMem (Register, (UINTN)(1 << InstructionData->DataSize), 0); - CopyMem (Register, Ghcb->SharedBuffer, Bytes); - break; - - // - // MMIO read w/ sign-extension (MOVSX regX, reg/memX) - // - case 0xBE: - Bytes = 1; - // - // fall through - // - case 0xBF: - DecodeModRm (Regs, InstructionData); - Bytes = (Bytes != 0) ? Bytes : 2; - - Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes); - if (Status != 0) { - return Status; - } - - ExitInfo1 = InstructionData->Ext.RmData; - ExitInfo2 = Bytes; - - Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer; - VmgSetOffsetValid (Ghcb, GhcbSwScratch); - Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2); - if (Status != 0) { - return Status; - } - - if (Bytes == 1) { - UINT8 *Data; - - Data = (UINT8 *)Ghcb->SharedBuffer; - SignByte = ((*Data & BIT7) != 0) ? 0xFF : 0x00; - } else { - UINT16 *Data; - - Data = (UINT16 *)Ghcb->SharedBuffer; - SignByte = ((*Data & BIT15) != 0) ? 0xFF : 0x00; - } - - Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg); - SetMem (Register, (UINTN)(1 << InstructionData->DataSize), SignByte); - CopyMem (Register, Ghcb->SharedBuffer, Bytes); - break; - - default: - DEBUG ((DEBUG_ERROR, "Invalid MMIO opcode (%x)\n", OpCode)); - Status = GP_EXCEPTION; - ASSERT (FALSE); - } - - return Status; -} - -/** - Handle a MWAIT event. - - Use the VMGEXIT instruction to handle a MWAIT event. - - @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication - Block - @param[in, out] Regs x64 processor context - @param[in] InstructionData Instruction parsing context - - @retval 0 Event handled successfully - @return New exception value to propagate - -**/ -STATIC -UINT64 -MwaitExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - DecodeModRm (Regs, InstructionData); - - Ghcb->SaveArea.Rax = Regs->Rax; - VmgSetOffsetValid (Ghcb, GhcbRax); - Ghcb->SaveArea.Rcx = Regs->Rcx; - VmgSetOffsetValid (Ghcb, GhcbRcx); - - return VmgExit (Ghcb, SVM_EXIT_MWAIT, 0, 0); -} - -/** - Handle a MONITOR event. - - Use the VMGEXIT instruction to handle a MONITOR event. - - @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication - Block - @param[in, out] Regs x64 processor context - @param[in] InstructionData Instruction parsing context - - @retval 0 Event handled successfully - @return New exception value to propagate - -**/ -STATIC -UINT64 -MonitorExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - DecodeModRm (Regs, InstructionData); - - Ghcb->SaveArea.Rax = Regs->Rax; // Identity mapped, so VA = PA - VmgSetOffsetValid (Ghcb, GhcbRax); - Ghcb->SaveArea.Rcx = Regs->Rcx; - VmgSetOffsetValid (Ghcb, GhcbRcx); - Ghcb->SaveArea.Rdx = Regs->Rdx; - VmgSetOffsetValid (Ghcb, GhcbRdx); - - return VmgExit (Ghcb, SVM_EXIT_MONITOR, 0, 0); -} - -/** - Handle a WBINVD event. - - Use the VMGEXIT instruction to handle a WBINVD event. - - @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication - Block - @param[in, out] Regs x64 processor context - @param[in] InstructionData Instruction parsing context - - @retval 0 Event handled successfully - @return New exception value to propagate - -**/ -STATIC -UINT64 -WbinvdExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - return VmgExit (Ghcb, SVM_EXIT_WBINVD, 0, 0); -} - -/** - Handle a RDTSCP event. - - Use the VMGEXIT instruction to handle a RDTSCP event. - - @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication - Block - @param[in, out] Regs x64 processor context - @param[in] InstructionData Instruction parsing context - - @retval 0 Event handled successfully - @return New exception value to propagate - -**/ -STATIC -UINT64 -RdtscpExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - UINT64 Status; - - DecodeModRm (Regs, InstructionData); - - Status = VmgExit (Ghcb, SVM_EXIT_RDTSCP, 0, 0); - if (Status != 0) { - return Status; - } - - if (!VmgIsOffsetValid (Ghcb, GhcbRax) || - !VmgIsOffsetValid (Ghcb, GhcbRcx) || - !VmgIsOffsetValid (Ghcb, GhcbRdx)) - { - return UnsupportedExit (Ghcb, Regs, InstructionData); - } - - Regs->Rax = Ghcb->SaveArea.Rax; - Regs->Rcx = Ghcb->SaveArea.Rcx; - Regs->Rdx = Ghcb->SaveArea.Rdx; - - return 0; -} - -/** - Handle a VMMCALL event. - - Use the VMGEXIT instruction to handle a VMMCALL event. - - @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication - Block - @param[in, out] Regs x64 processor context - @param[in] InstructionData Instruction parsing context - - @retval 0 Event handled successfully - @return New exception value to propagate - -**/ -STATIC -UINT64 -VmmCallExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - UINT64 Status; - - DecodeModRm (Regs, InstructionData); - - Ghcb->SaveArea.Rax = Regs->Rax; - VmgSetOffsetValid (Ghcb, GhcbRax); - Ghcb->SaveArea.Cpl = (UINT8)(Regs->Cs & 0x3); - VmgSetOffsetValid (Ghcb, GhcbCpl); - - Status = VmgExit (Ghcb, SVM_EXIT_VMMCALL, 0, 0); - if (Status != 0) { - return Status; - } - - if (!VmgIsOffsetValid (Ghcb, GhcbRax)) { - return UnsupportedExit (Ghcb, Regs, InstructionData); - } - - Regs->Rax = Ghcb->SaveArea.Rax; - - return 0; -} - -/** - Handle an MSR event. - - Use the VMGEXIT instruction to handle either a RDMSR or WRMSR event. - - @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication - Block - @param[in, out] Regs x64 processor context - @param[in] InstructionData Instruction parsing context - - @retval 0 Event handled successfully - @return New exception value to propagate - -**/ -STATIC -UINT64 -MsrExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - UINT64 ExitInfo1, Status; - - ExitInfo1 = 0; - - switch (*(InstructionData->OpCodes + 1)) { - case 0x30: // WRMSR - ExitInfo1 = 1; - Ghcb->SaveArea.Rax = Regs->Rax; - VmgSetOffsetValid (Ghcb, GhcbRax); - Ghcb->SaveArea.Rdx = Regs->Rdx; - VmgSetOffsetValid (Ghcb, GhcbRdx); - // - // fall through - // - case 0x32: // RDMSR - Ghcb->SaveArea.Rcx = Regs->Rcx; - VmgSetOffsetValid (Ghcb, GhcbRcx); - break; - default: - return UnsupportedExit (Ghcb, Regs, InstructionData); - } - - Status = VmgExit (Ghcb, SVM_EXIT_MSR, ExitInfo1, 0); - if (Status != 0) { - return Status; - } - - if (ExitInfo1 == 0) { - if (!VmgIsOffsetValid (Ghcb, GhcbRax) || - !VmgIsOffsetValid (Ghcb, GhcbRdx)) - { - return UnsupportedExit (Ghcb, Regs, InstructionData); - } - - Regs->Rax = Ghcb->SaveArea.Rax; - Regs->Rdx = Ghcb->SaveArea.Rdx; - } - - return 0; -} - -/** - Build the IOIO event information. - - The IOIO event information identifies the type of IO operation to be performed - by the hypervisor. Build this information based on the instruction data. - - @param[in] Regs x64 processor context - @param[in, out] InstructionData Instruction parsing context - - @return IOIO event information value - -**/ -STATIC -UINT64 -IoioExitInfo ( - IN EFI_SYSTEM_CONTEXT_X64 *Regs, - IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - UINT64 ExitInfo; - - ExitInfo = 0; - - switch (*(InstructionData->OpCodes)) { - // - // INS opcodes - // - case 0x6C: - case 0x6D: - ExitInfo |= IOIO_TYPE_INS; - ExitInfo |= IOIO_SEG_ES; - ExitInfo |= ((Regs->Rdx & 0xffff) << 16); - break; - - // - // OUTS opcodes - // - case 0x6E: - case 0x6F: - ExitInfo |= IOIO_TYPE_OUTS; - ExitInfo |= IOIO_SEG_DS; - ExitInfo |= ((Regs->Rdx & 0xffff) << 16); - break; - - // - // IN immediate opcodes - // - case 0xE4: - case 0xE5: - InstructionData->ImmediateSize = 1; - InstructionData->End++; - ExitInfo |= IOIO_TYPE_IN; - ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16); - break; - - // - // OUT immediate opcodes - // - case 0xE6: - case 0xE7: - InstructionData->ImmediateSize = 1; - InstructionData->End++; - ExitInfo |= IOIO_TYPE_OUT; - ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16) | IOIO_TYPE_OUT; - break; - - // - // IN register opcodes - // - case 0xEC: - case 0xED: - ExitInfo |= IOIO_TYPE_IN; - ExitInfo |= ((Regs->Rdx & 0xffff) << 16); - break; - - // - // OUT register opcodes - // - case 0xEE: - case 0xEF: - ExitInfo |= IOIO_TYPE_OUT; - ExitInfo |= ((Regs->Rdx & 0xffff) << 16); - break; - - default: - return 0; - } - - switch (*(InstructionData->OpCodes)) { - // - // Single-byte opcodes - // - case 0x6C: - case 0x6E: - case 0xE4: - case 0xE6: - case 0xEC: - case 0xEE: - ExitInfo |= IOIO_DATA_8; - break; - - // - // Length determined by instruction parsing - // - default: - ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16 - : IOIO_DATA_32; - } - - switch (InstructionData->AddrSize) { - case Size16Bits: - ExitInfo |= IOIO_ADDR_16; - break; - - case Size32Bits: - ExitInfo |= IOIO_ADDR_32; - break; - - case Size64Bits: - ExitInfo |= IOIO_ADDR_64; - break; - - default: - break; - } - - if (InstructionData->RepMode != 0) { - ExitInfo |= IOIO_REP; - } - - return ExitInfo; -} - -/** - Handle an IOIO event. - - Use the VMGEXIT instruction to handle an IOIO event. - - @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication - Block - @param[in, out] Regs x64 processor context - @param[in] InstructionData Instruction parsing context - - @retval 0 Event handled successfully - @return New exception value to propagate - -**/ -STATIC -UINT64 -IoioExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - UINT64 ExitInfo1, ExitInfo2, Status; - BOOLEAN IsString; - - ExitInfo1 = IoioExitInfo (Regs, InstructionData); - if (ExitInfo1 == 0) { - return UnsupportedExit (Ghcb, Regs, InstructionData); - } - - IsString = ((ExitInfo1 & IOIO_TYPE_STR) != 0) ? TRUE : FALSE; - if (IsString) { - UINTN IoBytes, VmgExitBytes; - UINTN GhcbCount, OpCount; - - Status = 0; - - IoBytes = IOIO_DATA_BYTES (ExitInfo1); - GhcbCount = sizeof (Ghcb->SharedBuffer) / IoBytes; - - OpCount = ((ExitInfo1 & IOIO_REP) != 0) ? Regs->Rcx : 1; - while (OpCount != 0) { - ExitInfo2 = MIN (OpCount, GhcbCount); - VmgExitBytes = ExitInfo2 * IoBytes; - - if ((ExitInfo1 & IOIO_TYPE_IN) == 0) { - CopyMem (Ghcb->SharedBuffer, (VOID *)Regs->Rsi, VmgExitBytes); - Regs->Rsi += VmgExitBytes; - } - - Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer; - VmgSetOffsetValid (Ghcb, GhcbSwScratch); - Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, ExitInfo2); - if (Status != 0) { - return Status; - } - - if ((ExitInfo1 & IOIO_TYPE_IN) != 0) { - CopyMem ((VOID *)Regs->Rdi, Ghcb->SharedBuffer, VmgExitBytes); - Regs->Rdi += VmgExitBytes; - } - - if ((ExitInfo1 & IOIO_REP) != 0) { - Regs->Rcx -= ExitInfo2; - } - - OpCount -= ExitInfo2; - } - } else { - if ((ExitInfo1 & IOIO_TYPE_IN) != 0) { - Ghcb->SaveArea.Rax = 0; - } else { - CopyMem (&Ghcb->SaveArea.Rax, &Regs->Rax, IOIO_DATA_BYTES (ExitInfo1)); - } - - VmgSetOffsetValid (Ghcb, GhcbRax); - - Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, 0); - if (Status != 0) { - return Status; - } - - if ((ExitInfo1 & IOIO_TYPE_IN) != 0) { - if (!VmgIsOffsetValid (Ghcb, GhcbRax)) { - return UnsupportedExit (Ghcb, Regs, InstructionData); - } - - CopyMem (&Regs->Rax, &Ghcb->SaveArea.Rax, IOIO_DATA_BYTES (ExitInfo1)); - } - } - - return 0; -} - -/** - Handle a INVD event. - - Use the VMGEXIT instruction to handle a INVD event. - - @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication - Block - @param[in, out] Regs x64 processor context - @param[in] InstructionData Instruction parsing context - - @retval 0 Event handled successfully - @return New exception value to propagate - -**/ -STATIC -UINT64 -InvdExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - return VmgExit (Ghcb, SVM_EXIT_INVD, 0, 0); -} - -/** - Fetch CPUID leaf/function via hypervisor/VMGEXIT. - - @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication - Block - @param[in] EaxIn EAX input for cpuid instruction - @param[in] EcxIn ECX input for cpuid instruction - @param[in] Xcr0In XCR0 at time of cpuid instruction - @param[in, out] Eax Pointer to store leaf's EAX value - @param[in, out] Ebx Pointer to store leaf's EBX value - @param[in, out] Ecx Pointer to store leaf's ECX value - @param[in, out] Edx Pointer to store leaf's EDX value - @param[in, out] Status Pointer to store status from VMGEXIT (always 0 - unless return value indicates failure) - @param[in, out] Unsupported Pointer to store indication of unsupported - VMGEXIT (always false unless return value - indicates failure) - - @retval TRUE CPUID leaf fetch successfully. - @retval FALSE Error occurred while fetching CPUID leaf. Callers - should Status and Unsupported and handle - accordingly if they indicate a more precise - error condition. - -**/ -STATIC -BOOLEAN -GetCpuidHyp ( - IN OUT GHCB *Ghcb, - IN UINT32 EaxIn, - IN UINT32 EcxIn, - IN UINT64 XCr0, - IN OUT UINT32 *Eax, - IN OUT UINT32 *Ebx, - IN OUT UINT32 *Ecx, - IN OUT UINT32 *Edx, - IN OUT UINT64 *Status, - IN OUT BOOLEAN *UnsupportedExit - ) -{ - *UnsupportedExit = FALSE; - Ghcb->SaveArea.Rax = EaxIn; - VmgSetOffsetValid (Ghcb, GhcbRax); - Ghcb->SaveArea.Rcx = EcxIn; - VmgSetOffsetValid (Ghcb, GhcbRcx); - if (EaxIn == CPUID_EXTENDED_STATE) { - Ghcb->SaveArea.XCr0 = XCr0; - VmgSetOffsetValid (Ghcb, GhcbXCr0); - } - - *Status = VmgExit (Ghcb, SVM_EXIT_CPUID, 0, 0); - if (*Status != 0) { - return FALSE; - } - - if (!VmgIsOffsetValid (Ghcb, GhcbRax) || - !VmgIsOffsetValid (Ghcb, GhcbRbx) || - !VmgIsOffsetValid (Ghcb, GhcbRcx) || - !VmgIsOffsetValid (Ghcb, GhcbRdx)) - { - *UnsupportedExit = TRUE; - return FALSE; - } - - if (Eax) { - *Eax = (UINT32)(UINTN)Ghcb->SaveArea.Rax; - } - - if (Ebx) { - *Ebx = (UINT32)(UINTN)Ghcb->SaveArea.Rbx; - } - - if (Ecx) { - *Ecx = (UINT32)(UINTN)Ghcb->SaveArea.Rcx; - } - - if (Edx) { - *Edx = (UINT32)(UINTN)Ghcb->SaveArea.Rdx; - } - - return TRUE; -} - -/** - Check if SEV-SNP enabled. - - @retval TRUE SEV-SNP is enabled. - @retval FALSE SEV-SNP is disabled. - -**/ -STATIC -BOOLEAN -SnpEnabled ( - VOID - ) -{ - MSR_SEV_STATUS_REGISTER Msr; - - Msr.Uint32 = AsmReadMsr32 (MSR_SEV_STATUS); - - return !!Msr.Bits.SevSnpBit; -} - -/** - Calculate the total XSAVE area size for enabled XSAVE areas - - @param[in] XFeaturesEnabled Bit-mask of enabled XSAVE features/areas as - indicated by XCR0/MSR_IA32_XSS bits - @param[in] XSaveBaseSize Base/legacy XSAVE area size (e.g. when - XCR0 is 1) - @param[in, out] XSaveSize Pointer to storage for calculated XSAVE area - size - @param[in] Compacted Whether or not the calculation is for the - normal XSAVE area size (leaf 0xD,0x0,EBX) or - compacted XSAVE area size (leaf 0xD,0x1,EBX) - - - @retval TRUE XSAVE size calculation was successful. - @retval FALSE XSAVE size calculation was unsuccessful. -**/ -STATIC -BOOLEAN -GetCpuidXSaveSize ( - IN UINT64 XFeaturesEnabled, - IN UINT32 XSaveBaseSize, - IN OUT UINT32 *XSaveSize, - IN BOOLEAN Compacted - ) -{ - SEV_SNP_CPUID_INFO *CpuidInfo; - UINT64 XFeaturesFound = 0; - UINT32 Idx; - - *XSaveSize = XSaveBaseSize; - CpuidInfo = (SEV_SNP_CPUID_INFO *)(UINT64)PcdGet32 (PcdOvmfCpuidBase); - - for (Idx = 0; Idx < CpuidInfo->Count; Idx++) { - SEV_SNP_CPUID_FUNCTION *CpuidFn = &CpuidInfo->function[Idx]; - - if (!((CpuidFn->EaxIn == 0xD) && - ((CpuidFn->EcxIn == 0) || (CpuidFn->EcxIn == 1)))) - { - continue; - } - - if (XFeaturesFound & (1ULL << CpuidFn->EcxIn) || - !(XFeaturesEnabled & (1ULL << CpuidFn->EcxIn))) - { - continue; - } - - XFeaturesFound |= (1ULL << CpuidFn->EcxIn); - if (Compacted) { - *XSaveSize += CpuidFn->Eax; - } else { - *XSaveSize = MAX (*XSaveSize, CpuidFn->Eax + CpuidFn->Ebx); - } - } - - /* - * Either the guest set unsupported XCR0/XSS bits, or the corresponding - * entries in the CPUID table were not present. This is an invalid state. - */ - if (XFeaturesFound != (XFeaturesEnabled & ~3UL)) { - return FALSE; - } - - return TRUE; -} - -/** - Check if a CPUID leaf/function is indexed via ECX sub-leaf/sub-function - - @param[in] EaxIn EAX input for cpuid instruction - - @retval FALSE cpuid leaf/function is not indexed by ECX input - @retval TRUE cpuid leaf/function is indexed by ECX input - -**/ -STATIC -BOOLEAN -IsFunctionIndexed ( - IN UINT32 EaxIn - ) -{ - switch (EaxIn) { - case CPUID_CACHE_PARAMS: - case CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS: - case CPUID_EXTENDED_TOPOLOGY: - case CPUID_EXTENDED_STATE: - case CPUID_INTEL_RDT_MONITORING: - case CPUID_INTEL_RDT_ALLOCATION: - case CPUID_INTEL_SGX: - case CPUID_INTEL_PROCESSOR_TRACE: - case CPUID_DETERMINISTIC_ADDRESS_TRANSLATION_PARAMETERS: - case CPUID_V2_EXTENDED_TOPOLOGY: - case 0x8000001D: /* Cache Topology Information */ - return TRUE; - } - - return FALSE; -} - -/** - Fetch CPUID leaf/function via SEV-SNP CPUID table. - - @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication - Block - @param[in] EaxIn EAX input for cpuid instruction - @param[in] EcxIn ECX input for cpuid instruction - @param[in] Xcr0In XCR0 at time of cpuid instruction - @param[in, out] Eax Pointer to store leaf's EAX value - @param[in, out] Ebx Pointer to store leaf's EBX value - @param[in, out] Ecx Pointer to store leaf's ECX value - @param[in, out] Edx Pointer to store leaf's EDX value - @param[in, out] Status Pointer to store status from VMGEXIT (always 0 - unless return value indicates failure) - @param[in, out] Unsupported Pointer to store indication of unsupported - VMGEXIT (always false unless return value - indicates failure) - - @retval TRUE CPUID leaf fetch successfully. - @retval FALSE Error occurred while fetching CPUID leaf. Callers - should Status and Unsupported and handle - accordingly if they indicate a more precise - error condition. - -**/ -STATIC -BOOLEAN -GetCpuidFw ( - IN OUT GHCB *Ghcb, - IN UINT32 EaxIn, - IN UINT32 EcxIn, - IN UINT64 XCr0, - IN OUT UINT32 *Eax, - IN OUT UINT32 *Ebx, - IN OUT UINT32 *Ecx, - IN OUT UINT32 *Edx, - IN OUT UINT64 *Status, - IN OUT BOOLEAN *Unsupported - ) -{ - SEV_SNP_CPUID_INFO *CpuidInfo; - BOOLEAN Found; - UINT32 Idx; - - CpuidInfo = (SEV_SNP_CPUID_INFO *)(UINT64)PcdGet32 (PcdOvmfCpuidBase); - Found = FALSE; - - for (Idx = 0; Idx < CpuidInfo->Count; Idx++) { - SEV_SNP_CPUID_FUNCTION *CpuidFn = &CpuidInfo->function[Idx]; - - if (CpuidFn->EaxIn != EaxIn) { - continue; - } - - if (IsFunctionIndexed (CpuidFn->EaxIn) && (CpuidFn->EcxIn != EcxIn)) { - continue; - } - - *Eax = CpuidFn->Eax; - *Ebx = CpuidFn->Ebx; - *Ecx = CpuidFn->Ecx; - *Edx = CpuidFn->Edx; - - Found = TRUE; - break; - } - - if (!Found) { - *Eax = *Ebx = *Ecx = *Edx = 0; - goto Out; - } - - if (EaxIn == CPUID_VERSION_INFO) { - IA32_CR4 Cr4; - UINT32 Ebx2; - UINT32 Edx2; - - if (!GetCpuidHyp ( - Ghcb, - EaxIn, - EcxIn, - XCr0, - NULL, - &Ebx2, - NULL, - &Edx2, - Status, - Unsupported - )) - { - return FALSE; - } - - /* initial APIC ID */ - *Ebx = (*Ebx & 0x00FFFFFF) | (Ebx2 & 0xFF000000); - /* APIC enabled bit */ - *Edx = (*Edx & ~BIT9) | (Edx2 & BIT9); - /* OSXSAVE enabled bit */ - Cr4.UintN = AsmReadCr4 (); - *Ecx = (Cr4.Bits.OSXSAVE) ? (*Ecx & ~BIT27) | (*Ecx & BIT27) - : (*Ecx & ~BIT27); - } else if (EaxIn == CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS) { - IA32_CR4 Cr4; - - Cr4.UintN = AsmReadCr4 (); - /* OSPKE enabled bit */ - *Ecx = (Cr4.Bits.PKE) ? (*Ecx | BIT4) : (*Ecx & ~BIT4); - } else if (EaxIn == CPUID_EXTENDED_TOPOLOGY) { - if (!GetCpuidHyp ( - Ghcb, - EaxIn, - EcxIn, - XCr0, - NULL, - NULL, - NULL, - Edx, - Status, - Unsupported - )) - { - return FALSE; - } - } else if ((EaxIn == CPUID_EXTENDED_STATE) && ((EcxIn == 0) || (EcxIn == 1))) { - MSR_IA32_XSS_REGISTER XssMsr; - BOOLEAN Compacted; - UINT32 XSaveSize; - - XssMsr.Uint64 = 0; - Compacted = FALSE; - if (EcxIn == 1) { - /* - * The PPR and APM aren't clear on what size should be encoded in - * 0xD:0x1:EBX when compaction is not enabled by either XSAVEC or - * XSAVES, as these are generally fixed to 1 on real CPUs. Report - * this undefined case as an error. - */ - if (!(*Eax & (BIT3 | BIT1))) { - /* (XSAVES | XSAVEC) */ - return FALSE; - } - - Compacted = TRUE; - XssMsr.Uint64 = AsmReadMsr64 (MSR_IA32_XSS); - } - - if (!GetCpuidXSaveSize ( - XCr0 | XssMsr.Uint64, - *Ebx, - &XSaveSize, - Compacted - )) - { - return FALSE; - } - - *Ebx = XSaveSize; - } else if (EaxIn == 0x8000001E) { - UINT32 Ebx2; - UINT32 Ecx2; - - /* extended APIC ID */ - if (!GetCpuidHyp ( - Ghcb, - EaxIn, - EcxIn, - XCr0, - Eax, - &Ebx2, - &Ecx2, - NULL, - Status, - Unsupported - )) - { - return FALSE; - } - - /* compute ID */ - *Ebx = (*Ebx & 0xFFFFFF00) | (Ebx2 & 0x000000FF); - /* node ID */ - *Ecx = (*Ecx & 0xFFFFFF00) | (Ecx2 & 0x000000FF); - } - -Out: - *Status = 0; - *Unsupported = FALSE; - return TRUE; -} - -/** - Handle a CPUID event. - - Use VMGEXIT instruction or CPUID table to handle a CPUID event. - - @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication - Block - @param[in, out] Regs x64 processor context - @param[in] InstructionData Instruction parsing context - - @retval 0 Event handled successfully - @return New exception value to propagate - -**/ -STATIC -UINT64 -CpuidExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - BOOLEAN Unsupported; - UINT64 Status; - UINT32 EaxIn; - UINT32 EcxIn; - UINT64 XCr0; - UINT32 Eax; - UINT32 Ebx; - UINT32 Ecx; - UINT32 Edx; - - EaxIn = (UINT32)(UINTN)Regs->Rax; - EcxIn = (UINT32)(UINTN)Regs->Rcx; - - if (EaxIn == CPUID_EXTENDED_STATE) { - IA32_CR4 Cr4; - - Cr4.UintN = AsmReadCr4 (); - Ghcb->SaveArea.XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1; - XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1; - } - - if (SnpEnabled ()) { - if (!GetCpuidFw ( - Ghcb, - EaxIn, - EcxIn, - XCr0, - &Eax, - &Ebx, - &Ecx, - &Edx, - &Status, - &Unsupported - )) - { - goto CpuidFail; - } - } else { - if (!GetCpuidHyp ( - Ghcb, - EaxIn, - EcxIn, - XCr0, - &Eax, - &Ebx, - &Ecx, - &Edx, - &Status, - &Unsupported - )) - { - goto CpuidFail; - } - } - - Regs->Rax = Eax; - Regs->Rbx = Ebx; - Regs->Rcx = Ecx; - Regs->Rdx = Edx; - - return 0; - -CpuidFail: - if (Unsupported) { - return UnsupportedExit (Ghcb, Regs, InstructionData); - } - - return Status; -} - -/** - Handle a RDPMC event. - - Use the VMGEXIT instruction to handle a RDPMC event. - - @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication - Block - @param[in, out] Regs x64 processor context - @param[in] InstructionData Instruction parsing context - - @retval 0 Event handled successfully - @return New exception value to propagate - -**/ -STATIC -UINT64 -RdpmcExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - UINT64 Status; - - Ghcb->SaveArea.Rcx = Regs->Rcx; - VmgSetOffsetValid (Ghcb, GhcbRcx); - - Status = VmgExit (Ghcb, SVM_EXIT_RDPMC, 0, 0); - if (Status != 0) { - return Status; - } - - if (!VmgIsOffsetValid (Ghcb, GhcbRax) || - !VmgIsOffsetValid (Ghcb, GhcbRdx)) - { - return UnsupportedExit (Ghcb, Regs, InstructionData); - } - - Regs->Rax = Ghcb->SaveArea.Rax; - Regs->Rdx = Ghcb->SaveArea.Rdx; - - return 0; -} - -/** - Handle a RDTSC event. - - Use the VMGEXIT instruction to handle a RDTSC event. - - @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication - Block - @param[in, out] Regs x64 processor context - @param[in] InstructionData Instruction parsing context - - @retval 0 Event handled successfully - @return New exception value to propagate - -**/ -STATIC -UINT64 -RdtscExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - UINT64 Status; - - Status = VmgExit (Ghcb, SVM_EXIT_RDTSC, 0, 0); - if (Status != 0) { - return Status; - } - - if (!VmgIsOffsetValid (Ghcb, GhcbRax) || - !VmgIsOffsetValid (Ghcb, GhcbRdx)) - { - return UnsupportedExit (Ghcb, Regs, InstructionData); - } - - Regs->Rax = Ghcb->SaveArea.Rax; - Regs->Rdx = Ghcb->SaveArea.Rdx; - - return 0; -} - -/** - Handle a DR7 register write event. - - Use the VMGEXIT instruction to handle a DR7 write event. - - @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication - Block - @param[in, out] Regs x64 processor context - @param[in] InstructionData Instruction parsing context - - @retval 0 Event handled successfully - @return New exception value to propagate - -**/ -STATIC -UINT64 -Dr7WriteExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - SEV_ES_INSTRUCTION_OPCODE_EXT *Ext; - SEV_ES_PER_CPU_DATA *SevEsData; - UINT64 *Register; - UINT64 Status; - - Ext = &InstructionData->Ext; - SevEsData = (SEV_ES_PER_CPU_DATA *)(Ghcb + 1); - - DecodeModRm (Regs, InstructionData); - - // - // MOV DRn always treats MOD == 3 no matter how encoded - // - Register = GetRegisterPointer (Regs, Ext->ModRm.Rm); - - // - // Using a value of 0 for ExitInfo1 means RAX holds the value - // - Ghcb->SaveArea.Rax = *Register; - VmgSetOffsetValid (Ghcb, GhcbRax); - - Status = VmgExit (Ghcb, SVM_EXIT_DR7_WRITE, 0, 0); - if (Status != 0) { - return Status; - } - - SevEsData->Dr7 = *Register; - SevEsData->Dr7Cached = 1; - - return 0; -} - -/** - Handle a DR7 register read event. - - Use the VMGEXIT instruction to handle a DR7 read event. - - @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication - Block - @param[in, out] Regs x64 processor context - @param[in] InstructionData Instruction parsing context - - @retval 0 Event handled successfully - -**/ -STATIC -UINT64 -Dr7ReadExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - SEV_ES_INSTRUCTION_OPCODE_EXT *Ext; - SEV_ES_PER_CPU_DATA *SevEsData; - UINT64 *Register; - - Ext = &InstructionData->Ext; - SevEsData = (SEV_ES_PER_CPU_DATA *)(Ghcb + 1); - - DecodeModRm (Regs, InstructionData); - - // - // MOV DRn always treats MOD == 3 no matter how encoded - // - Register = GetRegisterPointer (Regs, Ext->ModRm.Rm); - - // - // If there is a cached valued for DR7, return that. Otherwise return the - // DR7 standard reset value of 0x400 (no debug breakpoints set). - // - *Register = (SevEsData->Dr7Cached == 1) ? SevEsData->Dr7 : 0x400; - - return 0; -} - -/** - 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 - ) -{ - EFI_SYSTEM_CONTEXT_X64 *Regs; - NAE_EXIT NaeExit; - SEV_ES_INSTRUCTION_DATA InstructionData; - UINT64 ExitCode, Status; - EFI_STATUS VcRet; - BOOLEAN InterruptState; - - VcRet = EFI_SUCCESS; - - Regs = SystemContext.SystemContextX64; - - VmgInit (Ghcb, &InterruptState); - - ExitCode = Regs->ExceptionData; - switch (ExitCode) { - case SVM_EXIT_DR7_READ: - NaeExit = Dr7ReadExit; - break; - - case SVM_EXIT_DR7_WRITE: - NaeExit = Dr7WriteExit; - break; - - case SVM_EXIT_RDTSC: - NaeExit = RdtscExit; - break; - - case SVM_EXIT_RDPMC: - NaeExit = RdpmcExit; - break; - - case SVM_EXIT_CPUID: - NaeExit = CpuidExit; - break; - - case SVM_EXIT_INVD: - NaeExit = InvdExit; - break; - - case SVM_EXIT_IOIO_PROT: - NaeExit = IoioExit; - break; - - case SVM_EXIT_MSR: - NaeExit = MsrExit; - break; - - case SVM_EXIT_VMMCALL: - NaeExit = VmmCallExit; - break; - - case SVM_EXIT_RDTSCP: - NaeExit = RdtscpExit; - break; - - case SVM_EXIT_WBINVD: - NaeExit = WbinvdExit; - break; - - case SVM_EXIT_MONITOR: - NaeExit = MonitorExit; - break; - - case SVM_EXIT_MWAIT: - NaeExit = MwaitExit; - break; - - case SVM_EXIT_NPF: - NaeExit = MmioExit; - break; - - default: - NaeExit = UnsupportedExit; - } - - InitInstructionData (&InstructionData, Ghcb, Regs); - - Status = NaeExit (Ghcb, Regs, &InstructionData); - if (Status == 0) { - Regs->Rip += InstructionLength (&InstructionData); - } else { - GHCB_EVENT_INJECTION Event; - - Event.Uint64 = Status; - if (Event.Elements.ErrorCodeValid != 0) { - Regs->ExceptionData = Event.Elements.ErrorCode; - } else { - Regs->ExceptionData = 0; - } - - *ExceptionType = Event.Elements.Vector; - - VcRet = EFI_PROTOCOL_ERROR; - } - - VmgDone (Ghcb, InterruptState); - - 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/Library/VmgExitLib/VmgExitVcHandler.h b/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.h deleted file mode 100644 index 3a37cb04f6..0000000000 --- a/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.h +++ /dev/null @@ -1,53 +0,0 @@ -/** @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/X64/TdVmcallCpuid.nasm b/OvmfPkg/Library/VmgExitLib/X64/TdVmcallCpuid.nasm deleted file mode 100644 index fa86440904..0000000000 --- a/OvmfPkg/Library/VmgExitLib/X64/TdVmcallCpuid.nasm +++ /dev/null @@ -1,146 +0,0 @@ -;------------------------------------------------------------------------------ -;* -;* Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
-;* SPDX-License-Identifier: BSD-2-Clause-Patent -;* -;* -;------------------------------------------------------------------------------ - -DEFAULT REL -SECTION .text - -%define TDVMCALL_EXPOSE_REGS_MASK 0xffec -%define TDVMCALL 0x0 -%define EXIT_REASON_CPUID 0xa - -%macro tdcall 0 - db 0x66,0x0f,0x01,0xcc -%endmacro - -%macro tdcall_push_regs 0 - push rbp - mov rbp, rsp - push r15 - push r14 - push r13 - push r12 - push rbx - push rsi - push rdi -%endmacro - -%macro tdcall_pop_regs 0 - pop rdi - pop rsi - pop rbx - pop r12 - pop r13 - pop r14 - pop r15 - pop rbp -%endmacro - -%define number_of_regs_pushed 8 -%define number_of_parameters 4 - -; -; Keep these in sync for push_regs/pop_regs, code below -; uses them to find 5th or greater parameters -; -%define first_variable_on_stack_offset \ - ((number_of_regs_pushed * 8) + (number_of_parameters * 8) + 8) -%define second_variable_on_stack_offset \ - ((first_variable_on_stack_offset) + 8) - -%macro tdcall_regs_preamble 2 - mov rax, %1 - - xor rcx, rcx - mov ecx, %2 - - ; R10 = 0 (standard TDVMCALL) - - xor r10d, r10d - - ; Zero out unused (for standard TDVMCALL) registers to avoid leaking - ; secrets to the VMM. - - xor ebx, ebx - xor esi, esi - xor edi, edi - - xor edx, edx - xor ebp, ebp - xor r8d, r8d - xor r9d, r9d - xor r14, r14 - xor r15, r15 -%endmacro - -%macro tdcall_regs_postamble 0 - xor ebx, ebx - xor esi, esi - xor edi, edi - - xor ecx, ecx - xor edx, edx - xor r8d, r8d - xor r9d, r9d - xor r10d, r10d - xor r11d, r11d -%endmacro - -;------------------------------------------------------------------------------ -; 0 => RAX = TDCALL leaf / TDVMCALL -; M => RCX = TDVMCALL register behavior -; 0xa => R11 = TDVMCALL function / CPUID -; RCX => R12 = p1 -; RDX => R13 = p2 -; -; UINT64 -; EFIAPI -; TdVmCallCpuid ( -; UINT64 EaxIn, // Rcx -; UINT64 EcxIn, // Rdx -; UINT64 *Results // R8 -; ) -global ASM_PFX(TdVmCallCpuid) -ASM_PFX(TdVmCallCpuid): - tdcall_push_regs - - mov r11, EXIT_REASON_CPUID - mov r12, rcx - mov r13, rdx - - ; Save *results pointers - push r8 - - tdcall_regs_preamble TDVMCALL, TDVMCALL_EXPOSE_REGS_MASK - - tdcall - - ; ignore return data if TDCALL reports failure. - test rax, rax - jnz .no_return_data - - ; Propagate TDVMCALL success/failure to return value. - mov rax, r10 - test rax, rax - jnz .no_return_data - - ; Retrieve *Results - pop r8 - test r8, r8 - jz .no_return_data - ; Caller pass in buffer so store results r12-r15 contains eax-edx - mov [r8 + 0], r12 - mov [r8 + 8], r13 - mov [r8 + 16], r14 - mov [r8 + 24], r15 - -.no_return_data: - tdcall_regs_postamble - - tdcall_pop_regs - - ret diff --git a/OvmfPkg/Microvm/MicrovmX64.dsc b/OvmfPkg/Microvm/MicrovmX64.dsc index 7eff8e2a88..994a02d301 100644 --- a/OvmfPkg/Microvm/MicrovmX64.dsc +++ b/OvmfPkg/Microvm/MicrovmX64.dsc @@ -249,7 +249,7 @@ [LibraryClasses.common] BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf - VmgExitLib|OvmfPkg/Library/VmgExitLib/VmgExitLib.inf + CcExitLib|OvmfPkg/Library/CcExitLib/CcExitLib.inf SerialPortLib|MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf PlatformHookLib|MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf FdtLib|EmbeddedPkg/Library/FdtLib/FdtLib.inf @@ -277,7 +277,7 @@ !else CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf !endif - VmgExitLib|OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf + CcExitLib|OvmfPkg/Library/CcExitLib/SecCcExitLib.inf MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf [LibraryClasses.common.PEI_CORE] diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc index e9ba491237..6f774baf90 100644 --- a/OvmfPkg/OvmfPkgIa32.dsc +++ b/OvmfPkg/OvmfPkgIa32.dsc @@ -256,7 +256,7 @@ [LibraryClasses.common] BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf - VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf + CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf [LibraryClasses.common.SEC] TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseRomAcpiTimerLib.inf @@ -984,7 +984,7 @@ # OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf { - VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf + CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf } MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf { diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc index af566b953f..c851764dec 100644 --- a/OvmfPkg/OvmfPkgIa32X64.dsc +++ b/OvmfPkg/OvmfPkgIa32X64.dsc @@ -260,7 +260,7 @@ [LibraryClasses.common] BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf - VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf + CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf TdxLib|MdePkg/Library/TdxLib/TdxLib.inf TdxMailboxLib|OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf @@ -1002,7 +1002,7 @@ # OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf { - VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf + CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf } MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf { diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc index f39d9cd117..63c3a47aea 100644 --- a/OvmfPkg/OvmfPkgX64.dsc +++ b/OvmfPkg/OvmfPkgX64.dsc @@ -276,7 +276,7 @@ [LibraryClasses.common] BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf - VmgExitLib|OvmfPkg/Library/VmgExitLib/VmgExitLib.inf + CcExitLib|OvmfPkg/Library/CcExitLib/CcExitLib.inf TdxLib|MdePkg/Library/TdxLib/TdxLib.inf TdxMailboxLib|OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf @@ -302,7 +302,7 @@ !else CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf !endif - VmgExitLib|OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf + CcExitLib|OvmfPkg/Library/CcExitLib/SecCcExitLib.inf MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf CcProbeLib|OvmfPkg/Library/CcProbeLib/SecPeiCcProbeLib.inf @@ -1072,7 +1072,7 @@ # OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf { - VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf + CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf } MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf { diff --git a/OvmfPkg/OvmfXen.dsc b/OvmfPkg/OvmfXen.dsc index 58a7c97cdd..8bb497088b 100644 --- a/OvmfPkg/OvmfXen.dsc +++ b/OvmfPkg/OvmfXen.dsc @@ -231,7 +231,7 @@ [LibraryClasses.common] BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf - VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf + CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf TdxLib|MdePkg/Library/TdxLib/TdxLib.inf [LibraryClasses.common.SEC] diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c index 385562b44c..80a1194ffc 100644 --- a/OvmfPkg/PlatformPei/AmdSev.c +++ b/OvmfPkg/PlatformPei/AmdSev.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include "Platform.h" diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf index 3cd83e6ec3..1fadadeb55 100644 --- a/OvmfPkg/PlatformPei/PlatformPei.inf +++ b/OvmfPkg/PlatformPei/PlatformPei.inf @@ -63,7 +63,7 @@ MtrrLib MemEncryptSevLib PcdLib - VmgExitLib + CcExitLib PlatformInitLib [Pcd] diff --git a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf index 8bb2325157..f471704789 100644 --- a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf +++ b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf @@ -53,7 +53,7 @@ UefiBootServicesTableLib UefiDriverEntryPoint UefiRuntimeLib - VmgExitLib + CcExitLib [Guids] gEfiEventVirtualAddressChangeGuid # ALWAYS_CONSUMED diff --git a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlashDxe.c b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlashDxe.c index 172d6a4267..58bcad825d 100644 --- a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlashDxe.c +++ b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlashDxe.c @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include "QemuFlash.h" diff --git a/UefiCpuPkg/Include/Library/CcExitLib.h b/UefiCpuPkg/Include/Library/CcExitLib.h new file mode 100644 index 0000000000..1ae618c19b --- /dev/null +++ b/UefiCpuPkg/Include/Library/CcExitLib.h @@ -0,0 +1,176 @@ +/** @file + Public header file for the CcExitLib. + + This library class defines some routines used for below CcExit handler. + - Invoking the VMGEXIT instruction in support of SEV-ES and to handle + #VC exceptions. + - Handle #VE exception in TDX. + + Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.
+ Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef CC_EXIT_LIB_H_ +#define CC_EXIT_LIB_H_ + +#include +#include + +#define VE_EXCEPTION 20 + +/** + Perform VMGEXIT. + + Sets the necessary fields of the GHCB, invokes the VMGEXIT instruction and + then handles the return actions. + + @param[in, out] Ghcb A pointer to the GHCB + @param[in] ExitCode VMGEXIT code to be assigned to the SwExitCode + field of the GHCB. + @param[in] ExitInfo1 VMGEXIT information to be assigned to the + SwExitInfo1 field of the GHCB. + @param[in] ExitInfo2 VMGEXIT information to be assigned to the + SwExitInfo2 field of the GHCB. + + @retval 0 VMGEXIT succeeded. + @return Exception number to be propagated, VMGEXIT + processing did not succeed. + +**/ +UINT64 +EFIAPI +VmgExit ( + IN OUT GHCB *Ghcb, + IN UINT64 ExitCode, + IN UINT64 ExitInfo1, + IN UINT64 ExitInfo2 + ); + +/** + Perform pre-VMGEXIT initialization/preparation. + + Performs the necessary steps in preparation for invoking VMGEXIT. Must be + called before setting any fields within the GHCB. + + @param[in, out] Ghcb A pointer to the GHCB + @param[in, out] InterruptState A pointer to hold the current interrupt + state, used for restoring in VmgDone () + +**/ +VOID +EFIAPI +VmgInit ( + IN OUT GHCB *Ghcb, + IN OUT BOOLEAN *InterruptState + ); + +/** + Perform post-VMGEXIT cleanup. + + Performs the necessary steps to cleanup after invoking VMGEXIT. Must be + called after obtaining needed fields within the GHCB. + + @param[in, out] Ghcb A pointer to the GHCB + @param[in] InterruptState An indicator to conditionally (re)enable + interrupts + +**/ +VOID +EFIAPI +VmgDone ( + IN OUT GHCB *Ghcb, + IN BOOLEAN InterruptState + ); + +/** + Marks a specified offset as valid in the GHCB. + + The ValidBitmap area represents the areas of the GHCB that have been marked + valid. Set the bit in ValidBitmap for the input offset. + + @param[in, out] Ghcb A pointer to the GHCB + @param[in] Offset Qword offset in the GHCB to mark valid + +**/ +VOID +EFIAPI +VmgSetOffsetValid ( + IN OUT GHCB *Ghcb, + IN GHCB_REGISTER Offset + ); + +/** + Checks if a specified offset is valid in the GHCB. + + The ValidBitmap area represents the areas of the GHCB that have been marked + valid. Return whether the bit in the ValidBitmap is set for the input offset. + + @param[in] Ghcb A pointer to the GHCB + @param[in] Offset Qword offset in the GHCB to mark valid + + @retval TRUE Offset is marked valid in the GHCB + @retval FALSE Offset is not marked valid in the GHCB + +**/ +BOOLEAN +EFIAPI +VmgIsOffsetValid ( + IN GHCB *Ghcb, + IN GHCB_REGISTER Offset + ); + +/** + Handle a #VC exception. + + Performs the necessary processing to handle a #VC exception. + + The base library function returns an error equal to VC_EXCEPTION, + to be propagated to the standard exception handling stack. + + @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 + ); + +/** + Handle a #VE exception. + + Performs the necessary processing to handle a #VE exception. + + The base library function returns an error equal to VE_EXCEPTION, + to be propagated to the standard exception handling stack. + + @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 #VE not supported, (new) exception value to + propagate provided + @retval EFI_PROTOCOL_ERROR #VE handling failed, (new) exception value to + propagate provided + +**/ +EFI_STATUS +EFIAPI +VmTdExitHandleVe ( + IN OUT EFI_EXCEPTION_TYPE *ExceptionType, + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ); + +#endif diff --git a/UefiCpuPkg/Include/Library/VmgExitLib.h b/UefiCpuPkg/Include/Library/VmgExitLib.h deleted file mode 100644 index f9f911099a..0000000000 --- a/UefiCpuPkg/Include/Library/VmgExitLib.h +++ /dev/null @@ -1,173 +0,0 @@ -/** @file - Public header file for the VMGEXIT Support library class. - - This library class defines some routines used when invoking the VMGEXIT - instruction in support of SEV-ES and to handle #VC exceptions. - - Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.
- SPDX-License-Identifier: BSD-2-Clause-Patent - -**/ - -#ifndef __VMG_EXIT_LIB_H__ -#define __VMG_EXIT_LIB_H__ - -#include -#include - -#define VE_EXCEPTION 20 - -/** - Perform VMGEXIT. - - Sets the necessary fields of the GHCB, invokes the VMGEXIT instruction and - then handles the return actions. - - @param[in, out] Ghcb A pointer to the GHCB - @param[in] ExitCode VMGEXIT code to be assigned to the SwExitCode - field of the GHCB. - @param[in] ExitInfo1 VMGEXIT information to be assigned to the - SwExitInfo1 field of the GHCB. - @param[in] ExitInfo2 VMGEXIT information to be assigned to the - SwExitInfo2 field of the GHCB. - - @retval 0 VMGEXIT succeeded. - @return Exception number to be propagated, VMGEXIT - processing did not succeed. - -**/ -UINT64 -EFIAPI -VmgExit ( - IN OUT GHCB *Ghcb, - IN UINT64 ExitCode, - IN UINT64 ExitInfo1, - IN UINT64 ExitInfo2 - ); - -/** - Perform pre-VMGEXIT initialization/preparation. - - Performs the necessary steps in preparation for invoking VMGEXIT. Must be - called before setting any fields within the GHCB. - - @param[in, out] Ghcb A pointer to the GHCB - @param[in, out] InterruptState A pointer to hold the current interrupt - state, used for restoring in VmgDone () - -**/ -VOID -EFIAPI -VmgInit ( - IN OUT GHCB *Ghcb, - IN OUT BOOLEAN *InterruptState - ); - -/** - Perform post-VMGEXIT cleanup. - - Performs the necessary steps to cleanup after invoking VMGEXIT. Must be - called after obtaining needed fields within the GHCB. - - @param[in, out] Ghcb A pointer to the GHCB - @param[in] InterruptState An indicator to conditionally (re)enable - interrupts - -**/ -VOID -EFIAPI -VmgDone ( - IN OUT GHCB *Ghcb, - IN BOOLEAN InterruptState - ); - -/** - Marks a specified offset as valid in the GHCB. - - The ValidBitmap area represents the areas of the GHCB that have been marked - valid. Set the bit in ValidBitmap for the input offset. - - @param[in, out] Ghcb A pointer to the GHCB - @param[in] Offset Qword offset in the GHCB to mark valid - -**/ -VOID -EFIAPI -VmgSetOffsetValid ( - IN OUT GHCB *Ghcb, - IN GHCB_REGISTER Offset - ); - -/** - Checks if a specified offset is valid in the GHCB. - - The ValidBitmap area represents the areas of the GHCB that have been marked - valid. Return whether the bit in the ValidBitmap is set for the input offset. - - @param[in] Ghcb A pointer to the GHCB - @param[in] Offset Qword offset in the GHCB to mark valid - - @retval TRUE Offset is marked valid in the GHCB - @retval FALSE Offset is not marked valid in the GHCB - -**/ -BOOLEAN -EFIAPI -VmgIsOffsetValid ( - IN GHCB *Ghcb, - IN GHCB_REGISTER Offset - ); - -/** - Handle a #VC exception. - - Performs the necessary processing to handle a #VC exception. - - The base library function returns an error equal to VC_EXCEPTION, - to be propagated to the standard exception handling stack. - - @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 - ); - -/** - Handle a #VE exception. - - Performs the necessary processing to handle a #VE exception. - - The base library function returns an error equal to VE_EXCEPTION, - to be propagated to the standard exception handling stack. - - @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 #VE not supported, (new) exception value to - propagate provided - @retval EFI_PROTOCOL_ERROR #VE handling failed, (new) exception value to - propagate provided - -**/ -EFI_STATUS -EFIAPI -VmTdExitHandleVe ( - IN OUT EFI_EXCEPTION_TYPE *ExceptionType, - IN OUT EFI_SYSTEM_CONTEXT SystemContext - ); - -#endif diff --git a/UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.c b/UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.c new file mode 100644 index 0000000000..79eca74e13 --- /dev/null +++ b/UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.c @@ -0,0 +1,194 @@ +/** @file + CcExit Base Support Library. + + Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.
+ Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include + +/** + Perform VMGEXIT. + + Sets the necessary fields of the GHCB, invokes the VMGEXIT instruction and + then handles the return actions. + + The base library function returns an error in the form of a + GHCB_EVENT_INJECTION representing a GP_EXCEPTION. + + @param[in, out] Ghcb A pointer to the GHCB + @param[in] ExitCode VMGEXIT code to be assigned to the SwExitCode + field of the GHCB. + @param[in] ExitInfo1 VMGEXIT information to be assigned to the + SwExitInfo1 field of the GHCB. + @param[in] ExitInfo2 VMGEXIT information to be assigned to the + SwExitInfo2 field of the GHCB. + + @retval 0 VMGEXIT succeeded. + @return Exception number to be propagated, VMGEXIT + processing did not succeed. + +**/ +UINT64 +EFIAPI +VmgExit ( + IN OUT GHCB *Ghcb, + IN UINT64 ExitCode, + IN UINT64 ExitInfo1, + IN UINT64 ExitInfo2 + ) +{ + GHCB_EVENT_INJECTION Event; + + Event.Uint64 = 0; + Event.Elements.Vector = GP_EXCEPTION; + Event.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION; + Event.Elements.Valid = 1; + + return Event.Uint64; +} + +/** + Perform pre-VMGEXIT initialization/preparation. + + Performs the necessary steps in preparation for invoking VMGEXIT. Must be + called before setting any fields within the GHCB. + + @param[in, out] Ghcb A pointer to the GHCB + @param[in, out] InterruptState A pointer to hold the current interrupt + state, used for restoring in VmgDone () + +**/ +VOID +EFIAPI +VmgInit ( + IN OUT GHCB *Ghcb, + IN OUT BOOLEAN *InterruptState + ) +{ +} + +/** + Perform post-VMGEXIT cleanup. + + Performs the necessary steps to cleanup after invoking VMGEXIT. Must be + called after obtaining needed fields within the GHCB. + + @param[in, out] Ghcb A pointer to the GHCB + @param[in] InterruptState An indicator to conditionally (re)enable + interrupts + +**/ +VOID +EFIAPI +VmgDone ( + IN OUT GHCB *Ghcb, + IN BOOLEAN InterruptState + ) +{ +} + +/** + Marks a field at the specified offset as valid in the GHCB. + + The ValidBitmap area represents the areas of the GHCB that have been marked + valid. Set the bit in ValidBitmap for the input offset. + + @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication Block + @param[in] Offset Qword offset in the GHCB to mark valid + +**/ +VOID +EFIAPI +VmgSetOffsetValid ( + IN OUT GHCB *Ghcb, + IN GHCB_REGISTER Offset + ) +{ +} + +/** + Checks if a specified offset is valid in the GHCB. + + The ValidBitmap area represents the areas of the GHCB that have been marked + valid. Return whether the bit in the ValidBitmap is set for the input offset. + + @param[in] Ghcb A pointer to the GHCB + @param[in] Offset Qword offset in the GHCB to mark valid + + @retval TRUE Offset is marked valid in the GHCB + @retval FALSE Offset is not marked valid in the GHCB + +**/ +BOOLEAN +EFIAPI +VmgIsOffsetValid ( + IN GHCB *Ghcb, + IN GHCB_REGISTER Offset + ) +{ + return FALSE; +} + +/** + Handle a #VC exception. + + Performs the necessary processing to handle a #VC exception. + + The base library function returns an error equal to VC_EXCEPTION, + to be propagated to the standard exception handling stack. + + @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 + ) +{ + *ExceptionType = VC_EXCEPTION; + + return EFI_UNSUPPORTED; +} + +/** + Handle a #VE exception. + + Performs the necessary processing to handle a #VE 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 #VE not supported, (new) exception value to + propagate provided + @retval EFI_PROTOCOL_ERROR #VE handling failed, (new) exception value to + propagate provided + +**/ +EFI_STATUS +EFIAPI +VmTdExitHandleVe ( + IN OUT EFI_EXCEPTION_TYPE *ExceptionType, + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ) +{ + *ExceptionType = VE_EXCEPTION; + + return EFI_UNSUPPORTED; +} diff --git a/UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf b/UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf new file mode 100644 index 0000000000..ed7f611cbc --- /dev/null +++ b/UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf @@ -0,0 +1,28 @@ +## @file +# CcExit Base Support Library. +# +# Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.
+# Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = CcExitLibNull + MODULE_UNI_FILE = CcExitLibNull.uni + FILE_GUID = 3cd7368f-ef9b-4a9b-9571-2ed93813677e + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = CcExitLib + +[Sources.common] + CcExitLibNull.c + +[Packages] + MdePkg/MdePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + diff --git a/UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.uni b/UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.uni new file mode 100644 index 0000000000..b18ae8792e --- /dev/null +++ b/UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.uni @@ -0,0 +1,14 @@ +// /** @file +// CcExitLib instance. +// +// Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.
+// Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "CcExitLib NULL instance" + +#string STR_MODULE_DESCRIPTION #language en-US "CcExitLib NULL instance." + diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf index e7a81bebdb..d0f82095cf 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf @@ -60,4 +60,4 @@ PeCoffGetEntryPointLib MemoryAllocationLib DebugLib - VmgExitLib + CcExitLib diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf index 7c2ec3b2db..5339f8e604 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf @@ -52,7 +52,7 @@ HobLib MemoryAllocationLib SynchronizationLib - VmgExitLib + CcExitLib [Pcd] gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard # CONSUMES diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c index a7d0897ef1..2b6d9da5c7 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c @@ -7,7 +7,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include -#include +#include #include "CpuExceptionCommon.h" /** diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c index ad5e0e9ed4..0a9ea79f52 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c @@ -7,7 +7,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include -#include +#include #include "CpuExceptionCommon.h" CONST UINTN mDoFarReturnFlag = 0; diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf index 6a170286c8..df44371fe0 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf @@ -48,7 +48,7 @@ PrintLib LocalApicLib PeCoffGetEntryPointLib - VmgExitLib + CcExitLib [Pcd] gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf index 9dde07612a..8f8a5dab79 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf @@ -51,7 +51,7 @@ LocalApicLib PeCoffGetEntryPointLib DebugLib - VmgExitLib + CcExitLib [Pcd] gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Xcode5SecPeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Xcode5SecPeiCpuExceptionHandlerLib.inf index 6d2f66504a..619b39d7f1 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Xcode5SecPeiCpuExceptionHandlerLib.inf +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Xcode5SecPeiCpuExceptionHandlerLib.inf @@ -53,7 +53,7 @@ PrintLib LocalApicLib PeCoffGetEntryPointLib - VmgExitLib + CcExitLib [Pcd] gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard diff --git a/UefiCpuPkg/Library/MpInitLib/AmdSev.c b/UefiCpuPkg/Library/MpInitLib/AmdSev.c index 4e4c63a52d..2dd8f4d746 100644 --- a/UefiCpuPkg/Library/MpInitLib/AmdSev.c +++ b/UefiCpuPkg/Library/MpInitLib/AmdSev.c @@ -8,7 +8,7 @@ **/ #include "MpLib.h" -#include +#include /** Get Protected mode code segment with 16-bit default addressing diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf index e1cd0b3500..cd07de3a3c 100644 --- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf +++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf @@ -54,7 +54,7 @@ DebugAgentLib SynchronizationLib PcdLib - VmgExitLib + CcExitLib MicrocodeLib [Protocols] diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c index 78cc3e2b93..ef56af1f73 100644 --- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c index 1c053f87a4..e5dc852ed9 100644 --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c @@ -9,7 +9,7 @@ **/ #include "MpLib.h" -#include +#include #include #include diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf index 5facf4db94..afd551bb0f 100644 --- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf +++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf @@ -53,7 +53,7 @@ SynchronizationLib PeiServicesLib PcdLib - VmgExitLib + CcExitLib MicrocodeLib [Pcd] diff --git a/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c b/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c index a3cd377ef6..4c4f81af7c 100644 --- a/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c +++ b/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c @@ -9,7 +9,7 @@ **/ #include "MpLib.h" -#include +#include #include #include diff --git a/UefiCpuPkg/Library/VmgExitLibNull/VmTdExitNull.c b/UefiCpuPkg/Library/VmgExitLibNull/VmTdExitNull.c deleted file mode 100644 index 6a4e8087cb..0000000000 --- a/UefiCpuPkg/Library/VmgExitLibNull/VmTdExitNull.c +++ /dev/null @@ -1,38 +0,0 @@ -/** @file - - Copyright (c) 2021, Intel Corporation. All rights reserved.
- - SPDX-License-Identifier: BSD-2-Clause-Patent - -**/ -#include -#include -#include - -/** - Handle a #VE exception. - - Performs the necessary processing to handle a #VE 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 #VE not supported, (new) exception value to - propagate provided - @retval EFI_PROTOCOL_ERROR #VE handling failed, (new) exception value to - propagate provided - -**/ -EFI_STATUS -EFIAPI -VmTdExitHandleVe ( - IN OUT EFI_EXCEPTION_TYPE *ExceptionType, - IN OUT EFI_SYSTEM_CONTEXT SystemContext - ) -{ - *ExceptionType = VE_EXCEPTION; - - return EFI_UNSUPPORTED; -} diff --git a/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.c b/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.c deleted file mode 100644 index d661d85974..0000000000 --- a/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.c +++ /dev/null @@ -1,165 +0,0 @@ -/** @file - VMGEXIT Base Support Library. - - Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.
- SPDX-License-Identifier: BSD-2-Clause-Patent - -**/ - -#include -#include -#include - -/** - Perform VMGEXIT. - - Sets the necessary fields of the GHCB, invokes the VMGEXIT instruction and - then handles the return actions. - - The base library function returns an error in the form of a - GHCB_EVENT_INJECTION representing a GP_EXCEPTION. - - @param[in, out] Ghcb A pointer to the GHCB - @param[in] ExitCode VMGEXIT code to be assigned to the SwExitCode - field of the GHCB. - @param[in] ExitInfo1 VMGEXIT information to be assigned to the - SwExitInfo1 field of the GHCB. - @param[in] ExitInfo2 VMGEXIT information to be assigned to the - SwExitInfo2 field of the GHCB. - - @retval 0 VMGEXIT succeeded. - @return Exception number to be propagated, VMGEXIT - processing did not succeed. - -**/ -UINT64 -EFIAPI -VmgExit ( - IN OUT GHCB *Ghcb, - IN UINT64 ExitCode, - IN UINT64 ExitInfo1, - IN UINT64 ExitInfo2 - ) -{ - GHCB_EVENT_INJECTION Event; - - Event.Uint64 = 0; - Event.Elements.Vector = GP_EXCEPTION; - Event.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION; - Event.Elements.Valid = 1; - - return Event.Uint64; -} - -/** - Perform pre-VMGEXIT initialization/preparation. - - Performs the necessary steps in preparation for invoking VMGEXIT. Must be - called before setting any fields within the GHCB. - - @param[in, out] Ghcb A pointer to the GHCB - @param[in, out] InterruptState A pointer to hold the current interrupt - state, used for restoring in VmgDone () - -**/ -VOID -EFIAPI -VmgInit ( - IN OUT GHCB *Ghcb, - IN OUT BOOLEAN *InterruptState - ) -{ -} - -/** - Perform post-VMGEXIT cleanup. - - Performs the necessary steps to cleanup after invoking VMGEXIT. Must be - called after obtaining needed fields within the GHCB. - - @param[in, out] Ghcb A pointer to the GHCB - @param[in] InterruptState An indicator to conditionally (re)enable - interrupts - -**/ -VOID -EFIAPI -VmgDone ( - IN OUT GHCB *Ghcb, - IN BOOLEAN InterruptState - ) -{ -} - -/** - Marks a field at the specified offset as valid in the GHCB. - - The ValidBitmap area represents the areas of the GHCB that have been marked - valid. Set the bit in ValidBitmap for the input offset. - - @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication Block - @param[in] Offset Qword offset in the GHCB to mark valid - -**/ -VOID -EFIAPI -VmgSetOffsetValid ( - IN OUT GHCB *Ghcb, - IN GHCB_REGISTER Offset - ) -{ -} - -/** - Checks if a specified offset is valid in the GHCB. - - The ValidBitmap area represents the areas of the GHCB that have been marked - valid. Return whether the bit in the ValidBitmap is set for the input offset. - - @param[in] Ghcb A pointer to the GHCB - @param[in] Offset Qword offset in the GHCB to mark valid - - @retval TRUE Offset is marked valid in the GHCB - @retval FALSE Offset is not marked valid in the GHCB - -**/ -BOOLEAN -EFIAPI -VmgIsOffsetValid ( - IN GHCB *Ghcb, - IN GHCB_REGISTER Offset - ) -{ - return FALSE; -} - -/** - Handle a #VC exception. - - Performs the necessary processing to handle a #VC exception. - - The base library function returns an error equal to VC_EXCEPTION, - to be propagated to the standard exception handling stack. - - @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 - ) -{ - *ExceptionType = VC_EXCEPTION; - - return EFI_UNSUPPORTED; -} diff --git a/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf b/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf deleted file mode 100644 index 4aab601939..0000000000 --- a/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf +++ /dev/null @@ -1,28 +0,0 @@ -## @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 = VmgExitLibNull - MODULE_UNI_FILE = VmgExitLibNull.uni - FILE_GUID = 3cd7368f-ef9b-4a9b-9571-2ed93813677e - MODULE_TYPE = BASE - VERSION_STRING = 1.0 - LIBRARY_CLASS = VmgExitLib - -[Sources.common] - VmgExitLibNull.c - VmTdExitNull.c - -[Packages] - MdePkg/MdePkg.dec - UefiCpuPkg/UefiCpuPkg.dec - -[LibraryClasses] - BaseLib - diff --git a/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.uni b/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.uni deleted file mode 100644 index 8639bc0e8c..0000000000 --- a/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.uni +++ /dev/null @@ -1,15 +0,0 @@ -// /** @file -// VMGEXIT support library instance. -// -// VMGEXIT support library instance. -// -// Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.
-// SPDX-License-Identifier: BSD-2-Clause-Patent -// -// **/ - - -#string STR_MODULE_ABSTRACT #language en-US "VMGEXIT support NULL library instance" - -#string STR_MODULE_DESCRIPTION #language en-US "VMGEXIT support NULL library instance." - diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec index 718323d904..cff239d528 100644 --- a/UefiCpuPkg/UefiCpuPkg.dec +++ b/UefiCpuPkg/UefiCpuPkg.dec @@ -53,8 +53,8 @@ ## MpInitLib|Include/Library/MpInitLib.h - ## @libraryclass Provides function to support VMGEXIT processing. - VmgExitLib|Include/Library/VmgExitLib.h + ## @libraryclass Provides function to support CcExit processing. + CcExitLib|Include/Library/CcExitLib.h ## @libraryclass Provides function to get CPU cache information. CpuCacheInfoLib|Include/Library/CpuCacheInfoLib.h diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc index 0e1a99ddc0..67b0ce46e4 100644 --- a/UefiCpuPkg/UefiCpuPkg.dsc +++ b/UefiCpuPkg/UefiCpuPkg.dsc @@ -59,7 +59,7 @@ PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf - VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf + CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf MicrocodeLib|UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.inf SmmCpuRendezvousLib|UefiCpuPkg/Library/SmmCpuRendezvousLib/SmmCpuRendezvousLib.inf CpuPageTableLib|UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableLib.inf @@ -163,7 +163,7 @@ UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibStm.inf UefiCpuPkg/Library/SmmCpuFeaturesLib/StandaloneMmCpuFeaturesLib.inf - UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf + UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPei.inf UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmm.inf UefiCpuPkg/SecCore/SecCore.inf diff --git a/UefiPayloadPkg/UefiPayloadPkg.dsc b/UefiPayloadPkg/UefiPayloadPkg.dsc index 1150be6acd..723a50a422 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.dsc +++ b/UefiPayloadPkg/UefiPayloadPkg.dsc @@ -301,7 +301,7 @@ VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf VariableFlashInfoLib|MdeModulePkg/Library/BaseVariableFlashInfoLib/BaseVariableFlashInfoLib.inf - VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf + CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf [LibraryClasses.common] -- cgit v1.2.3