vmx realmode: Plumb through I/O port accesses in emulated realmode.
authorKeir Fraser <keir.fraser@citrix.com>
Sun, 25 Nov 2007 11:43:53 +0000 (11:43 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Sun, 25 Nov 2007 11:43:53 +0000 (11:43 +0000)
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
xen/arch/x86/hvm/io.c
xen/arch/x86/hvm/vmx/realmode.c
xen/arch/x86/hvm/vmx/vmx.c
xen/arch/x86/x86_emulate.c
xen/include/asm-x86/hvm/vcpu.h
xen/include/asm-x86/hvm/vmx/vmcs.h
xen/include/asm-x86/hvm/vmx/vmx.h

index fe540170121ea05996176efdae8da00cd2889e16..f522d603780f155561755d6ab4173285fe90f860 100644 (file)
@@ -841,13 +841,17 @@ void hvm_io_assist(void)
     if ( p->state != STATE_IORESP_READY )
     {
         gdprintk(XENLOG_ERR, "Unexpected HVM iorequest state %d.\n", p->state);
-        domain_crash_synchronous();
+        domain_crash(v->domain);
+        goto out;
     }
 
     rmb(); /* see IORESP_READY /then/ read contents of ioreq */
 
     p->state = STATE_IOREQ_NONE;
 
+    if ( v->arch.hvm_vcpu.io_complete && v->arch.hvm_vcpu.io_complete() )
+        goto out;
+
     switch ( p->type )
     {
     case IOREQ_TYPE_INVALIDATE:
index 53ec8e64a265be746e6c94923cdb0d71894ca258..49dac88840cdb21e95d7416d7a1549863cb4add3 100644 (file)
@@ -178,7 +178,24 @@ realmode_read_io(
     unsigned long *val,
     struct x86_emulate_ctxt *ctxt)
 {
-    return X86EMUL_UNHANDLEABLE;
+    struct vcpu *curr = current;
+
+    if ( curr->arch.hvm_vmx.real_mode_io_in_progress )
+        return X86EMUL_UNHANDLEABLE;
+
+    if ( !curr->arch.hvm_vmx.real_mode_io_completed )
+    {
+        curr->arch.hvm_vmx.real_mode_io_in_progress = 1;
+        send_pio_req(port, 1, bytes, 0, IOREQ_READ, 0, 0);
+    }
+
+    if ( !curr->arch.hvm_vmx.real_mode_io_completed )
+        return X86EMUL_UNHANDLEABLE;
+    
+    *val = curr->arch.hvm_vmx.real_mode_io_data;
+    curr->arch.hvm_vmx.real_mode_io_completed = 0;
+
+    return X86EMUL_OKAY;
 }
 
 static int realmode_write_io(
@@ -187,7 +204,15 @@ static int realmode_write_io(
     unsigned long val,
     struct x86_emulate_ctxt *ctxt)
 {
-    return X86EMUL_UNHANDLEABLE;
+    struct vcpu *curr = current;
+
+    if ( curr->arch.hvm_vmx.real_mode_io_in_progress )
+        return X86EMUL_UNHANDLEABLE;
+
+    curr->arch.hvm_vmx.real_mode_io_in_progress = 1;
+    send_pio_req(port, 1, bytes, val, IOREQ_WRITE, 0, 0);
+
+    return X86EMUL_OKAY;
 }
 
 static int
@@ -259,8 +284,19 @@ int vmx_realmode(struct cpu_user_regs *regs)
                  rm_ctxt.insn_buf[2], rm_ctxt.insn_buf[3],
                  rm_ctxt.insn_buf[4], rm_ctxt.insn_buf[5]);
 
-        if ( x86_emulate(&rm_ctxt.ctxt, &realmode_emulator_ops) )
-        {            
+        rc = x86_emulate(&rm_ctxt.ctxt, &realmode_emulator_ops);
+
+        if ( curr->arch.hvm_vmx.real_mode_io_in_progress )
+        {
+            ioreq_t *p = &get_ioreq(curr)->vp_ioreq;
+            gdprintk(XENLOG_DEBUG, "RM I/O %d %c addr=%lx data=%lx\n",
+                     p->type, p->dir ? 'R' : 'W', p->addr, p->data);
+            rc = 0;
+            break;
+        }
+
+        if ( rc )
+        {
             gdprintk(XENLOG_ERR, "Emulation failed\n");
             rc = -EINVAL;
             break;
@@ -272,3 +308,21 @@ int vmx_realmode(struct cpu_user_regs *regs)
 
     return rc;
 }
+
+int vmx_realmode_io_complete(void)
+{
+    struct vcpu *curr = current;
+    ioreq_t *p = &get_ioreq(curr)->vp_ioreq;
+
+    if ( !curr->arch.hvm_vmx.real_mode_io_in_progress )
+        return 0;
+
+    curr->arch.hvm_vmx.real_mode_io_in_progress = 0;
+    if ( p->dir == IOREQ_READ )
+    {
+        curr->arch.hvm_vmx.real_mode_io_completed = 1;
+        curr->arch.hvm_vmx.real_mode_io_data = p->data;
+    }
+
+    return 1;
+}
index da266fffc1dad5642dc16d4d5dd5520325c0f05c..b23e205f88c14dd98e97b49eb8e6f942fe240516 100644 (file)
@@ -95,6 +95,7 @@ static int vmx_vcpu_initialise(struct vcpu *v)
 #ifndef VMXASSIST
     if ( v->vcpu_id == 0 )
         v->arch.guest_context.user_regs.eax = 1;
+    v->arch.hvm_vcpu.io_complete = vmx_realmode_io_complete;
 #endif
 
     return 0;
index 48325f92fcf88b7e0188d0ff4778a1bbc0c5365a..3ff12f8112b96819c3c61ba66c7ecd325486c09a 100644 (file)
@@ -264,6 +264,7 @@ struct operand {
 };
 
 /* EFLAGS bit definitions. */
+#define EFLG_VM (1<<17)
 #define EFLG_RF (1<<16)
 #define EFLG_OF (1<<11)
 #define EFLG_DF (1<<10)
@@ -478,10 +479,6 @@ do {                                                    \
 /* In future we will be able to generate arbitrary exceptions. */
 #define generate_exception_if(p, e) fail_if(p)
 
-/* To be done... */
-#define mode_ring0() (0)
-#define mode_iopl()  (0)
-
 /* Given byte has even parity (even number of 1s)? */
 static int even_parity(uint8_t v)
 {
@@ -679,6 +676,35 @@ test_cc(
     return (!!rc ^ (condition & 1));
 }
 
+static int
+get_cpl(
+    struct x86_emulate_ctxt *ctxt,
+    struct x86_emulate_ops  *ops)
+{
+    struct segment_register reg;
+
+    if ( ctxt->regs->eflags & EFLG_VM )
+        return 3;
+
+    if ( (ops->read_segment == NULL) ||
+         ops->read_segment(x86_seg_ss, &reg, ctxt) )
+        return -1;
+
+    return reg.attr.fields.dpl;
+}
+
+static int
+_mode_iopl(
+    struct x86_emulate_ctxt *ctxt,
+    struct x86_emulate_ops  *ops)
+{
+    int cpl = get_cpl(ctxt, ops);
+    return ((cpl >= 0) && (cpl <= ((ctxt->regs->eflags >> 12) & 3)));
+}
+
+#define mode_ring0() (get_cpl(ctxt, ops) == 0)
+#define mode_iopl()  _mode_iopl(ctxt, ops)
+
 static int
 in_realmode(
     struct x86_emulate_ctxt *ctxt,
index 5d653f0ff989049e6673e61b9fdf8949f34db63b..f6c55dba12b8dd073165f0f17f8c2cab70e674ed 100644 (file)
@@ -59,6 +59,9 @@ struct hvm_vcpu {
     bool_t              flag_dr_dirty;
     bool_t              debug_state_latch;
 
+    /* Callback function for I/O completion. */
+    int                 (*io_complete)(void);
+
     union {
         struct arch_vmx_struct vmx;
         struct arch_svm_struct svm;
index 0654264b468301d8208fbe09e4f5dee75e8f4bd8..68d1819d325d94b962c2929cec38f1990a129208 100644 (file)
@@ -92,6 +92,10 @@ struct arch_vmx_struct {
     unsigned long        vmxassist_enabled:1;
     unsigned long        irqbase_mode:1;
     unsigned char        pm_irqbase[2];
+#else
+    bool_t               real_mode_io_in_progress;
+    bool_t               real_mode_io_completed;
+    unsigned long        real_mode_io_data;
 #endif
 };
 
index f6846a1d305981c2cc22615edabd24092e6bd3c8..4787226cd33f200ffa7d3f439d55318162fb4afd 100644 (file)
@@ -34,6 +34,7 @@ void vmx_do_resume(struct vcpu *);
 void set_guest_time(struct vcpu *v, u64 gtime);
 void vmx_vlapic_msr_changed(struct vcpu *v);
 int vmx_realmode(struct cpu_user_regs *regs);
+int vmx_realmode_io_complete(void);
 
 /*
  * Exit Reasons