[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




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.