summaryrefslogtreecommitdiffstats
path: root/arch/x86/coco/tdx/tdcall.S
blob: 2eca5f43734feb9aa93cddc18800201d6367934e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
/* SPDX-License-Identifier: GPL-2.0 */
#include <asm/asm-offsets.h>
#include <asm/asm.h>
#include <asm/frame.h>
#include <asm/unwind_hints.h>

#include <linux/linkage.h>
#include <linux/bits.h>
#include <linux/errno.h>

#include "../../virt/vmx/tdx/tdxcall.S"

/*
 * Bitmasks of exposed registers (with VMM).
 */
#define TDX_RDX		BIT(2)
#define TDX_RBX		BIT(3)
#define TDX_RSI		BIT(6)
#define TDX_RDI		BIT(7)
#define TDX_R8		BIT(8)
#define TDX_R9		BIT(9)
#define TDX_R10		BIT(10)
#define TDX_R11		BIT(11)
#define TDX_R12		BIT(12)
#define TDX_R13		BIT(13)
#define TDX_R14		BIT(14)
#define TDX_R15		BIT(15)

/*
 * These registers are clobbered to hold arguments for each
 * TDVMCALL. They are safe to expose to the VMM.
 * Each bit in this mask represents a register ID. Bit field
 * details can be found in TDX GHCI specification, section
 * titled "TDCALL [TDG.VP.VMCALL] leaf".
 */
#define TDVMCALL_EXPOSE_REGS_MASK	\
	( TDX_RDX | TDX_RBX | TDX_RSI | TDX_RDI | TDX_R8  | TDX_R9  | \
	  TDX_R10 | TDX_R11 | TDX_R12 | TDX_R13 | TDX_R14 | TDX_R15 )

.section .noinstr.text, "ax"

/*
 * __tdx_module_call()  - Used by TDX guests to request services from
 * the TDX module (does not include VMM services) using TDCALL instruction.
 *
 * Transforms function call register arguments into the TDCALL register ABI.
 * After TDCALL operation, TDX module output is saved in @out (if it is
 * provided by the user).
 *
 *-------------------------------------------------------------------------
 * TDCALL ABI:
 *-------------------------------------------------------------------------
 * Input Registers:
 *
 * RAX                 - TDCALL Leaf number.
 * RCX,RDX,R8-R9       - TDCALL Leaf specific input registers.
 *
 * Output Registers:
 *
 * RAX                 - TDCALL instruction error code.
 * RCX,RDX,R8-R11      - TDCALL Leaf specific output registers.
 *
 *-------------------------------------------------------------------------
 *
 * __tdx_module_call() function ABI:
 *
 * @fn  (RDI)          - TDCALL Leaf ID,    moved to RAX
 * @rcx (RSI)          - Input parameter 1, moved to RCX
 * @rdx (RDX)          - Input parameter 2, moved to RDX
 * @r8  (RCX)          - Input parameter 3, moved to R8
 * @r9  (R8)           - Input parameter 4, moved to R9
 *
 * @out (R9)           - struct tdx_module_output pointer
 *                       stored temporarily in R12 (not
 *                       shared with the TDX module). It
 *                       can be NULL.
 *
 * Return status of TDCALL via RAX.
 */
SYM_FUNC_START(__tdx_module_call)
	FRAME_BEGIN
	TDX_MODULE_CALL host=0
	FRAME_END
	RET
SYM_FUNC_END(__tdx_module_call)

/*
 * TDX_HYPERCALL - Make hypercalls to a TDX VMM using TDVMCALL leaf of TDCALL
 * instruction
 *
 * Transforms values in  function call argument struct tdx_hypercall_args @args
 * into the TDCALL register ABI. After TDCALL operation, VMM output is saved
 * back in @args, if \ret is 1.
 *
 *-------------------------------------------------------------------------
 * TD VMCALL ABI:
 *-------------------------------------------------------------------------
 *
 * Input Registers:
 *
 * RAX                 - TDCALL instruction leaf number (0 - TDG.VP.VMCALL)
 * RCX                 - BITMAP which controls which part of TD Guest GPR
 *                       is passed as-is to the VMM and back.
 * R10                 - Set 0 to indicate TDCALL follows standard TDX ABI
 *                       specification. Non zero value indicates vendor
 *                       specific ABI.
 * R11                 - VMCALL sub function number
 * RBX, RDX, RDI, RSI  - Used to pass VMCALL sub function specific arguments.
 * R8-R9, R12-R15      - Same as above.
 *
 * Output Registers:
 *
 * RAX                 - TDCALL instruction status (Not related to hypercall
 *                        output).
 * RBX, RDX, RDI, RSI  - Hypercall sub function specific output values.
 * R8-R15              - Same as above.
 *
 */
.macro TDX_HYPERCALL ret:req
	FRAME_BEGIN

	/* Save callee-saved GPRs as mandated by the x86_64 ABI */
	push %r15
	push %r14
	push %r13
	push %r12
	push %rbx

	/* Free RDI to be used as TDVMCALL arguments */
	movq %rdi, %rax

	/* Copy hypercall registers from arg struct: */
	movq TDX_HYPERCALL_r8(%rax),  %r8
	movq TDX_HYPERCALL_r9(%rax),  %r9
	movq TDX_HYPERCALL_r10(%rax), %r10
	movq TDX_HYPERCALL_r11(%rax), %r11
	movq TDX_HYPERCALL_r12(%rax), %r12
	movq TDX_HYPERCALL_r13(%rax), %r13
	movq TDX_HYPERCALL_r14(%rax), %r14
	movq TDX_HYPERCALL_r15(%rax), %r15
	movq TDX_HYPERCALL_rdi(%rax), %rdi
	movq TDX_HYPERCALL_rsi(%rax), %rsi
	movq TDX_HYPERCALL_rbx(%rax), %rbx
	movq TDX_HYPERCALL_rdx(%rax), %rdx

	push %rax

	/* Mangle function call ABI into TDCALL ABI: */
	/* Set TDCALL leaf ID (TDVMCALL (0)) in RAX */
	xor %eax, %eax

	movl $TDVMCALL_EXPOSE_REGS_MASK, %ecx

	tdcall

	/*
	 * RAX!=0 indicates a failure of the TDVMCALL mechanism itself and that
	 * something has gone horribly wrong with the TDX module.
	 *
	 * The return status of the hypercall operation is in a separate
	 * register (in R10). Hypercall errors are a part of normal operation
	 * and are handled by callers.
	 */
	testq %rax, %rax
	jne .Lpanic\@

	pop %rax

	.if \ret
	movq %r8,  TDX_HYPERCALL_r8(%rax)
	movq %r9,  TDX_HYPERCALL_r9(%rax)
	movq %r10, TDX_HYPERCALL_r10(%rax)
	movq %r11, TDX_HYPERCALL_r11(%rax)
	movq %r12, TDX_HYPERCALL_r12(%rax)
	movq %r13, TDX_HYPERCALL_r13(%rax)
	movq %r14, TDX_HYPERCALL_r14(%rax)
	movq %r15, TDX_HYPERCALL_r15(%rax)
	movq %rdi, TDX_HYPERCALL_rdi(%rax)
	movq %rsi, TDX_HYPERCALL_rsi(%rax)
	movq %rbx, TDX_HYPERCALL_rbx(%rax)
	movq %rdx, TDX_HYPERCALL_rdx(%rax)
	.endif

	/* TDVMCALL leaf return code is in R10 */
	movq %r10, %rax

	/*
	 * Zero out registers exposed to the VMM to avoid speculative execution
	 * with VMM-controlled values. This needs to include all registers
	 * present in TDVMCALL_EXPOSE_REGS_MASK, except RBX, and R12-R15 which
	 * will be restored.
	 */
	xor %r8d,  %r8d
	xor %r9d,  %r9d
	xor %r10d, %r10d
	xor %r11d, %r11d
	xor %rdi,  %rdi
	xor %rsi,  %rsi
	xor %rdx,  %rdx

	/* Restore callee-saved GPRs as mandated by the x86_64 ABI */
	pop %rbx
	pop %r12
	pop %r13
	pop %r14
	pop %r15

	FRAME_END

	RET
.Lpanic\@:
	call __tdx_hypercall_failed
	/* __tdx_hypercall_failed never returns */
	REACHABLE
	jmp .Lpanic\@
.endm

/*
 *
 * __tdx_hypercall() function ABI:
 *
 * @args  (RDI)        - struct tdx_hypercall_args for input
 *
 * On successful completion, return the hypercall error code.
 */
SYM_FUNC_START(__tdx_hypercall)
	TDX_HYPERCALL ret=0
SYM_FUNC_END(__tdx_hypercall)

/*
 *
 * __tdx_hypercall_ret() function ABI:
 *
 * @args  (RDI)        - struct tdx_hypercall_args for input and output
 *
 * On successful completion, return the hypercall error code.
 */
SYM_FUNC_START(__tdx_hypercall_ret)
	TDX_HYPERCALL ret=1
SYM_FUNC_END(__tdx_hypercall_ret)