ia64/xen-unstable

changeset 8559:c6f7774cae63

Pass NMIs to DOM0 via a dedicated callback, core Xen support.

This patch adds core and generic x86 support code to enable Xen to
pass NMI's to a dedicated NMI callback in DOM0 instead of raising a
VIRQ.

Introduces the nmi_op hypercall to allow DOM0 to (un)register the NMI
handler.

Signed-off-by: Ian Campbell <Ian.Campbell@XenSource.com>
author Ian.Campbell@xensource.com
date Wed Jan 11 15:51:56 2006 +0000 (2006-01-11)
parents 8bcfcfc13e21
children fe4d06b15a36
files xen/arch/x86/traps.c xen/common/kernel.c xen/include/asm-x86/nmi.h xen/include/public/arch-x86_32.h xen/include/public/arch-x86_64.h xen/include/public/nmi.h xen/include/public/xen.h xen/include/xen/sched.h xen/include/xen/softirq.h
line diff
     1.1 --- a/xen/arch/x86/traps.c	Wed Jan 11 15:51:18 2006 +0000
     1.2 +++ b/xen/arch/x86/traps.c	Wed Jan 11 15:51:56 2006 +0000
     1.3 @@ -1080,26 +1080,23 @@ asmlinkage int do_general_protection(str
     1.4      return 0;
     1.5  }
     1.6  
     1.7 +static void nmi_softirq(void)
     1.8 +{
     1.9 +    /* Only used to defer wakeup of dom0,vcpu0 to a safe (non-NMI) context. */
    1.10 +    evtchn_notify(dom0->vcpu[0]);
    1.11 +}
    1.12  
    1.13 -/* Defer dom0 notification to softirq context (unsafe in NMI context). */
    1.14 -static unsigned long nmi_dom0_softirq_reason;
    1.15 -#define NMI_DOM0_PARITY_ERR 0
    1.16 -#define NMI_DOM0_IO_ERR     1
    1.17 -#define NMI_DOM0_UNKNOWN    2
    1.18 +static void nmi_dom0_report(unsigned int reason_idx)
    1.19 +{
    1.20 +    struct domain *d;
    1.21  
    1.22 -static void nmi_dom0_softirq(void)
    1.23 -{
    1.24 -    if ( dom0 == NULL )
    1.25 +    if ( (d = dom0) == NULL )
    1.26          return;
    1.27  
    1.28 -    if ( test_and_clear_bit(NMI_DOM0_PARITY_ERR, &nmi_dom0_softirq_reason) )
    1.29 -        send_guest_virq(dom0->vcpu[0], VIRQ_PARITY_ERR);
    1.30 +    set_bit(reason_idx, &d->shared_info->arch.nmi_reason);
    1.31  
    1.32 -    if ( test_and_clear_bit(NMI_DOM0_IO_ERR, &nmi_dom0_softirq_reason) )
    1.33 -        send_guest_virq(dom0->vcpu[0], VIRQ_IO_ERR);
    1.34 -
    1.35 -    if ( test_and_clear_bit(NMI_DOM0_UNKNOWN, &nmi_dom0_softirq_reason) )
    1.36 -        send_guest_virq(dom0->vcpu[0], VIRQ_NMI);
    1.37 +    if ( test_and_set_bit(_VCPUF_nmi_pending, &d->vcpu[0]->vcpu_flags) )
    1.38 +        raise_softirq(NMI_SOFTIRQ); /* not safe to wake up a vcpu here */
    1.39  }
    1.40  
    1.41  asmlinkage void mem_parity_error(struct cpu_user_regs *regs)
    1.42 @@ -1107,8 +1104,7 @@ asmlinkage void mem_parity_error(struct 
    1.43      switch ( opt_nmi[0] )
    1.44      {
    1.45      case 'd': /* 'dom0' */
    1.46 -        set_bit(NMI_DOM0_PARITY_ERR, &nmi_dom0_softirq_reason);
    1.47 -        raise_softirq(NMI_DOM0_SOFTIRQ);
    1.48 +        nmi_dom0_report(_XEN_NMIREASON_parity_error);
    1.49      case 'i': /* 'ignore' */
    1.50          break;
    1.51      default:  /* 'fatal' */
    1.52 @@ -1127,8 +1123,7 @@ asmlinkage void io_check_error(struct cp
    1.53      switch ( opt_nmi[0] )
    1.54      {
    1.55      case 'd': /* 'dom0' */
    1.56 -        set_bit(NMI_DOM0_IO_ERR, &nmi_dom0_softirq_reason);
    1.57 -        raise_softirq(NMI_DOM0_SOFTIRQ);
    1.58 +        nmi_dom0_report(_XEN_NMIREASON_io_error);
    1.59      case 'i': /* 'ignore' */
    1.60          break;
    1.61      default:  /* 'fatal' */
    1.62 @@ -1147,8 +1142,7 @@ static void unknown_nmi_error(unsigned c
    1.63      switch ( opt_nmi[0] )
    1.64      {
    1.65      case 'd': /* 'dom0' */
    1.66 -        set_bit(NMI_DOM0_UNKNOWN, &nmi_dom0_softirq_reason);
    1.67 -        raise_softirq(NMI_DOM0_SOFTIRQ);
    1.68 +        nmi_dom0_report(_XEN_NMIREASON_unknown);
    1.69      case 'i': /* 'ignore' */
    1.70          break;
    1.71      default:  /* 'fatal' */
    1.72 @@ -1347,7 +1341,7 @@ void __init trap_init(void)
    1.73  
    1.74      cpu_init();
    1.75  
    1.76 -    open_softirq(NMI_DOM0_SOFTIRQ, nmi_dom0_softirq);
    1.77 +    open_softirq(NMI_SOFTIRQ, nmi_softirq);
    1.78  }
    1.79  
    1.80  
     2.1 --- a/xen/common/kernel.c	Wed Jan 11 15:51:18 2006 +0000
     2.2 +++ b/xen/common/kernel.c	Wed Jan 11 15:51:56 2006 +0000
     2.3 @@ -11,6 +11,7 @@
     2.4  #include <xen/compile.h>
     2.5  #include <xen/sched.h>
     2.6  #include <asm/current.h>
     2.7 +#include <public/nmi.h>
     2.8  #include <public/version.h>
     2.9  
    2.10  void cmdline_parse(char *cmdline)
    2.11 @@ -148,6 +149,30 @@ long do_xen_version(int cmd, void *arg)
    2.12      return -ENOSYS;
    2.13  }
    2.14  
    2.15 +long do_nmi_op(unsigned int cmd, void *arg)
    2.16 +{
    2.17 +    long rc = 0;
    2.18 +
    2.19 +    switch ( cmd )
    2.20 +    {
    2.21 +    case XENNMI_register_callback:
    2.22 +        if ( (current->domain->domain_id != 0) || (current->vcpu_id != 0) )
    2.23 +            rc = -EINVAL;
    2.24 +        else
    2.25 +            current->nmi_addr = (unsigned long)arg;
    2.26 +        printk("***** NMI handler at 0x%lx\n", current->nmi_addr);
    2.27 +        break;
    2.28 +    case XENNMI_unregister_callback:
    2.29 +        current->nmi_addr = 0;
    2.30 +        break;
    2.31 +    default:
    2.32 +        rc = -ENOSYS;
    2.33 +        break;
    2.34 +    }
    2.35 +
    2.36 +    return rc;
    2.37 +}
    2.38 +
    2.39  long do_vm_assist(unsigned int cmd, unsigned int type)
    2.40  {
    2.41      return vm_assist(current->domain, cmd, type);
     3.1 --- a/xen/include/asm-x86/nmi.h	Wed Jan 11 15:51:18 2006 +0000
     3.2 +++ b/xen/include/asm-x86/nmi.h	Wed Jan 11 15:51:56 2006 +0000
     3.3 @@ -2,6 +2,8 @@
     3.4  #ifndef ASM_NMI_H
     3.5  #define ASM_NMI_H
     3.6  
     3.7 +#include <public/nmi.h>
     3.8 +
     3.9  struct cpu_user_regs;
    3.10   
    3.11  typedef int (*nmi_callback_t)(struct cpu_user_regs *regs, int cpu);
     4.1 --- a/xen/include/public/arch-x86_32.h	Wed Jan 11 15:51:18 2006 +0000
     4.2 +++ b/xen/include/public/arch-x86_32.h	Wed Jan 11 15:51:56 2006 +0000
     4.3 @@ -135,6 +135,7 @@ typedef struct arch_shared_info {
     4.4      unsigned long max_pfn;                  /* max pfn that appears in table */
     4.5      /* Frame containing list of mfns containing list of mfns containing p2m. */
     4.6      unsigned long pfn_to_mfn_frame_list_list; 
     4.7 +    unsigned long nmi_reason;
     4.8  } arch_shared_info_t;
     4.9  
    4.10  typedef struct {
     5.1 --- a/xen/include/public/arch-x86_64.h	Wed Jan 11 15:51:18 2006 +0000
     5.2 +++ b/xen/include/public/arch-x86_64.h	Wed Jan 11 15:51:56 2006 +0000
     5.3 @@ -202,6 +202,7 @@ typedef struct arch_shared_info {
     5.4      unsigned long max_pfn;                  /* max pfn that appears in table */
     5.5      /* Frame containing list of mfns containing list of mfns containing p2m. */
     5.6      unsigned long pfn_to_mfn_frame_list_list; 
     5.7 +    unsigned long nmi_reason;
     5.8  } arch_shared_info_t;
     5.9  
    5.10  typedef struct {
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/xen/include/public/nmi.h	Wed Jan 11 15:51:56 2006 +0000
     6.3 @@ -0,0 +1,54 @@
     6.4 +/******************************************************************************
     6.5 + * nmi.h
     6.6 + * 
     6.7 + * NMI callback registration and reason codes.
     6.8 + * 
     6.9 + * Copyright (c) 2005, Keir Fraser <keir@xensource.com>
    6.10 + */
    6.11 +
    6.12 +#ifndef __XEN_PUBLIC_NMI_H__
    6.13 +#define __XEN_PUBLIC_NMI_H__
    6.14 +
    6.15 +/*
    6.16 + * NMI reason codes:
    6.17 + * Currently these are x86-specific, stored in arch_shared_info.nmi_reason.
    6.18 + */
    6.19 + /* I/O-check error reported via ISA port 0x61, bit 6. */
    6.20 +#define _XEN_NMIREASON_io_error     0
    6.21 +#define XEN_NMIREASON_io_error      (1UL << _XEN_NMIREASON_io_error)
    6.22 + /* Parity error reported via ISA port 0x61, bit 7. */
    6.23 +#define _XEN_NMIREASON_parity_error 1
    6.24 +#define XEN_NMIREASON_parity_error  (1UL << _XEN_NMIREASON_parity_error)
    6.25 + /* Unknown hardware-generated NMI. */
    6.26 +#define _XEN_NMIREASON_unknown      2
    6.27 +#define XEN_NMIREASON_unknown       (1UL << _XEN_NMIREASON_unknown)
    6.28 +
    6.29 +/*
    6.30 + * long nmi_op(unsigned int cmd, void *arg)
    6.31 + * NB. All ops return zero on success, else a negative error code.
    6.32 + */
    6.33 +
    6.34 +/*
    6.35 + * Register NMI callback for this (calling) VCPU. Currently this only makes
    6.36 + * sense for domain 0, vcpu 0. All other callers will be returned EINVAL.
    6.37 + * arg == address of callback function.
    6.38 + */
    6.39 +#define XENNMI_register_callback   0
    6.40 +
    6.41 +/*
    6.42 + * Deregister NMI callback for this (calling) VCPU.
    6.43 + * arg == NULL.
    6.44 + */
    6.45 +#define XENNMI_unregister_callback 1
    6.46 +
    6.47 +#endif /* __XEN_PUBLIC_NMI_H__ */
    6.48 +
    6.49 +/*
    6.50 + * Local variables:
    6.51 + * mode: C
    6.52 + * c-set-style: "BSD"
    6.53 + * c-basic-offset: 4
    6.54 + * tab-width: 4
    6.55 + * indent-tabs-mode: nil
    6.56 + * End:
    6.57 + */
     7.1 --- a/xen/include/public/xen.h	Wed Jan 11 15:51:18 2006 +0000
     7.2 +++ b/xen/include/public/xen.h	Wed Jan 11 15:51:56 2006 +0000
     7.3 @@ -59,6 +59,7 @@
     7.4  #define __HYPERVISOR_set_segment_base     25 /* x86/64 only */
     7.5  #define __HYPERVISOR_mmuext_op            26
     7.6  #define __HYPERVISOR_acm_op               27
     7.7 +#define __HYPERVISOR_nmi_op               28
     7.8  
     7.9  /* 
    7.10   * VIRTUAL INTERRUPTS
    7.11 @@ -69,10 +70,7 @@
    7.12  #define VIRQ_DEBUG      1  /* Request guest to dump debug info.           */
    7.13  #define VIRQ_CONSOLE    2  /* (DOM0) Bytes received on emergency console. */
    7.14  #define VIRQ_DOM_EXC    3  /* (DOM0) Exceptional event for some domain.   */
    7.15 -#define VIRQ_PARITY_ERR 4  /* (DOM0) NMI parity error (port 0x61, bit 7). */
    7.16 -#define VIRQ_IO_ERR     5  /* (DOM0) NMI I/O error    (port 0x61, bit 6). */
    7.17  #define VIRQ_DEBUGGER   6  /* (DOM0) A domain has paused for debugging.   */
    7.18 -#define VIRQ_NMI        7  /* (DOM0) Unknown NMI (not from ISA port 0x61).*/
    7.19  #define NR_VIRQS        8
    7.20  
    7.21  /*
     8.1 --- a/xen/include/xen/sched.h	Wed Jan 11 15:51:18 2006 +0000
     8.2 +++ b/xen/include/xen/sched.h	Wed Jan 11 15:51:56 2006 +0000
     8.3 @@ -81,6 +81,8 @@ struct vcpu
     8.4      /* Bitmask of CPUs on which this VCPU may run. */
     8.5      cpumask_t        cpu_affinity;
     8.6  
     8.7 +    unsigned long    nmi_addr;      /* NMI callback address. */
     8.8 +
     8.9      /* Bitmask of CPUs which are holding onto this VCPU's state. */
    8.10      cpumask_t        vcpu_dirty_cpumask;
    8.11  
    8.12 @@ -361,6 +363,12 @@ extern struct domain *domain_list;
    8.13   /* VCPU is not-runnable */
    8.14  #define _VCPUF_down            5
    8.15  #define VCPUF_down             (1UL<<_VCPUF_down)
    8.16 + /* NMI callback pending for this VCPU? */
    8.17 +#define _VCPUF_nmi_pending     8
    8.18 +#define VCPUF_nmi_pending      (1UL<<_VCPUF_nmi_pending)
    8.19 + /* Avoid NMI reentry by allowing NMIs to be masked for short periods. */
    8.20 +#define _VCPUF_nmi_masked      9
    8.21 +#define VCPUF_nmi_masked       (1UL<<_VCPUF_nmi_masked)
    8.22  
    8.23  /*
    8.24   * Per-domain flags (domain_flags).
     9.1 --- a/xen/include/xen/softirq.h	Wed Jan 11 15:51:18 2006 +0000
     9.2 +++ b/xen/include/xen/softirq.h	Wed Jan 11 15:51:56 2006 +0000
     9.3 @@ -6,7 +6,7 @@
     9.4  #define SCHEDULE_SOFTIRQ                  1
     9.5  #define NEW_TLBFLUSH_CLOCK_PERIOD_SOFTIRQ 2
     9.6  #define KEYPRESS_SOFTIRQ                  3
     9.7 -#define NMI_DOM0_SOFTIRQ                  4
     9.8 +#define NMI_SOFTIRQ                       4
     9.9  #define PAGE_SCRUB_SOFTIRQ                5
    9.10  #define DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ  6
    9.11  #define NR_SOFTIRQS                       7