#include <asm/apic.h>
#include <asm/random.h>
#include <asm/setup.h>
+#include <asm/shstk.h>
#include <mach_apic.h>
#include <public/sysctl.h> /* for XEN_INVALID_{SOCKET,CORE}_ID */
*/
if (cpu_has_xen_shstk) {
volatile uint64_t *ist_ssp = tss_page->ist_ssp;
+ unsigned long
+ mce_ssp = stack_top + (IST_MCE * IST_SHSTK_SIZE) - 8,
+ nmi_ssp = stack_top + (IST_NMI * IST_SHSTK_SIZE) - 8,
+ db_ssp = stack_top + (IST_DB * IST_SHSTK_SIZE) - 8,
+ df_ssp = stack_top + (IST_DF * IST_SHSTK_SIZE) - 8;
ist_ssp[0] = 0x8600111111111111ul;
- ist_ssp[IST_MCE] = stack_top + (IST_MCE * IST_SHSTK_SIZE) - 8;
- ist_ssp[IST_NMI] = stack_top + (IST_NMI * IST_SHSTK_SIZE) - 8;
- ist_ssp[IST_DB] = stack_top + (IST_DB * IST_SHSTK_SIZE) - 8;
- ist_ssp[IST_DF] = stack_top + (IST_DF * IST_SHSTK_SIZE) - 8;
+ ist_ssp[IST_MCE] = mce_ssp;
+ ist_ssp[IST_NMI] = nmi_ssp;
+ ist_ssp[IST_DB] = db_ssp;
+ ist_ssp[IST_DF] = df_ssp;
for ( i = IST_DF + 1; i < ARRAY_SIZE(tss_page->ist_ssp); ++i )
ist_ssp[i] = 0x8600111111111111ul;
+ if (IS_ENABLED(CONFIG_XEN_SHSTK) && rdssp() != SSP_NO_SHSTK) {
+ /*
+ * Rewrite supervisor tokens when shadow stacks are
+ * active. This resets any busy bits left across S3.
+ */
+ wrss(mce_ssp, _p(mce_ssp));
+ wrss(nmi_ssp, _p(nmi_ssp));
+ wrss(db_ssp, _p(db_ssp));
+ wrss(df_ssp, _p(df_ssp));
+ }
+
wrmsrl(MSR_INTERRUPT_SSP_TABLE, (unsigned long)ist_ssp);
}
--- /dev/null
+/******************************************************************************
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (c) 2022 Citrix Systems Ltd.
+ */
+#ifndef XEN_ASM_SHSTK_H
+#define XEN_ASM_SHSTK_H
+
+/*
+ * RDSSP is a nop when shadow stacks are inactive. Also, SSP has a minimum
+ * alignment of 4 which is enforced by hardware.
+ *
+ * We load 1 into a register, then RDSSP. If shadow stacks are not enabled,
+ * RDSSP is a nop, and the 1 is preserved. Otherwise, the 1 is clobbered with
+ * the real SSP, which has the bottom two bits clear.
+ */
+#define SSP_NO_SHSTK 1
+
+static inline unsigned long rdssp(void)
+{
+ unsigned long ssp;
+
+ asm volatile ( "rdsspq %0" : "=r" (ssp) : "0" (SSP_NO_SHSTK) );
+
+ return ssp;
+}
+
+static inline void wrss(unsigned long val, unsigned long *ptr)
+{
+ asm ( "wrssq %[val], %[ptr]"
+ : [ptr] "=m" (*ptr)
+ : [val] "r" (val) );
+}
+
+#endif /* XEN_ASM_SHSTK_H */
#include <asm/pv/traps.h>
#include <asm/pv/trace.h>
#include <asm/pv/mm.h>
+#include <asm/shstk.h>
/*
* opt_nmi: one of 'ignore', 'dom0', or 'fatal'.
{
unsigned long ssp, *ptr, *base;
- asm ( "rdsspq %0" : "=r" (ssp) : "0" (1) );
- if ( ssp == 1 )
+ if ( (ssp = rdssp()) == SSP_NO_SHSTK )
goto shstk_done;
ptr = _p(ssp);
*/
if ( ptr[0] == regs->rip && ptr[1] == regs->cs )
{
- asm ( "wrssq %[fix], %[stk]"
- : [stk] "=m" (ptr[0])
- : [fix] "r" (fixup) );
+ wrss(fixup, ptr);
goto shstk_done;
}
}