162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#include <asm/asm-offsets.h>
362306a36Sopenharmony_ci#include <asm/tdx.h>
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci/*
662306a36Sopenharmony_ci * TDCALL and SEAMCALL are supported in Binutils >= 2.36.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci#define tdcall		.byte 0x66,0x0f,0x01,0xcc
962306a36Sopenharmony_ci#define seamcall	.byte 0x66,0x0f,0x01,0xcf
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/*
1262306a36Sopenharmony_ci * TDX_MODULE_CALL - common helper macro for both
1362306a36Sopenharmony_ci *                 TDCALL and SEAMCALL instructions.
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci * TDCALL   - used by TDX guests to make requests to the
1662306a36Sopenharmony_ci *            TDX module and hypercalls to the VMM.
1762306a36Sopenharmony_ci * SEAMCALL - used by TDX hosts to make requests to the
1862306a36Sopenharmony_ci *            TDX module.
1962306a36Sopenharmony_ci */
2062306a36Sopenharmony_ci.macro TDX_MODULE_CALL host:req
2162306a36Sopenharmony_ci	/*
2262306a36Sopenharmony_ci	 * R12 will be used as temporary storage for struct tdx_module_output
2362306a36Sopenharmony_ci	 * pointer. Since R12-R15 registers are not used by TDCALL/SEAMCALL
2462306a36Sopenharmony_ci	 * services supported by this function, it can be reused.
2562306a36Sopenharmony_ci	 */
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	/* Callee saved, so preserve it */
2862306a36Sopenharmony_ci	push %r12
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	/*
3162306a36Sopenharmony_ci	 * Push output pointer to stack.
3262306a36Sopenharmony_ci	 * After the operation, it will be fetched into R12 register.
3362306a36Sopenharmony_ci	 */
3462306a36Sopenharmony_ci	push %r9
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	/* Mangle function call ABI into TDCALL/SEAMCALL ABI: */
3762306a36Sopenharmony_ci	/* Move Leaf ID to RAX */
3862306a36Sopenharmony_ci	mov %rdi, %rax
3962306a36Sopenharmony_ci	/* Move input 4 to R9 */
4062306a36Sopenharmony_ci	mov %r8,  %r9
4162306a36Sopenharmony_ci	/* Move input 3 to R8 */
4262306a36Sopenharmony_ci	mov %rcx, %r8
4362306a36Sopenharmony_ci	/* Move input 1 to RCX */
4462306a36Sopenharmony_ci	mov %rsi, %rcx
4562306a36Sopenharmony_ci	/* Leave input param 2 in RDX */
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	.if \host
4862306a36Sopenharmony_ci	seamcall
4962306a36Sopenharmony_ci	/*
5062306a36Sopenharmony_ci	 * SEAMCALL instruction is essentially a VMExit from VMX root
5162306a36Sopenharmony_ci	 * mode to SEAM VMX root mode.  VMfailInvalid (CF=1) indicates
5262306a36Sopenharmony_ci	 * that the targeted SEAM firmware is not loaded or disabled,
5362306a36Sopenharmony_ci	 * or P-SEAMLDR is busy with another SEAMCALL.  %rax is not
5462306a36Sopenharmony_ci	 * changed in this case.
5562306a36Sopenharmony_ci	 *
5662306a36Sopenharmony_ci	 * Set %rax to TDX_SEAMCALL_VMFAILINVALID for VMfailInvalid.
5762306a36Sopenharmony_ci	 * This value will never be used as actual SEAMCALL error code as
5862306a36Sopenharmony_ci	 * it is from the Reserved status code class.
5962306a36Sopenharmony_ci	 */
6062306a36Sopenharmony_ci	jnc .Lno_vmfailinvalid
6162306a36Sopenharmony_ci	mov $TDX_SEAMCALL_VMFAILINVALID, %rax
6262306a36Sopenharmony_ci.Lno_vmfailinvalid:
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	.else
6562306a36Sopenharmony_ci	tdcall
6662306a36Sopenharmony_ci	.endif
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	/*
6962306a36Sopenharmony_ci	 * Fetch output pointer from stack to R12 (It is used
7062306a36Sopenharmony_ci	 * as temporary storage)
7162306a36Sopenharmony_ci	 */
7262306a36Sopenharmony_ci	pop %r12
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	/*
7562306a36Sopenharmony_ci	 * Since this macro can be invoked with NULL as an output pointer,
7662306a36Sopenharmony_ci	 * check if caller provided an output struct before storing output
7762306a36Sopenharmony_ci	 * registers.
7862306a36Sopenharmony_ci	 *
7962306a36Sopenharmony_ci	 * Update output registers, even if the call failed (RAX != 0).
8062306a36Sopenharmony_ci	 * Other registers may contain details of the failure.
8162306a36Sopenharmony_ci	 */
8262306a36Sopenharmony_ci	test %r12, %r12
8362306a36Sopenharmony_ci	jz .Lno_output_struct
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	/* Copy result registers to output struct: */
8662306a36Sopenharmony_ci	movq %rcx, TDX_MODULE_rcx(%r12)
8762306a36Sopenharmony_ci	movq %rdx, TDX_MODULE_rdx(%r12)
8862306a36Sopenharmony_ci	movq %r8,  TDX_MODULE_r8(%r12)
8962306a36Sopenharmony_ci	movq %r9,  TDX_MODULE_r9(%r12)
9062306a36Sopenharmony_ci	movq %r10, TDX_MODULE_r10(%r12)
9162306a36Sopenharmony_ci	movq %r11, TDX_MODULE_r11(%r12)
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci.Lno_output_struct:
9462306a36Sopenharmony_ci	/* Restore the state of R12 register */
9562306a36Sopenharmony_ci	pop %r12
9662306a36Sopenharmony_ci.endm
97