From: Tom Lendacky <thomas.lenda...@amd.com> Under SEV-ES, a CPUID intercept generates a #VC exception. VMGEXIT must be used to allow the hypervisor to handle this intercept.
Add support to construct the required GHCB values to support a CPUID NAE event. Additionally, CPUID 0x0000_000d requires XCR0 to be supplied in the GHCB, so add support to issue the XGETBV instruction. Signed-off-by: Tom Lendacky <thomas.lenda...@amd.com> --- MdePkg/Library/BaseLib/BaseLib.inf | 1 + MdePkg/Include/Library/BaseLib.h | 16 +++++++ MdePkg/Library/BaseLib/X64/GccInline.c | 28 ++++++++++++ .../X64/AMDSevVcCommon.c | 45 +++++++++++++++++++ MdePkg/Library/BaseLib/X64/XGetBv.nasm | 39 ++++++++++++++++ 5 files changed, 129 insertions(+) create mode 100644 MdePkg/Library/BaseLib/X64/XGetBv.nasm diff --git a/MdePkg/Library/BaseLib/BaseLib.inf b/MdePkg/Library/BaseLib/BaseLib.inf index a41401340f95..7c1c077c63a9 100644 --- a/MdePkg/Library/BaseLib/BaseLib.inf +++ b/MdePkg/Library/BaseLib/BaseLib.inf @@ -287,6 +287,7 @@ [Sources.X64] X64/ReadCr0.nasm| MSFT X64/ReadEflags.nasm| MSFT X64/VmgExit.nasm | MSFT + X64/XGetBv.nasm | MSFT X64/Non-existing.c diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h index 80bd5cf57a72..ae16fa6f1c52 100644 --- a/MdePkg/Include/Library/BaseLib.h +++ b/MdePkg/Include/Library/BaseLib.h @@ -7893,6 +7893,22 @@ AsmVmgExit ( VOID ); +/** + Executes a XGETBV instruction + + Executes a XGETBV instruction. This function is only available on IA-32 and + x64. + + @param[in] Index Extended control register index + + @retval The current value of the extended control register +**/ +UINT64 +EFIAPI +AsmXGetBv ( + IN UINT32 Index + ); + /** Patch the immediate operand of an IA32 or X64 instruction such that the byte, diff --git a/MdePkg/Library/BaseLib/X64/GccInline.c b/MdePkg/Library/BaseLib/X64/GccInline.c index 17539caa0798..46aa96d67ab9 100644 --- a/MdePkg/Library/BaseLib/X64/GccInline.c +++ b/MdePkg/Library/BaseLib/X64/GccInline.c @@ -1814,4 +1814,32 @@ AsmVmgExit ( __asm__ __volatile__ ("rep; vmmcall":::"memory"); } +/** + Executes a XGETBV instruction + + Executes a XGETBV instruction. This function is only available on IA-32 and + x64. + + @param[in] Index Extended control register index + + @retval The current value of the extended control register +**/ +UINT64 +EFIAPI +AsmXGetBv ( + IN UINT32 Index + ) +{ + UINT32 LowData; + UINT32 HighData; + + __asm__ __volatile__ ( + "xgetbv" + : "=a" (LowData), // %0 + "=d" (HighData) // %1 + : "c" (Index) // %2 + ); + + return (((UINT64)HighData) << 32) | LowData; +} diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c index 2bc156840e74..66cd0f9eb196 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/AMDSevVcCommon.c @@ -3,6 +3,8 @@ #include <Library/DebugLib.h> #include "AMDSevVcCommon.h" +#define CR4_OSXSAVE (1 << 18) + typedef enum { LongMode64Bit = 0, LongModeCompat32Bit, @@ -473,6 +475,45 @@ IoioExit ( return 0; } +STATIC +UINTN +CpuidExit ( + GHCB *Ghcb, + EFI_SYSTEM_CONTEXT_X64 *Regs, + SEV_ES_INSTRUCTION_DATA *InstructionData + ) +{ + UINTN Status; + + Ghcb->SaveArea.Rax = Regs->Rax; + GhcbSetRegValid (Ghcb, GhcbRax); + Ghcb->SaveArea.Rcx = Regs->Rcx; + GhcbSetRegValid (Ghcb, GhcbRcx); + if (Regs->Rax == 0x0000000d) { + Ghcb->SaveArea.XCr0 = (AsmReadCr4 () & CR4_OSXSAVE) ? AsmXGetBv (0) : 1; + GhcbSetRegValid (Ghcb, GhcbXCr0); + } + + Status = VmgExit (Ghcb, SvmExitCpuid, 0, 0); + if (Status) { + return Status; + } + + if (!GhcbIsRegValid (Ghcb, GhcbRax) || + !GhcbIsRegValid (Ghcb, GhcbRbx) || + !GhcbIsRegValid (Ghcb, GhcbRcx) || + !GhcbIsRegValid (Ghcb, GhcbRdx)) { + VmgExit (Ghcb, SvmExitUnsupported, SvmExitCpuid, 0); + ASSERT (0); + } + Regs->Rax = Ghcb->SaveArea.Rax; + Regs->Rbx = Ghcb->SaveArea.Rbx; + Regs->Rcx = Ghcb->SaveArea.Rcx; + Regs->Rdx = Ghcb->SaveArea.Rdx; + + return 0; +} + UINTN DoVcCommon ( GHCB *Ghcb, @@ -489,6 +530,10 @@ DoVcCommon ( ExitCode = Regs->ExceptionData; switch (ExitCode) { + case SvmExitCpuid: + NaeExit = CpuidExit; + break; + case SvmExitIoioProt: NaeExit = IoioExit; break; diff --git a/MdePkg/Library/BaseLib/X64/XGetBv.nasm b/MdePkg/Library/BaseLib/X64/XGetBv.nasm new file mode 100644 index 000000000000..83c10b40e369 --- /dev/null +++ b/MdePkg/Library/BaseLib/X64/XGetBv.nasm @@ -0,0 +1,39 @@ +;------------------------------------------------------------------------------ +; +; Copyright (c) 2019, Advanced Micro Device, Inc. All rights reserved.<BR> +; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Module Name: +; +; XGetBv.Asm +; +; Abstract: +; +; AsmXgetBv function +; +; Notes: +; +;------------------------------------------------------------------------------ + + DEFAULT REL + SECTION .text + +;------------------------------------------------------------------------------ +; VOID +; EFIAPI +; AsmXGetBv ( +; IN UINT32 Index +; ); +;------------------------------------------------------------------------------ +global ASM_PFX(AsmXGetBv) +ASM_PFX(AsmXGetBv): + xgetbv + shl rdx, 0x20 + or rax, rdx + ret -- 2.17.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#46099): https://edk2.groups.io/g/devel/message/46099 Mute This Topic: https://groups.io/mt/32966271/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-