diff options
author | Tom Lendacky <thomas.lendacky@amd.com> | 2024-03-08 07:31:25 -0800 |
---|---|---|
committer | mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> | 2024-04-17 18:30:03 +0000 |
commit | c0bf953fe889f5a47fb830cec53a57bfa2380b4d (patch) | |
tree | 5783b0e313c076f18ba240cd8ff49f592f87d83e /MdePkg/Library | |
parent | 8ccbf075f0f4451c760ab56288623c00e4d96e65 (diff) | |
download | edk2-c0bf953fe889f5a47fb830cec53a57bfa2380b4d.zip edk2-c0bf953fe889f5a47fb830cec53a57bfa2380b4d.tar.gz edk2-c0bf953fe889f5a47fb830cec53a57bfa2380b4d.tar.bz2 |
MdePkg/BaseLib: Add a new VMGEXIT instruction invocation for SVSM
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4654
The SVSM specification relies on a specific register calling convention to
hold the parameters that are associated with the SVSM request. The SVSM is
invoked by requesting the hypervisor to run the VMPL0 VMSA of the guest
using the GHCB MSR Protocol or a GHCB NAE event.
Create a new version of the VMGEXIT instruction that will adhere to this
calling convention and load the SVSM function arguments into the proper
register before invoking the VMGEXIT instruction. On return, perform the
atomic exchange on the SVSM call pending value as specified in the SVSM
specification.
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Diffstat (limited to 'MdePkg/Library')
-rw-r--r-- | MdePkg/Library/BaseLib/BaseLib.inf | 2 | ||||
-rw-r--r-- | MdePkg/Library/BaseLib/Ia32/VmgExitSvsm.nasm | 39 | ||||
-rw-r--r-- | MdePkg/Library/BaseLib/X64/VmgExitSvsm.nasm | 94 |
3 files changed, 135 insertions, 0 deletions
diff --git a/MdePkg/Library/BaseLib/BaseLib.inf b/MdePkg/Library/BaseLib/BaseLib.inf index 4dbe94b..26e66a8 100644 --- a/MdePkg/Library/BaseLib/BaseLib.inf +++ b/MdePkg/Library/BaseLib/BaseLib.inf @@ -187,6 +187,7 @@ Ia32/XGetBv.nasm
Ia32/XSetBv.nasm
Ia32/VmgExit.nasm
+ Ia32/VmgExitSvsm.nasm
Ia32/DivS64x64Remainder.c
Ia32/InternalSwitchStack.c | MSFT
@@ -328,6 +329,7 @@ X64/XGetBv.nasm
X64/XSetBv.nasm
X64/VmgExit.nasm
+ X64/VmgExitSvsm.nasm
ChkStkGcc.c | GCC
[Sources.EBC]
diff --git a/MdePkg/Library/BaseLib/Ia32/VmgExitSvsm.nasm b/MdePkg/Library/BaseLib/Ia32/VmgExitSvsm.nasm new file mode 100644 index 0000000..14717bd --- /dev/null +++ b/MdePkg/Library/BaseLib/Ia32/VmgExitSvsm.nasm @@ -0,0 +1,39 @@ +;------------------------------------------------------------------------------
+;
+; Copyright (C) 2024, Advanced Micro Devices, Inc. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+; VmgExitSvsm.Asm
+;
+; Abstract:
+;
+; AsmVmgExitSvsm function
+;
+; Notes:
+;
+;------------------------------------------------------------------------------
+
+ DEFAULT REL
+ SECTION .text
+
+;------------------------------------------------------------------------------
+; UINT32
+; EFIAPI
+; AsmVmgExitSvsm (
+; SVSM_CALL_DATA *SvsmCallData
+; );
+;------------------------------------------------------------------------------
+global ASM_PFX(AsmVmgExitSvsm)
+ASM_PFX(AsmVmgExitSvsm):
+;
+; NASM doesn't support the vmmcall instruction in 32-bit mode and NASM versions
+; before 2.12 cannot translate the 64-bit "rep vmmcall" instruction into elf32
+; format. Given that VMGEXIT does not make sense on IA32, provide a stub
+; implementation that is identical to CpuBreakpoint(). In practice,
+; AsmVmgExitSvsm() should never be called on IA32.
+;
+ int 3
+ ret
+
diff --git a/MdePkg/Library/BaseLib/X64/VmgExitSvsm.nasm b/MdePkg/Library/BaseLib/X64/VmgExitSvsm.nasm new file mode 100644 index 0000000..b8af788 --- /dev/null +++ b/MdePkg/Library/BaseLib/X64/VmgExitSvsm.nasm @@ -0,0 +1,94 @@ +;------------------------------------------------------------------------------
+;
+; Copyright (C) 2024, Advanced Micro Devices, Inc. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+; VmgExitSvsm.Asm
+;
+; Abstract:
+;
+; AsmVmgExitSvsm function
+;
+; Notes:
+;
+;------------------------------------------------------------------------------
+
+ DEFAULT REL
+ SECTION .text
+
+;------------------------------------------------------------------------------
+; typedef struct {
+; VOID *Caa;
+; UINT64 RaxIn;
+; UINT64 RcxIn;
+; UINT64 RdxIn;
+; UINT64 R8In;
+; UINT64 R9In;
+; UINT64 RaxOut;
+; UINT64 RcxOut;
+; UINT64 RdxOut;
+; UINT64 R8Out;
+; UINT64 R9Out;
+; UINT8 *CallPending;
+; } SVSM_CALL_DATA;
+;
+; UINT32
+; EFIAPI
+; AsmVmgExitSvsm (
+; SVSM_CALL_DATA *SvsmCallData
+; );
+;------------------------------------------------------------------------------
+global ASM_PFX(AsmVmgExitSvsm)
+ASM_PFX(AsmVmgExitSvsm):
+ push r10
+ push r11
+ push r12
+
+;
+; Calling convention has SvsmCallData in RCX. Move RCX to R12 in order to
+; properly populate the SVSM register state.
+;
+ mov r12, rcx
+
+ mov rax, [r12 + 8]
+ mov rcx, [r12 + 16]
+ mov rdx, [r12 + 24]
+ mov r8, [r12 + 32]
+ mov r9, [r12 + 40]
+
+;
+; Set CA call pending
+;
+ mov r10, [r12]
+ mov byte [r10], 1
+
+ rep vmmcall
+
+ mov [r12 + 48], rax
+ mov [r12 + 56], rcx
+ mov [r12 + 64], rdx
+ mov [r12 + 72], r8
+ mov [r12 + 80], r9
+
+;
+; Perform the atomic exchange and return the CA call pending value.
+; The call pending value is a one-byte field at offset 0 into the CA,
+; which is currently the value in R10.
+;
+
+ mov r11, [r12 + 88] ; Get CallPending address
+ mov cl, byte [r11]
+ xchg byte [r10], cl
+ mov byte [r11], cl ; Return the exchanged value
+
+ pop r12
+ pop r11
+ pop r10
+
+;
+; RAX has the value to be returned from the SVSM
+;
+ ret
+
|