ia64/xen-unstable
changeset 8418:931acb64fbaf
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>
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>
author | kaf24@firebug.cl.cam.ac.uk |
---|---|
date | Tue Dec 20 17:55:20 2005 +0100 (2005-12-20) |
parents | b34f4169b12e |
children | d3b10a2a82d4 |
files | xen/arch/x86/traps.c xen/arch/x86/vmx.c xen/arch/x86/x86_32/entry.S xen/arch/x86/x86_32/traps.c xen/arch/x86/x86_64/entry.S xen/include/public/xen.h xen/include/xen/softirq.h |
line diff
1.1 --- a/xen/arch/x86/traps.c Tue Dec 20 12:55:19 2005 +0100 1.2 +++ b/xen/arch/x86/traps.c Tue Dec 20 17:55:20 2005 +0100 1.3 @@ -1074,29 +1074,35 @@ asmlinkage int do_general_protection(str 1.4 return 0; 1.5 } 1.6 1.7 -unsigned long nmi_softirq_reason; 1.8 -static void nmi_softirq(void) 1.9 + 1.10 +/* Defer dom0 notification to softirq context (unsafe in NMI context). */ 1.11 +static unsigned long nmi_dom0_softirq_reason; 1.12 +#define NMI_DOM0_PARITY_ERR 0 1.13 +#define NMI_DOM0_IO_ERR 1 1.14 +#define NMI_DOM0_UNKNOWN 2 1.15 + 1.16 +static void nmi_dom0_softirq(void) 1.17 { 1.18 if ( dom0 == NULL ) 1.19 return; 1.20 1.21 - if ( test_and_clear_bit(0, &nmi_softirq_reason) ) 1.22 + if ( test_and_clear_bit(NMI_DOM0_PARITY_ERR, &nmi_dom0_softirq_reason) ) 1.23 send_guest_virq(dom0->vcpu[0], VIRQ_PARITY_ERR); 1.24 1.25 - if ( test_and_clear_bit(1, &nmi_softirq_reason) ) 1.26 + if ( test_and_clear_bit(NMI_DOM0_IO_ERR, &nmi_dom0_softirq_reason) ) 1.27 send_guest_virq(dom0->vcpu[0], VIRQ_IO_ERR); 1.28 + 1.29 + if ( test_and_clear_bit(NMI_DOM0_UNKNOWN, &nmi_dom0_softirq_reason) ) 1.30 + send_guest_virq(dom0->vcpu[0], VIRQ_NMI); 1.31 } 1.32 1.33 asmlinkage void mem_parity_error(struct cpu_user_regs *regs) 1.34 { 1.35 - /* Clear and disable the parity-error line. */ 1.36 - outb((inb(0x61)&15)|4,0x61); 1.37 - 1.38 switch ( opt_nmi[0] ) 1.39 { 1.40 case 'd': /* 'dom0' */ 1.41 - set_bit(0, &nmi_softirq_reason); 1.42 - raise_softirq(NMI_SOFTIRQ); 1.43 + set_bit(NMI_DOM0_PARITY_ERR, &nmi_dom0_softirq_reason); 1.44 + raise_softirq(NMI_DOM0_SOFTIRQ); 1.45 case 'i': /* 'ignore' */ 1.46 break; 1.47 default: /* 'fatal' */ 1.48 @@ -1104,18 +1110,19 @@ asmlinkage void mem_parity_error(struct 1.49 printk("\n\nNMI - MEMORY ERROR\n"); 1.50 fatal_trap(TRAP_nmi, regs); 1.51 } 1.52 + 1.53 + outb((inb(0x61) & 0x0f) | 0x04, 0x61); /* clear-and-disable parity check */ 1.54 + mdelay(1); 1.55 + outb((inb(0x61) & 0x0b) | 0x00, 0x61); /* enable parity check */ 1.56 } 1.57 1.58 asmlinkage void io_check_error(struct cpu_user_regs *regs) 1.59 { 1.60 - /* Clear and disable the I/O-error line. */ 1.61 - outb((inb(0x61)&15)|8,0x61); 1.62 - 1.63 switch ( opt_nmi[0] ) 1.64 { 1.65 case 'd': /* 'dom0' */ 1.66 - set_bit(0, &nmi_softirq_reason); 1.67 - raise_softirq(NMI_SOFTIRQ); 1.68 + set_bit(NMI_DOM0_IO_ERR, &nmi_dom0_softirq_reason); 1.69 + raise_softirq(NMI_DOM0_SOFTIRQ); 1.70 case 'i': /* 'ignore' */ 1.71 break; 1.72 default: /* 'fatal' */ 1.73 @@ -1123,43 +1130,59 @@ asmlinkage void io_check_error(struct cp 1.74 printk("\n\nNMI - I/O ERROR\n"); 1.75 fatal_trap(TRAP_nmi, regs); 1.76 } 1.77 + 1.78 + outb((inb(0x61) & 0x0f) | 0x08, 0x61); /* clear-and-disable IOCK */ 1.79 + mdelay(1); 1.80 + outb((inb(0x61) & 0x07) | 0x00, 0x61); /* enable IOCK */ 1.81 } 1.82 1.83 static void unknown_nmi_error(unsigned char reason) 1.84 { 1.85 - printk("Uhhuh. NMI received for unknown reason %02x.\n", reason); 1.86 - printk("Dazed and confused, but trying to continue\n"); 1.87 - printk("Do you have a strange power saving mode enabled?\n"); 1.88 -} 1.89 - 1.90 -static void default_do_nmi(struct cpu_user_regs *regs, unsigned long reason) 1.91 -{ 1.92 - if ( nmi_watchdog ) 1.93 - nmi_watchdog_tick(regs); 1.94 - 1.95 - if ( reason & 0x80 ) 1.96 - mem_parity_error(regs); 1.97 - else if ( reason & 0x40 ) 1.98 - io_check_error(regs); 1.99 - else if ( !nmi_watchdog ) 1.100 - unknown_nmi_error((unsigned char)(reason&0xff)); 1.101 + switch ( opt_nmi[0] ) 1.102 + { 1.103 + case 'd': /* 'dom0' */ 1.104 + set_bit(NMI_DOM0_UNKNOWN, &nmi_dom0_softirq_reason); 1.105 + raise_softirq(NMI_DOM0_SOFTIRQ); 1.106 + case 'i': /* 'ignore' */ 1.107 + break; 1.108 + default: /* 'fatal' */ 1.109 + printk("Uhhuh. NMI received for unknown reason %02x.\n", reason); 1.110 + printk("Dazed and confused, but trying to continue\n"); 1.111 + printk("Do you have a strange power saving mode enabled?\n"); 1.112 + } 1.113 } 1.114 1.115 static int dummy_nmi_callback(struct cpu_user_regs *regs, int cpu) 1.116 { 1.117 - return 0; 1.118 + return 0; 1.119 } 1.120 1.121 static nmi_callback_t nmi_callback = dummy_nmi_callback; 1.122 1.123 -asmlinkage void do_nmi(struct cpu_user_regs *regs, unsigned long reason) 1.124 +asmlinkage void do_nmi(struct cpu_user_regs *regs) 1.125 { 1.126 unsigned int cpu = smp_processor_id(); 1.127 + unsigned char reason; 1.128 1.129 ++nmi_count(cpu); 1.130 1.131 - if ( !nmi_callback(regs, cpu) ) 1.132 - default_do_nmi(regs, reason); 1.133 + if ( nmi_callback(regs, cpu) ) 1.134 + return; 1.135 + 1.136 + if ( nmi_watchdog ) 1.137 + nmi_watchdog_tick(regs); 1.138 + 1.139 + /* Only the BSP gets external NMIs from the system. */ 1.140 + if ( cpu == 0 ) 1.141 + { 1.142 + reason = inb(0x61); 1.143 + if ( reason & 0x80 ) 1.144 + mem_parity_error(regs); 1.145 + else if ( reason & 0x40 ) 1.146 + io_check_error(regs); 1.147 + else if ( !nmi_watchdog ) 1.148 + unknown_nmi_error((unsigned char)(reason&0xff)); 1.149 + } 1.150 } 1.151 1.152 void set_nmi_callback(nmi_callback_t callback) 1.153 @@ -1169,7 +1192,7 @@ void set_nmi_callback(nmi_callback_t cal 1.154 1.155 void unset_nmi_callback(void) 1.156 { 1.157 - nmi_callback = dummy_nmi_callback; 1.158 + nmi_callback = dummy_nmi_callback; 1.159 } 1.160 1.161 asmlinkage int math_state_restore(struct cpu_user_regs *regs) 1.162 @@ -1318,7 +1341,7 @@ void __init trap_init(void) 1.163 1.164 cpu_init(); 1.165 1.166 - open_softirq(NMI_SOFTIRQ, nmi_softirq); 1.167 + open_softirq(NMI_DOM0_SOFTIRQ, nmi_dom0_softirq); 1.168 } 1.169 1.170
2.1 --- a/xen/arch/x86/vmx.c Tue Dec 20 12:55:19 2005 +0100 2.2 +++ b/xen/arch/x86/vmx.c Tue Dec 20 17:55:20 2005 +0100 2.3 @@ -335,7 +335,7 @@ static inline int long_mode_do_msr_writ 2.4 2.5 extern long evtchn_send(int lport); 2.6 extern long do_block(void); 2.7 -void do_nmi(struct cpu_user_regs *, unsigned long); 2.8 +void do_nmi(struct cpu_user_regs *); 2.9 2.10 static int check_vmx_controls(ctrls, msr) 2.11 { 2.12 @@ -1850,7 +1850,7 @@ asmlinkage void vmx_vmexit_handler(struc 2.13 break; 2.14 } 2.15 case TRAP_nmi: 2.16 - do_nmi(®s, 0); 2.17 + do_nmi(®s); 2.18 break; 2.19 default: 2.20 vmx_reflect_exception(v);
3.1 --- a/xen/arch/x86/x86_32/entry.S Tue Dec 20 12:55:19 2005 +0100 3.2 +++ b/xen/arch/x86/x86_32/entry.S Tue Dec 20 17:55:20 2005 +0100 3.3 @@ -601,15 +601,7 @@ ENTRY(nmi) 3.4 pushl %eax 3.5 SAVE_ALL_NOSEGREGS(a) 3.6 3.7 - # Check for hardware problems. 3.8 - inb $0x61,%al 3.9 - testb $0x80,%al 3.10 - jne nmi_parity_err 3.11 - testb $0x40,%al 3.12 - jne nmi_io_err 3.13 - movl %eax,%ebx 3.14 - 3.15 - # Okay, its almost a normal NMI tick. We can only process it if: 3.16 + # We can only process the NMI if: 3.17 # A. We are the outermost Xen activation (in which case we have 3.18 # the selectors safely saved on our stack) 3.19 # B. DS and ES contain sane Xen values. 3.20 @@ -619,7 +611,7 @@ ENTRY(nmi) 3.21 movl UREGS_eflags(%esp),%eax 3.22 movb UREGS_cs(%esp),%al 3.23 testl $(3|X86_EFLAGS_VM),%eax 3.24 - jnz do_watchdog_tick 3.25 + jnz continue_nmi 3.26 movl %ds,%eax 3.27 cmpw $(__HYPERVISOR_DS),%ax 3.28 jne defer_nmi 3.29 @@ -627,15 +619,14 @@ ENTRY(nmi) 3.30 cmpw $(__HYPERVISOR_DS),%ax 3.31 jne defer_nmi 3.32 3.33 -do_watchdog_tick: 3.34 +continue_nmi: 3.35 movl $(__HYPERVISOR_DS),%edx 3.36 movl %edx,%ds 3.37 movl %edx,%es 3.38 movl %esp,%edx 3.39 - pushl %ebx # reason 3.40 - pushl %edx # regs 3.41 + pushl %edx 3.42 call do_nmi 3.43 - addl $8,%esp 3.44 + addl $4,%esp 3.45 jmp ret_from_intr 3.46 3.47 defer_nmi: 3.48 @@ -649,55 +640,6 @@ 1: movl %ss:APIC_ICR(%eax),%ebx 3.49 TRAP_deferred_nmi),%ss:APIC_ICR(%eax) 3.50 jmp restore_all_xen 3.51 3.52 -nmi_parity_err: 3.53 - # Clear and disable the parity-error line 3.54 - andb $0xf,%al 3.55 - orb $0x4,%al 3.56 - outb %al,$0x61 3.57 - cmpb $'i',%ss:opt_nmi # nmi=ignore 3.58 - je nmi_out 3.59 - bts $0,%ss:nmi_softirq_reason 3.60 - bts $NMI_SOFTIRQ,%ss:irq_stat 3.61 - cmpb $'d',%ss:opt_nmi # nmi=dom0 3.62 - je nmi_out 3.63 - movl $(__HYPERVISOR_DS),%edx # nmi=fatal 3.64 - movl %edx,%ds 3.65 - movl %edx,%es 3.66 - movl %esp,%edx 3.67 - push %edx 3.68 - call mem_parity_error 3.69 - addl $4,%esp 3.70 -nmi_out:movl %ss:UREGS_eflags(%esp),%eax 3.71 - movb %ss:UREGS_cs(%esp),%al 3.72 - testl $(3|X86_EFLAGS_VM),%eax 3.73 - jz restore_all_xen 3.74 - movl $(__HYPERVISOR_DS),%edx 3.75 - movl %edx,%ds 3.76 - movl %edx,%es 3.77 - GET_CURRENT(%ebx) 3.78 - jmp test_all_events 3.79 - 3.80 -nmi_io_err: 3.81 - # Clear and disable the I/O-error line 3.82 - andb $0xf,%al 3.83 - orb $0x8,%al 3.84 - outb %al,$0x61 3.85 - cmpb $'i',%ss:opt_nmi # nmi=ignore 3.86 - je nmi_out 3.87 - bts $1,%ss:nmi_softirq_reason 3.88 - bts $NMI_SOFTIRQ,%ss:irq_stat 3.89 - cmpb $'d',%ss:opt_nmi # nmi=dom0 3.90 - je nmi_out 3.91 - movl $(__HYPERVISOR_DS),%edx # nmi=fatal 3.92 - movl %edx,%ds 3.93 - movl %edx,%es 3.94 - movl %esp,%edx 3.95 - push %edx 3.96 - call io_check_error 3.97 - addl $4,%esp 3.98 - jmp nmi_out 3.99 - 3.100 - 3.101 ENTRY(setup_vm86_frame) 3.102 # Copies the entire stack frame forwards by 16 bytes. 3.103 .macro copy_vm86_words count=18
4.1 --- a/xen/arch/x86/x86_32/traps.c Tue Dec 20 12:55:19 2005 +0100 4.2 +++ b/xen/arch/x86/x86_32/traps.c Tue Dec 20 17:55:20 2005 +0100 4.3 @@ -160,9 +160,9 @@ asmlinkage void do_double_fault(void) 4.4 BUILD_SMP_INTERRUPT(deferred_nmi, TRAP_deferred_nmi) 4.5 asmlinkage void smp_deferred_nmi(struct cpu_user_regs regs) 4.6 { 4.7 - asmlinkage void do_nmi(struct cpu_user_regs *, unsigned long); 4.8 + asmlinkage void do_nmi(struct cpu_user_regs *); 4.9 ack_APIC_irq(); 4.10 - do_nmi(®s, 0); 4.11 + do_nmi(®s); 4.12 } 4.13 4.14 void __init percpu_traps_init(void)
5.1 --- a/xen/arch/x86/x86_64/entry.S Tue Dec 20 12:55:19 2005 +0100 5.2 +++ b/xen/arch/x86/x86_64/entry.S Tue Dec 20 17:55:20 2005 +0100 5.3 @@ -567,9 +567,7 @@ ENTRY(double_fault) 5.4 ENTRY(nmi) 5.5 pushq $0 5.6 SAVE_ALL 5.7 - inb $0x61,%al 5.8 - movl %eax,%esi # reason 5.9 - movq %rsp,%rdi # regs 5.10 + movq %rsp,%rdi 5.11 call do_nmi 5.12 jmp restore_all_xen 5.13
6.1 --- a/xen/include/public/xen.h Tue Dec 20 12:55:19 2005 +0100 6.2 +++ b/xen/include/public/xen.h Tue Dec 20 17:55:20 2005 +0100 6.3 @@ -67,12 +67,13 @@ 6.4 */ 6.5 #define VIRQ_TIMER 0 /* Timebase update, and/or requested timeout. */ 6.6 #define VIRQ_DEBUG 1 /* Request guest to dump debug info. */ 6.7 -#define VIRQ_CONSOLE 2 /* (DOM0) bytes received on emergency console. */ 6.8 +#define VIRQ_CONSOLE 2 /* (DOM0) Bytes received on emergency console. */ 6.9 #define VIRQ_DOM_EXC 3 /* (DOM0) Exceptional event for some domain. */ 6.10 -#define VIRQ_PARITY_ERR 4 /* (DOM0) NMI parity error. */ 6.11 -#define VIRQ_IO_ERR 5 /* (DOM0) NMI I/O error. */ 6.12 +#define VIRQ_PARITY_ERR 4 /* (DOM0) NMI parity error (port 0x61, bit 7). */ 6.13 +#define VIRQ_IO_ERR 5 /* (DOM0) NMI I/O error (port 0x61, bit 6). */ 6.14 #define VIRQ_DEBUGGER 6 /* (DOM0) A domain has paused for debugging. */ 6.15 -#define NR_VIRQS 7 6.16 +#define VIRQ_NMI 7 /* (DOM0) Unknown NMI (not from ISA port 0x61).*/ 6.17 +#define NR_VIRQS 8 6.18 6.19 /* 6.20 * MMU-UPDATE REQUESTS
7.1 --- a/xen/include/xen/softirq.h Tue Dec 20 12:55:19 2005 +0100 7.2 +++ b/xen/include/xen/softirq.h Tue Dec 20 17:55:20 2005 +0100 7.3 @@ -6,7 +6,7 @@ 7.4 #define SCHEDULE_SOFTIRQ 1 7.5 #define NEW_TLBFLUSH_CLOCK_PERIOD_SOFTIRQ 2 7.6 #define KEYPRESS_SOFTIRQ 3 7.7 -#define NMI_SOFTIRQ 4 7.8 +#define NMI_DOM0_SOFTIRQ 4 7.9 #define PAGE_SCRUB_SOFTIRQ 5 7.10 #define DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ 6 7.11 #define NR_SOFTIRQS 7