[edk2-devel] [PATCH 03/16] MdePkg/BaseLib: Add a new VMGEXIT instruction invocation for SVSM

Lendacky, Thomas via groups.io posted 16 patches 7 months, 2 weeks ago
There is a newer version of this series
[edk2-devel] [PATCH 03/16] MdePkg/BaseLib: Add a new VMGEXIT instruction invocation for SVSM
Posted by Lendacky, Thomas via groups.io 7 months, 2 weeks ago
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.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 MdePkg/Library/BaseLib/BaseLib.inf           |  2 +
 MdePkg/Include/Library/BaseLib.h             | 39 ++++++++
 MdePkg/Library/BaseLib/Ia32/VmgExitSvsm.nasm | 39 ++++++++
 MdePkg/Library/BaseLib/X64/VmgExitSvsm.nasm  | 94 ++++++++++++++++++++
 4 files changed, 174 insertions(+)

diff --git a/MdePkg/Library/BaseLib/BaseLib.inf b/MdePkg/Library/BaseLib/BaseLib.inf
index 6b46949be332..2b3d9af36706 100644
--- a/MdePkg/Library/BaseLib/BaseLib.inf
+++ b/MdePkg/Library/BaseLib/BaseLib.inf
@@ -187,6 +187,7 @@ [Sources.Ia32]
   Ia32/XGetBv.nasm
   Ia32/XSetBv.nasm
   Ia32/VmgExit.nasm
+  Ia32/VmgExitSvsm.nasm
 
   Ia32/DivS64x64Remainder.c
   Ia32/InternalSwitchStack.c | MSFT
@@ -328,6 +329,7 @@ [Sources.X64]
   X64/XGetBv.nasm
   X64/XSetBv.nasm
   X64/VmgExit.nasm
+  X64/VmgExitSvsm.nasm
   ChkStkGcc.c  | GCC
 
 [Sources.EBC]
diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h
index ca0d06c7f335..149519d85233 100644
--- a/MdePkg/Include/Library/BaseLib.h
+++ b/MdePkg/Include/Library/BaseLib.h
@@ -7655,6 +7655,45 @@ AsmVmgExit (
   VOID
   );
 
+///
+/// The structure used to supply and return data to and from the SVSM.
+///
+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;
+
+/**
+  Executes a VMGEXIT instruction (VMMCALL with a REP prefix) with arguments
+  and return code
+
+  Executes a VMGEXIT instruction placing the specified arguments in the
+  corresponding registers before invocation. Upon return an XCHG is done to
+  atomically clear and retrieve the SVSM call pending value. The returned RAX
+  register value becomes the function return code. This function is intended
+  for use with an SVSM. This function is only available on IA-32 and x64.
+
+  @param[in,out]  SvsmCallPending  Pointer to the location of the SVSM call data
+
+  @return                          Value of the RAX register on return
+
+**/
+UINT32
+EFIAPI
+AsmVmgExitSvsm (
+  IN OUT SVSM_CALL_DATA  *SvsmCallData
+  );
+
 /**
   Patch the immediate operand of an IA32 or X64 instruction such that the byte,
   word, dword or qword operand is encoded at the end of the instruction's
diff --git a/MdePkg/Library/BaseLib/Ia32/VmgExitSvsm.nasm b/MdePkg/Library/BaseLib/Ia32/VmgExitSvsm.nasm
new file mode 100644
index 000000000000..14717bd1af02
--- /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 000000000000..b8af78890611
--- /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
+
-- 
2.42.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#114629): https://edk2.groups.io/g/devel/message/114629
Mute This Topic: https://groups.io/mt/103986440/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-