!else\r
CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf\r
!endif\r
+ VmgExitLib|OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf\r
\r
[LibraryClasses.common.PEI_CORE]\r
HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf\r
0x00C000|0x001000\r
gUefiOvmfPkgTokenSpaceGuid.PcdSevLaunchSecretBase|gUefiOvmfPkgTokenSpaceGuid.PcdSevLaunchSecretSize\r
\r
+0x00D000|0x001000\r
+gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize\r
+\r
0x010000|0x010000\r
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize\r
\r
\r
#include <Base.h>\r
\r
+//\r
+// Define the maximum number of #VCs allowed (e.g. the level of nesting\r
+// that is allowed => 2 allows for 1 nested #VCs). I this value is changed,\r
+// be sure to increase the size of\r
+// gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize\r
+// in any FDF file using this PCD.\r
+//\r
+#define VMGEXIT_MAXIMUM_VC_COUNT 2\r
+\r
+//\r
+// Per-CPU data mapping structure\r
+// Use UINT32 for cached indicators and compare to a specific value\r
+// so that the hypervisor can't indicate a value is cached by just\r
+// writing random data to that area.\r
+//\r
+typedef struct {\r
+ UINT32 Dr7Cached;\r
+ UINT64 Dr7;\r
+\r
+ UINTN VcCount;\r
+ VOID *GhcbBackupPages;\r
+} SEV_ES_PER_CPU_DATA;\r
+\r
//\r
// Internal structure for holding SEV-ES information needed during SEC phase\r
// and valid only during SEC phase and early PEI during platform\r
--- /dev/null
+/** @file\r
+ X64 #VC Exception Handler functon.\r
+\r
+ Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <Base.h>\r
+#include <Uefi.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemEncryptSevLib.h>\r
+#include <Library/VmgExitLib.h>\r
+#include <Register/Amd/Msr.h>\r
+\r
+#include "VmgExitVcHandler.h"\r
+\r
+/**\r
+ Handle a #VC exception.\r
+\r
+ Performs the necessary processing to handle a #VC exception.\r
+\r
+ @param[in, out] ExceptionType Pointer to an EFI_EXCEPTION_TYPE to be set\r
+ as value to use on error.\r
+ @param[in, out] SystemContext Pointer to EFI_SYSTEM_CONTEXT\r
+\r
+ @retval EFI_SUCCESS Exception handled\r
+ @retval EFI_UNSUPPORTED #VC not supported, (new) exception value to\r
+ propagate provided\r
+ @retval EFI_PROTOCOL_ERROR #VC handling failed, (new) exception value to\r
+ propagate provided\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VmgExitHandleVc (\r
+ IN OUT EFI_EXCEPTION_TYPE *ExceptionType,\r
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
+ )\r
+{\r
+ MSR_SEV_ES_GHCB_REGISTER Msr;\r
+ GHCB *Ghcb;\r
+ GHCB *GhcbBackup;\r
+ EFI_STATUS VcRet;\r
+ BOOLEAN InterruptState;\r
+ SEV_ES_PER_CPU_DATA *SevEsData;\r
+\r
+ InterruptState = GetInterruptState ();\r
+ if (InterruptState) {\r
+ DisableInterrupts ();\r
+ }\r
+\r
+ Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);\r
+ ASSERT (Msr.GhcbInfo.Function == 0);\r
+ ASSERT (Msr.Ghcb != 0);\r
+\r
+ Ghcb = Msr.Ghcb;\r
+ GhcbBackup = NULL;\r
+\r
+ SevEsData = (SEV_ES_PER_CPU_DATA *) (Ghcb + 1);\r
+ SevEsData->VcCount++;\r
+\r
+ //\r
+ // Check for maximum PEI/DXE #VC nesting.\r
+ //\r
+ if (SevEsData->VcCount > VMGEXIT_MAXIMUM_VC_COUNT) {\r
+ VmgExitIssueAssert (SevEsData);\r
+ } else if (SevEsData->VcCount > 1) {\r
+ //\r
+ // Nested #VC\r
+ //\r
+ if (SevEsData->GhcbBackupPages == NULL) {\r
+ VmgExitIssueAssert (SevEsData);\r
+ }\r
+\r
+ //\r
+ // Save the active GHCB to a backup page.\r
+ // To access the correct backup page, increment the backup page pointer\r
+ // based on the current VcCount.\r
+ //\r
+ GhcbBackup = (GHCB *) SevEsData->GhcbBackupPages;\r
+ GhcbBackup += (SevEsData->VcCount - 2);\r
+\r
+ CopyMem (GhcbBackup, Ghcb, sizeof (*Ghcb));\r
+ }\r
+\r
+ VcRet = InternalVmgExitHandleVc (Ghcb, ExceptionType, SystemContext);\r
+\r
+ if (GhcbBackup != NULL) {\r
+ //\r
+ // Restore the active GHCB from the backup page.\r
+ //\r
+ CopyMem (Ghcb, GhcbBackup, sizeof (*Ghcb));\r
+ }\r
+\r
+ SevEsData->VcCount--;\r
+\r
+ if (InterruptState) {\r
+ EnableInterrupts ();\r
+ }\r
+\r
+ return VcRet;\r
+}\r
--- /dev/null
+## @file\r
+# VMGEXIT Support Library.\r
+#\r
+# Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = SecVmgExitLib\r
+ FILE_GUID = dafff819-f86c-4cff-a70e-83161e5bcf9a\r
+ MODULE_TYPE = BASE\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = VmgExitLib|SEC\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = X64\r
+#\r
+\r
+[Sources.common]\r
+ VmgExitLib.c\r
+ VmgExitVcHandler.c\r
+ VmgExitVcHandler.h\r
+ SecVmgExitVcHandler.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ OvmfPkg/OvmfPkg.dec\r
+ UefiCpuPkg/UefiCpuPkg.dec\r
+\r
+[LibraryClasses]\r
+ BaseLib\r
+ BaseMemoryLib\r
+ DebugLib\r
+ PcdLib\r
+\r
+[FixedPcd]\r
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase\r
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize\r
+\r
--- /dev/null
+/** @file\r
+ X64 #VC Exception Handler functon.\r
+\r
+ Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <Base.h>\r
+#include <Uefi.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemEncryptSevLib.h>\r
+#include <Library/VmgExitLib.h>\r
+#include <Register/Amd/Msr.h>\r
+\r
+#include "VmgExitVcHandler.h"\r
+\r
+/**\r
+ Handle a #VC exception.\r
+\r
+ Performs the necessary processing to handle a #VC exception.\r
+\r
+ @param[in, out] ExceptionType Pointer to an EFI_EXCEPTION_TYPE to be set\r
+ as value to use on error.\r
+ @param[in, out] SystemContext Pointer to EFI_SYSTEM_CONTEXT\r
+\r
+ @retval EFI_SUCCESS Exception handled\r
+ @retval EFI_UNSUPPORTED #VC not supported, (new) exception value to\r
+ propagate provided\r
+ @retval EFI_PROTOCOL_ERROR #VC handling failed, (new) exception value to\r
+ propagate provided\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VmgExitHandleVc (\r
+ IN OUT EFI_EXCEPTION_TYPE *ExceptionType,\r
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
+ )\r
+{\r
+ MSR_SEV_ES_GHCB_REGISTER Msr;\r
+ GHCB *Ghcb;\r
+ GHCB *GhcbBackup;\r
+ EFI_STATUS VcRet;\r
+ BOOLEAN InterruptState;\r
+ SEV_ES_PER_CPU_DATA *SevEsData;\r
+\r
+ InterruptState = GetInterruptState ();\r
+ if (InterruptState) {\r
+ DisableInterrupts ();\r
+ }\r
+\r
+ Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);\r
+ ASSERT (Msr.GhcbInfo.Function == 0);\r
+ ASSERT (Msr.Ghcb != 0);\r
+\r
+ Ghcb = Msr.Ghcb;\r
+ GhcbBackup = NULL;\r
+\r
+ SevEsData = (SEV_ES_PER_CPU_DATA *) (Ghcb + 1);\r
+ SevEsData->VcCount++;\r
+\r
+ //\r
+ // Check for maximum SEC #VC nesting.\r
+ //\r
+ if (SevEsData->VcCount > VMGEXIT_MAXIMUM_VC_COUNT) {\r
+ VmgExitIssueAssert (SevEsData);\r
+ } else if (SevEsData->VcCount > 1) {\r
+ UINTN GhcbBackupSize;\r
+\r
+ //\r
+ // Be sure that the proper amount of pages are allocated\r
+ //\r
+ GhcbBackupSize = (VMGEXIT_MAXIMUM_VC_COUNT - 1) * sizeof (*Ghcb);\r
+ if (GhcbBackupSize > FixedPcdGet32 (PcdOvmfSecGhcbBackupSize)) {\r
+ //\r
+ // Not enough SEC backup pages allocated.\r
+ //\r
+ VmgExitIssueAssert (SevEsData);\r
+ }\r
+\r
+ //\r
+ // Save the active GHCB to a backup page.\r
+ // To access the correct backup page, increment the backup page pointer\r
+ // based on the current VcCount.\r
+ //\r
+ GhcbBackup = (GHCB *) FixedPcdGet32 (PcdOvmfSecGhcbBackupBase);\r
+ GhcbBackup += (SevEsData->VcCount - 2);\r
+\r
+ CopyMem (GhcbBackup, Ghcb, sizeof (*Ghcb));\r
+ }\r
+\r
+ VcRet = InternalVmgExitHandleVc (Ghcb, ExceptionType, SystemContext);\r
+\r
+ if (GhcbBackup != NULL) {\r
+ //\r
+ // Restore the active GHCB from the backup page.\r
+ //\r
+ CopyMem (Ghcb, GhcbBackup, sizeof (*Ghcb));\r
+ }\r
+\r
+ SevEsData->VcCount--;\r
+\r
+ if (InterruptState) {\r
+ EnableInterrupts ();\r
+ }\r
+\r
+ return VcRet;\r
+}\r
FILE_GUID = 0e923c25-13cd-430b-8714-ffe85652a97b\r
MODULE_TYPE = BASE\r
VERSION_STRING = 1.0\r
- LIBRARY_CLASS = VmgExitLib\r
+ LIBRARY_CLASS = VmgExitLib|PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_DRIVER\r
\r
#\r
# The following information is for reference only and not required by the build tools.\r
[Sources.common]\r
VmgExitLib.c\r
VmgExitVcHandler.c\r
+ VmgExitVcHandler.h\r
+ PeiDxeVmgExitVcHandler.c\r
\r
[Packages]\r
MdePkg/MdePkg.dec\r
#include <Base.h>\r
#include <Uefi.h>\r
#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemEncryptSevLib.h>\r
#include <Library/VmgExitLib.h>\r
#include <Register/Amd/Msr.h>\r
#include <Register/Intel/Cpuid.h>\r
#include <IndustryStandard/InstructionParsing.h>\r
\r
+#include "VmgExitVcHandler.h"\r
+\r
//\r
// Instruction execution mode definition\r
//\r
SEV_ES_INSTRUCTION_DATA *InstructionData\r
);\r
\r
-//\r
-// Per-CPU data mapping structure\r
-// Use UINT32 for cached indicators and compare to a specific value\r
-// so that the hypervisor can't indicate a value is cached by just\r
-// writing random data to that area.\r
-//\r
-typedef struct {\r
- UINT32 Dr7Cached;\r
- UINT64 Dr7;\r
-} SEV_ES_PER_CPU_DATA;\r
-\r
-\r
/**\r
Return a pointer to the contents of the specified register.\r
\r
\r
Performs the necessary processing to handle a #VC exception.\r
\r
+ @param[in, out] Ghcb Pointer to the GHCB\r
@param[in, out] ExceptionType Pointer to an EFI_EXCEPTION_TYPE to be set\r
as value to use on error.\r
@param[in, out] SystemContext Pointer to EFI_SYSTEM_CONTEXT\r
**/\r
EFI_STATUS\r
EFIAPI\r
-VmgExitHandleVc (\r
+InternalVmgExitHandleVc (\r
+ IN OUT GHCB *Ghcb,\r
IN OUT EFI_EXCEPTION_TYPE *ExceptionType,\r
IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
)\r
{\r
- MSR_SEV_ES_GHCB_REGISTER Msr;\r
EFI_SYSTEM_CONTEXT_X64 *Regs;\r
- GHCB *Ghcb;\r
NAE_EXIT NaeExit;\r
SEV_ES_INSTRUCTION_DATA InstructionData;\r
UINT64 ExitCode, Status;\r
\r
VcRet = EFI_SUCCESS;\r
\r
- Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);\r
- ASSERT (Msr.GhcbInfo.Function == 0);\r
- ASSERT (Msr.Ghcb != 0);\r
-\r
Regs = SystemContext.SystemContextX64;\r
- Ghcb = Msr.Ghcb;\r
\r
VmgInit (Ghcb, &InterruptState);\r
\r
\r
return VcRet;\r
}\r
+\r
+/**\r
+ Routine to allow ASSERT from within #VC.\r
+\r
+ @param[in, out] SevEsData Pointer to the per-CPU data\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VmgExitIssueAssert (\r
+ IN OUT SEV_ES_PER_CPU_DATA *SevEsData\r
+ )\r
+{\r
+ //\r
+ // Progress will be halted, so set VcCount to allow for ASSERT output\r
+ // to be seen.\r
+ //\r
+ SevEsData->VcCount = 0;\r
+\r
+ ASSERT (FALSE);\r
+ CpuDeadLoop ();\r
+}\r
--- /dev/null
+/** @file\r
+ X64 #VC Exception Handler functon header file.\r
+\r
+ Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef __VMG_EXIT_VC_HANDLER_H__\r
+#define __VMG_EXIT_VC_HANDLER_H__\r
+\r
+#include <Base.h>\r
+#include <Uefi.h>\r
+#include <Library/VmgExitLib.h>\r
+\r
+/**\r
+ Handle a #VC exception.\r
+\r
+ Performs the necessary processing to handle a #VC exception.\r
+\r
+ @param[in, out] Ghcb Pointer to the GHCB\r
+ @param[in, out] ExceptionType Pointer to an EFI_EXCEPTION_TYPE to be set\r
+ as value to use on error.\r
+ @param[in, out] SystemContext Pointer to EFI_SYSTEM_CONTEXT\r
+\r
+ @retval EFI_SUCCESS Exception handled\r
+ @retval EFI_UNSUPPORTED #VC not supported, (new) exception value to\r
+ propagate provided\r
+ @retval EFI_PROTOCOL_ERROR #VC handling failed, (new) exception value to\r
+ propagate provided\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InternalVmgExitHandleVc (\r
+ IN OUT GHCB *Ghcb,\r
+ IN OUT EFI_EXCEPTION_TYPE *ExceptionType,\r
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
+ );\r
+\r
+/**\r
+ Routine to allow ASSERT from within #VC.\r
+\r
+ @param[in, out] SevEsData Pointer to the per-CPU data\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VmgExitIssueAssert (\r
+ IN OUT SEV_ES_PER_CPU_DATA *SevEsData\r
+ );\r
+\r
+#endif\r
## The base address of the SEC GHCB page used by SEV-ES.\r
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|0|UINT32|0x40\r
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize|0|UINT32|0x41\r
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase|0|UINT32|0x44\r
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize|0|UINT32|0x45\r
\r
## The base address and size of the SEV Launch Secret Area provisioned\r
# after remote attestation. If this is set in the .fdf, the platform\r
!else\r
CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf\r
!endif\r
+ VmgExitLib|OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf\r
\r
[LibraryClasses.common.PEI_CORE]\r
HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf\r
0x00B000|0x001000\r
gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase|gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaSize\r
\r
+0x00C000|0x001000\r
+gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize\r
+\r
0x010000|0x010000\r
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize\r
\r
VOID\r
)\r
{\r
- VOID *GhcbBase;\r
- PHYSICAL_ADDRESS GhcbBasePa;\r
- UINTN GhcbPageCount, PageCount;\r
- RETURN_STATUS PcdStatus, DecryptStatus;\r
- IA32_DESCRIPTOR Gdtr;\r
- VOID *Gdt;\r
+ UINT8 *GhcbBase;\r
+ PHYSICAL_ADDRESS GhcbBasePa;\r
+ UINTN GhcbPageCount;\r
+ UINT8 *GhcbBackupBase;\r
+ UINT8 *GhcbBackupPages;\r
+ UINTN GhcbBackupPageCount;\r
+ SEV_ES_PER_CPU_DATA *SevEsData;\r
+ UINTN PageCount;\r
+ RETURN_STATUS PcdStatus, DecryptStatus;\r
+ IA32_DESCRIPTOR Gdtr;\r
+ VOID *Gdt;\r
\r
if (!MemEncryptSevEsIsEnabled ()) {\r
return;\r
"SEV-ES is enabled, %lu GHCB pages allocated starting at 0x%p\n",\r
(UINT64)GhcbPageCount, GhcbBase));\r
\r
+ //\r
+ // Allocate #VC recursion backup pages. The number of backup pages needed is\r
+ // one less than the maximum VC count.\r
+ //\r
+ GhcbBackupPageCount = mMaxCpuCount * (VMGEXIT_MAXIMUM_VC_COUNT - 1);\r
+ GhcbBackupBase = AllocatePages (GhcbBackupPageCount);\r
+ ASSERT (GhcbBackupBase != NULL);\r
+\r
+ GhcbBackupPages = GhcbBackupBase;\r
+ for (PageCount = 1; PageCount < GhcbPageCount; PageCount += 2) {\r
+ SevEsData =\r
+ (SEV_ES_PER_CPU_DATA *)(GhcbBase + EFI_PAGES_TO_SIZE (PageCount));\r
+ SevEsData->GhcbBackupPages = GhcbBackupPages;\r
+\r
+ GhcbBackupPages += EFI_PAGE_SIZE * (VMGEXIT_MAXIMUM_VC_COUNT - 1);\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO,\r
+ "SEV-ES is enabled, %lu GHCB backup pages allocated starting at 0x%p\n",\r
+ (UINT64)GhcbBackupPageCount, GhcbBackupBase));\r
+\r
AsmWriteMsr64 (MSR_SEV_ES_GHCB, GhcbBasePa);\r
\r
//\r