Mailing List Archive

Allow unknown NMIs to be propagated to domain0 via new
# HG changeset patch
# User kaf24@firebug.cl.cam.ac.uk
# Node ID 931acb64fbaf762fd47f9035b411ae6f1b5cb50b
# Parent b34f4169b12ea40e4f60f1cb805d6bcadb0d08fc
Allow unknown NMIs to be propagated to domain0 via new
VIRQ_NMI. Also simplify x86_32 NMI handling -- there's
no need to greedily consume IO/parity errors in
assembly code as they can be deferred without causing
an interrupt storm (the NMI pin is always edge-triggered
even though the sources are level-asserted).

Signed-off-by: Keir Fraser <keir@xensource.com>

diff -r b34f4169b12e -r 931acb64fbaf xen/arch/x86/traps.c
--- a/xen/arch/x86/traps.c Tue Dec 20 11:55:19 2005
+++ b/xen/arch/x86/traps.c Tue Dec 20 16:55:20 2005
@@ -1074,29 +1074,35 @@
return 0;
}

-unsigned long nmi_softirq_reason;
-static void nmi_softirq(void)
+
+/* Defer dom0 notification to softirq context (unsafe in NMI context). */
+static unsigned long nmi_dom0_softirq_reason;
+#define NMI_DOM0_PARITY_ERR 0
+#define NMI_DOM0_IO_ERR 1
+#define NMI_DOM0_UNKNOWN 2
+
+static void nmi_dom0_softirq(void)
{
if ( dom0 == NULL )
return;

- if ( test_and_clear_bit(0, &nmi_softirq_reason) )
+ if ( test_and_clear_bit(NMI_DOM0_PARITY_ERR, &nmi_dom0_softirq_reason) )
send_guest_virq(dom0->vcpu[0], VIRQ_PARITY_ERR);

- if ( test_and_clear_bit(1, &nmi_softirq_reason) )
+ if ( test_and_clear_bit(NMI_DOM0_IO_ERR, &nmi_dom0_softirq_reason) )
send_guest_virq(dom0->vcpu[0], VIRQ_IO_ERR);
+
+ if ( test_and_clear_bit(NMI_DOM0_UNKNOWN, &nmi_dom0_softirq_reason) )
+ send_guest_virq(dom0->vcpu[0], VIRQ_NMI);
}

asmlinkage void mem_parity_error(struct cpu_user_regs *regs)
{
- /* Clear and disable the parity-error line. */
- outb((inb(0x61)&15)|4,0x61);
-
switch ( opt_nmi[0] )
{
case 'd': /* 'dom0' */
- set_bit(0, &nmi_softirq_reason);
- raise_softirq(NMI_SOFTIRQ);
+ set_bit(NMI_DOM0_PARITY_ERR, &nmi_dom0_softirq_reason);
+ raise_softirq(NMI_DOM0_SOFTIRQ);
case 'i': /* 'ignore' */
break;
default: /* 'fatal' */
@@ -1104,18 +1110,19 @@
printk("\n\nNMI - MEMORY ERROR\n");
fatal_trap(TRAP_nmi, regs);
}
+
+ outb((inb(0x61) & 0x0f) | 0x04, 0x61); /* clear-and-disable parity check */
+ mdelay(1);
+ outb((inb(0x61) & 0x0b) | 0x00, 0x61); /* enable parity check */
}

asmlinkage void io_check_error(struct cpu_user_regs *regs)
{
- /* Clear and disable the I/O-error line. */
- outb((inb(0x61)&15)|8,0x61);
-
switch ( opt_nmi[0] )
{
case 'd': /* 'dom0' */
- set_bit(0, &nmi_softirq_reason);
- raise_softirq(NMI_SOFTIRQ);
+ set_bit(NMI_DOM0_IO_ERR, &nmi_dom0_softirq_reason);
+ raise_softirq(NMI_DOM0_SOFTIRQ);
case 'i': /* 'ignore' */
break;
default: /* 'fatal' */
@@ -1123,43 +1130,59 @@
printk("\n\nNMI - I/O ERROR\n");
fatal_trap(TRAP_nmi, regs);
}
+
+ outb((inb(0x61) & 0x0f) | 0x08, 0x61); /* clear-and-disable IOCK */
+ mdelay(1);
+ outb((inb(0x61) & 0x07) | 0x00, 0x61); /* enable IOCK */
}

static void unknown_nmi_error(unsigned char reason)
{
- printk("Uhhuh. NMI received for unknown reason %02x.\n", reason);
- printk("Dazed and confused, but trying to continue\n");
- printk("Do you have a strange power saving mode enabled?\n");
-}
-
-static void default_do_nmi(struct cpu_user_regs *regs, unsigned long reason)
-{
- if ( nmi_watchdog )
- nmi_watchdog_tick(regs);
-
- if ( reason & 0x80 )
- mem_parity_error(regs);
- else if ( reason & 0x40 )
- io_check_error(regs);
- else if ( !nmi_watchdog )
- unknown_nmi_error((unsigned char)(reason&0xff));
+ switch ( opt_nmi[0] )
+ {
+ case 'd': /* 'dom0' */
+ set_bit(NMI_DOM0_UNKNOWN, &nmi_dom0_softirq_reason);
+ raise_softirq(NMI_DOM0_SOFTIRQ);
+ case 'i': /* 'ignore' */
+ break;
+ default: /* 'fatal' */
+ printk("Uhhuh. NMI received for unknown reason %02x.\n", reason);
+ printk("Dazed and confused, but trying to continue\n");
+ printk("Do you have a strange power saving mode enabled?\n");
+ }
}

static int dummy_nmi_callback(struct cpu_user_regs *regs, int cpu)
{
- return 0;
+ return 0;
}

static nmi_callback_t nmi_callback = dummy_nmi_callback;

-asmlinkage void do_nmi(struct cpu_user_regs *regs, unsigned long reason)
+asmlinkage void do_nmi(struct cpu_user_regs *regs)
{
unsigned int cpu = smp_processor_id();
+ unsigned char reason;

++nmi_count(cpu);

- if ( !nmi_callback(regs, cpu) )
- default_do_nmi(regs, reason);
+ if ( nmi_callback(regs, cpu) )
+ return;
+
+ if ( nmi_watchdog )
+ nmi_watchdog_tick(regs);
+
+ /* Only the BSP gets external NMIs from the system. */
+ if ( cpu == 0 )
+ {
+ reason = inb(0x61);
+ if ( reason & 0x80 )
+ mem_parity_error(regs);
+ else if ( reason & 0x40 )
+ io_check_error(regs);
+ else if ( !nmi_watchdog )
+ unknown_nmi_error((unsigned char)(reason&0xff));
+ }
}

void set_nmi_callback(nmi_callback_t callback)
@@ -1169,7 +1192,7 @@

void unset_nmi_callback(void)
{
- nmi_callback = dummy_nmi_callback;
+ nmi_callback = dummy_nmi_callback;
}

asmlinkage int math_state_restore(struct cpu_user_regs *regs)
@@ -1318,7 +1341,7 @@

cpu_init();

- open_softirq(NMI_SOFTIRQ, nmi_softirq);
+ open_softirq(NMI_DOM0_SOFTIRQ, nmi_dom0_softirq);
}


diff -r b34f4169b12e -r 931acb64fbaf xen/arch/x86/vmx.c
--- a/xen/arch/x86/vmx.c Tue Dec 20 11:55:19 2005
+++ b/xen/arch/x86/vmx.c Tue Dec 20 16:55:20 2005
@@ -335,7 +335,7 @@

extern long evtchn_send(int lport);
extern long do_block(void);
-void do_nmi(struct cpu_user_regs *, unsigned long);
+void do_nmi(struct cpu_user_regs *);

static int check_vmx_controls(ctrls, msr)
{
@@ -1850,7 +1850,7 @@
break;
}
case TRAP_nmi:
- do_nmi(&regs, 0);
+ do_nmi(&regs);
break;
default:
vmx_reflect_exception(v);
diff -r b34f4169b12e -r 931acb64fbaf xen/arch/x86/x86_32/entry.S
--- a/xen/arch/x86/x86_32/entry.S Tue Dec 20 11:55:19 2005
+++ b/xen/arch/x86/x86_32/entry.S Tue Dec 20 16:55:20 2005
@@ -601,15 +601,7 @@
pushl %eax
SAVE_ALL_NOSEGREGS(a)

- # Check for hardware problems.
- inb $0x61,%al
- testb $0x80,%al
- jne nmi_parity_err
- testb $0x40,%al
- jne nmi_io_err
- movl %eax,%ebx
-
- # Okay, its almost a normal NMI tick. We can only process it if:
+ # We can only process the NMI if:
# A. We are the outermost Xen activation (in which case we have
# the selectors safely saved on our stack)
# B. DS and ES contain sane Xen values.
@@ -619,7 +611,7 @@
movl UREGS_eflags(%esp),%eax
movb UREGS_cs(%esp),%al
testl $(3|X86_EFLAGS_VM),%eax
- jnz do_watchdog_tick
+ jnz continue_nmi
movl %ds,%eax
cmpw $(__HYPERVISOR_DS),%ax
jne defer_nmi
@@ -627,15 +619,14 @@
cmpw $(__HYPERVISOR_DS),%ax
jne defer_nmi

-do_watchdog_tick:
+continue_nmi:
movl $(__HYPERVISOR_DS),%edx
movl %edx,%ds
movl %edx,%es
movl %esp,%edx
- pushl %ebx # reason
- pushl %edx # regs
+ pushl %edx
call do_nmi
- addl $8,%esp
+ addl $4,%esp
jmp ret_from_intr

defer_nmi:
@@ -648,55 +639,6 @@
movl $(APIC_DM_FIXED | APIC_DEST_SELF | APIC_DEST_LOGICAL | \
TRAP_deferred_nmi),%ss:APIC_ICR(%eax)
jmp restore_all_xen
-
-nmi_parity_err:
- # Clear and disable the parity-error line
- andb $0xf,%al
- orb $0x4,%al
- outb %al,$0x61
- cmpb $'i',%ss:opt_nmi # nmi=ignore
- je nmi_out
- bts $0,%ss:nmi_softirq_reason
- bts $NMI_SOFTIRQ,%ss:irq_stat
- cmpb $'d',%ss:opt_nmi # nmi=dom0
- je nmi_out
- movl $(__HYPERVISOR_DS),%edx # nmi=fatal
- movl %edx,%ds
- movl %edx,%es
- movl %esp,%edx
- push %edx
- call mem_parity_error
- addl $4,%esp
-nmi_out:movl %ss:UREGS_eflags(%esp),%eax
- movb %ss:UREGS_cs(%esp),%al
- testl $(3|X86_EFLAGS_VM),%eax
- jz restore_all_xen
- movl $(__HYPERVISOR_DS),%edx
- movl %edx,%ds
- movl %edx,%es
- GET_CURRENT(%ebx)
- jmp test_all_events
-
-nmi_io_err:
- # Clear and disable the I/O-error line
- andb $0xf,%al
- orb $0x8,%al
- outb %al,$0x61
- cmpb $'i',%ss:opt_nmi # nmi=ignore
- je nmi_out
- bts $1,%ss:nmi_softirq_reason
- bts $NMI_SOFTIRQ,%ss:irq_stat
- cmpb $'d',%ss:opt_nmi # nmi=dom0
- je nmi_out
- movl $(__HYPERVISOR_DS),%edx # nmi=fatal
- movl %edx,%ds
- movl %edx,%es
- movl %esp,%edx
- push %edx
- call io_check_error
- addl $4,%esp
- jmp nmi_out
-

ENTRY(setup_vm86_frame)
# Copies the entire stack frame forwards by 16 bytes.
diff -r b34f4169b12e -r 931acb64fbaf xen/arch/x86/x86_32/traps.c
--- a/xen/arch/x86/x86_32/traps.c Tue Dec 20 11:55:19 2005
+++ b/xen/arch/x86/x86_32/traps.c Tue Dec 20 16:55:20 2005
@@ -160,9 +160,9 @@
BUILD_SMP_INTERRUPT(deferred_nmi, TRAP_deferred_nmi)
asmlinkage void smp_deferred_nmi(struct cpu_user_regs regs)
{
- asmlinkage void do_nmi(struct cpu_user_regs *, unsigned long);
+ asmlinkage void do_nmi(struct cpu_user_regs *);
ack_APIC_irq();
- do_nmi(&regs, 0);
+ do_nmi(&regs);
}

void __init percpu_traps_init(void)
diff -r b34f4169b12e -r 931acb64fbaf xen/arch/x86/x86_64/entry.S
--- a/xen/arch/x86/x86_64/entry.S Tue Dec 20 11:55:19 2005
+++ b/xen/arch/x86/x86_64/entry.S Tue Dec 20 16:55:20 2005
@@ -567,9 +567,7 @@
ENTRY(nmi)
pushq $0
SAVE_ALL
- inb $0x61,%al
- movl %eax,%esi # reason
- movq %rsp,%rdi # regs
+ movq %rsp,%rdi
call do_nmi
jmp restore_all_xen

diff -r b34f4169b12e -r 931acb64fbaf xen/include/public/xen.h
--- a/xen/include/public/xen.h Tue Dec 20 11:55:19 2005
+++ b/xen/include/public/xen.h Tue Dec 20 16:55:20 2005
@@ -67,12 +67,13 @@
*/
#define VIRQ_TIMER 0 /* Timebase update, and/or requested timeout. */
#define VIRQ_DEBUG 1 /* Request guest to dump debug info. */
-#define VIRQ_CONSOLE 2 /* (DOM0) bytes received on emergency console. */
+#define VIRQ_CONSOLE 2 /* (DOM0) Bytes received on emergency console. */
#define VIRQ_DOM_EXC 3 /* (DOM0) Exceptional event for some domain. */
-#define VIRQ_PARITY_ERR 4 /* (DOM0) NMI parity error. */
-#define VIRQ_IO_ERR 5 /* (DOM0) NMI I/O error. */
+#define VIRQ_PARITY_ERR 4 /* (DOM0) NMI parity error (port 0x61, bit 7). */
+#define VIRQ_IO_ERR 5 /* (DOM0) NMI I/O error (port 0x61, bit 6). */
#define VIRQ_DEBUGGER 6 /* (DOM0) A domain has paused for debugging. */
-#define NR_VIRQS 7
+#define VIRQ_NMI 7 /* (DOM0) Unknown NMI (not from ISA port 0x61).*/
+#define NR_VIRQS 8

/*
* MMU-UPDATE REQUESTS
diff -r b34f4169b12e -r 931acb64fbaf xen/include/xen/softirq.h
--- a/xen/include/xen/softirq.h Tue Dec 20 11:55:19 2005
+++ b/xen/include/xen/softirq.h Tue Dec 20 16:55:20 2005
@@ -6,7 +6,7 @@
#define SCHEDULE_SOFTIRQ 1
#define NEW_TLBFLUSH_CLOCK_PERIOD_SOFTIRQ 2
#define KEYPRESS_SOFTIRQ 3
-#define NMI_SOFTIRQ 4
+#define NMI_DOM0_SOFTIRQ 4
#define PAGE_SCRUB_SOFTIRQ 5
#define DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ 6
#define NR_SOFTIRQS 7

_______________________________________________
Xen-changelog mailing list
Xen-changelog@lists.xensource.com
http://lists.xensource.com/xen-changelog