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