1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #include <asm/asm-offsets.h> 3 #include <asm/frame.h> 4 #include <asm/asm.h> 5 #include <asm/tdx.h> 6 7 /* 8 * TDCALL and SEAMCALL are supported in Binutils >= 2.36. 9 */ 10 #define tdcall .byte 0x66,0x0f,0x01,0xcc 11 #define seamcall .byte 0x66,0x0f,0x01,0xcf 12 13 /* 14 * TDX_MODULE_CALL - common helper macro for both 15 * TDCALL and SEAMCALL instructions. 16 * 17 * TDCALL - used by TDX guests to make requests to the 18 * TDX module and hypercalls to the VMM. 19 * SEAMCALL - used by TDX hosts to make requests to the 20 * TDX module. 21 * 22 *------------------------------------------------------------------------- 23 * TDCALL/SEAMCALL ABI: 24 *------------------------------------------------------------------------- 25 * Input Registers: 26 * 27 * RAX - TDCALL/SEAMCALL Leaf number. 28 * RCX,RDX,RDI,RSI,RBX,R8-R15 - TDCALL/SEAMCALL Leaf specific input registers. 29 * 30 * Output Registers: 31 * 32 * RAX - TDCALL/SEAMCALL instruction error code. 33 * RCX,RDX,RDI,RSI,RBX,R8-R15 - TDCALL/SEAMCALL Leaf specific output registers. 34 * 35 *------------------------------------------------------------------------- 36 * 37 * So while the common core (RAX,RCX,RDX,R8-R11) fits nicely in the 38 * callee-clobbered registers and even leaves RDI,RSI free to act as a 39 * base pointer, some leafs (e.g., VP.ENTER) make a giant mess of things. 40 * 41 * For simplicity, assume that anything that needs the callee-saved regs 42 * also tramples on RDI,RSI. This isn't strictly true, see for example 43 * TDH.EXPORT.MEM. 44 */ 45 .macro TDX_MODULE_CALL host:req ret=0 saved=0 46 FRAME_BEGIN 47 48 /* Move Leaf ID to RAX */ 49 mov %rdi, %rax 50 51 /* Move other input regs from 'struct tdx_module_args' */ 52 movq TDX_MODULE_rcx(%rsi), %rcx 53 movq TDX_MODULE_rdx(%rsi), %rdx 54 movq TDX_MODULE_r8(%rsi), %r8 55 movq TDX_MODULE_r9(%rsi), %r9 56 movq TDX_MODULE_r10(%rsi), %r10 57 movq TDX_MODULE_r11(%rsi), %r11 58 59 .if \saved 60 /* 61 * Move additional input regs from the structure. For simplicity 62 * assume that anything needs the callee-saved regs also tramples 63 * on RDI/RSI (see VP.ENTER). 64 */ 65 /* Save those callee-saved GPRs as mandated by the x86_64 ABI */ 66 pushq %rbx 67 pushq %r12 68 pushq %r13 69 pushq %r14 70 pushq %r15 71 72 movq TDX_MODULE_r12(%rsi), %r12 73 movq TDX_MODULE_r13(%rsi), %r13 74 movq TDX_MODULE_r14(%rsi), %r14 75 movq TDX_MODULE_r15(%rsi), %r15 76 movq TDX_MODULE_rbx(%rsi), %rbx 77 78 .if \ret 79 /* Save the structure pointer as RSI is about to be clobbered */ 80 pushq %rsi 81 .endif 82 83 movq TDX_MODULE_rdi(%rsi), %rdi 84 /* RSI needs to be done at last */ 85 movq TDX_MODULE_rsi(%rsi), %rsi 86 .endif /* \saved */ 87 88 .if \host 89 .Lseamcall\@: 90 seamcall 91 /* 92 * SEAMCALL instruction is essentially a VMExit from VMX root 93 * mode to SEAM VMX root mode. VMfailInvalid (CF=1) indicates 94 * that the targeted SEAM firmware is not loaded or disabled, 95 * or P-SEAMLDR is busy with another SEAMCALL. %rax is not 96 * changed in this case. 97 * 98 * Set %rax to TDX_SEAMCALL_VMFAILINVALID for VMfailInvalid. 99 * This value will never be used as actual SEAMCALL error code as 100 * it is from the Reserved status code class. 101 */ 102 jc .Lseamcall_vmfailinvalid\@ 103 .else 104 tdcall 105 .endif 106 107 .if \ret 108 .if \saved 109 /* 110 * Restore the structure from stack to save the output registers 111 * 112 * In case of VP.ENTER returns due to TDVMCALL, all registers are 113 * valid thus no register can be used as spare to restore the 114 * structure from the stack (see "TDH.VP.ENTER Output Operands 115 * Definition on TDCALL(TDG.VP.VMCALL) Following a TD Entry"). 116 * For this case, need to make one register as spare by saving it 117 * to the stack and then manually load the structure pointer to 118 * the spare register. 119 * 120 * Note for other TDCALLs/SEAMCALLs there are spare registers 121 * thus no need for such hack but just use this for all. 122 */ 123 pushq %rax /* save the TDCALL/SEAMCALL return code */ 124 movq 8(%rsp), %rax /* restore the structure pointer */ 125 movq %rsi, TDX_MODULE_rsi(%rax) /* save RSI */ 126 popq %rax /* restore the return code */ 127 popq %rsi /* pop the structure pointer */ 128 129 /* Copy additional output regs to the structure */ 130 movq %r12, TDX_MODULE_r12(%rsi) 131 movq %r13, TDX_MODULE_r13(%rsi) 132 movq %r14, TDX_MODULE_r14(%rsi) 133 movq %r15, TDX_MODULE_r15(%rsi) 134 movq %rbx, TDX_MODULE_rbx(%rsi) 135 movq %rdi, TDX_MODULE_rdi(%rsi) 136 .endif /* \saved */ 137 138 /* Copy output registers to the structure */ 139 movq %rcx, TDX_MODULE_rcx(%rsi) 140 movq %rdx, TDX_MODULE_rdx(%rsi) 141 movq %r8, TDX_MODULE_r8(%rsi) 142 movq %r9, TDX_MODULE_r9(%rsi) 143 movq %r10, TDX_MODULE_r10(%rsi) 144 movq %r11, TDX_MODULE_r11(%rsi) 145 .endif /* \ret */ 146 147 .if \saved && \ret 148 /* 149 * Clear registers shared by guest for VP.VMCALL/VP.ENTER to prevent 150 * speculative use of guest's/VMM's values, including those are 151 * restored from the stack. 152 * 153 * See arch/x86/kvm/vmx/vmenter.S: 154 * 155 * In theory, a L1 cache miss when restoring register from stack 156 * could lead to speculative execution with guest's values. 157 * 158 * Note: RBP/RSP are not used as shared register. RSI has been 159 * restored already. 160 * 161 * XOR is cheap, thus unconditionally do for all leafs. 162 */ 163 xorl %ecx, %ecx 164 xorl %edx, %edx 165 xorl %r8d, %r8d 166 xorl %r9d, %r9d 167 xorl %r10d, %r10d 168 xorl %r11d, %r11d 169 xorl %r12d, %r12d 170 xorl %r13d, %r13d 171 xorl %r14d, %r14d 172 xorl %r15d, %r15d 173 xorl %ebx, %ebx 174 xorl %edi, %edi 175 .endif /* \ret && \host */ 176 177 .if \host 178 .Lout\@: 179 .endif 180 181 .if \saved 182 /* Restore callee-saved GPRs as mandated by the x86_64 ABI */ 183 popq %r15 184 popq %r14 185 popq %r13 186 popq %r12 187 popq %rbx 188 .endif /* \saved */ 189 190 FRAME_END 191 RET 192 193 .if \host 194 .Lseamcall_vmfailinvalid\@: 195 mov $TDX_SEAMCALL_VMFAILINVALID, %rax 196 jmp .Lseamcall_fail\@ 197 198 .Lseamcall_trap\@: 199 /* 200 * SEAMCALL caused #GP or #UD. By reaching here RAX contains 201 * the trap number. Convert the trap number to the TDX error 202 * code by setting TDX_SW_ERROR to the high 32-bits of RAX. 203 * 204 * Note cannot OR TDX_SW_ERROR directly to RAX as OR instruction 205 * only accepts 32-bit immediate at most. 206 */ 207 movq $TDX_SW_ERROR, %rdi 208 orq %rdi, %rax 209 210 .Lseamcall_fail\@: 211 .if \ret && \saved 212 /* pop the unused structure pointer back to RSI */ 213 popq %rsi 214 .endif 215 jmp .Lout\@ 216 217 _ASM_EXTABLE_FAULT(.Lseamcall\@, .Lseamcall_trap\@) 218 .endif /* \host */ 219 220 .endm
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.