xref: /openbmc/linux/arch/x86/kvm/svm/vmenter.S (revision 9a234a2a)
1/* SPDX-License-Identifier: GPL-2.0 */
2#include <linux/linkage.h>
3#include <asm/asm.h>
4#include <asm/bitsperlong.h>
5#include <asm/kvm_vcpu_regs.h>
6#include <asm/nospec-branch.h>
7#include "kvm-asm-offsets.h"
8
9#define WORD_SIZE (BITS_PER_LONG / 8)
10
11/* Intentionally omit RAX as it's context switched by hardware */
12#define VCPU_RCX	(SVM_vcpu_arch_regs + __VCPU_REGS_RCX * WORD_SIZE)
13#define VCPU_RDX	(SVM_vcpu_arch_regs + __VCPU_REGS_RDX * WORD_SIZE)
14#define VCPU_RBX	(SVM_vcpu_arch_regs + __VCPU_REGS_RBX * WORD_SIZE)
15/* Intentionally omit RSP as it's context switched by hardware */
16#define VCPU_RBP	(SVM_vcpu_arch_regs + __VCPU_REGS_RBP * WORD_SIZE)
17#define VCPU_RSI	(SVM_vcpu_arch_regs + __VCPU_REGS_RSI * WORD_SIZE)
18#define VCPU_RDI	(SVM_vcpu_arch_regs + __VCPU_REGS_RDI * WORD_SIZE)
19
20#ifdef CONFIG_X86_64
21#define VCPU_R8		(SVM_vcpu_arch_regs + __VCPU_REGS_R8  * WORD_SIZE)
22#define VCPU_R9		(SVM_vcpu_arch_regs + __VCPU_REGS_R9  * WORD_SIZE)
23#define VCPU_R10	(SVM_vcpu_arch_regs + __VCPU_REGS_R10 * WORD_SIZE)
24#define VCPU_R11	(SVM_vcpu_arch_regs + __VCPU_REGS_R11 * WORD_SIZE)
25#define VCPU_R12	(SVM_vcpu_arch_regs + __VCPU_REGS_R12 * WORD_SIZE)
26#define VCPU_R13	(SVM_vcpu_arch_regs + __VCPU_REGS_R13 * WORD_SIZE)
27#define VCPU_R14	(SVM_vcpu_arch_regs + __VCPU_REGS_R14 * WORD_SIZE)
28#define VCPU_R15	(SVM_vcpu_arch_regs + __VCPU_REGS_R15 * WORD_SIZE)
29#endif
30
31#define SVM_vmcb01_pa	(SVM_vmcb01 + KVM_VMCB_pa)
32
33.section .noinstr.text, "ax"
34
35.macro RESTORE_GUEST_SPEC_CTRL
36	/* No need to do anything if SPEC_CTRL is unset or V_SPEC_CTRL is set */
37	ALTERNATIVE_2 "", \
38		"jmp 800f", X86_FEATURE_MSR_SPEC_CTRL, \
39		"", X86_FEATURE_V_SPEC_CTRL
40801:
41.endm
42.macro RESTORE_GUEST_SPEC_CTRL_BODY
43800:
44	/*
45	 * SPEC_CTRL handling: if the guest's SPEC_CTRL value differs from the
46	 * host's, write the MSR.  This is kept out-of-line so that the common
47	 * case does not have to jump.
48	 *
49	 * IMPORTANT: To avoid RSB underflow attacks and any other nastiness,
50	 * there must not be any returns or indirect branches between this code
51	 * and vmentry.
52	 */
53	movl SVM_spec_ctrl(%_ASM_DI), %eax
54	cmp PER_CPU_VAR(x86_spec_ctrl_current), %eax
55	je 801b
56	mov $MSR_IA32_SPEC_CTRL, %ecx
57	xor %edx, %edx
58	wrmsr
59	jmp 801b
60.endm
61
62.macro RESTORE_HOST_SPEC_CTRL
63	/* No need to do anything if SPEC_CTRL is unset or V_SPEC_CTRL is set */
64	ALTERNATIVE_2 "", \
65		"jmp 900f", X86_FEATURE_MSR_SPEC_CTRL, \
66		"", X86_FEATURE_V_SPEC_CTRL
67901:
68.endm
69.macro RESTORE_HOST_SPEC_CTRL_BODY
70900:
71	/* Same for after vmexit.  */
72	mov $MSR_IA32_SPEC_CTRL, %ecx
73
74	/*
75	 * Load the value that the guest had written into MSR_IA32_SPEC_CTRL,
76	 * if it was not intercepted during guest execution.
77	 */
78	cmpb $0, (%_ASM_SP)
79	jnz 998f
80	rdmsr
81	movl %eax, SVM_spec_ctrl(%_ASM_DI)
82998:
83
84	/* Now restore the host value of the MSR if different from the guest's.  */
85	movl PER_CPU_VAR(x86_spec_ctrl_current), %eax
86	cmp SVM_spec_ctrl(%_ASM_DI), %eax
87	je 901b
88	xor %edx, %edx
89	wrmsr
90	jmp 901b
91.endm
92
93
94/**
95 * __svm_vcpu_run - Run a vCPU via a transition to SVM guest mode
96 * @svm:	struct vcpu_svm *
97 * @spec_ctrl_intercepted: bool
98 */
99SYM_FUNC_START(__svm_vcpu_run)
100	push %_ASM_BP
101#ifdef CONFIG_X86_64
102	push %r15
103	push %r14
104	push %r13
105	push %r12
106#else
107	push %edi
108	push %esi
109#endif
110	push %_ASM_BX
111
112	/*
113	 * Save variables needed after vmexit on the stack, in inverse
114	 * order compared to when they are needed.
115	 */
116
117	/* Accessed directly from the stack in RESTORE_HOST_SPEC_CTRL.  */
118	push %_ASM_ARG2
119
120	/* Needed to restore access to percpu variables.  */
121	__ASM_SIZE(push) PER_CPU_VAR(svm_data + SD_save_area_pa)
122
123	/* Finally save @svm. */
124	push %_ASM_ARG1
125
126.ifnc _ASM_ARG1, _ASM_DI
127	/*
128	 * Stash @svm in RDI early. On 32-bit, arguments are in RAX, RCX
129	 * and RDX which are clobbered by RESTORE_GUEST_SPEC_CTRL.
130	 */
131	mov %_ASM_ARG1, %_ASM_DI
132.endif
133
134	/* Clobbers RAX, RCX, RDX.  */
135	RESTORE_GUEST_SPEC_CTRL
136
137	/*
138	 * Use a single vmcb (vmcb01 because it's always valid) for
139	 * context switching guest state via VMLOAD/VMSAVE, that way
140	 * the state doesn't need to be copied between vmcb01 and
141	 * vmcb02 when switching vmcbs for nested virtualization.
142	 */
143	mov SVM_vmcb01_pa(%_ASM_DI), %_ASM_AX
1441:	vmload %_ASM_AX
1452:
146
147	/* Get svm->current_vmcb->pa into RAX. */
148	mov SVM_current_vmcb(%_ASM_DI), %_ASM_AX
149	mov KVM_VMCB_pa(%_ASM_AX), %_ASM_AX
150
151	/* Load guest registers. */
152	mov VCPU_RCX(%_ASM_DI), %_ASM_CX
153	mov VCPU_RDX(%_ASM_DI), %_ASM_DX
154	mov VCPU_RBX(%_ASM_DI), %_ASM_BX
155	mov VCPU_RBP(%_ASM_DI), %_ASM_BP
156	mov VCPU_RSI(%_ASM_DI), %_ASM_SI
157#ifdef CONFIG_X86_64
158	mov VCPU_R8 (%_ASM_DI),  %r8
159	mov VCPU_R9 (%_ASM_DI),  %r9
160	mov VCPU_R10(%_ASM_DI), %r10
161	mov VCPU_R11(%_ASM_DI), %r11
162	mov VCPU_R12(%_ASM_DI), %r12
163	mov VCPU_R13(%_ASM_DI), %r13
164	mov VCPU_R14(%_ASM_DI), %r14
165	mov VCPU_R15(%_ASM_DI), %r15
166#endif
167	mov VCPU_RDI(%_ASM_DI), %_ASM_DI
168
169	/* Enter guest mode */
170	sti
171
1723:	vmrun %_ASM_AX
1734:
174	cli
175
176	/* Pop @svm to RAX while it's the only available register. */
177	pop %_ASM_AX
178
179	/* Save all guest registers.  */
180	mov %_ASM_CX,   VCPU_RCX(%_ASM_AX)
181	mov %_ASM_DX,   VCPU_RDX(%_ASM_AX)
182	mov %_ASM_BX,   VCPU_RBX(%_ASM_AX)
183	mov %_ASM_BP,   VCPU_RBP(%_ASM_AX)
184	mov %_ASM_SI,   VCPU_RSI(%_ASM_AX)
185	mov %_ASM_DI,   VCPU_RDI(%_ASM_AX)
186#ifdef CONFIG_X86_64
187	mov %r8,  VCPU_R8 (%_ASM_AX)
188	mov %r9,  VCPU_R9 (%_ASM_AX)
189	mov %r10, VCPU_R10(%_ASM_AX)
190	mov %r11, VCPU_R11(%_ASM_AX)
191	mov %r12, VCPU_R12(%_ASM_AX)
192	mov %r13, VCPU_R13(%_ASM_AX)
193	mov %r14, VCPU_R14(%_ASM_AX)
194	mov %r15, VCPU_R15(%_ASM_AX)
195#endif
196
197	/* @svm can stay in RDI from now on.  */
198	mov %_ASM_AX, %_ASM_DI
199
200	mov SVM_vmcb01_pa(%_ASM_DI), %_ASM_AX
2015:	vmsave %_ASM_AX
2026:
203
204	/* Restores GSBASE among other things, allowing access to percpu data.  */
205	pop %_ASM_AX
2067:	vmload %_ASM_AX
2078:
208
209#ifdef CONFIG_RETPOLINE
210	/* IMPORTANT: Stuff the RSB immediately after VM-Exit, before RET! */
211	FILL_RETURN_BUFFER %_ASM_AX, RSB_CLEAR_LOOPS, X86_FEATURE_RETPOLINE
212#endif
213
214	/* Clobbers RAX, RCX, RDX.  */
215	RESTORE_HOST_SPEC_CTRL
216
217	/*
218	 * Mitigate RETBleed for AMD/Hygon Zen uarch. RET should be
219	 * untrained as soon as we exit the VM and are back to the
220	 * kernel. This should be done before re-enabling interrupts
221	 * because interrupt handlers won't sanitize 'ret' if the return is
222	 * from the kernel.
223	 */
224	UNTRAIN_RET
225
226	/*
227	 * Clear all general purpose registers except RSP and RAX to prevent
228	 * speculative use of the guest's values, even those that are reloaded
229	 * via the stack.  In theory, an L1 cache miss when restoring registers
230	 * could lead to speculative execution with the guest's values.
231	 * Zeroing XORs are dirt cheap, i.e. the extra paranoia is essentially
232	 * free.  RSP and RAX are exempt as they are restored by hardware
233	 * during VM-Exit.
234	 */
235	xor %ecx, %ecx
236	xor %edx, %edx
237	xor %ebx, %ebx
238	xor %ebp, %ebp
239	xor %esi, %esi
240	xor %edi, %edi
241#ifdef CONFIG_X86_64
242	xor %r8d,  %r8d
243	xor %r9d,  %r9d
244	xor %r10d, %r10d
245	xor %r11d, %r11d
246	xor %r12d, %r12d
247	xor %r13d, %r13d
248	xor %r14d, %r14d
249	xor %r15d, %r15d
250#endif
251
252	/* "Pop" @spec_ctrl_intercepted.  */
253	pop %_ASM_BX
254
255	pop %_ASM_BX
256
257#ifdef CONFIG_X86_64
258	pop %r12
259	pop %r13
260	pop %r14
261	pop %r15
262#else
263	pop %esi
264	pop %edi
265#endif
266	pop %_ASM_BP
267	RET
268
269	RESTORE_GUEST_SPEC_CTRL_BODY
270	RESTORE_HOST_SPEC_CTRL_BODY
271
27210:	cmpb $0, kvm_rebooting
273	jne 2b
274	ud2
27530:	cmpb $0, kvm_rebooting
276	jne 4b
277	ud2
27850:	cmpb $0, kvm_rebooting
279	jne 6b
280	ud2
28170:	cmpb $0, kvm_rebooting
282	jne 8b
283	ud2
284
285	_ASM_EXTABLE(1b, 10b)
286	_ASM_EXTABLE(3b, 30b)
287	_ASM_EXTABLE(5b, 50b)
288	_ASM_EXTABLE(7b, 70b)
289
290SYM_FUNC_END(__svm_vcpu_run)
291
292/**
293 * __svm_sev_es_vcpu_run - Run a SEV-ES vCPU via a transition to SVM guest mode
294 * @svm:	struct vcpu_svm *
295 * @spec_ctrl_intercepted: bool
296 */
297SYM_FUNC_START(__svm_sev_es_vcpu_run)
298	push %_ASM_BP
299#ifdef CONFIG_X86_64
300	push %r15
301	push %r14
302	push %r13
303	push %r12
304#else
305	push %edi
306	push %esi
307#endif
308	push %_ASM_BX
309
310	/*
311	 * Save variables needed after vmexit on the stack, in inverse
312	 * order compared to when they are needed.
313	 */
314
315	/* Accessed directly from the stack in RESTORE_HOST_SPEC_CTRL.  */
316	push %_ASM_ARG2
317
318	/* Save @svm. */
319	push %_ASM_ARG1
320
321.ifnc _ASM_ARG1, _ASM_DI
322	/*
323	 * Stash @svm in RDI early. On 32-bit, arguments are in RAX, RCX
324	 * and RDX which are clobbered by RESTORE_GUEST_SPEC_CTRL.
325	 */
326	mov %_ASM_ARG1, %_ASM_DI
327.endif
328
329	/* Clobbers RAX, RCX, RDX.  */
330	RESTORE_GUEST_SPEC_CTRL
331
332	/* Get svm->current_vmcb->pa into RAX. */
333	mov SVM_current_vmcb(%_ASM_DI), %_ASM_AX
334	mov KVM_VMCB_pa(%_ASM_AX), %_ASM_AX
335
336	/* Enter guest mode */
337	sti
338
3391:	vmrun %_ASM_AX
340
3412:	cli
342
343	/* Pop @svm to RDI, guest registers have been saved already. */
344	pop %_ASM_DI
345
346#ifdef CONFIG_RETPOLINE
347	/* IMPORTANT: Stuff the RSB immediately after VM-Exit, before RET! */
348	FILL_RETURN_BUFFER %_ASM_AX, RSB_CLEAR_LOOPS, X86_FEATURE_RETPOLINE
349#endif
350
351	/* Clobbers RAX, RCX, RDX.  */
352	RESTORE_HOST_SPEC_CTRL
353
354	/*
355	 * Mitigate RETBleed for AMD/Hygon Zen uarch. RET should be
356	 * untrained as soon as we exit the VM and are back to the
357	 * kernel. This should be done before re-enabling interrupts
358	 * because interrupt handlers won't sanitize RET if the return is
359	 * from the kernel.
360	 */
361	UNTRAIN_RET
362
363	/* "Pop" @spec_ctrl_intercepted.  */
364	pop %_ASM_BX
365
366	pop %_ASM_BX
367
368#ifdef CONFIG_X86_64
369	pop %r12
370	pop %r13
371	pop %r14
372	pop %r15
373#else
374	pop %esi
375	pop %edi
376#endif
377	pop %_ASM_BP
378	RET
379
380	RESTORE_GUEST_SPEC_CTRL_BODY
381	RESTORE_HOST_SPEC_CTRL_BODY
382
3833:	cmpb $0, kvm_rebooting
384	jne 2b
385	ud2
386
387	_ASM_EXTABLE(1b, 3b)
388
389SYM_FUNC_END(__svm_sev_es_vcpu_run)
390