|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH 3/3] x86/pv: Don't use IST for NMI/#MC/#DB in !CONFIG_PV builds
ISTs are used to force a stack switch on CPL0=>0 interrupts/exceptions. They
however come with a nasty corner case in the case of reentrancy where the
outer exception frame gets clobbered.
When the SYSCALL/SYSRET instructions aren't used, there is no need to use IST
for anything other than #DF, which reduces the number of corner cases.
Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
---
CC: Jan Beulich <JBeulich@xxxxxxxx>
CC: Wei Liu <wl@xxxxxxx>
CC: Roger Pau Monné <roger.pau@xxxxxxxxxx>
---
xen/arch/x86/cpu/common.c | 8 +++++---
xen/include/asm-x86/processor.h | 12 +++++++++++-
2 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/xen/arch/x86/cpu/common.c b/xen/arch/x86/cpu/common.c
index 7b093cb421..d45495c701 100644
--- a/xen/arch/x86/cpu/common.c
+++ b/xen/arch/x86/cpu/common.c
@@ -732,15 +732,17 @@ void load_system_tables(void)
.rsp2 = 0x8600111111111111ul,
/*
- * MCE, NMI and Double Fault handlers get their own stacks.
+ * #DF always uses a separate stack. NMI/#MC/#DB only need a
+ * separate stacks when PV guests are used.
* All others poisoned.
*/
.ist = {
- [IST_MCE - 1] = stack_top + IST_MCE * PAGE_SIZE,
[IST_DF - 1] = stack_top + IST_DF * PAGE_SIZE,
+#ifdef CONFIG_PV
[IST_NMI - 1] = stack_top + IST_NMI * PAGE_SIZE,
+ [IST_MCE - 1] = stack_top + IST_MCE * PAGE_SIZE,
[IST_DB - 1] = stack_top + IST_DB * PAGE_SIZE,
-
+#endif
[IST_MAX ... ARRAY_SIZE(tss->ist) - 1] =
0x8600111111111111ul,
},
diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h
index ea6e5497f4..33f2052c8e 100644
--- a/xen/include/asm-x86/processor.h
+++ b/xen/include/asm-x86/processor.h
@@ -441,12 +441,18 @@ struct tss_page {
};
DECLARE_PER_CPU(struct tss_page, tss_page);
+/*
+ * Interrupt Stack Tables. Used to force a stack switch on a CPL0=>0
+ * interrupt/exception. #DF uses IST all the time to detect stack overflows
+ * cleanly. NMI/#MC/#DB only need IST to cover the SYSCALL gap, and therefore
+ * only necessary with PV guests.
+ */
#define IST_NONE 0UL
#define IST_DF 1UL
#define IST_NMI 2UL
#define IST_MCE 3UL
#define IST_DB 4UL
-#define IST_MAX 4UL
+#define IST_MAX (IS_ENABLED(CONFIG_PV) ? 4ul : 1ul)
/* Set the Interrupt Stack Table used by a particular IDT entry. */
static inline void set_ist(idt_entry_t *idt, unsigned int ist)
@@ -461,6 +467,8 @@ static inline void set_ist(idt_entry_t *idt, unsigned int
ist)
static inline void enable_each_ist(idt_entry_t *idt)
{
set_ist(&idt[TRAP_double_fault], IST_DF);
+ if ( !IS_ENABLED(CONFIG_PV) )
+ return;
set_ist(&idt[TRAP_nmi], IST_NMI);
set_ist(&idt[TRAP_machine_check], IST_MCE);
set_ist(&idt[TRAP_debug], IST_DB);
@@ -469,6 +477,8 @@ static inline void enable_each_ist(idt_entry_t *idt)
static inline void disable_each_ist(idt_entry_t *idt)
{
set_ist(&idt[TRAP_double_fault], IST_NONE);
+ if ( !IS_ENABLED(CONFIG_PV) )
+ return;
set_ist(&idt[TRAP_nmi], IST_NONE);
set_ist(&idt[TRAP_machine_check], IST_NONE);
set_ist(&idt[TRAP_debug], IST_NONE);
--
2.11.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |