All of lore.kernel.org
 help / color / mirror / Atom feed
From: Anthony Liguori <aliguori@us.ibm.com>
To: xen-devel@lists.xensource.com, "Kamble,
	Nitin A" <nitin.a.kamble@intel.com>,
	"Nakajima, Jun" <jun.nakajima@intel.com>,
	Keir Fraser <keir@xensource.com>
Subject: [PATCH][RFC] Emulating real mode with x86_emulate
Date: Sun, 25 Mar 2007 18:35:42 -0500	[thread overview]
Message-ID: <4607074E.1030807@us.ibm.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 1649 bytes --]

Howdy,

Attached is a patch that begins to lay down the infrastructure for 
emulating real mode with x86_emulate().  With a little more refactoring, 
I think it could also replace the SVM emulator.

The patch introduces an HVMOP hypercall to set a flag in the hvm vcpu 
struct to signal that real mode should be emulated with x86_emulate 
instead of using vm86.  This is to make development a little bit easier 
since x86_emulate is not quite there yet wrt 16 bit emulation.  It can 
be enabled by passing -emulate-16bit to qemu-dm (I use a wrapper script 
similar to qemu-dm.debug).

The VT code keeps track of the whether it's in the emulator and loops on 
the do_resume path in x86_emulate.  I think this code probably should be 
refactored into the common HVM code although this would require changing 
some of the HVM ops.  This would allow SVM to use the x86_emulate to 
handle individual instructions.

There are some issues to work out.  Namely, x86_emulate appears to want 
blocking PIO calls which isn't conducive to the wait PIO works today in 
HVM.  This is only a problem for instructions at the moment.  I'm also a 
bit confused about how to properly loop in the emulator.  schedule_tail 
is not meant to return so perhaps we should loop on emulating == 1 
instead of hypercall_preempt_check?  I didn't think the hypervisor was 
preemptable though.

The current code doesn't handle non-flat segments as I don't think 
hvm_copy_from/to_guest handles it (which I assume it would need to).

However, it is enough to start running instructions in x86_emulate so 
it's enough to start working on enhancing that.

Regards,

Anthony Liguori


[-- Attachment #2: hvm_emulate_realmode.diff --]
[-- Type: text/x-patch, Size: 12405 bytes --]

diff -r 3fd9b0c71b8c tools/firmware/hvmloader/hvmloader.c
--- a/tools/firmware/hvmloader/hvmloader.c	Tue Mar 20 17:36:18 2007 +0000
+++ b/tools/firmware/hvmloader/hvmloader.c	Sun Mar 25 13:14:43 2007 -0500
@@ -349,6 +349,14 @@ static void cmos_write_memory_size(void)
     cmos_outb(0x35, (uint8_t)( alt_mem >> 8));
 }
 
+#define DOMID_SELF (0x7FF0U)
+
+#define HVMOP_emulate_realmode 6
+struct xen_hvm_op_emulate_realmode
+{
+    uint16_t domid;
+};
+
 int main(void)
 {
     int acpi_sz;
@@ -401,15 +409,23 @@ int main(void)
 
     if ( !check_amd() )
     {
-        printf("Loading VMXAssist ...\n");
-        memcpy((void *)VMXASSIST_PHYSICAL_ADDRESS,
-               vmxassist, sizeof(vmxassist));
-
-        printf("VMX go ...\n");
-        __asm__ __volatile__(
-            "jmp *%%eax"
-            : : "a" (VMXASSIST_PHYSICAL_ADDRESS), "d" (0)
-            );
+        printf("Loading VMXAssist ... %x\n", inl(0x595));
+        if (inl(0x595) == 0xdeadbeef) {
+            struct xen_hvm_op_emulate_realmode op;
+
+            printf("foo\n");
+            op.domid = DOMID_SELF;
+            hypercall_hvm_op(HVMOP_emulate_realmode, &op);
+        } else {
+            memcpy((void *)VMXASSIST_PHYSICAL_ADDRESS,
+                   vmxassist, sizeof(vmxassist));
+
+            printf("VMX go ...\n");
+            __asm__ __volatile__(
+                                 "jmp *%%eax"
+                                 : : "a" (VMXASSIST_PHYSICAL_ADDRESS), "d" (0)
+                                 );
+        }
     }
 
     printf("Invoking ROMBIOS ...\n");
diff -r 3fd9b0c71b8c tools/ioemu/hw/pc.c
--- a/tools/ioemu/hw/pc.c	Tue Mar 20 17:36:18 2007 +0000
+++ b/tools/ioemu/hw/pc.c	Fri Mar 23 11:32:33 2007 -0500
@@ -316,6 +316,13 @@ static uint32_t ioport92_read(void *opaq
     return ioport_get_a20() << 1;
 }
 
+static uint32_t emulate_16bit_read(void *opaque, uint32_t addr)
+{
+    if (emulate_16bit)
+	return 0xdeadbeef;
+    return 0;
+}
+
 /***********************************************************/
 /* Bochs BIOS debug ports */
 
@@ -728,6 +735,8 @@ static void pc_init1(uint64_t ram_size, 
     
     bochs_bios_init();
 
+    register_ioport_read(0x595, 1, 4, emulate_16bit_read, NULL);
+
 #ifndef CONFIG_DM
     if (linux_boot) {
         uint8_t bootsect[512];
diff -r 3fd9b0c71b8c tools/ioemu/vl.c
--- a/tools/ioemu/vl.c	Tue Mar 20 17:36:18 2007 +0000
+++ b/tools/ioemu/vl.c	Fri Mar 23 11:32:33 2007 -0500
@@ -161,6 +161,7 @@ int vnc_display = -1;
 #endif
 int acpi_enabled = 0;
 int fd_bootchk = 1;
+int emulate_16bit;
 
 extern int vcpus;
 
@@ -5535,6 +5536,7 @@ enum {
     QEMU_OPTION_vncviewer,
     QEMU_OPTION_vncunused,
     QEMU_OPTION_vnclisten,
+    QEMU_OPTION_emulate_16bit,
 };
 
 typedef struct QEMUOption {
@@ -5614,6 +5616,7 @@ const QEMUOption qemu_options[] = {
     { "vncviewer", 0, QEMU_OPTION_vncviewer },
     { "vncunused", 0, QEMU_OPTION_vncunused },
     { "vnclisten", HAS_ARG, QEMU_OPTION_vnclisten },
+    { "emulate-16bit", 0, QEMU_OPTION_emulate_16bit },
     
     /* temporary options */
     { "usb", 0, QEMU_OPTION_usb },
@@ -6522,6 +6525,9 @@ int main(int argc, char **argv)
             case QEMU_OPTION_vnclisten:
                 parse_host(&vnclisten_addr, optarg);
                 break;
+	    case QEMU_OPTION_emulate_16bit:
+		emulate_16bit = 1;
+		break;
             }
         }
     }
diff -r 3fd9b0c71b8c tools/ioemu/vl.h
--- a/tools/ioemu/vl.h	Tue Mar 20 17:36:18 2007 +0000
+++ b/tools/ioemu/vl.h	Fri Mar 23 11:32:33 2007 -0500
@@ -156,6 +156,7 @@ extern void *shared_vram;
 
 extern FILE *logfile;
 
+int emulate_16bit;
 
 #if defined(__i386__) || defined(__x86_64__)
 
diff -r 3fd9b0c71b8c xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c	Tue Mar 20 17:36:18 2007 +0000
+++ b/xen/arch/x86/hvm/hvm.c	Fri Mar 23 12:16:25 2007 -0500
@@ -185,6 +185,41 @@ static int hvmop_drain_io(
 
  out:
     rcu_unlock_domain(d);
+    return rc;
+}
+
+static int hvmop_emulate_realmode(
+    XEN_GUEST_HANDLE(xen_hvm_emulate_realmode_t) uop)
+{
+    struct xen_hvm_emulate_realmode op;
+    struct domain *d;
+    struct vcpu *v;
+    int rc;
+
+    printk("hvmop_emulate_realmode\n");
+
+    if ( copy_from_guest(&op, uop, 1) )
+        return -EFAULT;
+
+    if ( op.domid != DOMID_SELF )
+        return -EPERM;
+
+    d = rcu_lock_current_domain();
+    if ( d == NULL )
+        return -ESRCH;
+
+    printk("guest requests real mode emulation\n");
+
+    for_each_vcpu(d, v)
+    {
+        v->arch.hvm_vcpu.emulate_realmode = 1;
+    }
+
+    rc = 0;
+
+    rcu_unlock_domain(d);
+    printk("foo %d\n", __LINE__);
+
     return rc;
 }
 
@@ -963,6 +998,10 @@ long do_hvm_op(unsigned long op, XEN_GUE
             guest_handle_cast(arg, xen_hvm_drain_io_t));
         break;
 
+    case HVMOP_emulate_realmode:
+        rc = hvmop_emulate_realmode(
+            guest_handle_cast(arg, xen_hvm_emulate_realmode_t));
+        break;
 
     default:
     {
diff -r 3fd9b0c71b8c xen/arch/x86/hvm/vmx/vmcs.c
--- a/xen/arch/x86/hvm/vmx/vmcs.c	Tue Mar 20 17:36:18 2007 +0000
+++ b/xen/arch/x86/hvm/vmx/vmcs.c	Sun Mar 25 13:02:08 2007 -0500
@@ -493,6 +493,142 @@ void vm_resume_fail(unsigned long eflags
     domain_crash_synchronous();
 }
 
+static int vmx_em_read(enum x86_segment seg,
+                       unsigned long offset,
+                       unsigned long *val,
+                       unsigned int bytes,
+                       struct x86_emulate_ctxt *ctxt)
+{
+    /* FIXME deal with non-flat segments */
+    if ( hvm_copy_from_guest_virt(val, offset, bytes) )
+        return -1;
+    return 0;
+}
+
+static int vmx_em_fetch(enum x86_segment seg,
+                        unsigned long offset,
+                        unsigned long *val,
+                        unsigned int bytes,
+                        struct x86_emulate_ctxt *ctxt)
+{
+    /* FIXME deal with non-flat segments */
+    if ( hvm_copy_from_guest_virt(val, offset, bytes) )
+        return -1;
+    return 0;
+}
+
+static int vmx_em_write(enum x86_segment seg,
+                        unsigned long offset,
+                        unsigned long val,
+                        unsigned int bytes,
+                        struct x86_emulate_ctxt *ctxt)
+{
+    /* FIXME deal with non-flat segments */
+    if ( hvm_copy_to_guest_virt(offset, &val, bytes) )
+        return -1;
+    return 0;
+}
+
+static int vmx_em_read_io(unsigned int port,
+                          unsigned int bytes, 
+                          unsigned long *val,
+                          struct x86_emulate_ctxt *ctxt)
+{
+    /* FIXME we need a smarter interface in x86_emulate since we cannot block
+       here */
+    return -1;
+}
+
+static int vmx_em_write_io(unsigned int port,
+                           unsigned int bytes, 
+                           unsigned long val,
+                           struct x86_emulate_ctxt *ctxt)
+{
+    send_pio_req(port, 1, bytes, val, IOREQ_WRITE, 0, 0);
+    return 0;
+}
+
+static int vmx_em_read_cr(unsigned int ret,
+                          unsigned long *val,
+                          struct x86_emulate_ctxt *ctxt)
+{
+    struct vcpu *v = current;
+
+    switch (ret) {
+    case 0:
+        *val = v->arch.hvm_vmx.cpu_shadow_cr0;
+        break;
+    case 2:
+        *val = v->arch.hvm_vmx.cpu_cr2;
+        break;
+    case 3:
+        *val = v->arch.hvm_vmx.cpu_cr3;
+        break;
+    case 4:
+        *val = v->arch.hvm_vmx.cpu_shadow_cr4;
+        break;
+    default:
+        return -1;
+    }
+    return 0;
+}
+
+static int vmx_em_write_cr(unsigned int ret,
+                           unsigned long val,
+                           struct x86_emulate_ctxt *ctxt)
+{
+    extern int vmx_set_cr0(unsigned long value);
+
+    if (ret != 0)
+        return -1;
+
+    return vmx_set_cr0(val);
+}
+
+static int vmx_em_write_rflags(unsigned long val,
+                               struct x86_emulate_ctxt *ctxt)
+{
+    ctxt->regs->eflags = val;
+    return 0;
+}
+
+struct x86_emulate_ops em_ops = {
+    .read = vmx_em_read,
+    .write = vmx_em_write,
+    .insn_fetch = vmx_em_fetch,
+    .read_io = vmx_em_read_io,
+    .write_io = vmx_em_write_io,
+    .read_cr = vmx_em_read_cr,
+    .write_cr = vmx_em_write_cr,
+    .write_rflags = vmx_em_write_rflags,
+};
+
+static void vmx_do_emulate(struct vcpu *v)
+{
+    struct x86_emulate_ctxt ctxt;
+    struct cpu_user_regs *regs = &v->arch.guest_context.user_regs;
+
+    hvm_store_cpu_guest_regs(v, regs, NULL);
+    ctxt.regs = regs;
+
+    /* FIXME determine this dynamically */
+    ctxt.addr_size = 16;
+    ctxt.sp_size = 16;
+
+    while (!hypercall_preempt_check()) {
+        if (x86_emulate(&ctxt, &em_ops)) {
+            unsigned long eip;
+
+            eip = __vmread(GUEST_RIP);
+            printk("failed to emulate instruction at %%eip = 0x%lx\n", eip);
+            domain_crash_synchronous();
+        }
+    }
+    hvm_load_cpu_guest_regs(v, regs);
+    /* FIXME how can we ensure we loop here without taking all CPU? */
+    domain_crash_synchronous();
+}
+
 void arch_vmx_do_resume(struct vcpu *v)
 {
     if ( v->arch.hvm_vmx.active_cpu == smp_processor_id() )
@@ -508,7 +644,11 @@ void arch_vmx_do_resume(struct vcpu *v)
     }
 
     hvm_do_resume(v);
-    reset_stack_and_jump(vmx_asm_do_vmentry);
+
+    if (v->arch.hvm_vmx.emulating)
+        vmx_do_emulate(v);
+    else
+        reset_stack_and_jump(vmx_asm_do_vmentry);
 }
 
 /* Dump a section of VMCS */
diff -r 3fd9b0c71b8c xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c	Tue Mar 20 17:36:18 2007 +0000
+++ b/xen/arch/x86/hvm/vmx/vmx.c	Sun Mar 25 12:10:46 2007 -0500
@@ -1865,7 +1865,7 @@ static int vmx_assist(struct vcpu *v, in
     return 0;
 }
 
-static int vmx_set_cr0(unsigned long value)
+int vmx_set_cr0(unsigned long value)
 {
     struct vcpu *v = current;
     unsigned long mfn;
@@ -1982,13 +1982,29 @@ static int vmx_set_cr0(unsigned long val
             }
         }
 
-        if ( vmx_assist(v, VMX_ASSIST_INVOKE) )
+        if ( v->arch.hvm_vcpu.emulate_realmode )
+        {
+            eip = __vmread(GUEST_RIP);
+            HVM_DBG_LOG(DBG_LEVEL_1,
+                        "Transfering control to x86_emulate %%eip 0x%lx\n", eip);
+            v->arch.hvm_vmx.emulating = 1;
+            return 1;
+        }
+        else if ( vmx_assist(v, VMX_ASSIST_INVOKE) )
         {
             eip = __vmread(GUEST_RIP);
             HVM_DBG_LOG(DBG_LEVEL_1,
                         "Transfering control to vmxassist %%eip 0x%lx\n", eip);
             return 0; /* do not update eip! */
         }
+    }
+    else if ( v->arch.hvm_vmx.emulating )
+    {
+        eip = __vmread(GUEST_RIP);
+        HVM_DBG_LOG(DBG_LEVEL_1,
+                    "Enabling CR0.PE at %%eip 0x%lx\n", eip);
+        v->arch.hvm_vmx.emulating = 0;
+        return 1;
     }
     else if ( v->arch.hvm_vmx.vmxassist_enabled )
     {
diff -r 3fd9b0c71b8c xen/include/asm-x86/hvm/vcpu.h
--- a/xen/include/asm-x86/hvm/vcpu.h	Tue Mar 20 17:36:18 2007 +0000
+++ b/xen/include/asm-x86/hvm/vcpu.h	Fri Mar 23 11:32:33 2007 -0500
@@ -44,6 +44,7 @@ struct hvm_vcpu {
 
     /* Flags */
     int                 flag_dr_dirty;
+    unsigned long       emulate_realmode;
 
     union {
         struct arch_vmx_struct vmx;
diff -r 3fd9b0c71b8c xen/include/asm-x86/hvm/vmx/vmcs.h
--- a/xen/include/asm-x86/hvm/vmx/vmcs.h	Tue Mar 20 17:36:18 2007 +0000
+++ b/xen/include/asm-x86/hvm/vmx/vmcs.h	Sun Mar 25 11:52:28 2007 -0500
@@ -77,6 +77,7 @@ struct arch_vmx_struct {
     unsigned long        cpu_cr2; /* save CR2 */
     unsigned long        cpu_cr3;
     struct vmx_msr_state msr_state;
+    unsigned long        emulating;
     unsigned long        vmxassist_enabled:1;
 };
 
diff -r 3fd9b0c71b8c xen/include/public/hvm/hvm_op.h
--- a/xen/include/public/hvm/hvm_op.h	Tue Mar 20 17:36:18 2007 +0000
+++ b/xen/include/public/hvm/hvm_op.h	Fri Mar 23 11:32:33 2007 -0500
@@ -78,4 +78,13 @@ typedef struct xen_hvm_drain_io xen_hvm_
 typedef struct xen_hvm_drain_io xen_hvm_drain_io_t;
 DEFINE_XEN_GUEST_HANDLE(xen_hvm_drain_io_t);
 
+/* Enter into 16 bit emulation */
+#define HVMOP_emulate_realmode    6
+struct xen_hvm_emulate_realmode {
+    /* Should be DOMID_SELF */
+    domid_t  domid;
+};
+typedef struct xen_hvm_emulate_realmode xen_hvm_emulate_realmode_t;
+DEFINE_XEN_GUEST_HANDLE(xen_hvm_emulate_realmode_t);
+
 #endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

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

             reply	other threads:[~2007-03-25 23:35 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-03-25 23:35 Anthony Liguori [this message]
2007-03-29 21:17 ` [PATCH][RFC] Emulating real mode with x86_emulate Kamble, Nitin A
2007-03-29 23:24   ` Anthony Liguori
2007-03-29 23:52     ` Kamble, Nitin A
2007-03-30  0:11       ` Anthony Liguori
2007-03-30  0:59         ` Kamble, Nitin A
2007-03-30  2:20           ` Kamble, Nitin A
2007-03-30  3:20             ` Anthony Liguori
2007-03-30  3:55               ` Anthony Liguori
2007-03-30 18:53               ` Kamble, Nitin A
2007-03-30 19:00                 ` Anthony Liguori
2007-03-30 21:08                   ` Kamble, Nitin A
2007-03-30 21:24                     ` Kamble, Nitin A
2007-03-30 22:11                       ` Anthony Liguori
2007-04-02 18:45                         ` Kamble, Nitin A
2007-04-02 18:54                           ` Anthony Liguori
2007-04-02 23:52                             ` Kamble, Nitin A
2007-04-03  6:25                               ` Keir Fraser
2007-04-03 14:03                               ` Anthony Liguori
2007-04-05  1:24                                 ` Kamble, Nitin A
2007-03-30 22:10 ` Andi Kleen
2007-03-30 21:20   ` Anthony Liguori
2007-03-30 21:25     ` Andi Kleen
2007-03-30 22:00       ` Anthony Liguori

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4607074E.1030807@us.ibm.com \
    --to=aliguori@us.ibm.com \
    --cc=jun.nakajima@intel.com \
    --cc=keir@xensource.com \
    --cc=nitin.a.kamble@intel.com \
    --cc=xen-devel@lists.xensource.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.