xref: /openbmc/linux/arch/x86/virt/vmx/tdx/tdxcall.S (revision 527a534c)
1*527a534cSKirill A. Shutemov/* SPDX-License-Identifier: GPL-2.0 */
2*527a534cSKirill A. Shutemov#include <asm/asm-offsets.h>
3*527a534cSKirill A. Shutemov#include <asm/tdx.h>
4*527a534cSKirill A. Shutemov
5*527a534cSKirill A. Shutemov/*
6*527a534cSKirill A. Shutemov * TDCALL and SEAMCALL are supported in Binutils >= 2.36.
7*527a534cSKirill A. Shutemov */
8*527a534cSKirill A. Shutemov#define tdcall		.byte 0x66,0x0f,0x01,0xcc
9*527a534cSKirill A. Shutemov#define seamcall	.byte 0x66,0x0f,0x01,0xcf
10*527a534cSKirill A. Shutemov
11*527a534cSKirill A. Shutemov/*
12*527a534cSKirill A. Shutemov * TDX_MODULE_CALL - common helper macro for both
13*527a534cSKirill A. Shutemov *                 TDCALL and SEAMCALL instructions.
14*527a534cSKirill A. Shutemov *
15*527a534cSKirill A. Shutemov * TDCALL   - used by TDX guests to make requests to the
16*527a534cSKirill A. Shutemov *            TDX module and hypercalls to the VMM.
17*527a534cSKirill A. Shutemov * SEAMCALL - used by TDX hosts to make requests to the
18*527a534cSKirill A. Shutemov *            TDX module.
19*527a534cSKirill A. Shutemov */
20*527a534cSKirill A. Shutemov.macro TDX_MODULE_CALL host:req
21*527a534cSKirill A. Shutemov	/*
22*527a534cSKirill A. Shutemov	 * R12 will be used as temporary storage for struct tdx_module_output
23*527a534cSKirill A. Shutemov	 * pointer. Since R12-R15 registers are not used by TDCALL/SEAMCALL
24*527a534cSKirill A. Shutemov	 * services supported by this function, it can be reused.
25*527a534cSKirill A. Shutemov	 */
26*527a534cSKirill A. Shutemov
27*527a534cSKirill A. Shutemov	/* Callee saved, so preserve it */
28*527a534cSKirill A. Shutemov	push %r12
29*527a534cSKirill A. Shutemov
30*527a534cSKirill A. Shutemov	/*
31*527a534cSKirill A. Shutemov	 * Push output pointer to stack.
32*527a534cSKirill A. Shutemov	 * After the operation, it will be fetched into R12 register.
33*527a534cSKirill A. Shutemov	 */
34*527a534cSKirill A. Shutemov	push %r9
35*527a534cSKirill A. Shutemov
36*527a534cSKirill A. Shutemov	/* Mangle function call ABI into TDCALL/SEAMCALL ABI: */
37*527a534cSKirill A. Shutemov	/* Move Leaf ID to RAX */
38*527a534cSKirill A. Shutemov	mov %rdi, %rax
39*527a534cSKirill A. Shutemov	/* Move input 4 to R9 */
40*527a534cSKirill A. Shutemov	mov %r8,  %r9
41*527a534cSKirill A. Shutemov	/* Move input 3 to R8 */
42*527a534cSKirill A. Shutemov	mov %rcx, %r8
43*527a534cSKirill A. Shutemov	/* Move input 1 to RCX */
44*527a534cSKirill A. Shutemov	mov %rsi, %rcx
45*527a534cSKirill A. Shutemov	/* Leave input param 2 in RDX */
46*527a534cSKirill A. Shutemov
47*527a534cSKirill A. Shutemov	.if \host
48*527a534cSKirill A. Shutemov	seamcall
49*527a534cSKirill A. Shutemov	/*
50*527a534cSKirill A. Shutemov	 * SEAMCALL instruction is essentially a VMExit from VMX root
51*527a534cSKirill A. Shutemov	 * mode to SEAM VMX root mode.  VMfailInvalid (CF=1) indicates
52*527a534cSKirill A. Shutemov	 * that the targeted SEAM firmware is not loaded or disabled,
53*527a534cSKirill A. Shutemov	 * or P-SEAMLDR is busy with another SEAMCALL.  %rax is not
54*527a534cSKirill A. Shutemov	 * changed in this case.
55*527a534cSKirill A. Shutemov	 *
56*527a534cSKirill A. Shutemov	 * Set %rax to TDX_SEAMCALL_VMFAILINVALID for VMfailInvalid.
57*527a534cSKirill A. Shutemov	 * This value will never be used as actual SEAMCALL error code as
58*527a534cSKirill A. Shutemov	 * it is from the Reserved status code class.
59*527a534cSKirill A. Shutemov	 */
60*527a534cSKirill A. Shutemov	jnc .Lno_vmfailinvalid
61*527a534cSKirill A. Shutemov	mov $TDX_SEAMCALL_VMFAILINVALID, %rax
62*527a534cSKirill A. Shutemov.Lno_vmfailinvalid:
63*527a534cSKirill A. Shutemov
64*527a534cSKirill A. Shutemov	.else
65*527a534cSKirill A. Shutemov	tdcall
66*527a534cSKirill A. Shutemov	.endif
67*527a534cSKirill A. Shutemov
68*527a534cSKirill A. Shutemov	/*
69*527a534cSKirill A. Shutemov	 * Fetch output pointer from stack to R12 (It is used
70*527a534cSKirill A. Shutemov	 * as temporary storage)
71*527a534cSKirill A. Shutemov	 */
72*527a534cSKirill A. Shutemov	pop %r12
73*527a534cSKirill A. Shutemov
74*527a534cSKirill A. Shutemov	/*
75*527a534cSKirill A. Shutemov	 * Since this macro can be invoked with NULL as an output pointer,
76*527a534cSKirill A. Shutemov	 * check if caller provided an output struct before storing output
77*527a534cSKirill A. Shutemov	 * registers.
78*527a534cSKirill A. Shutemov	 *
79*527a534cSKirill A. Shutemov	 * Update output registers, even if the call failed (RAX != 0).
80*527a534cSKirill A. Shutemov	 * Other registers may contain details of the failure.
81*527a534cSKirill A. Shutemov	 */
82*527a534cSKirill A. Shutemov	test %r12, %r12
83*527a534cSKirill A. Shutemov	jz .Lno_output_struct
84*527a534cSKirill A. Shutemov
85*527a534cSKirill A. Shutemov	/* Copy result registers to output struct: */
86*527a534cSKirill A. Shutemov	movq %rcx, TDX_MODULE_rcx(%r12)
87*527a534cSKirill A. Shutemov	movq %rdx, TDX_MODULE_rdx(%r12)
88*527a534cSKirill A. Shutemov	movq %r8,  TDX_MODULE_r8(%r12)
89*527a534cSKirill A. Shutemov	movq %r9,  TDX_MODULE_r9(%r12)
90*527a534cSKirill A. Shutemov	movq %r10, TDX_MODULE_r10(%r12)
91*527a534cSKirill A. Shutemov	movq %r11, TDX_MODULE_r11(%r12)
92*527a534cSKirill A. Shutemov
93*527a534cSKirill A. Shutemov.Lno_output_struct:
94*527a534cSKirill A. Shutemov	/* Restore the state of R12 register */
95*527a534cSKirill A. Shutemov	pop %r12
96*527a534cSKirill A. Shutemov.endm
97