diff --git a/xen/arch/x86/boot/x86_64.S b/xen/arch/x86/boot/x86_64.S index 11a7e9d3bd..9705d03f84 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 differs between IDT or FRED 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 hotplug this clears the busy bit so @@ -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 872a8c63f9..44da5efa1d 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -908,7 +909,29 @@ static void __init noreturn reinit_bsp_stack(void) if ( cpu_has_xen_shstk ) { 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. + * + * In IDT mode, we use SETSSBSY (itself using MSR_PL0_SSP, configured + * previously) to mark the Supervisor Token as Busy. In FRED mode, + * there is no token, so we need to create a temporary 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);