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