xref: /openbmc/linux/arch/x86/coco/tdx/tdcall.S (revision c3982c1a)
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_R10		BIT(10)
17#define TDX_R11		BIT(11)
18#define TDX_R12		BIT(12)
19#define TDX_R13		BIT(13)
20#define TDX_R14		BIT(14)
21#define TDX_R15		BIT(15)
22
23/*
24 * These registers are clobbered to hold arguments for each
25 * TDVMCALL. They are safe to expose to the VMM.
26 * Each bit in this mask represents a register ID. Bit field
27 * details can be found in TDX GHCI specification, section
28 * titled "TDCALL [TDG.VP.VMCALL] leaf".
29 */
30#define TDVMCALL_EXPOSE_REGS_MASK	( TDX_R10 | TDX_R11 | \
31					  TDX_R12 | TDX_R13 | \
32					  TDX_R14 | TDX_R15 )
33
34.section .noinstr.text, "ax"
35
36/*
37 * __tdx_module_call()  - Used by TDX guests to request services from
38 * the TDX module (does not include VMM services) using TDCALL instruction.
39 *
40 * Transforms function call register arguments into the TDCALL register ABI.
41 * After TDCALL operation, TDX module output is saved in @out (if it is
42 * provided by the user).
43 *
44 *-------------------------------------------------------------------------
45 * TDCALL ABI:
46 *-------------------------------------------------------------------------
47 * Input Registers:
48 *
49 * RAX                 - TDCALL Leaf number.
50 * RCX,RDX,R8-R9       - TDCALL Leaf specific input registers.
51 *
52 * Output Registers:
53 *
54 * RAX                 - TDCALL instruction error code.
55 * RCX,RDX,R8-R11      - TDCALL Leaf specific output registers.
56 *
57 *-------------------------------------------------------------------------
58 *
59 * __tdx_module_call() function ABI:
60 *
61 * @fn  (RDI)          - TDCALL Leaf ID,    moved to RAX
62 * @rcx (RSI)          - Input parameter 1, moved to RCX
63 * @rdx (RDX)          - Input parameter 2, moved to RDX
64 * @r8  (RCX)          - Input parameter 3, moved to R8
65 * @r9  (R8)           - Input parameter 4, moved to R9
66 *
67 * @out (R9)           - struct tdx_module_output pointer
68 *                       stored temporarily in R12 (not
69 *                       shared with the TDX module). It
70 *                       can be NULL.
71 *
72 * Return status of TDCALL via RAX.
73 */
74SYM_FUNC_START(__tdx_module_call)
75	FRAME_BEGIN
76	TDX_MODULE_CALL host=0
77	FRAME_END
78	RET
79SYM_FUNC_END(__tdx_module_call)
80
81/*
82 * __tdx_hypercall() - Make hypercalls to a TDX VMM using TDVMCALL leaf
83 * of TDCALL instruction
84 *
85 * Transforms values in  function call argument struct tdx_hypercall_args @args
86 * into the TDCALL register ABI. After TDCALL operation, VMM output is saved
87 * back in @args.
88 *
89 *-------------------------------------------------------------------------
90 * TD VMCALL ABI:
91 *-------------------------------------------------------------------------
92 *
93 * Input Registers:
94 *
95 * RAX                 - TDCALL instruction leaf number (0 - TDG.VP.VMCALL)
96 * RCX                 - BITMAP which controls which part of TD Guest GPR
97 *                       is passed as-is to the VMM and back.
98 * R10                 - Set 0 to indicate TDCALL follows standard TDX ABI
99 *                       specification. Non zero value indicates vendor
100 *                       specific ABI.
101 * R11                 - VMCALL sub function number
102 * RBX, RBP, RDI, RSI  - Used to pass VMCALL sub function specific arguments.
103 * R8-R9, R12-R15      - Same as above.
104 *
105 * Output Registers:
106 *
107 * RAX                 - TDCALL instruction status (Not related to hypercall
108 *                        output).
109 * R10                 - Hypercall output error code.
110 * R11-R15             - Hypercall sub function specific output values.
111 *
112 *-------------------------------------------------------------------------
113 *
114 * __tdx_hypercall() function ABI:
115 *
116 * @args  (RDI)        - struct tdx_hypercall_args for input and output
117 * @flags (RSI)        - TDX_HCALL_* flags
118 *
119 * On successful completion, return the hypercall error code.
120 */
121SYM_FUNC_START(__tdx_hypercall)
122	FRAME_BEGIN
123
124	/* Save callee-saved GPRs as mandated by the x86_64 ABI */
125	push %r15
126	push %r14
127	push %r13
128	push %r12
129
130	/* Mangle function call ABI into TDCALL ABI: */
131	/* Set TDCALL leaf ID (TDVMCALL (0)) in RAX */
132	xor %eax, %eax
133
134	/* Copy hypercall registers from arg struct: */
135	movq TDX_HYPERCALL_r10(%rdi), %r10
136	movq TDX_HYPERCALL_r11(%rdi), %r11
137	movq TDX_HYPERCALL_r12(%rdi), %r12
138	movq TDX_HYPERCALL_r13(%rdi), %r13
139	movq TDX_HYPERCALL_r14(%rdi), %r14
140	movq TDX_HYPERCALL_r15(%rdi), %r15
141
142	movl $TDVMCALL_EXPOSE_REGS_MASK, %ecx
143
144	tdcall
145
146	/*
147	 * RAX==0 indicates a failure of the TDVMCALL mechanism itself and that
148	 * something has gone horribly wrong with the TDX module.
149	 *
150	 * The return status of the hypercall operation is in a separate
151	 * register (in R10). Hypercall errors are a part of normal operation
152	 * and are handled by callers.
153	 */
154	testq %rax, %rax
155	jne .Lpanic
156
157	/* TDVMCALL leaf return code is in R10 */
158	movq %r10, %rax
159
160	/* Copy hypercall result registers to arg struct if needed */
161	testq $TDX_HCALL_HAS_OUTPUT, %rsi
162	jz .Lout
163
164	movq %r10, TDX_HYPERCALL_r10(%rdi)
165	movq %r11, TDX_HYPERCALL_r11(%rdi)
166	movq %r12, TDX_HYPERCALL_r12(%rdi)
167	movq %r13, TDX_HYPERCALL_r13(%rdi)
168	movq %r14, TDX_HYPERCALL_r14(%rdi)
169	movq %r15, TDX_HYPERCALL_r15(%rdi)
170.Lout:
171	/*
172	 * Zero out registers exposed to the VMM to avoid speculative execution
173	 * with VMM-controlled values. This needs to include all registers
174	 * present in TDVMCALL_EXPOSE_REGS_MASK (except R12-R15). R12-R15
175	 * context will be restored.
176	 */
177	xor %r10d, %r10d
178	xor %r11d, %r11d
179
180	/* Restore callee-saved GPRs as mandated by the x86_64 ABI */
181	pop %r12
182	pop %r13
183	pop %r14
184	pop %r15
185
186	FRAME_END
187
188	RET
189.Lpanic:
190	call __tdx_hypercall_failed
191	/* __tdx_hypercall_failed never returns */
192	REACHABLE
193	jmp .Lpanic
194SYM_FUNC_END(__tdx_hypercall)
195