xref: /openbmc/linux/arch/x86/coco/tdx/tdcall.S (revision 752d1330)
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	push %rbp
135
136	/* Free RDI and RSI to be used as TDVMCALL arguments */
137	movq %rdi, %rax
138	movq %rsi, %rbp
139
140	/* Copy hypercall registers from arg struct: */
141	movq TDX_HYPERCALL_r8(%rax),  %r8
142	movq TDX_HYPERCALL_r9(%rax),  %r9
143	movq TDX_HYPERCALL_r10(%rax), %r10
144	movq TDX_HYPERCALL_r11(%rax), %r11
145	movq TDX_HYPERCALL_r12(%rax), %r12
146	movq TDX_HYPERCALL_r13(%rax), %r13
147	movq TDX_HYPERCALL_r14(%rax), %r14
148	movq TDX_HYPERCALL_r15(%rax), %r15
149	movq TDX_HYPERCALL_rdi(%rax), %rdi
150	movq TDX_HYPERCALL_rsi(%rax), %rsi
151	movq TDX_HYPERCALL_rbx(%rax), %rbx
152	movq TDX_HYPERCALL_rdx(%rax), %rdx
153
154	push %rax
155
156	/* Mangle function call ABI into TDCALL ABI: */
157	/* Set TDCALL leaf ID (TDVMCALL (0)) in RAX */
158	xor %eax, %eax
159
160	movl $TDVMCALL_EXPOSE_REGS_MASK, %ecx
161
162	/*
163	 * For the idle loop STI needs to be called directly before the TDCALL
164	 * that enters idle (EXIT_REASON_HLT case). STI instruction enables
165	 * interrupts only one instruction later. If there is a window between
166	 * STI and the instruction that emulates the HALT state, there is a
167	 * chance for interrupts to happen in this window, which can delay the
168	 * HLT operation indefinitely. Since this is the not the desired
169	 * result, conditionally call STI before TDCALL.
170	 */
171	testq $TDX_HCALL_ISSUE_STI, %rbp
172	jz .Lskip_sti
173	sti
174.Lskip_sti:
175	tdcall
176
177	/*
178	 * RAX!=0 indicates a failure of the TDVMCALL mechanism itself and that
179	 * something has gone horribly wrong with the TDX module.
180	 *
181	 * The return status of the hypercall operation is in a separate
182	 * register (in R10). Hypercall errors are a part of normal operation
183	 * and are handled by callers.
184	 */
185	testq %rax, %rax
186	jne .Lpanic
187
188	pop %rax
189
190	/* Copy hypercall result registers to arg struct if needed */
191	testq $TDX_HCALL_HAS_OUTPUT, %rbp
192	jz .Lout
193
194	movq %r8,  TDX_HYPERCALL_r8(%rax)
195	movq %r9,  TDX_HYPERCALL_r9(%rax)
196	movq %r10, TDX_HYPERCALL_r10(%rax)
197	movq %r11, TDX_HYPERCALL_r11(%rax)
198	movq %r12, TDX_HYPERCALL_r12(%rax)
199	movq %r13, TDX_HYPERCALL_r13(%rax)
200	movq %r14, TDX_HYPERCALL_r14(%rax)
201	movq %r15, TDX_HYPERCALL_r15(%rax)
202	movq %rdi, TDX_HYPERCALL_rdi(%rax)
203	movq %rsi, TDX_HYPERCALL_rsi(%rax)
204	movq %rbx, TDX_HYPERCALL_rbx(%rax)
205	movq %rdx, TDX_HYPERCALL_rdx(%rax)
206.Lout:
207	/* TDVMCALL leaf return code is in R10 */
208	movq %r10, %rax
209
210	/*
211	 * Zero out registers exposed to the VMM to avoid speculative execution
212	 * with VMM-controlled values. This needs to include all registers
213	 * present in TDVMCALL_EXPOSE_REGS_MASK, except RBX, and R12-R15 which
214	 * will be restored.
215	 */
216	xor %r8d,  %r8d
217	xor %r9d,  %r9d
218	xor %r10d, %r10d
219	xor %r11d, %r11d
220	xor %rdi,  %rdi
221	xor %rsi,  %rsi
222	xor %rdx,  %rdx
223
224	/* Restore callee-saved GPRs as mandated by the x86_64 ABI */
225	pop %rbp
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