ia64/xen-unstable

changeset 5185:af908567e181

bitkeeper revision 1.1576 (42983193Zhd1D5IEn8s4gplr_BeXnQ)

[PATCH] vmx-io.patch

Fix some of the race conditions that show up when the device models are
running on one CPU and the VMX domain is running on another on a SMP
system.

Signed-off-by: Arun Sharma <arun.sharma@intel.com>
author arun.sharma@intel.com[kaf24]
date Sat May 28 08:53:39 2005 +0000 (2005-05-28)
parents ed6682910675
children a825a76d6b0f
files xen/arch/x86/vmx.c xen/arch/x86/vmx_io.c xen/arch/x86/vmx_platform.c xen/include/asm-x86/vmx_platform.h
line diff
     1.1 --- a/xen/arch/x86/vmx.c	Fri May 27 10:51:06 2005 +0000
     1.2 +++ b/xen/arch/x86/vmx.c	Sat May 28 08:53:39 2005 +0000
     1.3 @@ -465,7 +465,7 @@ static void vmx_io_instruction(struct cp
     1.4      set_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags);
     1.5      p->state = STATE_IOREQ_READY;
     1.6      evtchn_send(IOPACKET_PORT);
     1.7 -    do_block();
     1.8 +    vmx_wait_io();
     1.9  }
    1.10  
    1.11  enum { COPY_IN = 0, COPY_OUT };
    1.12 @@ -1266,7 +1266,6 @@ asmlinkage void vmx_vmexit_handler(struc
    1.13      case EXIT_REASON_PENDING_INTERRUPT:
    1.14          __vmwrite(CPU_BASED_VM_EXEC_CONTROL, 
    1.15                MONITOR_CPU_BASED_EXEC_CONTROLS);
    1.16 -        vmx_intr_assist(ed);
    1.17          break;
    1.18      case EXIT_REASON_TASK_SWITCH:
    1.19          __vmx_bug(&regs);
     2.1 --- a/xen/arch/x86/vmx_io.c	Fri May 27 10:51:06 2005 +0000
     2.2 +++ b/xen/arch/x86/vmx_io.c	Sat May 28 08:53:39 2005 +0000
     2.3 @@ -34,9 +34,6 @@
     2.4  #include <asm/vmx_virpit.h>
     2.5  
     2.6  #ifdef CONFIG_VMX
     2.7 -
     2.8 -extern long do_block();
     2.9 -  
    2.10  #if defined (__i386__)
    2.11  static void load_cpu_user_regs(struct cpu_user_regs *regs)
    2.12  { 
    2.13 @@ -186,7 +183,6 @@ void vmx_io_assist(struct exec_domain *e
    2.14  {
    2.15      vcpu_iodata_t *vio;
    2.16      ioreq_t *p;
    2.17 -    struct domain *d = ed->domain;
    2.18      struct cpu_user_regs *regs = guest_cpu_user_regs();
    2.19      unsigned long old_eax;
    2.20      int sign;
    2.21 @@ -196,12 +192,6 @@ void vmx_io_assist(struct exec_domain *e
    2.22      mpci_p = &ed->arch.arch_vmx.vmx_platform.mpci;
    2.23      inst_decoder_regs = mpci_p->inst_decoder_regs;
    2.24  
    2.25 -    /* clear the pending event */
    2.26 -    ed->vcpu_info->evtchn_upcall_pending = 0;
    2.27 -    /* clear the pending bit for port 2 */
    2.28 -    clear_bit(IOPACKET_PORT>>5, &ed->vcpu_info->evtchn_pending_sel);
    2.29 -    clear_bit(IOPACKET_PORT, &d->shared_info->evtchn_pending[0]);
    2.30 -
    2.31      vio = (vcpu_iodata_t *) ed->arch.arch_vmx.vmx_platform.shared_page_va;
    2.32      if (vio == 0) {
    2.33          VMX_DBG_LOG(DBG_LEVEL_1, 
    2.34 @@ -217,8 +207,8 @@ void vmx_io_assist(struct exec_domain *e
    2.35      /* clear IO wait VMX flag */
    2.36      if (test_bit(ARCH_VMX_IO_WAIT, &ed->arch.arch_vmx.flags)) {
    2.37          if (p->state != STATE_IORESP_READY) {
    2.38 -            printk("got a false I/O reponse\n");
    2.39 -            do_block();
    2.40 +                /* An interrupt send event raced us */
    2.41 +                return;
    2.42          } else {
    2.43              p->state = STATE_INVALID;
    2.44          }
    2.45 @@ -282,6 +272,51 @@ void vmx_io_assist(struct exec_domain *e
    2.46      }
    2.47  }
    2.48  
    2.49 +int vmx_clear_pending_io_event(struct exec_domain *ed) 
    2.50 +{
    2.51 +    struct domain *d = ed->domain;
    2.52 +
    2.53 +    /* evtchn_pending is shared by other event channels in 0-31 range */
    2.54 +    if (!d->shared_info->evtchn_pending[IOPACKET_PORT>>5])
    2.55 +        clear_bit(IOPACKET_PORT>>5, &ed->vcpu_info->evtchn_pending_sel);
    2.56 +
    2.57 +    /* Note: VMX domains may need upcalls as well */
    2.58 +    if (!ed->vcpu_info->evtchn_pending_sel) 
    2.59 +        ed->vcpu_info->evtchn_upcall_pending = 0;
    2.60 +
    2.61 +    /* clear the pending bit for IOPACKET_PORT */
    2.62 +    return test_and_clear_bit(IOPACKET_PORT, 
    2.63 +                              &d->shared_info->evtchn_pending[0]);
    2.64 +}
    2.65 +
    2.66 +/* Because we've cleared the pending events first, we need to guarantee that
    2.67 + * all events to be handled by xen for VMX domains are taken care of here.
    2.68 + *
    2.69 + * interrupts are guaranteed to be checked before resuming guest. 
    2.70 + * VMX upcalls have been already arranged for if necessary. 
    2.71 + */
    2.72 +void vmx_check_events(struct exec_domain *d) 
    2.73 +{
    2.74 +    /* clear the event *before* checking for work. This should avoid 
    2.75 +       the set-and-check races */
    2.76 +    if (vmx_clear_pending_io_event(current))
    2.77 +        vmx_io_assist(d);
    2.78 +}
    2.79 +
    2.80 +/* On exit from vmx_wait_io, we're guaranteed to have a I/O response from 
    2.81 +   the device model */
    2.82 +void vmx_wait_io()
    2.83 +{
    2.84 +    extern void do_block();
    2.85 +
    2.86 +    do {
    2.87 +        do_block();
    2.88 +        vmx_check_events(current);
    2.89 +        if (!test_bit(ARCH_VMX_IO_WAIT, &current->arch.arch_vmx.flags))
    2.90 +            break;
    2.91 +    } while(1);
    2.92 +}
    2.93 +
    2.94  #if defined(__i386__) || defined(__x86_64__)
    2.95  static inline int __fls(u32 word)
    2.96  {
    2.97 @@ -440,22 +475,17 @@ void vmx_do_resume(struct exec_domain *d
    2.98      __vmwrite(HOST_ESP, (unsigned long)get_stack_bottom());
    2.99  
   2.100      if (event_pending(d)) {
   2.101 -        if (test_bit(IOPACKET_PORT, &d->domain->shared_info->evtchn_pending[0])) 
   2.102 -            vmx_io_assist(d);
   2.103 +        vmx_check_events(d);
   2.104 +
   2.105 +        if (test_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags))
   2.106 +            vmx_wait_io();
   2.107 +    }
   2.108  
   2.109 -        else if (test_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags)) {
   2.110 -            printk("got an event while blocked on I/O\n");
   2.111 -            do_block();
   2.112 -        }
   2.113 -                
   2.114 -        /* Assumption: device model will not inject an interrupt
   2.115 -         * while an ioreq_t is pending i.e. the response and 
   2.116 -         * interrupt can come together. But an interrupt without 
   2.117 -         * a response to ioreq_t is not ok.
   2.118 -         */
   2.119 -    }
   2.120 -    if (!test_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags))
   2.121 -        vmx_intr_assist(d);
   2.122 +    /* We can't resume the guest if we're waiting on I/O */
   2.123 +    ASSERT(!test_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags));
   2.124 +
   2.125 +    /* We always check for interrupts before resuming guest */
   2.126 +    vmx_intr_assist(d);
   2.127  }
   2.128  
   2.129  #endif /* CONFIG_VMX */
     3.1 --- a/xen/arch/x86/vmx_platform.c	Fri May 27 10:51:06 2005 +0000
     3.2 +++ b/xen/arch/x86/vmx_platform.c	Sat May 28 08:53:39 2005 +0000
     3.3 @@ -470,7 +470,6 @@ static void send_mmio_req(unsigned long 
     3.4      struct mi_per_cpu_info *mpci_p;
     3.5      struct cpu_user_regs *inst_decoder_regs;
     3.6      extern long evtchn_send(int lport);
     3.7 -    extern long do_block(void);
     3.8  
     3.9      mpci_p = &current->arch.arch_vmx.vmx_platform.mpci;
    3.10      inst_decoder_regs = mpci_p->inst_decoder_regs;
    3.11 @@ -520,7 +519,7 @@ static void send_mmio_req(unsigned long 
    3.12  #endif
    3.13  
    3.14      evtchn_send(IOPACKET_PORT);
    3.15 -    do_block(); 
    3.16 +    vmx_wait_io();
    3.17  }
    3.18  
    3.19  void handle_mmio(unsigned long va, unsigned long gpa)
     4.1 --- a/xen/include/asm-x86/vmx_platform.h	Fri May 27 10:51:06 2005 +0000
     4.2 +++ b/xen/include/asm-x86/vmx_platform.h	Sat May 28 08:53:39 2005 +0000
     4.3 @@ -85,6 +85,7 @@ struct virutal_platform_def {
     4.4  };
     4.5  
     4.6  extern void handle_mmio(unsigned long, unsigned long);
     4.7 +extern void vmx_wait_io(void);
     4.8  extern int vmx_setup_platform(struct exec_domain *, struct cpu_user_regs *);
     4.9  
    4.10  // XXX - think about this -- maybe use bit 30 of the mfn to signify an MMIO frame.