Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/tdx: Reimplement __tdx_hypercall() using TDX_MODULE_CALL asm

Now the TDX_HYPERCALL asm is basically identical to the TDX_MODULE_CALL
with both '\saved' and '\ret' enabled, with two minor things though:

1) The way to restore the structure pointer is different

The TDX_HYPERCALL uses RCX as spare to restore the structure pointer,
but the TDX_MODULE_CALL assumes no spare register can be used. In other
words, TDX_MODULE_CALL already covers what TDX_HYPERCALL does.

2) TDX_MODULE_CALL only clears shared registers for TDH.VP.ENTER

For this just need to make that code available for the non-host case.

Thus, remove the TDX_HYPERCALL and reimplement the __tdx_hypercall()
using the TDX_MODULE_CALL.

Extend the TDX_MODULE_CALL to cover "clear shared registers" for
TDG.VP.VMCALL. Introduce a new __tdcall_saved_ret() to replace the
temporary __tdcall_hypercall().

The __tdcall_saved_ret() can also be used for those new TDCALLs which
require more input/output registers than the basic TDCALLs do.

Suggested-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Kai Huang <kai.huang@intel.com>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/all/e68a2473fb6f5bcd78b078cae7510e9d0753b3df.1692096753.git.kai.huang%40intel.com

authored by

Kai Huang and committed by
Dave Hansen
90f5ecd3 c641cfb5

+15 -132
+8 -125
arch/x86/coco/tdx/tdcall.S
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 */ 2 2 #include <asm/asm-offsets.h> 3 3 #include <asm/asm.h> 4 - #include <asm/frame.h> 5 4 6 5 #include <linux/linkage.h> 7 6 #include <linux/errno.h> ··· 45 46 SYM_FUNC_END(__tdcall_ret) 46 47 47 48 /* 48 - * TDX_HYPERCALL - Make hypercalls to a TDX VMM using TDVMCALL leaf of TDCALL 49 - * instruction 49 + * __tdcall_saved_ret() - Used by TDX guests to request services from the 50 + * TDX module (including VMM services) using TDCALL instruction, with 51 + * saving output registers to the 'struct tdx_module_args' used as input. 50 52 * 51 - * Transforms values in function call argument struct tdx_module_args @args 52 - * into the TDCALL register ABI. After TDCALL operation, VMM output is saved 53 - * back in @args, if \ret is 1. 54 - * 55 - * Depends on the caller to pass TDG.VP.VMCALL as the TDCALL leaf, and set 56 - * @args::rcx to TDVMCALL_EXPOSE_REGS_MASK. 57 - * 58 - *------------------------------------------------------------------------- 59 - * TD VMCALL ABI: 60 - *------------------------------------------------------------------------- 61 - * 62 - * Input Registers: 63 - * 64 - * RAX - TDCALL instruction leaf number (0 - TDG.VP.VMCALL) 65 - * RCX - BITMAP which controls which part of TD Guest GPR 66 - * is passed as-is to the VMM and back. 67 - * R10 - Set 0 to indicate TDCALL follows standard TDX ABI 68 - * specification. Non zero value indicates vendor 69 - * specific ABI. 70 - * R11 - VMCALL sub function number 71 - * RBX, RDX, RDI, RSI - Used to pass VMCALL sub function specific arguments. 72 - * R8-R9, R12-R15 - Same as above. 73 - * 74 - * Output Registers: 75 - * 76 - * RAX - TDCALL instruction status (Not related to hypercall 77 - * output). 78 - * RBX, RDX, RDI, RSI - Hypercall sub function specific output values. 79 - * R8-R15 - Same as above. 80 - * 81 - */ 82 - .macro TDX_HYPERCALL 83 - FRAME_BEGIN 84 - 85 - /* Save callee-saved GPRs as mandated by the x86_64 ABI */ 86 - push %r15 87 - push %r14 88 - push %r13 89 - push %r12 90 - push %rbx 91 - 92 - /* Move Leaf ID to RAX */ 93 - movq %rdi, %rax 94 - 95 - /* Move bitmap of shared registers to RCX */ 96 - movq TDX_MODULE_rcx(%rsi), %rcx 97 - 98 - /* Copy hypercall registers from arg struct: */ 99 - movq TDX_MODULE_r8(%rsi), %r8 100 - movq TDX_MODULE_r9(%rsi), %r9 101 - movq TDX_MODULE_r10(%rsi), %r10 102 - movq TDX_MODULE_r11(%rsi), %r11 103 - movq TDX_MODULE_r12(%rsi), %r12 104 - movq TDX_MODULE_r13(%rsi), %r13 105 - movq TDX_MODULE_r14(%rsi), %r14 106 - movq TDX_MODULE_r15(%rsi), %r15 107 - movq TDX_MODULE_rdi(%rsi), %rdi 108 - movq TDX_MODULE_rbx(%rsi), %rbx 109 - movq TDX_MODULE_rdx(%rsi), %rdx 110 - 111 - pushq %rsi 112 - movq TDX_MODULE_rsi(%rsi), %rsi 113 - 114 - tdcall 115 - 116 - /* 117 - * Restore the pointer of the structure to save output registers. 118 - * 119 - * RCX is used as bitmap of shared registers and doesn't hold any 120 - * value provided by the VMM, thus it can be used as spare to 121 - * restore the structure pointer. 122 - */ 123 - popq %rcx 124 - movq %rsi, TDX_MODULE_rsi(%rcx) 125 - movq %rcx, %rsi 126 - 127 - movq %r8, TDX_MODULE_r8(%rsi) 128 - movq %r9, TDX_MODULE_r9(%rsi) 129 - movq %r10, TDX_MODULE_r10(%rsi) 130 - movq %r11, TDX_MODULE_r11(%rsi) 131 - movq %r12, TDX_MODULE_r12(%rsi) 132 - movq %r13, TDX_MODULE_r13(%rsi) 133 - movq %r14, TDX_MODULE_r14(%rsi) 134 - movq %r15, TDX_MODULE_r15(%rsi) 135 - movq %rdi, TDX_MODULE_rdi(%rsi) 136 - movq %rbx, TDX_MODULE_rbx(%rsi) 137 - movq %rdx, TDX_MODULE_rdx(%rsi) 138 - 139 - /* 140 - * Zero out registers exposed to the VMM to avoid speculative execution 141 - * with VMM-controlled values. This needs to include all registers 142 - * present in TDVMCALL_EXPOSE_REGS_MASK, except RBX, and R12-R15 which 143 - * will be restored. 144 - */ 145 - xor %r8d, %r8d 146 - xor %r9d, %r9d 147 - xor %r10d, %r10d 148 - xor %r11d, %r11d 149 - xor %rdi, %rdi 150 - xor %rsi, %rsi 151 - xor %rdx, %rdx 152 - 153 - /* Restore callee-saved GPRs as mandated by the x86_64 ABI */ 154 - pop %rbx 155 - pop %r12 156 - pop %r13 157 - pop %r14 158 - pop %r15 159 - 160 - FRAME_END 161 - 162 - RET 163 - .endm 164 - 165 - /* 166 - * 167 - * __tdcall_hypercall() function ABI: 53 + * __tdcall_saved_ret() function ABI: 168 54 * 169 55 * @fn (RDI) - TDCALL leaf ID, moved to RAX 170 56 * @args (RSI) - struct tdx_module_args for input/output 171 57 * 172 - * @fn and @args::rcx from the caller must be TDG_VP_VMCALL and 173 - * TDVMCALL_EXPOSE_REGS_MASK respectively. 58 + * All registers in @args are used as input/output registers. 174 59 * 175 60 * On successful completion, return the hypercall error code. 176 61 */ 177 - SYM_FUNC_START(__tdcall_hypercall) 178 - TDX_HYPERCALL 179 - SYM_FUNC_END(__tdcall_hypercall) 62 + SYM_FUNC_START(__tdcall_saved_ret) 63 + TDX_MODULE_CALL host=0 ret=1 saved=1 64 + SYM_FUNC_END(__tdcall_saved_ret)
+2 -2
arch/x86/coco/tdx/tdx-shared.c
··· 89 89 }; 90 90 91 91 /* 92 - * Failure of __tdcall_hypercall() indicates a failure of the TDVMCALL 92 + * Failure of __tdcall_saved_ret() indicates a failure of the TDVMCALL 93 93 * mechanism itself and that something has gone horribly wrong with 94 94 * the TDX module. __tdx_hypercall_failed() never returns. 95 95 */ 96 - if (__tdcall_hypercall(TDG_VP_VMCALL, &margs)) 96 + if (__tdcall_saved_ret(TDG_VP_VMCALL, &margs)) 97 97 __tdx_hypercall_failed(); 98 98 99 99 args->r8 = margs.r8;
+1 -1
arch/x86/include/asm/shared/tdx.h
··· 83 83 /* Used to communicate with the TDX module */ 84 84 u64 __tdcall(u64 fn, struct tdx_module_args *args); 85 85 u64 __tdcall_ret(u64 fn, struct tdx_module_args *args); 86 + u64 __tdcall_saved_ret(u64 fn, struct tdx_module_args *args); 86 87 87 88 /* 88 89 * Used in __tdx_hypercall() to pass down and get back registers' values of ··· 107 106 }; 108 107 109 108 /* Used to request services from the VMM */ 110 - u64 __tdcall_hypercall(u64 fn, struct tdx_module_args *args); 111 109 u64 __tdx_hypercall(struct tdx_hypercall_args *args); 112 110 113 111 /*
+4 -4
arch/x86/virt/vmx/tdx/tdxcall.S
··· 142 142 movq %r11, TDX_MODULE_r11(%rsi) 143 143 .endif /* \ret */ 144 144 145 - .if \host && \saved && \ret 145 + .if \saved && \ret 146 146 /* 147 - * Clear registers shared by guest for VP.ENTER to prevent 148 - * speculative use of guest's values, including those are 147 + * Clear registers shared by guest for VP.VMCALL/VP.ENTER to prevent 148 + * speculative use of guest's/VMM's values, including those are 149 149 * restored from the stack. 150 150 * 151 151 * See arch/x86/kvm/vmx/vmenter.S: ··· 170 170 xorl %r15d, %r15d 171 171 xorl %ebx, %ebx 172 172 xorl %edi, %edi 173 - .endif /* \host && \ret && \host */ 173 + .endif /* \ret && \host */ 174 174 175 175 .if \host 176 176 .Lout\@: