mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-09-02 16:44:59 +00:00

Intel TDX protects guest VM's from malicious host and certain physical attacks. TDX introduces a new operation mode, Secure Arbitration Mode (SEAM) to isolate and protect guest VM's. A TDX guest VM runs in SEAM and, unlike VMX, direct control and interaction with the guest by the host VMM is not possible. Instead, Intel TDX Module, which also runs in SEAM, provides a SEAMCALL API. The SEAMCALL that provides the ability to enter a guest is TDH.VP.ENTER. The TDX Module processes TDH.VP.ENTER, and enters the guest via VMX VMLAUNCH/VMRESUME instructions. When a guest VM-exit requires host VMM interaction, the TDH.VP.ENTER SEAMCALL returns to the host VMM (KVM). Add tdh_vp_enter() to wrap the SEAMCALL invocation of TDH.VP.ENTER; tdh_vp_enter() needs to be noinstr because VM entry in KVM is noinstr as well, which is for two reasons: * marking the area as CT_STATE_GUEST via guest_state_enter_irqoff() and guest_state_exit_irqoff() * IRET must be avoided between VM-exit and NMI handling, in order to avoid prematurely releasing the NMI inhibit. TDH.VP.ENTER is different from other SEAMCALLs in several ways: it uses more arguments, and after it returns some host state may need to be restored. Therefore tdh_vp_enter() uses __seamcall_saved_ret() instead of __seamcall_ret(); since it is the only caller of __seamcall_saved_ret(), it can be made noinstr also. TDH.VP.ENTER arguments are passed through General Purpose Registers (GPRs). For the special case of the TD guest invoking TDG.VP.VMCALL, nearly any GPR can be used, as well as XMM0 to XMM15. Notably, RBP is not used, and Linux mandates the TDX Module feature NO_RBP_MOD, which is enforced elsewhere. Additionally, XMM registers are not required for the existing Guest Hypervisor Communication Interface and are handled by existing KVM code should they be modified by the guest. There are 2 input formats and 5 output formats for TDH.VP.ENTER arguments. Input #1 : Initial entry or following a previous async. TD Exit Input #2 : Following a previous TDCALL(TDG.VP.VMCALL) Output #1 : On Error (No TD Entry) Output #2 : Async. Exits with a VMX Architectural Exit Reason Output #3 : Async. Exits with a non-VMX TD Exit Status Output #4 : Async. Exits with Cross-TD Exit Details Output #5 : On TDCALL(TDG.VP.VMCALL) Currently, to keep things simple, the wrapper function does not attempt to support different formats, and just passes all the GPRs that could be used. The GPR values are held by KVM in the area set aside for guest GPRs. KVM code uses the guest GPR area (vcpu->arch.regs[]) to set up for or process results of tdh_vp_enter(). Therefore changing tdh_vp_enter() to use more complex argument formats would also alter the way KVM code interacts with tdh_vp_enter(). Signed-off-by: Kai Huang <kai.huang@intel.com> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Message-ID: <20241121201448.36170-2-adrian.hunter@intel.com> Acked-by: Dave Hansen <dave.hansen@linux.intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
65 lines
2.0 KiB
ArmAsm
65 lines
2.0 KiB
ArmAsm
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#include <linux/linkage.h>
|
|
#include <asm/frame.h>
|
|
|
|
#include "tdxcall.S"
|
|
|
|
/*
|
|
* __seamcall() - Host-side interface functions to SEAM software
|
|
* (the P-SEAMLDR or the TDX module).
|
|
*
|
|
* __seamcall() function ABI:
|
|
*
|
|
* @fn (RDI) - SEAMCALL Leaf number, moved to RAX
|
|
* @args (RSI) - struct tdx_module_args for input
|
|
*
|
|
* Only RCX/RDX/R8-R11 are used as input registers.
|
|
*
|
|
* Return (via RAX) TDX_SEAMCALL_VMFAILINVALID if the SEAMCALL itself
|
|
* fails, or the completion status of the SEAMCALL leaf function.
|
|
*/
|
|
SYM_FUNC_START(__seamcall)
|
|
TDX_MODULE_CALL host=1
|
|
SYM_FUNC_END(__seamcall)
|
|
|
|
/*
|
|
* __seamcall_ret() - Host-side interface functions to SEAM software
|
|
* (the P-SEAMLDR or the TDX module), with saving output registers to
|
|
* the 'struct tdx_module_args' used as input.
|
|
*
|
|
* __seamcall_ret() function ABI:
|
|
*
|
|
* @fn (RDI) - SEAMCALL Leaf number, moved to RAX
|
|
* @args (RSI) - struct tdx_module_args for input and output
|
|
*
|
|
* Only RCX/RDX/R8-R11 are used as input/output registers.
|
|
*
|
|
* Return (via RAX) TDX_SEAMCALL_VMFAILINVALID if the SEAMCALL itself
|
|
* fails, or the completion status of the SEAMCALL leaf function.
|
|
*/
|
|
SYM_FUNC_START(__seamcall_ret)
|
|
TDX_MODULE_CALL host=1 ret=1
|
|
SYM_FUNC_END(__seamcall_ret)
|
|
|
|
/* KVM requires non-instrumentable __seamcall_saved_ret() for TDH.VP.ENTER */
|
|
.section .noinstr.text, "ax"
|
|
|
|
/*
|
|
* __seamcall_saved_ret() - Host-side interface functions to SEAM software
|
|
* (the P-SEAMLDR or the TDX module), with saving output registers to the
|
|
* 'struct tdx_module_args' used as input.
|
|
*
|
|
* __seamcall_saved_ret() function ABI:
|
|
*
|
|
* @fn (RDI) - SEAMCALL Leaf number, moved to RAX
|
|
* @args (RSI) - struct tdx_module_args for input and output
|
|
*
|
|
* All registers in @args are used as input/output registers.
|
|
*
|
|
* Return (via RAX) TDX_SEAMCALL_VMFAILINVALID if the SEAMCALL itself
|
|
* fails, or the completion status of the SEAMCALL leaf function.
|
|
*/
|
|
SYM_FUNC_START(__seamcall_saved_ret)
|
|
TDX_MODULE_CALL host=1 ret=1 saved=1
|
|
SYM_FUNC_END(__seamcall_saved_ret)
|