vmx realmode: Detect and correctly plumb mmio accesses from emulated
authorKeir Fraser <keir.fraser@citrix.com>
Sun, 25 Nov 2007 21:24:48 +0000 (21:24 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Sun, 25 Nov 2007 21:24:48 +0000 (21:24 +0000)
realmode. Also correctly handle debug output to I/O port 0xe9.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
xen/arch/x86/hvm/platform.c
xen/arch/x86/hvm/vmx/realmode.c
xen/include/asm-x86/hvm/io.h

index e22f3f3ebbc5327bda57dcf9068007d02b6d638e..7a61dc043748f9f3dcd26e15d3f4dcf42dd42e72 100644 (file)
@@ -885,9 +885,9 @@ void send_pio_req(unsigned long port, unsigned long count, int size,
     hvm_send_assist_req(v);
 }
 
-static void send_mmio_req(unsigned char type, unsigned long gpa,
-                          unsigned long count, int size, paddr_t value,
-                          int dir, int df, int value_is_ptr)
+void send_mmio_req(unsigned char type, unsigned long 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;
index 1de0b372f65754ae42e5a62b506ed8240910bc9a..840200eaf77718151c424c033e2987ec1dbb76b2 100644 (file)
@@ -108,8 +108,39 @@ realmode_read(
     struct realmode_emulate_ctxt *rm_ctxt)
 {
     uint32_t addr = rm_ctxt->seg_reg[seg].base + offset;
+    int todo;
+
     *val = 0;
-    (void)hvm_copy_from_guest_phys(val, addr, bytes);
+    todo = hvm_copy_from_guest_phys(val, addr, bytes);
+
+    if ( todo )
+    {
+        struct vcpu *curr = current;
+
+        if ( todo != bytes )
+        {
+            gdprintk(XENLOG_WARNING, "RM: Partial read at %08x (%d/%d)\n",
+                     addr, todo, bytes);
+            return X86EMUL_UNHANDLEABLE;
+        }
+
+        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_mmio_req(IOREQ_TYPE_COPY, addr, 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;
 }
 
@@ -161,7 +192,29 @@ realmode_emulate_write(
     struct realmode_emulate_ctxt *rm_ctxt =
         container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
     uint32_t addr = rm_ctxt->seg_reg[seg].base + offset;
-    (void)hvm_copy_to_guest_phys(addr, &val, bytes);
+    int todo;
+
+    todo = hvm_copy_to_guest_phys(addr, &val, bytes);
+
+    if ( todo )
+    {
+        struct vcpu *curr = current;
+
+        if ( todo != bytes )
+        {
+            gdprintk(XENLOG_WARNING, "RM: Partial write at %08x (%d/%d)\n",
+                     addr, todo, bytes);
+            return X86EMUL_UNHANDLEABLE;
+        }
+
+        if ( curr->arch.hvm_vmx.real_mode_io_in_progress )
+            return X86EMUL_UNHANDLEABLE;
+
+        curr->arch.hvm_vmx.real_mode_io_in_progress = 1;
+        send_mmio_req(IOREQ_TYPE_COPY, addr, 1, bytes,
+                      val, IOREQ_WRITE, 0, 0);
+    }
+
     return X86EMUL_OKAY;
 }
 
@@ -244,6 +297,12 @@ static int realmode_write_io(
 {
     struct vcpu *curr = current;
 
+    if ( port == 0xe9 )
+    {
+        hvm_print_line(curr, val);
+        return X86EMUL_OKAY;
+    }
+
     if ( curr->arch.hvm_vmx.real_mode_io_in_progress )
         return X86EMUL_UNHANDLEABLE;
 
index daea36d3bb3f3d6a040de2d9c0f78fa4ac3b354f..26614e7d78db10580bddd1a441e028e0f8dc6c00 100644 (file)
@@ -149,8 +149,11 @@ static inline int register_buffered_io_handler(
     return register_io_handler(d, addr, size, action, HVM_BUFFERED_IO);
 }
 
-extern 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_mmio_req(unsigned char type, unsigned long 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);
 extern void handle_mmio(unsigned long gpa);