/* SPDX-License-Identifier: GPL-2.0 */1#include <asm/asm-offsets.h>2#include <asm/frame.h>3#include <asm/asm.h>4#include <asm/tdx.h>56/*7* TDCALL and SEAMCALL are supported in Binutils >= 2.36.8*/9#define tdcall .byte 0x66,0x0f,0x01,0xcc10#define seamcall .byte 0x66,0x0f,0x01,0xcf1112/*13* TDX_MODULE_CALL - common helper macro for both14* TDCALL and SEAMCALL instructions.15*16* TDCALL - used by TDX guests to make requests to the17* TDX module and hypercalls to the VMM.18* SEAMCALL - used by TDX hosts to make requests to the19* TDX module.20*21*-------------------------------------------------------------------------22* TDCALL/SEAMCALL ABI:23*-------------------------------------------------------------------------24* Input Registers:25*26* RAX - TDCALL/SEAMCALL Leaf number.27* RCX,RDX,RDI,RSI,RBX,R8-R15 - TDCALL/SEAMCALL Leaf specific input registers.28*29* Output Registers:30*31* RAX - TDCALL/SEAMCALL instruction error code.32* RCX,RDX,RDI,RSI,RBX,R8-R15 - TDCALL/SEAMCALL Leaf specific output registers.33*34*-------------------------------------------------------------------------35*36* So while the common core (RAX,RCX,RDX,R8-R11) fits nicely in the37* callee-clobbered registers and even leaves RDI,RSI free to act as a38* base pointer, some leafs (e.g., VP.ENTER) make a giant mess of things.39*40* For simplicity, assume that anything that needs the callee-saved regs41* also tramples on RDI,RSI. This isn't strictly true, see for example42* TDH.EXPORT.MEM.43*/44.macro TDX_MODULE_CALL host:req ret=0 saved=045FRAME_BEGIN4647/* Move Leaf ID to RAX */48mov %rdi, %rax4950/* Move other input regs from 'struct tdx_module_args' */51movq TDX_MODULE_rcx(%rsi), %rcx52movq TDX_MODULE_rdx(%rsi), %rdx53movq TDX_MODULE_r8(%rsi), %r854movq TDX_MODULE_r9(%rsi), %r955movq TDX_MODULE_r10(%rsi), %r1056movq TDX_MODULE_r11(%rsi), %r115758.if \saved59/*60* Move additional input regs from the structure. For simplicity61* assume that anything needs the callee-saved regs also tramples62* on RDI/RSI (see VP.ENTER).63*/64/* Save those callee-saved GPRs as mandated by the x86_64 ABI */65pushq %rbx66pushq %r1267pushq %r1368pushq %r1469pushq %r157071movq TDX_MODULE_r12(%rsi), %r1272movq TDX_MODULE_r13(%rsi), %r1373movq TDX_MODULE_r14(%rsi), %r1474movq TDX_MODULE_r15(%rsi), %r1575movq TDX_MODULE_rbx(%rsi), %rbx7677.if \ret78/* Save the structure pointer as RSI is about to be clobbered */79pushq %rsi80.endif8182movq TDX_MODULE_rdi(%rsi), %rdi83/* RSI needs to be done at last */84movq TDX_MODULE_rsi(%rsi), %rsi85.endif /* \saved */8687.if \host88.Lseamcall\@:89seamcall90/*91* SEAMCALL instruction is essentially a VMExit from VMX root92* mode to SEAM VMX root mode. VMfailInvalid (CF=1) indicates93* that the targeted SEAM firmware is not loaded or disabled,94* or P-SEAMLDR is busy with another SEAMCALL. %rax is not95* changed in this case.96*97* Set %rax to TDX_SEAMCALL_VMFAILINVALID for VMfailInvalid.98* This value will never be used as actual SEAMCALL error code as99* it is from the Reserved status code class.100*/101jc .Lseamcall_vmfailinvalid\@102.else103tdcall104.endif105106.if \ret107.if \saved108/*109* Restore the structure from stack to save the output registers110*111* In case of VP.ENTER returns due to TDVMCALL, all registers are112* valid thus no register can be used as spare to restore the113* structure from the stack (see "TDH.VP.ENTER Output Operands114* Definition on TDCALL(TDG.VP.VMCALL) Following a TD Entry").115* For this case, need to make one register as spare by saving it116* to the stack and then manually load the structure pointer to117* the spare register.118*119* Note for other TDCALLs/SEAMCALLs there are spare registers120* thus no need for such hack but just use this for all.121*/122pushq %rax /* save the TDCALL/SEAMCALL return code */123movq 8(%rsp), %rax /* restore the structure pointer */124movq %rsi, TDX_MODULE_rsi(%rax) /* save RSI */125popq %rax /* restore the return code */126popq %rsi /* pop the structure pointer */127128/* Copy additional output regs to the structure */129movq %r12, TDX_MODULE_r12(%rsi)130movq %r13, TDX_MODULE_r13(%rsi)131movq %r14, TDX_MODULE_r14(%rsi)132movq %r15, TDX_MODULE_r15(%rsi)133movq %rbx, TDX_MODULE_rbx(%rsi)134movq %rdi, TDX_MODULE_rdi(%rsi)135.endif /* \saved */136137/* Copy output registers to the structure */138movq %rcx, TDX_MODULE_rcx(%rsi)139movq %rdx, TDX_MODULE_rdx(%rsi)140movq %r8, TDX_MODULE_r8(%rsi)141movq %r9, TDX_MODULE_r9(%rsi)142movq %r10, TDX_MODULE_r10(%rsi)143movq %r11, TDX_MODULE_r11(%rsi)144.endif /* \ret */145146.if \saved && \ret147/*148* Clear registers shared by guest for VP.VMCALL/VP.ENTER to prevent149* speculative use of guest's/VMM's values, including those are150* restored from the stack.151*152* See arch/x86/kvm/vmx/vmenter.S:153*154* In theory, a L1 cache miss when restoring register from stack155* could lead to speculative execution with guest's values.156*157* Note: RBP/RSP are not used as shared register. RSI has been158* restored already.159*160* XOR is cheap, thus unconditionally do for all leafs.161*/162xorl %ecx, %ecx163xorl %edx, %edx164xorl %r8d, %r8d165xorl %r9d, %r9d166xorl %r10d, %r10d167xorl %r11d, %r11d168xorl %r12d, %r12d169xorl %r13d, %r13d170xorl %r14d, %r14d171xorl %r15d, %r15d172xorl %ebx, %ebx173xorl %edi, %edi174.endif /* \ret && \host */175176.if \host177.Lout\@:178.endif179180.if \saved181/* Restore callee-saved GPRs as mandated by the x86_64 ABI */182popq %r15183popq %r14184popq %r13185popq %r12186popq %rbx187.endif /* \saved */188189FRAME_END190RET191192.if \host193.Lseamcall_vmfailinvalid\@:194mov $TDX_SEAMCALL_VMFAILINVALID, %rax195jmp .Lseamcall_fail\@196197.Lseamcall_trap\@:198/*199* SEAMCALL caused #GP or #UD. By reaching here RAX contains200* the trap number. Convert the trap number to the TDX error201* code by setting TDX_SW_ERROR to the high 32-bits of RAX.202*203* Note cannot OR TDX_SW_ERROR directly to RAX as OR instruction204* only accepts 32-bit immediate at most.205*/206movq $TDX_SW_ERROR, %rdi207orq %rdi, %rax208209.Lseamcall_fail\@:210.if \ret && \saved211/* pop the unused structure pointer back to RSI */212popq %rsi213.endif214jmp .Lout\@215216_ASM_EXTABLE_FAULT(.Lseamcall\@, .Lseamcall_trap\@)217.endif /* \host */218219.endm220221222