|
| 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_R10 BIT(10) |
| 17 | +#define TDX_R11 BIT(11) |
| 18 | +#define TDX_R12 BIT(12) |
| 19 | +#define TDX_R13 BIT(13) |
| 20 | +#define TDX_R14 BIT(14) |
| 21 | +#define TDX_R15 BIT(15) |
| 22 | + |
| 23 | +/* |
| 24 | + * These registers are clobbered to hold arguments for each |
| 25 | + * TDVMCALL. They are safe to expose to the VMM. |
| 26 | + * Each bit in this mask represents a register ID. Bit field |
| 27 | + * details can be found in TDX GHCI specification, section |
| 28 | + * titled "TDCALL [TDG.VP.VMCALL] leaf". |
| 29 | + */ |
| 30 | +#define TDVMCALL_EXPOSE_REGS_MASK ( TDX_R10 | TDX_R11 | \ |
| 31 | + TDX_R12 | TDX_R13 | \ |
| 32 | + TDX_R14 | TDX_R15 ) |
| 33 | + |
| 34 | +/* |
| 35 | + * __tdx_module_call() - Used by TDX guests to request services from |
| 36 | + * the TDX module (does not include VMM services) using TDCALL instruction. |
| 37 | + * |
| 38 | + * Transforms function call register arguments into the TDCALL register ABI. |
| 39 | + * After TDCALL operation, TDX module output is saved in @out (if it is |
| 40 | + * provided by the user). |
| 41 | + * |
| 42 | + *------------------------------------------------------------------------- |
| 43 | + * TDCALL ABI: |
| 44 | + *------------------------------------------------------------------------- |
| 45 | + * Input Registers: |
| 46 | + * |
| 47 | + * RAX - TDCALL Leaf number. |
| 48 | + * RCX,RDX,R8-R9 - TDCALL Leaf specific input registers. |
| 49 | + * |
| 50 | + * Output Registers: |
| 51 | + * |
| 52 | + * RAX - TDCALL instruction error code. |
| 53 | + * RCX,RDX,R8-R11 - TDCALL Leaf specific output registers. |
| 54 | + * |
| 55 | + *------------------------------------------------------------------------- |
| 56 | + * |
| 57 | + * __tdx_module_call() function ABI: |
| 58 | + * |
| 59 | + * @fn (RDI) - TDCALL Leaf ID, moved to RAX |
| 60 | + * @rcx (RSI) - Input parameter 1, moved to RCX |
| 61 | + * @rdx (RDX) - Input parameter 2, moved to RDX |
| 62 | + * @r8 (RCX) - Input parameter 3, moved to R8 |
| 63 | + * @r9 (R8) - Input parameter 4, moved to R9 |
| 64 | + * |
| 65 | + * @out (R9) - struct tdx_module_output pointer |
| 66 | + * stored temporarily in R12 (not |
| 67 | + * shared with the TDX module). It |
| 68 | + * can be NULL. |
| 69 | + * |
| 70 | + * Return status of TDCALL via RAX. |
| 71 | + */ |
| 72 | +SYM_FUNC_START(__tdx_module_call) |
| 73 | + FRAME_BEGIN |
| 74 | + TDX_MODULE_CALL host=0 |
| 75 | + FRAME_END |
| 76 | + ret |
| 77 | +SYM_FUNC_END(__tdx_module_call) |
| 78 | + |
| 79 | +/* |
| 80 | + * __tdx_hypercall() - Make hypercalls to a TDX VMM using TDVMCALL leaf |
| 81 | + * of TDCALL instruction |
| 82 | + * |
| 83 | + * Transforms values in function call argument struct tdx_hypercall_args @args |
| 84 | + * into the TDCALL register ABI. After TDCALL operation, VMM output is saved |
| 85 | + * back in @args. |
| 86 | + * |
| 87 | + *------------------------------------------------------------------------- |
| 88 | + * TD VMCALL ABI: |
| 89 | + *------------------------------------------------------------------------- |
| 90 | + * |
| 91 | + * Input Registers: |
| 92 | + * |
| 93 | + * RAX - TDCALL instruction leaf number (0 - TDG.VP.VMCALL) |
| 94 | + * RCX - BITMAP which controls which part of TD Guest GPR |
| 95 | + * is passed as-is to the VMM and back. |
| 96 | + * R10 - Set 0 to indicate TDCALL follows standard TDX ABI |
| 97 | + * specification. Non zero value indicates vendor |
| 98 | + * specific ABI. |
| 99 | + * R11 - VMCALL sub function number |
| 100 | + * RBX, RBP, RDI, RSI - Used to pass VMCALL sub function specific arguments. |
| 101 | + * R8-R9, R12-R15 - Same as above. |
| 102 | + * |
| 103 | + * Output Registers: |
| 104 | + * |
| 105 | + * RAX - TDCALL instruction status (Not related to hypercall |
| 106 | + * output). |
| 107 | + * R10 - Hypercall output error code. |
| 108 | + * R11-R15 - Hypercall sub function specific output values. |
| 109 | + * |
| 110 | + *------------------------------------------------------------------------- |
| 111 | + * |
| 112 | + * __tdx_hypercall() function ABI: |
| 113 | + * |
| 114 | + * @args (RDI) - struct tdx_hypercall_args for input and output |
| 115 | + * @flags (RSI) - TDX_HCALL_* flags |
| 116 | + * |
| 117 | + * On successful completion, return the hypercall error code. |
| 118 | + */ |
| 119 | +SYM_FUNC_START(__tdx_hypercall) |
| 120 | + FRAME_BEGIN |
| 121 | + |
| 122 | + /* Save callee-saved GPRs as mandated by the x86_64 ABI */ |
| 123 | + push %r15 |
| 124 | + push %r14 |
| 125 | + push %r13 |
| 126 | + push %r12 |
| 127 | + |
| 128 | + /* Mangle function call ABI into TDCALL ABI: */ |
| 129 | + /* Set TDCALL leaf ID (TDVMCALL (0)) in RAX */ |
| 130 | + xor %eax, %eax |
| 131 | + |
| 132 | + /* Copy hypercall registers from arg struct: */ |
| 133 | + movq TDX_HYPERCALL_r10(%rdi), %r10 |
| 134 | + movq TDX_HYPERCALL_r11(%rdi), %r11 |
| 135 | + movq TDX_HYPERCALL_r12(%rdi), %r12 |
| 136 | + movq TDX_HYPERCALL_r13(%rdi), %r13 |
| 137 | + movq TDX_HYPERCALL_r14(%rdi), %r14 |
| 138 | + movq TDX_HYPERCALL_r15(%rdi), %r15 |
| 139 | + |
| 140 | + movl $TDVMCALL_EXPOSE_REGS_MASK, %ecx |
| 141 | + |
| 142 | + tdcall |
| 143 | + |
| 144 | + /* |
| 145 | + * RAX==0 indicates a failure of the TDVMCALL mechanism itself and that |
| 146 | + * something has gone horribly wrong with the TDX module. |
| 147 | + * |
| 148 | + * The return status of the hypercall operation is in a separate |
| 149 | + * register (in R10). Hypercall errors are a part of normal operation |
| 150 | + * and are handled by callers. |
| 151 | + */ |
| 152 | + testq %rax, %rax |
| 153 | + jne .Lpanic |
| 154 | + |
| 155 | + /* TDVMCALL leaf return code is in R10 */ |
| 156 | + movq %r10, %rax |
| 157 | + |
| 158 | + /* Copy hypercall result registers to arg struct if needed */ |
| 159 | + testq $TDX_HCALL_HAS_OUTPUT, %rsi |
| 160 | + jz .Lout |
| 161 | + |
| 162 | + movq %r10, TDX_HYPERCALL_r10(%rdi) |
| 163 | + movq %r11, TDX_HYPERCALL_r11(%rdi) |
| 164 | + movq %r12, TDX_HYPERCALL_r12(%rdi) |
| 165 | + movq %r13, TDX_HYPERCALL_r13(%rdi) |
| 166 | + movq %r14, TDX_HYPERCALL_r14(%rdi) |
| 167 | + movq %r15, TDX_HYPERCALL_r15(%rdi) |
| 168 | +.Lout: |
| 169 | + /* |
| 170 | + * Zero out registers exposed to the VMM to avoid speculative execution |
| 171 | + * with VMM-controlled values. This needs to include all registers |
| 172 | + * present in TDVMCALL_EXPOSE_REGS_MASK (except R12-R15). R12-R15 |
| 173 | + * context will be restored. |
| 174 | + */ |
| 175 | + xor %r10d, %r10d |
| 176 | + xor %r11d, %r11d |
| 177 | + |
| 178 | + /* Restore callee-saved GPRs as mandated by the x86_64 ABI */ |
| 179 | + pop %r12 |
| 180 | + pop %r13 |
| 181 | + pop %r14 |
| 182 | + pop %r15 |
| 183 | + |
| 184 | + FRAME_END |
| 185 | + |
| 186 | + retq |
| 187 | +.Lpanic: |
| 188 | + call __tdx_hypercall_failed |
| 189 | + /* __tdx_hypercall_failed never returns */ |
| 190 | + jmp .Lpanic |
| 191 | +SYM_FUNC_END(__tdx_hypercall) |
0 commit comments