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>
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(&regs, 0);
    2.17 +            do_nmi(&regs);
    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(&regs, 0);
    4.11 +    do_nmi(&regs);
    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