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 .section .noinstr.text, "ax"
41 
42 /*
43  * __tdx_module_call()  - Used by TDX guests to request services from
44  * the TDX module (does not include VMM services) using TDCALL instruction.
45  *
46  * Transforms function call register arguments into the TDCALL register ABI.
47  * After TDCALL operation, TDX module output is saved in @out (if it is
48  * provided by the user).
49  *
50  *-------------------------------------------------------------------------
51  * TDCALL ABI:
52  *-------------------------------------------------------------------------
53  * Input Registers:
54  *
55  * RAX                 - TDCALL Leaf number.
56  * RCX,RDX,R8-R9       - TDCALL Leaf specific input registers.
57  *
58  * Output Registers:
59  *
60  * RAX                 - TDCALL instruction error code.
61  * RCX,RDX,R8-R11      - TDCALL Leaf specific output registers.
62  *
63  *-------------------------------------------------------------------------
64  *
65  * __tdx_module_call() function ABI:
66  *
67  * @fn  (RDI)          - TDCALL Leaf ID,    moved to RAX
68  * @rcx (RSI)          - Input parameter 1, moved to RCX
69  * @rdx (RDX)          - Input parameter 2, moved to RDX
70  * @r8  (RCX)          - Input parameter 3, moved to R8
71  * @r9  (R8)           - Input parameter 4, moved to R9
72  *
73  * @out (R9)           - struct tdx_module_output pointer
74  *                       stored temporarily in R12 (not
75  *                       shared with the TDX module). It
76  *                       can be NULL.
77  *
78  * Return status of TDCALL via RAX.
79  */
80 SYM_FUNC_START(__tdx_module_call)
81 	FRAME_BEGIN
82 	TDX_MODULE_CALL host=0
83 	FRAME_END
84 	RET
85 SYM_FUNC_END(__tdx_module_call)
86 
87 /*
88  * TDX_HYPERCALL - Make hypercalls to a TDX VMM using TDVMCALL leaf of TDCALL
89  * instruction
90  *
91  * Transforms values in  function call argument struct tdx_hypercall_args @args
92  * into the TDCALL register ABI. After TDCALL operation, VMM output is saved
93  * back in @args, if \ret is 1.
94  *
95  *-------------------------------------------------------------------------
96  * TD VMCALL ABI:
97  *-------------------------------------------------------------------------
98  *
99  * Input Registers:
100  *
101  * RAX                 - TDCALL instruction leaf number (0 - TDG.VP.VMCALL)
102  * RCX                 - BITMAP which controls which part of TD Guest GPR
103  *                       is passed as-is to the VMM and back.
104  * R10                 - Set 0 to indicate TDCALL follows standard TDX ABI
105  *                       specification. Non zero value indicates vendor
106  *                       specific ABI.
107  * R11                 - VMCALL sub function number
108  * RBX, RDX, RDI, RSI  - Used to pass VMCALL sub function specific arguments.
109  * R8-R9, R12-R15      - Same as above.
110  *
111  * Output Registers:
112  *
113  * RAX                 - TDCALL instruction status (Not related to hypercall
114  *                        output).
115  * RBX, RDX, RDI, RSI  - Hypercall sub function specific output values.
116  * R8-R15              - Same as above.
117  *
118  */
119 .macro TDX_HYPERCALL ret:req
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 	push %rbx
128 
129 	/* Free RDI to be used as TDVMCALL arguments */
130 	movq %rdi, %rax
131 
132 	/* Copy hypercall registers from arg struct: */
133 	movq TDX_HYPERCALL_r8(%rax),  %r8
134 	movq TDX_HYPERCALL_r9(%rax),  %r9
135 	movq TDX_HYPERCALL_r10(%rax), %r10
136 	movq TDX_HYPERCALL_r11(%rax), %r11
137 	movq TDX_HYPERCALL_r12(%rax), %r12
138 	movq TDX_HYPERCALL_r13(%rax), %r13
139 	movq TDX_HYPERCALL_r14(%rax), %r14
140 	movq TDX_HYPERCALL_r15(%rax), %r15
141 	movq TDX_HYPERCALL_rdi(%rax), %rdi
142 	movq TDX_HYPERCALL_rsi(%rax), %rsi
143 	movq TDX_HYPERCALL_rbx(%rax), %rbx
144 	movq TDX_HYPERCALL_rdx(%rax), %rdx
145 
146 	push %rax
147 
148 	/* Mangle function call ABI into TDCALL ABI: */
149 	/* Set TDCALL leaf ID (TDVMCALL (0)) in RAX */
150 	xor %eax, %eax
151 
152 	movl $TDVMCALL_EXPOSE_REGS_MASK, %ecx
153 
154 	tdcall
155 
156 	/*
157 	 * RAX!=0 indicates a failure of the TDVMCALL mechanism itself and that
158 	 * something has gone horribly wrong with the TDX module.
159 	 *
160 	 * The return status of the hypercall operation is in a separate
161 	 * register (in R10). Hypercall errors are a part of normal operation
162 	 * and are handled by callers.
163 	 */
164 	testq %rax, %rax
165 	jne .Lpanic\@
166 
167 	pop %rax
168 
169 	.if \ret
170 	movq %r8,  TDX_HYPERCALL_r8(%rax)
171 	movq %r9,  TDX_HYPERCALL_r9(%rax)
172 	movq %r10, TDX_HYPERCALL_r10(%rax)
173 	movq %r11, TDX_HYPERCALL_r11(%rax)
174 	movq %r12, TDX_HYPERCALL_r12(%rax)
175 	movq %r13, TDX_HYPERCALL_r13(%rax)
176 	movq %r14, TDX_HYPERCALL_r14(%rax)
177 	movq %r15, TDX_HYPERCALL_r15(%rax)
178 	movq %rdi, TDX_HYPERCALL_rdi(%rax)
179 	movq %rsi, TDX_HYPERCALL_rsi(%rax)
180 	movq %rbx, TDX_HYPERCALL_rbx(%rax)
181 	movq %rdx, TDX_HYPERCALL_rdx(%rax)
182 	.endif
183 
184 	/* TDVMCALL leaf return code is in R10 */
185 	movq %r10, %rax
186 
187 	/*
188 	 * Zero out registers exposed to the VMM to avoid speculative execution
189 	 * with VMM-controlled values. This needs to include all registers
190 	 * present in TDVMCALL_EXPOSE_REGS_MASK, except RBX, and R12-R15 which
191 	 * will be restored.
192 	 */
193 	xor %r8d,  %r8d
194 	xor %r9d,  %r9d
195 	xor %r10d, %r10d
196 	xor %r11d, %r11d
197 	xor %rdi,  %rdi
198 	xor %rsi,  %rsi
199 	xor %rdx,  %rdx
200 
201 	/* Restore callee-saved GPRs as mandated by the x86_64 ABI */
202 	pop %rbx
203 	pop %r12
204 	pop %r13
205 	pop %r14
206 	pop %r15
207 
208 	FRAME_END
209 
210 	RET
211 .Lpanic\@:
212 	call __tdx_hypercall_failed
213 	/* __tdx_hypercall_failed never returns */
214 	REACHABLE
215 	jmp .Lpanic\@
216 .endm
217 
218 /*
219  *
220  * __tdx_hypercall() function ABI:
221  *
222  * @args  (RDI)        - struct tdx_hypercall_args for input
223  *
224  * On successful completion, return the hypercall error code.
225  */
226 SYM_FUNC_START(__tdx_hypercall)
227 	TDX_HYPERCALL ret=0
228 SYM_FUNC_END(__tdx_hypercall)
229 
230 /*
231  *
232  * __tdx_hypercall_ret() function ABI:
233  *
234  * @args  (RDI)        - struct tdx_hypercall_args for input and output
235  *
236  * On successful completion, return the hypercall error code.
237  */
238 SYM_FUNC_START(__tdx_hypercall_ret)
239 	TDX_HYPERCALL ret=1
240 SYM_FUNC_END(__tdx_hypercall_ret)
241