# HG changeset patch
# User Ian.Campbell@xxxxxxxxxxxxx
# Node ID 0ffd94a0231812372c0072af7caeeb3b8ff8ac0e
# Parent 278e536ade72e6b31651315e12095b47f3be8676
Pass NMIs to DOM0 via a dedicated callback, Xen/Linux x86_64 support.
Register our NMI handler with Xen. Do an iret via the hypervisor
whenever the return CS is > RING0.
Add include/asm-xen/asm-x86_64/nmi.h as a Xen modified copy of
include/asm-x86_64/nmi.h in order that we can implement
get_nmi_reason() in a manner suitable for Xen.
Signed-off-by: Ian Campbell <Ian.Campbell@xxxxxxxxxxxxx>
diff -r 278e536ade72 -r 0ffd94a02318
linux-2.6-xen-sparse/arch/xen/x86_64/kernel/entry.S
--- a/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/entry.S Wed Jan 11
15:52:54 2006
+++ b/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/entry.S Wed Jan 11
15:53:59 2006
@@ -121,19 +121,19 @@
.endm
/*
- * Must be consistent with the definition in arch_x86_64.h:
- * struct switch_to_user {
+ * Must be consistent with the definition in arch-x86_64.h:
+ * struct iret_context {
* u64 rax, r11, rcx, flags, rip, cs, rflags, rsp, ss;
* };
* #define VGCF_IN_SYSCALL (1<<8)
*/
- .macro SWITCH_TO_USER flag
+ .macro HYPERVISOR_IRET flag
subq $8*4,%rsp # reuse rip, cs, rflags, rsp, ss in
the stack
movq %rax,(%rsp)
movq %r11,1*8(%rsp)
movq %rcx,2*8(%rsp) # we saved %rcx upon exceptions
movq $\flag,3*8(%rsp)
- movq $__HYPERVISOR_switch_to_user,%rax
+ movq $__HYPERVISOR_iret,%rax
syscall
.endm
@@ -225,7 +225,7 @@
jnz sysret_careful
XEN_UNBLOCK_EVENTS(%rsi)
RESTORE_ARGS 0,8,0
- SWITCH_TO_USER VGCF_IN_SYSCALL
+ HYPERVISOR_IRET VGCF_IN_SYSCALL
/* Handle reschedules */
/* edx: work, edi: workmask */
@@ -478,7 +478,7 @@
orb $3,1*8(%rsp)
iretq
user_mode:
- SWITCH_TO_USER 0
+ HYPERVISOR_IRET 0
/* edi: workmask, edx: work */
retint_careful:
@@ -719,6 +719,16 @@
call evtchn_do_upcall
jmp error_exit
+ENTRY(nmi)
+ zeroentry do_nmi_callback
+ENTRY(do_nmi_callback)
+ addq $8, %rsp
+ call do_nmi
+ RESTORE_REST
+ XEN_BLOCK_EVENTS(%rsi)
+ GET_THREAD_INFO(%rcx)
+ jmp retint_restore_args
+
ALIGN
restore_all_enable_events:
XEN_UNBLOCK_EVENTS(%rsi) # %rsi is already set up...
@@ -733,7 +743,7 @@
orb $3,1*8(%rsp)
iretq
crit_user_mode:
- SWITCH_TO_USER 0
+ HYPERVISOR_IRET 0
14: XEN_LOCKED_BLOCK_EVENTS(%rsi)
XEN_PUT_VCPU_INFO(%rsi)
diff -r 278e536ade72 -r 0ffd94a02318
linux-2.6-xen-sparse/arch/xen/x86_64/kernel/setup.c
--- a/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/setup.c Wed Jan 11
15:52:54 2006
+++ b/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/setup.c Wed Jan 11
15:53:59 2006
@@ -62,6 +62,7 @@
#include <asm-xen/xen-public/physdev.h>
#include "setup_arch_pre.h"
#include <asm/hypervisor.h>
+#include <asm-xen/xen-public/nmi.h>
#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
#define PFN_PHYS(x) ((x) << PAGE_SHIFT)
#define end_pfn_map end_pfn
diff -r 278e536ade72 -r 0ffd94a02318
linux-2.6-xen-sparse/arch/xen/x86_64/kernel/traps.c
--- a/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/traps.c Wed Jan 11
15:52:54 2006
+++ b/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/traps.c Wed Jan 11
15:53:59 2006
@@ -559,9 +559,11 @@
printk("Uhhuh. NMI received. Dazed and confused, but trying to
continue\n");
printk("You probably have a hardware problem with your RAM chips\n");
+#if 0 /* XEN */
/* Clear and disable the memory parity error line. */
reason = (reason & 0xf) | 4;
outb(reason, 0x61);
+#endif /* XEN */
}
static void io_check_error(unsigned char reason, struct pt_regs * regs)
@@ -569,12 +571,14 @@
printk("NMI: IOCK error (debug interrupt?)\n");
show_registers(regs);
+#if 0 /* XEN */
/* Re-enable the IOCK line, wait for a few seconds */
reason = (reason & 0xf) | 8;
outb(reason, 0x61);
mdelay(2000);
reason &= ~8;
outb(reason, 0x61);
+#endif /* XEN */
}
static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
diff -r 278e536ade72 -r 0ffd94a02318
linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/hypercall.h
--- a/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/hypercall.h Wed Jan
11 15:52:54 2006
+++ b/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/hypercall.h Wed Jan
11 15:53:59 2006
@@ -287,9 +287,9 @@
}
static inline int
-HYPERVISOR_switch_to_user(void)
-{
- return _hypercall0(int, switch_to_user);
+HYPERVISOR_iret(void)
+{
+ return _hypercall0(int, iret);
}
static inline int
@@ -305,6 +305,14 @@
{
return _hypercall3(int, sched_op, SCHEDOP_shutdown,
SHUTDOWN_suspend, srec);
+}
+
+static inline int
+HYPERVISOR_nmi_op(
+ unsigned long op,
+ unsigned long arg)
+{
+ return _hypercall2(int, nmi_op, op, arg);
}
#endif /* __HYPERCALL_H__ */
diff -r 278e536ade72 -r 0ffd94a02318
linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/setup_arch_post.h
---
a/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/setup_arch_post.h
Wed Jan 11 15:52:54 2006
+++
b/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/setup_arch_post.h
Wed Jan 11 15:53:59 2006
@@ -35,6 +35,7 @@
extern void hypervisor_callback(void);
extern void failsafe_callback(void);
+extern void nmi(void);
static void __init machine_specific_arch_setup(void)
{
@@ -43,5 +44,7 @@
(unsigned long) failsafe_callback,
(unsigned long) system_call);
+ HYPERVISOR_nmi_op(XENNMI_register_callback, (unsigned long)&nmi);
+
machine_specific_modify_cpu_capabilities(&boot_cpu_data);
}
diff -r 278e536ade72 -r 0ffd94a02318
linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/nmi.h
--- /dev/null Wed Jan 11 15:52:54 2006
+++ b/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/nmi.h Wed Jan 11
15:53:59 2006
@@ -0,0 +1,75 @@
+/*
+ * linux/include/asm-i386/nmi.h
+ */
+#ifndef ASM_NMI_H
+#define ASM_NMI_H
+
+#include <linux/pm.h>
+
+#include <asm-xen/xen-public/nmi.h>
+
+struct pt_regs;
+
+typedef int (*nmi_callback_t)(struct pt_regs * regs, int cpu);
+
+/**
+ * set_nmi_callback
+ *
+ * Set a handler for an NMI. Only one handler may be
+ * set. Return 1 if the NMI was handled.
+ */
+void set_nmi_callback(nmi_callback_t callback);
+
+/**
+ * unset_nmi_callback
+ *
+ * Remove the handler previously set.
+ */
+void unset_nmi_callback(void);
+
+#ifdef CONFIG_PM
+
+/** Replace the PM callback routine for NMI. */
+struct pm_dev * set_nmi_pm_callback(pm_callback callback);
+
+/** Unset the PM callback routine back to the default. */
+void unset_nmi_pm_callback(struct pm_dev * dev);
+
+#else
+
+static inline struct pm_dev * set_nmi_pm_callback(pm_callback callback)
+{
+ return 0;
+}
+
+static inline void unset_nmi_pm_callback(struct pm_dev * dev)
+{
+}
+
+#endif /* CONFIG_PM */
+
+extern void default_do_nmi(struct pt_regs *);
+extern void die_nmi(char *str, struct pt_regs *regs);
+
+static inline unsigned char get_nmi_reason(void)
+{
+ shared_info_t *s = HYPERVISOR_shared_info;
+ unsigned char reason = 0;
+
+ /* construct a value which looks like it came from
+ * port 0x61.
+ */
+ if (test_bit(_XEN_NMIREASON_io_error, &s->arch.nmi_reason))
+ reason |= 0x40;
+ if (test_bit(_XEN_NMIREASON_parity_error, &s->arch.nmi_reason))
+ reason |= 0x80;
+
+ return reason;
+}
+
+extern int panic_on_timeout;
+extern int unknown_nmi_panic;
+
+extern int check_nmi_watchdog(void);
+
+#endif /* ASM_NMI_H */
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|