[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] x86_emulate: Clean up HVM emulated I/O handling.



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1206558057 0
# Node ID 2e84414ea14a384c3b3d4da0125d30dea9f62de5
# Parent  89121c8b3c0d0713131d0494f1f76155e4f480de
x86_emulate: Clean up HVM emulated I/O handling.
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
 xen/arch/x86/hvm/emulate.c      |  182 +++++++++++++++++++---------------------
 xen/arch/x86/hvm/io.c           |   93 +++-----------------
 xen/arch/x86/hvm/vmx/realmode.c |    4 
 xen/include/asm-x86/hvm/io.h    |    5 -
 xen/include/asm-x86/hvm/vcpu.h  |   12 +-
 5 files changed, 115 insertions(+), 181 deletions(-)

diff -r 89121c8b3c0d -r 2e84414ea14a xen/arch/x86/hvm/emulate.c
--- a/xen/arch/x86/hvm/emulate.c        Wed Mar 26 15:50:45 2008 +0000
+++ b/xen/arch/x86/hvm/emulate.c        Wed Mar 26 19:00:57 2008 +0000
@@ -18,6 +18,77 @@
 #include <asm/hvm/emulate.h>
 #include <asm/hvm/hvm.h>
 #include <asm/hvm/support.h>
+
+static int hvmemul_do_io(
+    int is_mmio, paddr_t addr, unsigned long count, int size,
+    paddr_t value, int dir, int df, int value_is_ptr, unsigned long *val)
+{
+    struct vcpu *curr = current;
+    vcpu_iodata_t *vio = get_ioreq(curr);
+    ioreq_t *p = &vio->vp_ioreq;
+
+    switch ( curr->arch.hvm_vcpu.io_state )
+    {
+    case HVMIO_none:
+        break;
+    case HVMIO_completed:
+        curr->arch.hvm_vcpu.io_state = HVMIO_none;
+        if ( val == NULL )
+            return X86EMUL_UNHANDLEABLE;
+        *val = curr->arch.hvm_vcpu.io_data;
+        return X86EMUL_OKAY;
+    default:
+        return X86EMUL_UNHANDLEABLE;
+    }
+
+    curr->arch.hvm_vcpu.io_state =
+        (val == NULL) ? HVMIO_dispatched : HVMIO_awaiting_completion;
+
+    if ( p->state != STATE_IOREQ_NONE )
+        gdprintk(XENLOG_WARNING, "WARNING: io already pending (%d)?\n",
+                 p->state);
+
+    p->dir = dir;
+    p->data_is_ptr = value_is_ptr;
+    p->type = is_mmio ? IOREQ_TYPE_COPY : IOREQ_TYPE_PIO;
+    p->size = size;
+    p->addr = addr;
+    p->count = count;
+    p->df = df;
+    p->data = value;
+    p->io_count++;
+
+    if ( is_mmio
+         ? (hvm_mmio_intercept(p) || hvm_buffered_io_intercept(p))
+         : hvm_portio_intercept(p) )
+    {
+        p->state = STATE_IORESP_READY;
+        hvm_io_assist();
+        if ( val != NULL )
+            *val = curr->arch.hvm_vcpu.io_data;
+        curr->arch.hvm_vcpu.io_state = HVMIO_none;
+        return X86EMUL_OKAY;
+    }
+
+    hvm_send_assist_req(curr);
+    return (val != NULL) ? X86EMUL_RETRY : X86EMUL_OKAY;
+}
+
+static int hvmemul_do_pio(
+    unsigned long port, unsigned long count, int size,
+    paddr_t value, int dir, int df, int value_is_ptr, unsigned long *val)
+{
+    return hvmemul_do_io(0, port, count, size, value,
+                         dir, df, value_is_ptr, val);
+}
+
+static int hvmemul_do_mmio(
+    paddr_t gpa, unsigned long count, int size,
+    paddr_t value, int dir, int df, int value_is_ptr, unsigned long *val)
+{
+    return hvmemul_do_io(1, gpa, count, size, value,
+                         dir, df, value_is_ptr, val);
+}
 
 /*
  * Convert addr from linear to physical form, valid over the range
@@ -161,7 +232,6 @@ static int __hvmemul_read(
 
     if ( rc == HVMCOPY_bad_gfn_to_mfn )
     {
-        struct vcpu *curr = current;
         unsigned long reps = 1;
         paddr_t gpa;
 
@@ -173,21 +243,7 @@ static int __hvmemul_read(
         if ( rc != X86EMUL_OKAY )
             return rc;
 
-        if ( curr->arch.hvm_vcpu.io_in_progress )
-            return X86EMUL_UNHANDLEABLE;
-
-        if ( !curr->arch.hvm_vcpu.io_completed )
-        {
-            curr->arch.hvm_vcpu.io_in_progress = 1;
-            send_mmio_req(IOREQ_TYPE_COPY, gpa, 1, bytes,
-                          0, IOREQ_READ, 0, 0);
-        }
-
-        if ( !curr->arch.hvm_vcpu.io_completed )
-            return X86EMUL_RETRY;
-
-        *val = curr->arch.hvm_vcpu.io_data;
-        curr->arch.hvm_vcpu.io_completed = 0;
+        return hvmemul_do_mmio(gpa, 1, bytes, 0, IOREQ_READ, 0, 0, val);
     }
 
     return X86EMUL_OKAY;
@@ -251,7 +307,6 @@ static int hvmemul_write(
 
     if ( rc == HVMCOPY_bad_gfn_to_mfn )
     {
-        struct vcpu *curr = current;
         unsigned long reps = 1;
         paddr_t gpa;
 
@@ -260,12 +315,7 @@ static int hvmemul_write(
         if ( rc != X86EMUL_OKAY )
             return rc;
 
-        if ( curr->arch.hvm_vcpu.io_in_progress )
-            return X86EMUL_UNHANDLEABLE;
-
-        curr->arch.hvm_vcpu.io_in_progress = 1;
-        send_mmio_req(IOREQ_TYPE_COPY, gpa, 1, bytes,
-                      val, IOREQ_WRITE, 0, 0);
+        return hvmemul_do_mmio(gpa, 1, bytes, val, IOREQ_WRITE, 0, 0, NULL);
     }
 
     return X86EMUL_OKAY;
@@ -293,7 +343,6 @@ static int hvmemul_rep_ins(
 {
     struct hvm_emulate_ctxt *hvmemul_ctxt =
         container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
-    struct vcpu *curr = current;
     unsigned long addr;
     paddr_t gpa;
     int rc;
@@ -309,14 +358,8 @@ static int hvmemul_rep_ins(
     if ( rc != X86EMUL_OKAY )
         return rc;
 
-    if ( curr->arch.hvm_vcpu.io_in_progress )
-        return X86EMUL_UNHANDLEABLE;
-
-    curr->arch.hvm_vcpu.io_in_progress = 1;
-    send_pio_req(src_port, *reps, bytes_per_rep, gpa, IOREQ_READ,
-                 !!(ctxt->regs->eflags & X86_EFLAGS_DF), 1);
-
-    return X86EMUL_OKAY;
+    return hvmemul_do_pio(src_port, *reps, bytes_per_rep, gpa, IOREQ_READ,
+                          !!(ctxt->regs->eflags & X86_EFLAGS_DF), 1, NULL);
 }
 
 static int hvmemul_rep_outs(
@@ -329,7 +372,6 @@ static int hvmemul_rep_outs(
 {
     struct hvm_emulate_ctxt *hvmemul_ctxt =
         container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
-    struct vcpu *curr = current;
     unsigned long addr;
     paddr_t gpa;
     int rc;
@@ -345,15 +387,8 @@ static int hvmemul_rep_outs(
     if ( rc != X86EMUL_OKAY )
         return rc;
 
-    if ( curr->arch.hvm_vcpu.io_in_progress )
-        return X86EMUL_UNHANDLEABLE;
-
-    curr->arch.hvm_vcpu.io_in_progress = 1;
-    send_pio_req(dst_port, *reps, bytes_per_rep,
-                 gpa, IOREQ_WRITE,
-                 !!(ctxt->regs->eflags & X86_EFLAGS_DF), 1);
-
-    return X86EMUL_OKAY;
+    return hvmemul_do_pio(dst_port, *reps, bytes_per_rep, gpa, IOREQ_WRITE,
+                          !!(ctxt->regs->eflags & X86_EFLAGS_DF), 1, NULL);
 }
 
 static int hvmemul_rep_movs(
@@ -367,7 +402,6 @@ static int hvmemul_rep_movs(
 {
     struct hvm_emulate_ctxt *hvmemul_ctxt =
         container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
-    struct vcpu *curr = current;
     unsigned long saddr, daddr;
     paddr_t sgpa, dgpa;
     p2m_type_t p2mt;
@@ -395,29 +429,18 @@ static int hvmemul_rep_movs(
     if ( rc != X86EMUL_OKAY )
         return rc;
 
-    if ( curr->arch.hvm_vcpu.io_in_progress )
-        return X86EMUL_UNHANDLEABLE;
-
     (void)gfn_to_mfn_current(sgpa >> PAGE_SHIFT, &p2mt);
     if ( !p2m_is_ram(p2mt) )
-    {
-        curr->arch.hvm_vcpu.io_in_progress = 1;
-        send_mmio_req(IOREQ_TYPE_COPY, sgpa, *reps, bytes_per_rep,
-                      dgpa, IOREQ_READ,
-                      !!(ctxt->regs->eflags & X86_EFLAGS_DF), 1);
-    }
-    else
-    {
-        (void)gfn_to_mfn_current(dgpa >> PAGE_SHIFT, &p2mt);
-        if ( p2m_is_ram(p2mt) )
-            return X86EMUL_UNHANDLEABLE;
-        curr->arch.hvm_vcpu.io_in_progress = 1;
-        send_mmio_req(IOREQ_TYPE_COPY, dgpa, *reps, bytes_per_rep,
-                      sgpa, IOREQ_WRITE,
-                      !!(ctxt->regs->eflags & X86_EFLAGS_DF), 1);
-    }
-
-    return X86EMUL_OKAY;
+        return hvmemul_do_mmio(
+            sgpa, *reps, bytes_per_rep, dgpa, IOREQ_READ,
+            !!(ctxt->regs->eflags & X86_EFLAGS_DF), 1, NULL);
+
+    (void)gfn_to_mfn_current(dgpa >> PAGE_SHIFT, &p2mt);
+    if ( p2m_is_ram(p2mt) )
+        return X86EMUL_UNHANDLEABLE;
+    return hvmemul_do_mmio(
+        dgpa, *reps, bytes_per_rep, sgpa, IOREQ_WRITE,
+        !!(ctxt->regs->eflags & X86_EFLAGS_DF), 1, NULL);
 }
 
 static int hvmemul_read_segment(
@@ -453,24 +476,7 @@ static int hvmemul_read_io(
     unsigned long *val,
     struct x86_emulate_ctxt *ctxt)
 {
-    struct vcpu *curr = current;
-
-    if ( curr->arch.hvm_vcpu.io_in_progress )
-        return X86EMUL_UNHANDLEABLE;
-
-    if ( !curr->arch.hvm_vcpu.io_completed )
-    {
-        curr->arch.hvm_vcpu.io_in_progress = 1;
-        send_pio_req(port, 1, bytes, 0, IOREQ_READ, 0, 0);
-    }
-
-    if ( !curr->arch.hvm_vcpu.io_completed )
-        return X86EMUL_RETRY;
-
-    *val = curr->arch.hvm_vcpu.io_data;
-    curr->arch.hvm_vcpu.io_completed = 0;
-
-    return X86EMUL_OKAY;
+    return hvmemul_do_pio(port, 1, bytes, 0, IOREQ_READ, 0, 0, val);
 }
 
 static int hvmemul_write_io(
@@ -479,21 +485,13 @@ static int hvmemul_write_io(
     unsigned long val,
     struct x86_emulate_ctxt *ctxt)
 {
-    struct vcpu *curr = current;
-
     if ( port == 0xe9 )
     {
-        hvm_print_line(curr, val);
+        hvm_print_line(current, val);
         return X86EMUL_OKAY;
     }
 
-    if ( curr->arch.hvm_vcpu.io_in_progress )
-        return X86EMUL_UNHANDLEABLE;
-
-    curr->arch.hvm_vcpu.io_in_progress = 1;
-    send_pio_req(port, 1, bytes, val, IOREQ_WRITE, 0, 0);
-
-    return X86EMUL_OKAY;
+    return hvmemul_do_pio(port, 1, bytes, val, IOREQ_WRITE, 0, 0, NULL);
 }
 
 static int hvmemul_read_cr(
diff -r 89121c8b3c0d -r 2e84414ea14a xen/arch/x86/hvm/io.c
--- a/xen/arch/x86/hvm/io.c     Wed Mar 26 15:50:45 2008 +0000
+++ b/xen/arch/x86/hvm/io.c     Wed Mar 26 19:00:57 2008 +0000
@@ -123,73 +123,6 @@ int hvm_buffered_io_send(ioreq_t *p)
     return 1;
 }
 
-void send_pio_req(unsigned long port, unsigned long count, int size,
-                  paddr_t value, int dir, int df, int value_is_ptr)
-{
-    struct vcpu *v = current;
-    vcpu_iodata_t *vio = get_ioreq(v);
-    ioreq_t *p = &vio->vp_ioreq;
-
-    if ( p->state != STATE_IOREQ_NONE )
-        gdprintk(XENLOG_WARNING,
-                 "WARNING: send pio with something already pending (%d)?\n",
-                 p->state);
-
-    p->dir = dir;
-    p->data_is_ptr = value_is_ptr;
-    p->type = IOREQ_TYPE_PIO;
-    p->size = size;
-    p->addr = port;
-    p->count = count;
-    p->df = df;
-    p->data = value;
-    p->io_count++;
-
-    if ( hvm_portio_intercept(p) )
-    {
-        p->state = STATE_IORESP_READY;
-        hvm_io_assist();
-    }
-    else
-    {
-        hvm_send_assist_req(v);
-    }
-}
-
-void send_mmio_req(unsigned char type, paddr_t gpa,
-                   unsigned long count, int size, paddr_t value,
-                   int dir, int df, int value_is_ptr)
-{
-    struct vcpu *v = current;
-    vcpu_iodata_t *vio = get_ioreq(v);
-    ioreq_t *p = &vio->vp_ioreq;
-
-    if ( p->state != STATE_IOREQ_NONE )
-        gdprintk(XENLOG_WARNING,
-                 "WARNING: send mmio with something already pending (%d)?\n",
-                 p->state);
-
-    p->dir = dir;
-    p->data_is_ptr = value_is_ptr;
-    p->type = type;
-    p->size = size;
-    p->addr = gpa;
-    p->count = count;
-    p->df = df;
-    p->data = value;
-    p->io_count++;
-
-    if ( hvm_mmio_intercept(p) || hvm_buffered_io_intercept(p) )
-    {
-        p->state = STATE_IORESP_READY;
-        hvm_io_assist();
-    }
-    else
-    {
-        hvm_send_assist_req(v);
-    }
-}
-
 void send_timeoffset_req(unsigned long timeoff)
 {
     ioreq_t p[1];
@@ -248,6 +181,9 @@ int handle_mmio(void)
     hvm_emulate_prepare(&ctxt, guest_cpu_user_regs());
 
     rc = hvm_emulate_one(&ctxt);
+
+    if ( curr->arch.hvm_vcpu.io_state == HVMIO_awaiting_completion )
+       curr->arch.hvm_vcpu.io_state = HVMIO_handle_mmio_awaiting_completion;
 
     switch ( rc )
     {
@@ -271,8 +207,6 @@ int handle_mmio(void)
 
     hvm_emulate_writeback(&ctxt);
 
-    curr->arch.hvm_vcpu.mmio_in_progress = curr->arch.hvm_vcpu.io_in_progress;
-
     return 1;
 }
 
@@ -280,6 +214,7 @@ void hvm_io_assist(void)
 {
     struct vcpu *v = current;
     ioreq_t *p = &get_ioreq(v)->vp_ioreq;
+    enum hvm_io_state io_state;
 
     if ( p->state != STATE_IORESP_READY )
     {
@@ -292,16 +227,16 @@ void hvm_io_assist(void)
 
     p->state = STATE_IOREQ_NONE;
 
-    if ( v->arch.hvm_vcpu.io_in_progress )
-    {
-        v->arch.hvm_vcpu.io_in_progress = 0;
-        if ( (p->dir == IOREQ_READ) && !p->data_is_ptr )
-        {
-            v->arch.hvm_vcpu.io_completed = 1;
-            v->arch.hvm_vcpu.io_data = p->data;
-            if ( v->arch.hvm_vcpu.mmio_in_progress )
-                (void)handle_mmio();
-        }
+    io_state = v->arch.hvm_vcpu.io_state;
+    v->arch.hvm_vcpu.io_state = HVMIO_none;
+
+    if ( (io_state == HVMIO_awaiting_completion) ||
+         (io_state == HVMIO_handle_mmio_awaiting_completion) )
+    {
+        v->arch.hvm_vcpu.io_state = HVMIO_completed;
+        v->arch.hvm_vcpu.io_data = p->data;
+        if ( io_state == HVMIO_handle_mmio_awaiting_completion )
+            (void)handle_mmio();
     }
 
  out:
diff -r 89121c8b3c0d -r 2e84414ea14a xen/arch/x86/hvm/vmx/realmode.c
--- a/xen/arch/x86/hvm/vmx/realmode.c   Wed Mar 26 15:50:45 2008 +0000
+++ b/xen/arch/x86/hvm/vmx/realmode.c   Wed Mar 26 19:00:57 2008 +0000
@@ -190,7 +190,7 @@ void vmx_realmode(struct cpu_user_regs *
 
     hvm_emulate_prepare(&hvmemul_ctxt, regs);
 
-    if ( curr->arch.hvm_vcpu.io_completed )
+    if ( curr->arch.hvm_vcpu.io_state == HVMIO_completed )
         realmode_emulate_one(&hvmemul_ctxt);
 
     /* Only deliver interrupts into emulated real mode. */
@@ -203,7 +203,7 @@ void vmx_realmode(struct cpu_user_regs *
 
     while ( curr->arch.hvm_vmx.vmxemul &&
             !softirq_pending(smp_processor_id()) &&
-            !curr->arch.hvm_vcpu.io_in_progress )
+            (curr->arch.hvm_vcpu.io_state == HVMIO_none) )
     {
         /*
          * Check for pending interrupts only every 16 instructions, because
diff -r 89121c8b3c0d -r 2e84414ea14a xen/include/asm-x86/hvm/io.h
--- a/xen/include/asm-x86/hvm/io.h      Wed Mar 26 15:50:45 2008 +0000
+++ b/xen/include/asm-x86/hvm/io.h      Wed Mar 26 19:00:57 2008 +0000
@@ -96,11 +96,6 @@ static inline int register_buffered_io_h
     return register_io_handler(d, addr, size, action, HVM_BUFFERED_IO);
 }
 
-void send_mmio_req(unsigned char type, paddr_t gpa,
-                   unsigned long count, int size, paddr_t value,
-                   int dir, int df, int value_is_ptr);
-void send_pio_req(unsigned long port, unsigned long count, int size,
-                  paddr_t value, int dir, int df, int value_is_ptr);
 void send_timeoffset_req(unsigned long timeoff);
 void send_invalidate_req(void);
 int handle_mmio(void);
diff -r 89121c8b3c0d -r 2e84414ea14a xen/include/asm-x86/hvm/vcpu.h
--- a/xen/include/asm-x86/hvm/vcpu.h    Wed Mar 26 15:50:45 2008 +0000
+++ b/xen/include/asm-x86/hvm/vcpu.h    Wed Mar 26 19:00:57 2008 +0000
@@ -28,6 +28,14 @@
 
 #define HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM          0
 #define HVM_VCPU_INIT_SIPI_SIPI_STATE_WAIT_SIPI     1
+
+enum hvm_io_state {
+    HVMIO_none = 0,
+    HVMIO_dispatched,
+    HVMIO_awaiting_completion,
+    HVMIO_handle_mmio_awaiting_completion,
+    HVMIO_completed
+};
 
 struct hvm_vcpu {
     /* Guest control-register and EFER values, just as the guest sees them. */
@@ -70,9 +78,7 @@ struct hvm_vcpu {
     u8                  cache_mode;
 
     /* I/O request in flight to device model. */
-    bool_t              mmio_in_progress;
-    bool_t              io_in_progress;
-    bool_t              io_completed;
+    enum hvm_io_state   io_state;
     unsigned long       io_data;
 };
 

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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.