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