1/* SPDX-License-Identifier: GPL-2.0 */ 2#include <asm/asm-offsets.h> 3#include <asm/asm.h> 4#include <asm/frame.h> 5#include <asm/unwind_hints.h> 6 7#include <linux/linkage.h> 8#include <linux/bits.h> 9#include <linux/errno.h> 10 11#include "../../virt/vmx/tdx/tdxcall.S" 12 13/* 14 * Bitmasks of exposed registers (with VMM). 15 */ 16#define TDX_RDX BIT(2) 17#define TDX_RBX BIT(3) 18#define TDX_RSI BIT(6) 19#define TDX_RDI BIT(7) 20#define TDX_R8 BIT(8) 21#define TDX_R9 BIT(9) 22#define TDX_R10 BIT(10) 23#define TDX_R11 BIT(11) 24#define TDX_R12 BIT(12) 25#define TDX_R13 BIT(13) 26#define TDX_R14 BIT(14) 27#define TDX_R15 BIT(15) 28 29/* 30 * These registers are clobbered to hold arguments for each 31 * TDVMCALL. They are safe to expose to the VMM. 32 * Each bit in this mask represents a register ID. Bit field 33 * details can be found in TDX GHCI specification, section 34 * titled "TDCALL [TDG.VP.VMCALL] leaf". 35 */ 36#define TDVMCALL_EXPOSE_REGS_MASK \ 37 ( TDX_RDX | TDX_RBX | TDX_RSI | TDX_RDI | TDX_R8 | TDX_R9 | \ 38 TDX_R10 | TDX_R11 | TDX_R12 | TDX_R13 | TDX_R14 | TDX_R15 ) 39 40/* 41 * __tdx_module_call() - Used by TDX guests to request services from 42 * the TDX module (does not include VMM services) using TDCALL instruction. 43 * 44 * Transforms function call register arguments into the TDCALL register ABI. 45 * After TDCALL operation, TDX module output is saved in @out (if it is 46 * provided by the user). 47 * 48 *------------------------------------------------------------------------- 49 * TDCALL ABI: 50 *------------------------------------------------------------------------- 51 * Input Registers: 52 * 53 * RAX - TDCALL Leaf number. 54 * RCX,RDX,R8-R9 - TDCALL Leaf specific input registers. 55 * 56 * Output Registers: 57 * 58 * RAX - TDCALL instruction error code. 59 * RCX,RDX,R8-R11 - TDCALL Leaf specific output registers. 60 * 61 *------------------------------------------------------------------------- 62 * 63 * __tdx_module_call() function ABI: 64 * 65 * @fn (RDI) - TDCALL Leaf ID, moved to RAX 66 * @rcx (RSI) - Input parameter 1, moved to RCX 67 * @rdx (RDX) - Input parameter 2, moved to RDX 68 * @r8 (RCX) - Input parameter 3, moved to R8 69 * @r9 (R8) - Input parameter 4, moved to R9 70 * 71 * @out (R9) - struct tdx_module_output pointer 72 * stored temporarily in R12 (not 73 * shared with the TDX module). It 74 * can be NULL. 75 * 76 * Return status of TDCALL via RAX. 77 */ 78SYM_FUNC_START(__tdx_module_call) 79 FRAME_BEGIN 80 TDX_MODULE_CALL host=0 81 FRAME_END 82 RET 83SYM_FUNC_END(__tdx_module_call) 84 85/* 86 * __tdx_hypercall() - Make hypercalls to a TDX VMM using TDVMCALL leaf 87 * of TDCALL instruction 88 * 89 * Transforms values in function call argument struct tdx_hypercall_args @args 90 * into the TDCALL register ABI. After TDCALL operation, VMM output is saved 91 * back in @args. 92 * 93 *------------------------------------------------------------------------- 94 * TD VMCALL ABI: 95 *------------------------------------------------------------------------- 96 * 97 * Input Registers: 98 * 99 * RAX - TDCALL instruction leaf number (0 - TDG.VP.VMCALL) 100 * RCX - BITMAP which controls which part of TD Guest GPR 101 * is passed as-is to the VMM and back. 102 * R10 - Set 0 to indicate TDCALL follows standard TDX ABI 103 * specification. Non zero value indicates vendor 104 * specific ABI. 105 * R11 - VMCALL sub function number 106 * RBX, RBP, RDI, RSI - Used to pass VMCALL sub function specific arguments. 107 * R8-R9, R12-R15 - Same as above. 108 * 109 * Output Registers: 110 * 111 * RAX - TDCALL instruction status (Not related to hypercall 112 * output). 113 * R10 - Hypercall output error code. 114 * R11-R15 - Hypercall sub function specific output values. 115 * 116 *------------------------------------------------------------------------- 117 * 118 * __tdx_hypercall() function ABI: 119 * 120 * @args (RDI) - struct tdx_hypercall_args for input and output 121 * @flags (RSI) - TDX_HCALL_* flags 122 * 123 * On successful completion, return the hypercall error code. 124 */ 125SYM_FUNC_START(__tdx_hypercall) 126 FRAME_BEGIN 127 128 /* Save callee-saved GPRs as mandated by the x86_64 ABI */ 129 push %r15 130 push %r14 131 push %r13 132 push %r12 133 push %rbx 134 135 /* Free RDI and RSI to be used as TDVMCALL arguments */ 136 movq %rdi, %rax 137 push %rsi 138 139 /* Copy hypercall registers from arg struct: */ 140 movq TDX_HYPERCALL_r8(%rax), %r8 141 movq TDX_HYPERCALL_r9(%rax), %r9 142 movq TDX_HYPERCALL_r10(%rax), %r10 143 movq TDX_HYPERCALL_r11(%rax), %r11 144 movq TDX_HYPERCALL_r12(%rax), %r12 145 movq TDX_HYPERCALL_r13(%rax), %r13 146 movq TDX_HYPERCALL_r14(%rax), %r14 147 movq TDX_HYPERCALL_r15(%rax), %r15 148 movq TDX_HYPERCALL_rdi(%rax), %rdi 149 movq TDX_HYPERCALL_rsi(%rax), %rsi 150 movq TDX_HYPERCALL_rbx(%rax), %rbx 151 movq TDX_HYPERCALL_rdx(%rax), %rdx 152 153 push %rax 154 155 /* Mangle function call ABI into TDCALL ABI: */ 156 /* Set TDCALL leaf ID (TDVMCALL (0)) in RAX */ 157 xor %eax, %eax 158 159 movl $TDVMCALL_EXPOSE_REGS_MASK, %ecx 160 161 /* 162 * For the idle loop STI needs to be called directly before the TDCALL 163 * that enters idle (EXIT_REASON_HLT case). STI instruction enables 164 * interrupts only one instruction later. If there is a window between 165 * STI and the instruction that emulates the HALT state, there is a 166 * chance for interrupts to happen in this window, which can delay the 167 * HLT operation indefinitely. Since this is the not the desired 168 * result, conditionally call STI before TDCALL. 169 */ 170 testq $TDX_HCALL_ISSUE_STI, 8(%rsp) 171 jz .Lskip_sti 172 sti 173.Lskip_sti: 174 tdcall 175 176 /* 177 * RAX!=0 indicates a failure of the TDVMCALL mechanism itself and that 178 * something has gone horribly wrong with the TDX module. 179 * 180 * The return status of the hypercall operation is in a separate 181 * register (in R10). Hypercall errors are a part of normal operation 182 * and are handled by callers. 183 */ 184 testq %rax, %rax 185 jne .Lpanic 186 187 pop %rax 188 189 /* Copy hypercall result registers to arg struct if needed */ 190 testq $TDX_HCALL_HAS_OUTPUT, (%rsp) 191 jz .Lout 192 193 movq %r8, TDX_HYPERCALL_r8(%rax) 194 movq %r9, TDX_HYPERCALL_r9(%rax) 195 movq %r10, TDX_HYPERCALL_r10(%rax) 196 movq %r11, TDX_HYPERCALL_r11(%rax) 197 movq %r12, TDX_HYPERCALL_r12(%rax) 198 movq %r13, TDX_HYPERCALL_r13(%rax) 199 movq %r14, TDX_HYPERCALL_r14(%rax) 200 movq %r15, TDX_HYPERCALL_r15(%rax) 201 movq %rdi, TDX_HYPERCALL_rdi(%rax) 202 movq %rsi, TDX_HYPERCALL_rsi(%rax) 203 movq %rbx, TDX_HYPERCALL_rbx(%rax) 204 movq %rdx, TDX_HYPERCALL_rdx(%rax) 205.Lout: 206 /* TDVMCALL leaf return code is in R10 */ 207 movq %r10, %rax 208 209 /* 210 * Zero out registers exposed to the VMM to avoid speculative execution 211 * with VMM-controlled values. This needs to include all registers 212 * present in TDVMCALL_EXPOSE_REGS_MASK, except RBX, and R12-R15 which 213 * will be restored. 214 */ 215 xor %r8d, %r8d 216 xor %r9d, %r9d 217 xor %r10d, %r10d 218 xor %r11d, %r11d 219 xor %rdi, %rdi 220 xor %rdx, %rdx 221 222 /* Remove TDX_HCALL_* flags from the stack */ 223 pop %rsi 224 225 /* Restore callee-saved GPRs as mandated by the x86_64 ABI */ 226 pop %rbx 227 pop %r12 228 pop %r13 229 pop %r14 230 pop %r15 231 232 FRAME_END 233 234 RET 235.Lpanic: 236 call __tdx_hypercall_failed 237 /* __tdx_hypercall_failed never returns */ 238 REACHABLE 239 jmp .Lpanic 240SYM_FUNC_END(__tdx_hypercall) 241