*/
#define STK_REL(field, top_of_stk) ((field) - (top_of_stk))
-.macro DO_SPEC_CTRL_COND_VERW
+.macro SPEC_CTRL_COND_VERW \
+ scf=STK_REL(CPUINFO_spec_ctrl_flags, CPUINFO_error_code), \
+ sel=STK_REL(CPUINFO_verw_sel, CPUINFO_error_code)
/*
- * Requires %rsp=cpuinfo
+ * Requires \scf and \sel as %rsp-relative expressions
+ * Clobbers eflags
+ *
+ * VERW needs to run after guest GPRs have been restored, where only %rsp is
+ * good to use. Default to expecting %rsp pointing at CPUINFO_error_code.
+ * Contexts where this is not true must provide an alternative \scf and \sel.
*
* Issue a VERW for its flushing side effect, if indicated. This is a Spectre
* v1 gadget, but the IRET/VMEntry is serialising.
*/
- testb $SCF_verw, CPUINFO_spec_ctrl_flags(%rsp)
+ testb $SCF_verw, \scf(%rsp)
jz .L\@_verw_skip
- verw CPUINFO_verw_sel(%rsp)
+ verw \sel(%rsp)
.L\@_verw_skip:
.endm
*/
ALTERNATIVE "", DO_SPEC_CTRL_EXIT_TO_GUEST, X86_FEATURE_SC_MSR_PV
- DO_SPEC_CTRL_COND_VERW
-
ALTERNATIVE "", DO_SPEC_CTRL_DIV, X86_FEATURE_SC_DIV
.endm
*/
.macro SPEC_CTRL_EXIT_TO_XEN
/*
- * Requires %r12=ist_exit, %r14=stack_end
+ * Requires %r12=ist_exit, %r14=stack_end, %rsp=regs
* Clobbers %rax, %rbx, %rcx, %rdx
*/
movzbl STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14), %ebx
test %r12, %r12
jz .L\@_skip_ist_exit
- /* Logically DO_SPEC_CTRL_COND_VERW but without the %rsp=cpuinfo dependency */
- testb $SCF_verw, %bl
- jz .L\@_skip_verw
- verw STACK_CPUINFO_FIELD(verw_sel)(%r14)
-.L\@_skip_verw:
+ /*
+ * Stash SCF and verw_sel above eflags in the case of an IST_exit. The
+ * VERW logic needs to run after guest GPRs have been restored; i.e. where
+ * we cannot use %r12 or %r14 for the purposes they have here.
+ *
+ * When the CPU pushed this exception frame, it zero-extended eflags.
+ * Therefore it is safe for the VERW logic to look at the stashed SCF
+ * outside of the ist_exit condition. Also, this stashing won't influence
+ * any other restore_all_guest() paths.
+ */
+ or $(__HYPERVISOR_DS32 << 16), %ebx
+ mov %ebx, UREGS_eflags + 4(%rsp) /* EFRAME_shadow_scf/sel */
ALTERNATIVE "", DO_SPEC_CTRL_DIV, X86_FEATURE_SC_DIV
* EFRAME_* is for the entry/exit logic where %rsp is pointing at
* UREGS_error_code and GPRs are still/already guest values.
*/
-#define OFFSET_EF(sym, mem) \
+#define OFFSET_EF(sym, mem, ...) \
DEFINE(sym, offsetof(struct cpu_user_regs, mem) - \
- offsetof(struct cpu_user_regs, error_code))
+ offsetof(struct cpu_user_regs, error_code) __VA_ARGS__)
OFFSET_EF(EFRAME_entry_vector, entry_vector);
OFFSET_EF(EFRAME_rip, rip);
OFFSET_EF(EFRAME_cs, cs);
OFFSET_EF(EFRAME_eflags, eflags);
+
+ /*
+ * These aren't real fields. They're spare space, used by the IST
+ * exit-to-xen path.
+ */
+ OFFSET_EF(EFRAME_shadow_scf, eflags, +4);
+ OFFSET_EF(EFRAME_shadow_sel, eflags, +6);
+
OFFSET_EF(EFRAME_rsp, rsp);
BLANK();
OFFSET(CPUINFO_guest_cpu_user_regs, struct cpu_info, guest_cpu_user_regs);
OFFSET(CPUINFO_error_code, struct cpu_info, guest_cpu_user_regs.error_code);
+ OFFSET(CPUINFO_rip, struct cpu_info, guest_cpu_user_regs.rip);
OFFSET(CPUINFO_processor_id, struct cpu_info, processor_id);
OFFSET(CPUINFO_verw_sel, struct cpu_info, verw_sel);
OFFSET(CPUINFO_current_vcpu, struct cpu_info, current_vcpu);
SPEC_CTRL_EXIT_TO_PV /* Req: a=spec_ctrl %rsp=regs/cpuinfo, Clob: cd */
RESTORE_ALL adj=8, compat=1
+
+ /* Account for ev/ec having already been popped off the stack. */
+ SPEC_CTRL_COND_VERW \
+ scf=STK_REL(CPUINFO_spec_ctrl_flags, CPUINFO_rip), \
+ sel=STK_REL(CPUINFO_verw_sel, CPUINFO_rip)
+
.Lft0: iretq
_ASM_PRE_EXTABLE(.Lft0, handle_exception)
END(compat_restore_all_guest)
#endif
mov EFRAME_rip(%rsp), %rcx
+
+ SPEC_CTRL_COND_VERW /* Req: %rsp=eframe Clob: efl */
+
cmpw $FLAT_USER_CS32, EFRAME_cs(%rsp)
mov EFRAME_rsp(%rsp), %rsp
je 1f
iret_exit_to_guest:
andl $~(X86_EFLAGS_IOPL | X86_EFLAGS_VM), EFRAME_eflags(%rsp)
orl $X86_EFLAGS_IF, EFRAME_eflags(%rsp)
+
+ SPEC_CTRL_COND_VERW /* Req: %rsp=eframe Clob: efl */
+
addq $8,%rsp
.Lft0: iretq
_ASM_PRE_EXTABLE(.Lft0, handle_exception)
UNLIKELY_END(exit_cr3)
/* WARNING! `ret`, `call *`, `jmp *` not safe beyond this point. */
- SPEC_CTRL_EXIT_TO_XEN /* Req: %r12=ist_exit %r14=end, Clob: abcd */
+ SPEC_CTRL_EXIT_TO_XEN /* Req: %r12=ist_exit %r14=end %rsp=regs, Clob: abcd */
RESTORE_ALL adj=8
+
+ /*
+ * When the CPU pushed this exception frame, it zero-extended eflags.
+ * For an IST exit, SPEC_CTRL_EXIT_TO_XEN stashed shadow copies of
+ * spec_ctrl_flags and ver_sel above eflags, as we can't use any GPRs,
+ * and we're at a random place on the stack, not in a CPUFINFO block.
+ *
+ * Account for ev/ec having already been popped off the stack.
+ */
+ SPEC_CTRL_COND_VERW \
+ scf=STK_REL(EFRAME_shadow_scf, EFRAME_rip), \
+ sel=STK_REL(EFRAME_shadow_sel, EFRAME_rip)
+
iretq
END(restore_all_xen)