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