/******************************************************************************
* include/asm-x86/spec_ctrl.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; If not, see .
*
* Copyright (c) 2017-2018 Citrix Systems Ltd.
*/
#ifndef __X86_SPEC_CTRL_ASM_H__
#define __X86_SPEC_CTRL_ASM_H__
#ifdef __ASSEMBLY__
#include
#include
/*
* Saving and restoring MSR_SPEC_CTRL state is a little tricky.
*
* We want the guests choice of SPEC_CTRL while in guest context, and Xen's
* choice (set or clear, depending on the hardware) while running in Xen
* context. Therefore, a simplistic algorithm is:
*
* - Set/clear IBRS on entry to Xen
* - Set the guests' choice on exit to guest
* - Leave SPEC_CTRL unchanged on exit to xen
*
* There are two complicating factors:
* 1) HVM guests can have direct access to the MSR, so it can change
* behind Xen's back.
* 2) An NMI or MCE can interrupt at any point, including early in the entry
* path, or late in the exit path after restoring the guest value. This
* will corrupt the guest value.
*
* Factor 1 is dealt with:
* - On VMX by using MSR load/save lists to have vmentry/exit atomically
* load/save the guest value. Xen's value is loaded in regular code, and
* there is no need to use the shadow logic (below).
* - On SVM by altering MSR_SPEC_CTRL inside the CLGI/STGI region. This
* makes the changes atomic with respect to NMIs/etc, so no need for
* shadowing logic.
*
* Factor 2 is harder. We maintain a shadow_spec_ctrl value, and a use_shadow
* boolean in the per cpu spec_ctrl_flags. The synchronous use is:
*
* 1) Store guest value in shadow_spec_ctrl
* 2) Set the use_shadow boolean
* 3) Load guest value into MSR_SPEC_CTRL
* 4) Exit to guest
* 5) Entry from guest
* 6) Clear the use_shadow boolean
* 7) Load Xen's value into MSR_SPEC_CTRL
*
* The asynchronous use for interrupts/exceptions is:
* - Set/clear IBRS on entry to Xen
* - On exit to Xen, check use_shadow
* - If set, load shadow_spec_ctrl
*
* Therefore, an interrupt/exception which hits the synchronous path between
* steps 2 and 6 will restore the shadow value rather than leaving Xen's value
* loaded and corrupting the value used in guest context.
*
* Additionally, in some cases it is safe to skip writes to MSR_SPEC_CTRL when
* we don't require any of the side effects of an identical write. Maintain a
* per-cpu last_spec_ctrl value for this purpose.
*
* The following ASM fragments implement this algorithm. See their local
* comments for further details.
* - SPEC_CTRL_ENTRY_FROM_PV
* - SPEC_CTRL_ENTRY_FROM_INTR
* - SPEC_CTRL_ENTRY_FROM_INTR_IST
* - SPEC_CTRL_EXIT_TO_XEN_IST
* - SPEC_CTRL_EXIT_TO_XEN
* - SPEC_CTRL_EXIT_TO_PV
*
* Additionally, the following grep-fodder exists to find the HVM logic.
* - SPEC_CTRL_ENTRY_FROM_{SVM,VMX}
* - SPEC_CTRL_EXIT_TO_{SVM,VMX}
*/
.macro DO_OVERWRITE_RSB tmp=rax
/*
* Requires nothing
* Clobbers \tmp (%rax by default), %rcx
*
* Requires 256 bytes of {,shadow}stack space, but %rsp/SSP has no net
* change. Based on Google's performance numbers, the loop is unrolled to 16
* iterations and two calls per iteration.
*
* The call filling the RSB needs a nonzero displacement. A nop would do, but
* we use "1: pause; lfence; jmp 1b" to safely contains any ret-based
* speculation, even if the loop is speculatively executed prematurely.
*
* %rsp is preserved by using an extra GPR because a) we've got plenty spare,
* b) the two movs are shorter to encode than `add $32*8, %rsp`, and c) can be
* optimised with mov-elimination in modern cores.
*/
mov $16, %ecx /* 16 iterations, two calls per loop */
mov %rsp, %\tmp /* Store the current %rsp */
.L\@_fill_rsb_loop:
.irp n, 1, 2 /* Unrolled twice. */
call .L\@_insert_rsb_entry_\n /* Create an RSB entry. */
.L\@_capture_speculation_\n:
pause
lfence
jmp .L\@_capture_speculation_\n /* Capture rogue speculation. */
.L\@_insert_rsb_entry_\n:
.endr
sub $1, %ecx
jnz .L\@_fill_rsb_loop
mov %\tmp, %rsp /* Restore old %rsp */
#ifdef CONFIG_XEN_SHSTK
mov $1, %ecx
rdsspd %ecx
cmp $1, %ecx
je .L\@_shstk_done
mov $64, %ecx /* 64 * 4 bytes, given incsspd */
incsspd %ecx /* Restore old SSP */
.L\@_shstk_done:
#endif
.endm
.macro DO_SPEC_CTRL_ENTRY maybexen:req
/*
* Requires %rsp=regs (also cpuinfo if !maybexen)
* Requires %r14=stack_end (if maybexen)
* Clobbers %rax, %rcx, %rdx
*
* PV guests can't update MSR_SPEC_CTRL behind Xen's back, so no need to read
* it back. Entries from guest context need to clear SPEC_CTRL shadowing,
* while entries from Xen must leave shadowing in its current state.
*/
mov $MSR_SPEC_CTRL, %ecx
xor %edx, %edx
/*
* Clear SPEC_CTRL shadowing *before* loading Xen's value. If entering
* from a possibly-xen context, %rsp doesn't necessarily alias the cpuinfo
* block so calculate the position directly.
*/
.if \maybexen
xor %eax, %eax
/* Branchless `if ( !xen ) clear_shadowing` */
testb $3, UREGS_cs(%rsp)
setnz %al
not %eax
and %al, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14)
movzbl STACK_CPUINFO_FIELD(xen_spec_ctrl)(%r14), %eax
.else
andb $~SCF_use_shadow, CPUINFO_spec_ctrl_flags(%rsp)
movzbl CPUINFO_xen_spec_ctrl(%rsp), %eax
.endif
wrmsr
.endm
.macro DO_SPEC_CTRL_EXIT_TO_XEN
/*
* Requires %rbx=stack_end
* Clobbers %rax, %rcx, %rdx
*
* When returning to Xen context, look to see whether SPEC_CTRL shadowing is
* in effect, and reload the shadow value. This covers race conditions which
* exist with an NMI/MCE/etc hitting late in the return-to-guest path.
*/
xor %edx, %edx
testb $SCF_use_shadow, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%rbx)
jz .L\@_skip
mov STACK_CPUINFO_FIELD(shadow_spec_ctrl)(%rbx), %eax
mov $MSR_SPEC_CTRL, %ecx
wrmsr
.L\@_skip:
.endm
.macro DO_SPEC_CTRL_EXIT_TO_GUEST
/*
* Requires %eax=spec_ctrl, %rsp=regs/cpuinfo
* Clobbers %rcx, %rdx
*
* When returning to guest context, set up SPEC_CTRL shadowing and load the
* guest value.
*/
/* Set up shadow value *before* enabling shadowing. */
mov %eax, CPUINFO_shadow_spec_ctrl(%rsp)
/* Set SPEC_CTRL shadowing *before* loading the guest value. */
orb $SCF_use_shadow, CPUINFO_spec_ctrl_flags(%rsp)
mov $MSR_SPEC_CTRL, %ecx
xor %edx, %edx
wrmsr
.endm
/* Use after an entry from PV context (syscall/sysenter/int80/int82/etc). */
#define SPEC_CTRL_ENTRY_FROM_PV \
ALTERNATIVE "", DO_OVERWRITE_RSB, X86_FEATURE_SC_RSB_PV; \
ALTERNATIVE "", __stringify(DO_SPEC_CTRL_ENTRY maybexen=0), \
X86_FEATURE_SC_MSR_PV
/* Use in interrupt/exception context. May interrupt Xen or PV context. */
#define SPEC_CTRL_ENTRY_FROM_INTR \
ALTERNATIVE "", DO_OVERWRITE_RSB, X86_FEATURE_SC_RSB_PV; \
ALTERNATIVE "", __stringify(DO_SPEC_CTRL_ENTRY maybexen=1), \
X86_FEATURE_SC_MSR_PV
/* Use when exiting to Xen context. */
#define SPEC_CTRL_EXIT_TO_XEN \
ALTERNATIVE "", \
DO_SPEC_CTRL_EXIT_TO_XEN, X86_FEATURE_SC_MSR_PV
/* Use when exiting to PV guest context. */
#define SPEC_CTRL_EXIT_TO_PV \
ALTERNATIVE "", \
DO_SPEC_CTRL_EXIT_TO_GUEST, X86_FEATURE_SC_MSR_PV; \
ALTERNATIVE "", __stringify(verw CPUINFO_verw_sel(%rsp)), \
X86_FEATURE_SC_VERW_PV
/*
* Use in IST interrupt/exception context. May interrupt Xen or PV context.
* Fine grain control of SCF_ist_wrmsr is needed for safety in the S3 resume
* path to avoid using MSR_SPEC_CTRL before the microcode introducing it has
* been reloaded.
*/
.macro SPEC_CTRL_ENTRY_FROM_INTR_IST
/*
* Requires %rsp=regs, %r14=stack_end
* Clobbers %rax, %rcx, %rdx
*
* This is logical merge of DO_OVERWRITE_RSB and DO_SPEC_CTRL_ENTRY
* maybexen=1, but with conditionals rather than alternatives.
*/
movzbl STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14), %eax
test $SCF_ist_rsb, %al
jz .L\@_skip_rsb
DO_OVERWRITE_RSB tmp=rdx /* Clobbers %rcx/%rdx */
.L\@_skip_rsb:
test $SCF_ist_wrmsr, %al
jz .L\@_skip_wrmsr
xor %edx, %edx
testb $3, UREGS_cs(%rsp)
setnz %dl
not %edx
and %dl, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14)
/* Load Xen's intended value. */
mov $MSR_SPEC_CTRL, %ecx
movzbl STACK_CPUINFO_FIELD(xen_spec_ctrl)(%r14), %eax
xor %edx, %edx
wrmsr
/* Opencoded UNLIKELY_START() with no condition. */
UNLIKELY_DISPATCH_LABEL(\@_serialise):
.subsection 1
/*
* In the case that we might need to set SPEC_CTRL.IBRS for safety, we
* need to ensure that an attacker can't poison the `jz .L\@_skip_wrmsr`
* to speculate around the WRMSR. As a result, we need a dispatch
* serialising instruction in the else clause.
*/
.L\@_skip_wrmsr:
lfence
UNLIKELY_END(\@_serialise)
.endm
/* Use when exiting to Xen in IST context. */
.macro SPEC_CTRL_EXIT_TO_XEN_IST
/*
* Requires %rbx=stack_end
* Clobbers %rax, %rcx, %rdx
*/
testb $SCF_ist_wrmsr, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%rbx)
jz .L\@_skip
DO_SPEC_CTRL_EXIT_TO_XEN
.L\@_skip:
.endm
#endif /* __ASSEMBLY__ */
#endif /* !__X86_SPEC_CTRL_ASM_H__ */
/*
* Local variables:
* mode: C
* c-file-style: "BSD"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/