Under FRED, SETSSBSY is unavailable, and we want to be setting up FRED prior to setting up shadow stacks. As we still need Supervisor Tokens in IDT mode, we need mode-specific logic to establish SSP.
In FRED mode, write a Restore Token, RSTORSSP it, and discard the resulting Previous-SSP token. No change outside of FRED mode. Signed-off-by: Andrew Cooper <andrew.coop...@citrix.com> --- CC: Jan Beulich <jbeul...@suse.com> CC: Roger Pau Monné <roger....@citrix.com> --- xen/arch/x86/boot/x86_64.S | 23 +++++++++++++++++++++-- xen/arch/x86/setup.c | 27 ++++++++++++++++++++++++--- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/xen/arch/x86/boot/x86_64.S b/xen/arch/x86/boot/x86_64.S index ebb91d5e3f60..138501f52158 100644 --- a/xen/arch/x86/boot/x86_64.S +++ b/xen/arch/x86/boot/x86_64.S @@ -53,17 +53,21 @@ ENTRY(__high_start) mov %rcx, STACK_CPUINFO_FIELD(cr4)(%r15) mov %rcx, %cr4 - /* WARNING! call/ret now fatal (iff SHSTK) until SETSSBSY loads SSP */ + /* WARNING! CALL/RET now fatal (iff SHSTK) until SETSSBSY/RSTORSSP loads SSP */ #if defined(CONFIG_XEN_SHSTK) test $CET_SHSTK_EN, %al jz .L_ap_cet_done - /* Derive the supervisor token address from %rsp. */ + /* Derive the token address from %rsp. */ mov %rsp, %rdx and $~(STACK_SIZE - 1), %rdx or $(PRIMARY_SHSTK_SLOT + 1) * PAGE_SIZE - 8, %rdx + /* Establishing SSP depends on whether we're using FRED or IDT mode. */ + bt $32 /* ilog2(X86_CR4_FRED) */, %rcx + jc .L_fred_shstk + /* * Write a new Supervisor Token. It doesn't matter the first time a * CPU boots, but for S3 resume or CPU hot re-add, this clears the @@ -71,6 +75,21 @@ ENTRY(__high_start) */ wrssq %rdx, (%rdx) setssbsy + jmp .L_ap_cet_done + +.L_fred_shstk: + + /* + * Write a Restore Token, value: &token + 8 + * 64BIT (bit 0) at the + * base of the shstk (which isn't in use yet). + */ + lea 9(%rdx), %rdi + wrssq %rdi, (%rdx) + rstorssp (%rdx) + + /* Discard the Previous-SSP Token from the shstk. */ + mov $2, %edx + incsspd %edx #endif /* CONFIG_XEN_SHSTK */ .L_ap_cet_done: diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 6fb42c5a5f95..c5dd2051dffe 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -53,6 +53,7 @@ #include <asm/prot-key.h> #include <asm/pv/domain.h> #include <asm/setup.h> +#include <asm/shstk.h> #include <asm/smp.h> #include <asm/spec_ctrl.h> #include <asm/stubs.h> @@ -912,10 +913,30 @@ static void __init noreturn reinit_bsp_stack(void) if ( cpu_has_xen_shstk ) { - wrmsrl(MSR_PL0_SSP, - (unsigned long)stack + (PRIMARY_SHSTK_SLOT + 1) * PAGE_SIZE - 8); wrmsrl(MSR_S_CET, xen_msr_s_cet_value()); - asm volatile ("setssbsy" ::: "memory"); + + /* + * IDT and FRED differ by a Supervisor Token on the shadow stack, and + * therefore by the value in MSR_PL0_SSP. + * + * In IDT mode, we use SETSSBSY to mark the Supervisor Token as busy. + * In FRED mode, there is no token, so we need a transient Restore + * Token to establish SSP. + */ + if ( opt_fred ) + { + unsigned long *token = + (void *)stack + (PRIMARY_SHSTK_SLOT + 1) * PAGE_SIZE - 8; + + wrss((unsigned long)token + 9, token); + asm volatile ( "rstorssp %0" : "+m" (*token) ); + /* + * We need to discard the resulting Previous-SSP Token, but + * reset_stack_and_jump() will do that for us. + */ + } + else + asm volatile ( "setssbsy" ::: "memory" ); } reset_stack_and_jump(init_done); -- 2.39.5