|
@@ -579,6 +579,70 @@ static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum,
|
|
|
preempt_enable();
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_X86_64
|
|
|
+struct trap_array_entry {
|
|
|
+ void (*orig)(void);
|
|
|
+ void (*xen)(void);
|
|
|
+ bool ist_okay;
|
|
|
+};
|
|
|
+
|
|
|
+static struct trap_array_entry trap_array[] = {
|
|
|
+ { debug, xen_xendebug, true },
|
|
|
+ { int3, xen_xenint3, true },
|
|
|
+ { double_fault, xen_double_fault, true },
|
|
|
+#ifdef CONFIG_X86_MCE
|
|
|
+ { machine_check, xen_machine_check, true },
|
|
|
+#endif
|
|
|
+ { nmi, xen_nmi, true },
|
|
|
+ { overflow, xen_overflow, false },
|
|
|
+#ifdef CONFIG_IA32_EMULATION
|
|
|
+ { entry_INT80_compat, xen_entry_INT80_compat, false },
|
|
|
+#endif
|
|
|
+ { page_fault, xen_page_fault, false },
|
|
|
+ { divide_error, xen_divide_error, false },
|
|
|
+ { bounds, xen_bounds, false },
|
|
|
+ { invalid_op, xen_invalid_op, false },
|
|
|
+ { device_not_available, xen_device_not_available, false },
|
|
|
+ { coprocessor_segment_overrun, xen_coprocessor_segment_overrun, false },
|
|
|
+ { invalid_TSS, xen_invalid_TSS, false },
|
|
|
+ { segment_not_present, xen_segment_not_present, false },
|
|
|
+ { stack_segment, xen_stack_segment, false },
|
|
|
+ { general_protection, xen_general_protection, false },
|
|
|
+ { spurious_interrupt_bug, xen_spurious_interrupt_bug, false },
|
|
|
+ { coprocessor_error, xen_coprocessor_error, false },
|
|
|
+ { alignment_check, xen_alignment_check, false },
|
|
|
+ { simd_coprocessor_error, xen_simd_coprocessor_error, false },
|
|
|
+};
|
|
|
+
|
|
|
+static bool get_trap_addr(void **addr, unsigned int ist)
|
|
|
+{
|
|
|
+ unsigned int nr;
|
|
|
+ bool ist_okay = false;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Replace trap handler addresses by Xen specific ones.
|
|
|
+ * Check for known traps using IST and whitelist them.
|
|
|
+ * The debugger ones are the only ones we care about.
|
|
|
+ * Xen will handle faults like double_fault, * so we should never see
|
|
|
+ * them. Warn if there's an unexpected IST-using fault handler.
|
|
|
+ */
|
|
|
+ for (nr = 0; nr < ARRAY_SIZE(trap_array); nr++) {
|
|
|
+ struct trap_array_entry *entry = trap_array + nr;
|
|
|
+
|
|
|
+ if (*addr == entry->orig) {
|
|
|
+ *addr = entry->xen;
|
|
|
+ ist_okay = entry->ist_okay;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (WARN_ON(ist != 0 && !ist_okay))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
static int cvt_gate_to_trap(int vector, const gate_desc *val,
|
|
|
struct trap_info *info)
|
|
|
{
|
|
@@ -591,40 +655,8 @@ static int cvt_gate_to_trap(int vector, const gate_desc *val,
|
|
|
|
|
|
addr = gate_offset(val);
|
|
|
#ifdef CONFIG_X86_64
|
|
|
- /*
|
|
|
- * Look for known traps using IST, and substitute them
|
|
|
- * appropriately. The debugger ones are the only ones we care
|
|
|
- * about. Xen will handle faults like double_fault,
|
|
|
- * so we should never see them. Warn if
|
|
|
- * there's an unexpected IST-using fault handler.
|
|
|
- */
|
|
|
- if (addr == (unsigned long)debug)
|
|
|
- addr = (unsigned long)xen_debug;
|
|
|
- else if (addr == (unsigned long)int3)
|
|
|
- addr = (unsigned long)xen_int3;
|
|
|
- else if (addr == (unsigned long)stack_segment)
|
|
|
- addr = (unsigned long)xen_stack_segment;
|
|
|
- else if (addr == (unsigned long)double_fault) {
|
|
|
- /* Don't need to handle these */
|
|
|
+ if (!get_trap_addr((void **)&addr, val->bits.ist))
|
|
|
return 0;
|
|
|
-#ifdef CONFIG_X86_MCE
|
|
|
- } else if (addr == (unsigned long)machine_check) {
|
|
|
- /*
|
|
|
- * when xen hypervisor inject vMCE to guest,
|
|
|
- * use native mce handler to handle it
|
|
|
- */
|
|
|
- ;
|
|
|
-#endif
|
|
|
- } else if (addr == (unsigned long)nmi)
|
|
|
- /*
|
|
|
- * Use the native version as well.
|
|
|
- */
|
|
|
- ;
|
|
|
- else {
|
|
|
- /* Some other trap using IST? */
|
|
|
- if (WARN_ON(val->bits.ist != 0))
|
|
|
- return 0;
|
|
|
- }
|
|
|
#endif /* CONFIG_X86_64 */
|
|
|
info->address = addr;
|
|
|
|