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

[Xen-changelog] [xen-unstable] x86, hvm: Hyper-V guest interface support with small set of enlightenments



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1223977529 -3600
# Node ID 8d993552673a98cbe26ed0df05499659c852b8d4
# Parent  a26194601c8f2b223e380bbb7153df7027e8d7f5
x86, hvm: Hyper-V guest interface support with small set of enlightenments

A minimal implementation of the Viridian (Hyper-V) guest
interface. The only enlightenments advertised and supported are vAPIC
MSRs and long-spin-wait notifications. The set of enlightenments can
easily be extended in future, as they are found to provide a
performance win, and configured via an extended HVM_PARAM_VIRIDIAN hvm
parameter.

Signed-off-by: Peter Johnston <peter.johnston@xxxxxxxxxx>
Signed-off-by: Tim Deegan <tim.deegan@xxxxxxxxxx>
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
 tools/firmware/hvmloader/hvmloader.c                     |   32 
 tools/python/xen/xend/XendConfig.py                      |    3 
 tools/python/xen/xend/XendConstants.py                   |    7 
 tools/python/xen/xend/XendDomainInfo.py                  |    5 
 tools/python/xen/xm/create.py                            |    8 
 tools/python/xen/xm/xenapi_create.py                     |    1 
 unmodified_drivers/linux-2.6/platform-pci/platform-pci.c |   59 
 xen/arch/x86/hvm/Makefile                                |    1 
 xen/arch/x86/hvm/hvm.c                                   |   10 
 xen/arch/x86/hvm/svm/svm.c                               |    6 
 xen/arch/x86/hvm/viridian.c                              |  350 +++
 xen/arch/x86/hvm/vlapic.c                                |    2 
 xen/arch/x86/hvm/vmx/vmx.c                               |    7 
 xen/arch/x86/traps.c                                     |   26 
 xen/arch/x86/x86_emulate/x86_emulate.c                   | 1709 +++++++--------
 xen/include/asm-x86/hvm/domain.h                         |    3 
 xen/include/asm-x86/hvm/hvm.h                            |    3 
 xen/include/asm-x86/hvm/viridian.h                       |   65 
 xen/include/asm-x86/hvm/vlapic.h                         |    4 
 xen/include/asm-x86/perfc_defn.h                         |   16 
 xen/include/public/arch-x86/hvm/save.h                   |   13 
 xen/include/public/hvm/params.h                          |    7 
 22 files changed, 1421 insertions(+), 916 deletions(-)

diff -r a26194601c8f -r 8d993552673a tools/firmware/hvmloader/hvmloader.c
--- a/tools/firmware/hvmloader/hvmloader.c      Mon Oct 13 13:15:20 2008 +0100
+++ b/tools/firmware/hvmloader/hvmloader.c      Tue Oct 14 10:45:29 2008 +0100
@@ -101,30 +101,36 @@ asm (
 
 static enum { VGA_none, VGA_std, VGA_cirrus } virtual_vga = VGA_none;
 
-static void
-init_hypercalls(void)
+static void init_hypercalls(void)
 {
     uint32_t eax, ebx, ecx, edx;
     unsigned long i;
     char signature[13];
     xen_extraversion_t extraversion;
-
-    cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
-
-    *(uint32_t *)(signature + 0) = ebx;
-    *(uint32_t *)(signature + 4) = ecx;
-    *(uint32_t *)(signature + 8) = edx;
-    signature[12] = '\0';
-
-    BUG_ON(strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002));
+    uint32_t base;
+
+    for ( base = 0x40000000; base < 0x40001000; base += 0x100 )
+    {
+        cpuid(base, &eax, &ebx, &ecx, &edx);
+
+        *(uint32_t *)(signature + 0) = ebx;
+        *(uint32_t *)(signature + 4) = ecx;
+        *(uint32_t *)(signature + 8) = edx;
+        signature[12] = '\0';
+
+        if ( !strcmp("XenVMMXenVMM", signature) )
+            break;
+    }
+
+    BUG_ON(strcmp("XenVMMXenVMM", signature) || ((eax - base) < 2));
 
     /* Fill in hypercall transfer pages. */
-    cpuid(0x40000002, &eax, &ebx, &ecx, &edx);
+    cpuid(base + 2, &eax, &ebx, &ecx, &edx);
     for ( i = 0; i < eax; i++ )
         wrmsr(ebx, HYPERCALL_PHYSICAL_ADDRESS + (i << 12) + i);
 
     /* Print version information. */
-    cpuid(0x40000001, &eax, &ebx, &ecx, &edx);
+    cpuid(base + 1, &eax, &ebx, &ecx, &edx);
     hypercall_xen_version(XENVER_extraversion, extraversion);
     printf("Detected Xen v%u.%u%s\n", eax >> 16, eax & 0xffff, extraversion);
 }
diff -r a26194601c8f -r 8d993552673a tools/python/xen/xend/XendConfig.py
--- a/tools/python/xen/xend/XendConfig.py       Mon Oct 13 13:15:20 2008 +0100
+++ b/tools/python/xen/xend/XendConfig.py       Tue Oct 14 10:45:29 2008 +0100
@@ -155,6 +155,7 @@ XENAPI_PLATFORM_CFG_TYPES = {
     'vncdisplay': int,
     'vnclisten': str,
     'timer_mode': int,
+    'viridian': int,
     'vncpasswd': str,
     'vncunused': int,
     'xauthority': str,
@@ -442,6 +443,8 @@ class XendConfig(dict):
         if self.is_hvm():
             if 'timer_mode' not in self['platform']:
                 self['platform']['timer_mode'] = 1
+            if 'viridian' not in self['platform']:
+                self['platform']['viridian'] = 0
             if 'rtc_timeoffset' not in self['platform']:
                 self['platform']['rtc_timeoffset'] = 0
             if 'hpet' not in self['platform']:
diff -r a26194601c8f -r 8d993552673a tools/python/xen/xend/XendConstants.py
--- a/tools/python/xen/xend/XendConstants.py    Mon Oct 13 13:15:20 2008 +0100
+++ b/tools/python/xen/xend/XendConstants.py    Tue Oct 14 10:45:29 2008 +0100
@@ -43,9 +43,10 @@ HVM_PARAM_PAE_ENABLED  = 4
 HVM_PARAM_PAE_ENABLED  = 4
 HVM_PARAM_IOREQ_PFN    = 5
 HVM_PARAM_BUFIOREQ_PFN = 6
-HVM_PARAM_NVRAM_FD     = 7
-HVM_PARAM_VHPT_SIZE    = 8
-HVM_PARAM_BUFPIOREQ_PFN = 9
+HVM_PARAM_NVRAM_FD     = 7 # ia64
+HVM_PARAM_VHPT_SIZE    = 8 # ia64
+HVM_PARAM_BUFPIOREQ_PFN = 9 # ia64
+HVM_PARAM_VIRIDIAN     = 9 # x86
 HVM_PARAM_TIMER_MODE   = 10
 HVM_PARAM_HPET_ENABLED = 11
 HVM_PARAM_ACPI_S_STATE = 14
diff -r a26194601c8f -r 8d993552673a tools/python/xen/xend/XendDomainInfo.py
--- a/tools/python/xen/xend/XendDomainInfo.py   Mon Oct 13 13:15:20 2008 +0100
+++ b/tools/python/xen/xend/XendDomainInfo.py   Tue Oct 14 10:45:29 2008 +0100
@@ -2078,6 +2078,11 @@ class XendDomainInfo:
             xc.hvm_set_param(self.domid, HVM_PARAM_TIMER_MODE,
                              long(timer_mode))
 
+        # Set Viridian interface configuration of domain
+        viridian = self.info["platform"].get("viridian")
+        if arch.type == "x86" and hvm and viridian is not None:
+            xc.hvm_set_param(self.domid, HVM_PARAM_VIRIDIAN, long(viridian))
+
         # Optionally enable virtual HPET
         hpet = self.info["platform"].get("hpet")
         if hvm and hpet is not None:
diff -r a26194601c8f -r 8d993552673a tools/python/xen/xm/create.py
--- a/tools/python/xen/xm/create.py     Mon Oct 13 13:15:20 2008 +0100
+++ b/tools/python/xen/xm/create.py     Tue Oct 14 10:45:29 2008 +0100
@@ -217,6 +217,11 @@ gopts.var('timer_mode', val='TIMER_MODE'
           fn=set_int, default=1,
           use="""Timer mode (0=delay virtual time when ticks are missed;
           1=virtual time is always wallclock time.""")
+
+gopts.var('viridian', val='VIRIDIAN',
+          fn=set_int, default=0,
+          use="""Expose Viridian interface to x86 HVM guest?
+          (Default is 0).""")
 
 gopts.var('acpi', val='ACPI',
           fn=set_int, default=1,
@@ -856,7 +861,8 @@ def configure_hvm(config_image, vals):
              'vnc', 'vncdisplay', 'vncunused', 'vncconsole', 'vnclisten',
              'sdl', 'display', 'xauthority', 'rtc_timeoffset', 'monitor',
              'acpi', 'apic', 'usb', 'usbdevice', 'keymap', 'pci', 'hpet',
-             'guest_os_type', 'hap', 'opengl', 'cpuid', 'cpuid_check']
+             'guest_os_type', 'hap', 'opengl', 'cpuid', 'cpuid_check',
+             'viridian' ]
 
     for a in args:
         if a in vals.__dict__ and vals.__dict__[a] is not None:
diff -r a26194601c8f -r 8d993552673a tools/python/xen/xm/xenapi_create.py
--- a/tools/python/xen/xm/xenapi_create.py      Mon Oct 13 13:15:20 2008 +0100
+++ b/tools/python/xen/xm/xenapi_create.py      Tue Oct 14 10:45:29 2008 +0100
@@ -969,6 +969,7 @@ class sxp2xml:
             'usbdevice',
             'hpet',
             'timer_mode',
+            'viridian',
             'vhpt',
             'guest_os_type',
             'hap',
diff -r a26194601c8f -r 8d993552673a 
unmodified_drivers/linux-2.6/platform-pci/platform-pci.c
--- a/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c  Mon Oct 13 
13:15:20 2008 +0100
+++ b/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c  Tue Oct 14 
10:45:29 2008 +0100
@@ -111,26 +111,37 @@ unsigned long alloc_xen_mmio(unsigned lo
 
 #ifndef __ia64__
 
+static uint32_t xen_cpuid_base(void)
+{
+       uint32_t base, eax, ebx, ecx, edx;
+       char signature[13];
+
+       for (base = 0x40000000; base < 0x40001000; base += 0x100) {
+               cpuid(base, &eax, &ebx, &ecx, &edx);
+               *(uint32_t*)(signature + 0) = ebx;
+               *(uint32_t*)(signature + 4) = ecx;
+               *(uint32_t*)(signature + 8) = edx;
+               signature[12] = 0;
+
+               if (!strcmp("XenVMMXenVMM", signature) && ((eax - base) >= 2))
+                       return base;
+       }
+
+       return 0;
+}
+
 static int init_hypercall_stubs(void)
 {
-       uint32_t eax, ebx, ecx, edx, pages, msr, i;
-       char signature[13];
-
-       cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
-       *(uint32_t*)(signature + 0) = ebx;
-       *(uint32_t*)(signature + 4) = ecx;
-       *(uint32_t*)(signature + 8) = edx;
-       signature[12] = 0;
-
-       if (strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002)) {
+       uint32_t eax, ebx, ecx, edx, pages, msr, i, base;
+
+       base = xen_cpuid_base();
+       if (base == 0) {
                printk(KERN_WARNING
-                      "Detected Xen platform device but not Xen VMM?"
-                      " (sig %s, eax %x)\n",
-                      signature, eax);
+                      "Detected Xen platform device but not Xen VMM?\n");
                return -EINVAL;
        }
 
-       cpuid(0x40000001, &eax, &ebx, &ecx, &edx);
+       cpuid(base + 1, &eax, &ebx, &ecx, &edx);
 
        printk(KERN_INFO "Xen version %d.%d.\n", eax >> 16, eax & 0xffff);
 
@@ -138,7 +149,7 @@ static int init_hypercall_stubs(void)
         * Find largest supported number of hypercall pages.
         * We'll create as many as possible up to this number.
         */
-       cpuid(0x40000002, &pages, &msr, &ecx, &edx);
+       cpuid(base + 2, &pages, &msr, &ecx, &edx);
 
        /*
         * Use __vmalloc() because vmalloc_exec() is not an exported symbol.
@@ -174,18 +185,12 @@ static int init_hypercall_stubs(void)
 
 static void resume_hypercall_stubs(void)
 {
-       uint32_t eax, ebx, ecx, edx, pages, msr, i;
-       char signature[13];
-
-       cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
-       *(uint32_t*)(signature + 0) = ebx;
-       *(uint32_t*)(signature + 4) = ecx;
-       *(uint32_t*)(signature + 8) = edx;
-       signature[12] = 0;
-
-       BUG_ON(strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002));
-
-       cpuid(0x40000002, &pages, &msr, &ecx, &edx);
+       uint32_t base, ecx, edx, pages, msr, i;
+
+       base = xen_cpuid_base();
+       BUG_ON(base == 0);
+
+       cpuid(base + 2, &pages, &msr, &ecx, &edx);
 
        if (pages > max_hypercall_stub_pages)
                pages = max_hypercall_stub_pages;
diff -r a26194601c8f -r 8d993552673a xen/arch/x86/hvm/Makefile
--- a/xen/arch/x86/hvm/Makefile Mon Oct 13 13:15:20 2008 +0100
+++ b/xen/arch/x86/hvm/Makefile Tue Oct 14 10:45:29 2008 +0100
@@ -18,3 +18,4 @@ obj-y += save.o
 obj-y += save.o
 obj-y += vmsi.o
 obj-y += stdvga.o
+obj-y += viridian.o
diff -r a26194601c8f -r 8d993552673a xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c    Mon Oct 13 13:15:20 2008 +0100
+++ b/xen/arch/x86/hvm/hvm.c    Tue Oct 14 10:45:29 2008 +0100
@@ -1636,6 +1636,9 @@ void hvm_cpuid(unsigned int input, unsig
 {
     struct vcpu *v = current;
 
+    if ( cpuid_viridian_leaves(input, eax, ebx, ecx, edx) )
+        return;
+
     if ( cpuid_hypervisor_leaves(input, eax, ebx, ecx, edx) )
         return;
 
@@ -1953,6 +1956,9 @@ int hvm_do_hypercall(struct cpu_user_reg
     case 0:
         break;
     }
+
+    if ( (eax & 0x80000000) && is_viridian_domain(curr->domain) )
+        return viridian_hypercall(regs);
 
     if ( (eax >= NR_hypercalls) || !hvm_hypercall32_table[eax] )
     {
@@ -2378,6 +2384,10 @@ long do_hvm_op(unsigned long op, XEN_GUE
                 break;
             case HVM_PARAM_TIMER_MODE:
                 if ( a.value > HVMPTM_one_missed_tick_pending )
+                    rc = -EINVAL;
+                break;
+            case HVM_PARAM_VIRIDIAN:
+                if ( a.value > 1 )
                     rc = -EINVAL;
                 break;
             case HVM_PARAM_IDENT_PT:
diff -r a26194601c8f -r 8d993552673a xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c        Mon Oct 13 13:15:20 2008 +0100
+++ b/xen/arch/x86/hvm/svm/svm.c        Tue Oct 14 10:45:29 2008 +0100
@@ -1005,7 +1005,8 @@ static int svm_msr_read_intercept(struct
         break;
 
     default:
-        if ( rdmsr_hypervisor_regs(ecx, &eax, &edx) ||
+        if ( rdmsr_viridian_regs(ecx, &eax, &edx) ||
+             rdmsr_hypervisor_regs(ecx, &eax, &edx) ||
              rdmsr_safe(ecx, eax, edx) == 0 )
         {
             regs->eax = eax;
@@ -1073,6 +1074,9 @@ static int svm_msr_write_intercept(struc
         break;
 
     default:
+        if ( wrmsr_viridian_regs(ecx, regs->eax, regs->edx) )
+            break;
+
         switch ( long_mode_do_msr_write(regs) )
         {
         case HNDL_unhandled:
diff -r a26194601c8f -r 8d993552673a xen/arch/x86/hvm/viridian.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/x86/hvm/viridian.c       Tue Oct 14 10:45:29 2008 +0100
@@ -0,0 +1,350 @@
+/******************************************************************************
+ * viridian.c
+ *
+ * An implementation of the Viridian hypercall interface.
+ */
+
+#include <xen/sched.h>
+#include <xen/version.h>
+#include <xen/perfc.h>
+#include <xen/hypercall.h>
+#include <xen/domain_page.h>
+#include <asm/paging.h>
+#include <asm/p2m.h>
+#include <asm/hvm/support.h>
+#include <public/sched.h>
+#include <public/hvm/hvm_op.h>
+
+/* Viridian MSR numbers. */
+#define VIRIDIAN_MSR_GUEST_OS_ID 0x40000000
+#define VIRIDIAN_MSR_HYPERCALL   0x40000001
+#define VIRIDIAN_MSR_VP_INDEX    0x40000002
+#define VIRIDIAN_MSR_EOI         0x40000070
+#define VIRIDIAN_MSR_ICR         0x40000071
+#define VIRIDIAN_MSR_TPR         0x40000072
+
+/* Viridian Hypercall Status Codes. */
+#define HV_STATUS_SUCCESS                       0x0000
+#define HV_STATUS_INVALID_HYPERCALL_CODE        0x0002
+
+/* Viridian Hypercall Codes and Parameters. */
+#define HvNotifyLongSpinWait    8
+
+/* Viridian CPUID 4000003, Viridian MSR availability. */
+#define CPUID3A_MSR_APIC_ACCESS (1 << 4)
+#define CPUID3A_MSR_HYPERCALL   (1 << 5)
+#define CPUID3A_MSR_VP_INDEX    (1 << 6)
+
+/* Viridian CPUID 4000004, Implementation Recommendations. */
+#define CPUID4A_MSR_BASED_APIC  (1 << 3)
+
+int cpuid_viridian_leaves(unsigned int leaf, unsigned int *eax,
+                          unsigned int *ebx, unsigned int *ecx,
+                          unsigned int *edx)
+{
+    struct domain *d = current->domain;
+
+    if ( !is_viridian_domain(d) )
+        return 0;
+
+    leaf -= 0x40000000;
+    if ( leaf > 5 )
+        return 0;
+
+    *eax = *ebx = *ecx = *edx = 0;
+    switch ( leaf )
+    {
+    case 0:
+        *eax = 0x40000005; /* Maximum leaf */
+        *ebx = 0x7263694d; /* Magic numbers  */
+        *ecx = 0x666F736F;
+        *edx = 0x76482074;
+        break;
+    case 1:
+        *eax = 0x31237648; /* Version number */
+        break;
+    case 2:
+        /* Hypervisor information, but only if the guest has set its
+           own version number. */
+        if ( d->arch.hvm_domain.viridian.guest_os_id.raw == 0 )
+            break;
+        *eax = 1; /* Build number */
+        *ebx = (xen_major_version() << 16) | xen_minor_version();
+        *ecx = 0; /* SP */
+        *edx = 0; /* Service branch and number */
+        break;
+    case 3:
+        /* Which hypervisor MSRs are available to the guest */
+        *eax = (CPUID3A_MSR_APIC_ACCESS |
+                CPUID3A_MSR_HYPERCALL   |
+                CPUID3A_MSR_VP_INDEX);
+        break;
+    case 4:
+        /* Recommended hypercall usage. */
+        if ( (d->arch.hvm_domain.viridian.guest_os_id.raw == 0) ||
+             (d->arch.hvm_domain.viridian.guest_os_id.fields.os < 4) )
+            break;
+        *eax = CPUID4A_MSR_BASED_APIC;
+        *ebx = 2047; /* long spin count */
+        break;
+    }
+
+    return 1;
+}
+
+static void enable_hypercall_page(void)
+{
+    struct domain *d = current->domain;
+    unsigned long gmfn = d->arch.hvm_domain.viridian.hypercall_gpa.fields.pfn;
+    unsigned long mfn = gmfn_to_mfn(d, gmfn);
+    uint8_t *p;
+
+    if ( !mfn_valid(mfn) ||
+         !get_page_and_type(mfn_to_page(mfn), d, PGT_writable_page) )
+    {
+        gdprintk(XENLOG_WARNING, "Bad GMFN %lx (MFN %lx)\n", gmfn, mfn);
+        return;
+    }
+
+    p = map_domain_page(mfn);
+
+    /*
+     * We set the bit 31 in %eax (reserved field in the Viridian hypercall
+     * calling convention) to differentiate Xen and Viridian hypercalls.
+     */
+    *(u8  *)(p + 0) = 0x0d; /* orl $0x80000000, %eax */
+    *(u32 *)(p + 1) = 0x80000000;
+    *(u8  *)(p + 5) = 0x0f; /* vmcall/vmmcall */
+    *(u8  *)(p + 6) = 0x01;
+    *(u8  *)(p + 7) = ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
+                       ? 0xc1 : 0xd9);
+    *(u8  *)(p + 8) = 0xc3; /* ret */
+    memset(p + 9, 0xcc, PAGE_SIZE - 9); /* int3, int3, ... */
+
+    unmap_domain_page(p);
+
+    put_page_and_type(mfn_to_page(mfn));
+}
+
+int wrmsr_viridian_regs(uint32_t idx, uint32_t eax, uint32_t edx)
+{
+    struct domain *d = current->domain;
+    uint64_t val = ((uint64_t)edx << 32) | eax;
+
+    if ( !is_viridian_domain(d) )
+        return 0;
+
+    switch ( idx )
+    {
+    case VIRIDIAN_MSR_GUEST_OS_ID:
+        perfc_incr(mshv_wrmsr_osid);
+        d->arch.hvm_domain.viridian.guest_os_id.raw = val;
+        gdprintk(XENLOG_INFO, "Guest os:\n");
+        gdprintk(XENLOG_INFO, "\tvendor: %x\n",
+               d->arch.hvm_domain.viridian.guest_os_id.fields.vendor);
+        gdprintk(XENLOG_INFO, "\tos: %x\n",
+               d->arch.hvm_domain.viridian.guest_os_id.fields.os);
+        gdprintk(XENLOG_INFO, "\tmajor: %x\n",
+               d->arch.hvm_domain.viridian.guest_os_id.fields.major);
+        gdprintk(XENLOG_INFO, "\tminor: %x\n",
+               d->arch.hvm_domain.viridian.guest_os_id.fields.minor);
+        gdprintk(XENLOG_INFO, "\tsp: %x\n",
+               d->arch.hvm_domain.viridian.guest_os_id.fields.service_pack);
+        gdprintk(XENLOG_INFO, "\tbuild: %x\n",
+               d->arch.hvm_domain.viridian.guest_os_id.fields.build_number);
+        break;
+
+    case VIRIDIAN_MSR_HYPERCALL:
+        perfc_incr(mshv_wrmsr_hc_page);
+        gdprintk(XENLOG_INFO, "Set hypercall page %"PRIx64".\n", val);
+        if ( d->arch.hvm_domain.viridian.guest_os_id.raw == 0 )
+            break;
+        d->arch.hvm_domain.viridian.hypercall_gpa.raw = val;
+        if ( d->arch.hvm_domain.viridian.hypercall_gpa.fields.enabled )
+            enable_hypercall_page();
+        break;
+
+    case VIRIDIAN_MSR_VP_INDEX:
+        perfc_incr(mshv_wrmsr_vp_index);
+        gdprintk(XENLOG_INFO, "Set VP index %"PRIu64".\n", val);
+        break;
+
+    case VIRIDIAN_MSR_EOI:
+        perfc_incr(mshv_wrmsr_eoi);
+        vlapic_EOI_set(vcpu_vlapic(current));
+        break;
+
+    case VIRIDIAN_MSR_ICR: {
+        struct vlapic *vlapic = vcpu_vlapic(current);
+        perfc_incr(mshv_wrmsr_icr);
+        eax &= ~(1 << 12);
+        edx &= 0xff000000;
+        vlapic_set_reg(vlapic, APIC_ICR2, edx);
+        if ( vlapic_ipi(vlapic, eax, edx) == X86EMUL_OKAY )
+            vlapic_set_reg(vlapic, APIC_ICR, eax);
+        break;
+    }
+
+    case VIRIDIAN_MSR_TPR:
+        perfc_incr(mshv_wrmsr_tpr);
+        vlapic_set_reg(vcpu_vlapic(current), APIC_TASKPRI, eax & 0xff);
+        break;
+
+    default:
+        return 0;
+    }
+
+    return 1;
+}
+
+int rdmsr_viridian_regs(uint32_t idx, uint32_t *eax, uint32_t *edx)
+{
+    uint64_t val;
+    struct vcpu *v = current;
+    
+    if ( !is_viridian_domain(v->domain) )
+        return 0;
+
+    switch ( idx )
+    {
+    case VIRIDIAN_MSR_GUEST_OS_ID:
+        perfc_incr(mshv_rdmsr_osid);
+        val = v->domain->arch.hvm_domain.viridian.guest_os_id.raw;
+        break;
+
+    case VIRIDIAN_MSR_HYPERCALL:
+        perfc_incr(mshv_rdmsr_hc_page);
+        val = v->domain->arch.hvm_domain.viridian.hypercall_gpa.raw;
+        break;
+
+    case VIRIDIAN_MSR_VP_INDEX:
+        perfc_incr(mshv_rdmsr_vp_index);
+        val = v->vcpu_id;
+        break;
+
+    case VIRIDIAN_MSR_ICR:
+        perfc_incr(mshv_rdmsr_icr);
+        val = (((uint64_t)vlapic_get_reg(vcpu_vlapic(v), APIC_ICR2) << 32) |
+               vlapic_get_reg(vcpu_vlapic(v), APIC_ICR));
+        break;
+
+    case VIRIDIAN_MSR_TPR:
+        perfc_incr(mshv_rdmsr_tpr);
+        val = vlapic_get_reg(vcpu_vlapic(v), APIC_TASKPRI);
+        break;
+
+    default:
+        return 0;
+    }
+
+    *eax = val;
+    *edx = val >> 32;
+    return 1;
+}
+
+int viridian_hypercall(struct cpu_user_regs *regs)
+{
+    struct domain *d = current->domain;
+    int mode = hvm_guest_x86_mode(current);
+    unsigned long input_params_gpa, output_params_gpa;
+    uint16_t status = HV_STATUS_SUCCESS;
+
+    union hypercall_input {
+        uint64_t raw;
+        struct {
+            uint16_t call_code;
+            uint16_t rsvd1;
+            unsigned rep_count:12;
+            unsigned rsvd2:4;
+            unsigned rep_start:12;
+            unsigned rsvd3:4;
+        };
+    } input;
+
+    union hypercall_output {
+        uint64_t raw;
+        struct {
+            uint16_t result;
+            uint16_t rsvd1;
+            unsigned rep_complete:12;
+            unsigned rsvd2:20;
+        };
+    } output = { 0 };
+
+    ASSERT(is_viridian_domain(d));
+
+    switch ( mode )
+    {
+#ifdef __x86_64__
+    case 8:
+        input.raw = regs->rcx;
+        input_params_gpa = regs->rdx;
+        output_params_gpa = regs->r8;
+        break;
+#endif
+    case 4:
+        input.raw = ((uint64_t)regs->edx << 32) | regs->eax;
+        input_params_gpa = ((uint64_t)regs->ebx << 32) | regs->ecx;
+        output_params_gpa = ((uint64_t)regs->edi << 32) | regs->esi;
+        break;
+    default:
+        goto out;
+    }
+
+    switch ( input.call_code )
+    {
+    case HvNotifyLongSpinWait:
+        perfc_incr(mshv_call_long_wait);
+        do_sched_op_compat(SCHEDOP_yield, 0);
+        status = HV_STATUS_SUCCESS;
+        break;
+    default:
+        status = HV_STATUS_INVALID_HYPERCALL_CODE;
+        break;
+    }
+
+out:
+    output.result = status;
+    switch (mode) {
+#ifdef __x86_64__
+    case 8:
+        regs->rax = output.raw;
+        break;
+#endif
+    default:
+        regs->edx = output.raw >> 32;
+        regs->eax = output.raw;
+        break;
+    }
+
+    return HVM_HCALL_completed;
+}
+
+static int viridian_save_cpu_ctxt(struct domain *d, hvm_domain_context_t *h)
+{
+    struct hvm_viridian_context ctxt;
+
+    if ( !is_viridian_domain(d) )
+        return 0;
+
+    ctxt.hypercall_gpa = d->arch.hvm_domain.viridian.hypercall_gpa.raw;
+    ctxt.guest_os_id   = d->arch.hvm_domain.viridian.guest_os_id.raw;
+
+    return (hvm_save_entry(VIRIDIAN, 0, h, &ctxt) != 0);
+}
+
+static int viridian_load_cpu_ctxt(struct domain *d, hvm_domain_context_t *h)
+{
+    struct hvm_viridian_context ctxt;
+
+    if ( hvm_load_entry(VIRIDIAN, h, &ctxt) != 0 )
+        return -EINVAL;
+
+    d->arch.hvm_domain.viridian.hypercall_gpa.raw = ctxt.hypercall_gpa;
+    d->arch.hvm_domain.viridian.guest_os_id.raw   = ctxt.guest_os_id;
+
+    return 0;
+}
+
+HVM_REGISTER_SAVE_RESTORE(VIRIDIAN, viridian_save_cpu_ctxt,
+                          viridian_load_cpu_ctxt, 1, HVMSR_PER_DOM);
diff -r a26194601c8f -r 8d993552673a xen/arch/x86/hvm/vlapic.c
--- a/xen/arch/x86/hvm/vlapic.c Mon Oct 13 13:15:20 2008 +0100
+++ b/xen/arch/x86/hvm/vlapic.c Tue Oct 14 10:45:29 2008 +0100
@@ -417,7 +417,7 @@ void vlapic_EOI_set(struct vlapic *vlapi
     hvm_dpci_msi_eoi(current->domain, vector);
 }
 
-static int vlapic_ipi(
+int vlapic_ipi(
     struct vlapic *vlapic, uint32_t icr_low, uint32_t icr_high)
 {
     unsigned int dest =         GET_xAPIC_DEST_FIELD(icr_high);
diff -r a26194601c8f -r 8d993552673a xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c        Mon Oct 13 13:15:20 2008 +0100
+++ b/xen/arch/x86/hvm/vmx/vmx.c        Tue Oct 14 10:45:29 2008 +0100
@@ -1677,7 +1677,8 @@ static int vmx_msr_read_intercept(struct
             break;
         }
 
-        if ( rdmsr_hypervisor_regs(ecx, &eax, &edx) ||
+        if ( rdmsr_viridian_regs(ecx, &eax, &edx) ||
+             rdmsr_hypervisor_regs(ecx, &eax, &edx) ||
              rdmsr_safe(ecx, eax, edx) == 0 )
         {
             regs->eax = eax;
@@ -1852,6 +1853,10 @@ static int vmx_msr_write_intercept(struc
     default:
         if ( vpmu_do_wrmsr(regs) )
             return X86EMUL_OKAY;
+
+        if ( wrmsr_viridian_regs(ecx, regs->eax, regs->edx) ) 
+            break;
+
         switch ( long_mode_do_msr_write(regs) )
         {
             case HNDL_unhandled:
diff -r a26194601c8f -r 8d993552673a xen/arch/x86/traps.c
--- a/xen/arch/x86/traps.c      Mon Oct 13 13:15:20 2008 +0100
+++ b/xen/arch/x86/traps.c      Tue Oct 14 10:45:29 2008 +0100
@@ -577,7 +577,11 @@ int rdmsr_hypervisor_regs(
 int rdmsr_hypervisor_regs(
     uint32_t idx, uint32_t *eax, uint32_t *edx)
 {
-    idx -= 0x40000000;
+    struct domain *d = current->domain;
+    /* Optionally shift out of the way of Viridian architectural MSRs. */
+    uint32_t base = is_viridian_domain(d) ? 0x40000200 : 0x40000000;
+
+    idx -= base;
     if ( idx > 0 )
         return 0;
 
@@ -599,8 +603,10 @@ int wrmsr_hypervisor_regs(
     uint32_t idx, uint32_t eax, uint32_t edx)
 {
     struct domain *d = current->domain;
-
-    idx -= 0x40000000;
+    /* Optionally shift out of the way of Viridian architectural MSRs. */
+    uint32_t base = is_viridian_domain(d) ? 0x40000200 : 0x40000000;
+
+    idx -= base;
     if ( idx > 0 )
         return 0;
 
@@ -628,7 +634,7 @@ int wrmsr_hypervisor_regs(
         {
             gdprintk(XENLOG_WARNING,
                      "Bad GMFN %lx (MFN %lx) to MSR %08x\n",
-                     gmfn, mfn, 0x40000000);
+                     gmfn, mfn, base + idx);
             return 0;
         }
 
@@ -650,14 +656,18 @@ int cpuid_hypervisor_leaves(
 int cpuid_hypervisor_leaves(
     uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
 {
-    idx -= 0x40000000;
-    if ( idx > 2 )
+    struct domain *d = current->domain;
+    /* Optionally shift out of the way of Viridian architectural leaves. */
+    uint32_t base = is_viridian_domain(d) ? 0x40000100 : 0x40000000;
+
+    idx -= base;
+    if ( idx > 2 ) 
         return 0;
 
     switch ( idx )
     {
     case 0:
-        *eax = 0x40000002; /* Largest leaf */
+        *eax = base + 2; /* Largest leaf */
         *ebx = XEN_CPUID_SIGNATURE_EBX;
         *ecx = XEN_CPUID_SIGNATURE_ECX;
         *edx = XEN_CPUID_SIGNATURE_EDX;
@@ -673,6 +683,8 @@ int cpuid_hypervisor_leaves(
     case 2:
         *eax = 1;          /* Number of hypercall-transfer pages */
         *ebx = 0x40000000; /* MSR base address */
+        if ( is_viridian_domain(d) )
+            *ebx = 0x40000200;
         *ecx = 0;          /* Features 1 */
         *edx = 0;          /* Features 2 */
         if ( !is_hvm_vcpu(current) )
diff -r a26194601c8f -r 8d993552673a xen/arch/x86/x86_emulate/x86_emulate.c
--- a/xen/arch/x86/x86_emulate/x86_emulate.c    Mon Oct 13 13:15:20 2008 +0100
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c    Tue Oct 14 10:45:29 2008 +0100
@@ -24,8 +24,9 @@
 /* Operand sizes: 8-bit operands or specified/overridden size. */
 #define ByteOp      (1<<0) /* 8-bit operands. */
 /* Destination operand type. */
-#define DstBitBase  (0<<1) /* Memory operand, bit string. */
-#define ImplicitOps (1<<1) /* Implicit in opcode. No generic decode. */
+#define DstNone     (0<<1) /* No destination operand. */
+#define DstImplicit (0<<1) /* Destination operand is implicit in the opcode. */
+#define DstBitBase  (1<<1) /* Memory operand, bit string. */
 #define DstReg      (2<<1) /* Register operand. */
 #define DstMem      (3<<1) /* Memory operand. */
 #define DstMask     (3<<1)
@@ -42,6 +43,8 @@
 #define ModRM       (1<<6)
 /* Destination is only written; never read. */
 #define Mov         (1<<7)
+/* All operands are implicit in the opcode. */
+#define ImplicitOps (DstImplicit|SrcImplicit)
 
 static uint8_t opcode_table[256] = {
     /* 0x00 - 0x07 */
@@ -1174,13 +1177,12 @@ x86_emulate(
     int override_seg = -1, rc = X86EMUL_OKAY;
     struct operand src, dst;
 
-    /* Data operand effective address (usually computed from ModRM). */
-    struct operand ea;
-
-    /* Default is a memory operand relative to segment DS. */
-    ea.type    = OP_MEM;
-    ea.mem.seg = x86_seg_ds;
-    ea.mem.off = 0;
+    /*
+     * Data operand effective address (usually computed from ModRM).
+     * Default is a memory operand relative to segment DS.
+     */
+    struct operand ea = { .type = OP_MEM };
+    ea.mem.seg = x86_seg_ds; /* gcc may reject anon union initializer */
 
     ctxt->retire.byte = 0;
 
@@ -1408,14 +1410,11 @@ x86_emulate(
     if ( override_seg != -1 )
         ea.mem.seg = override_seg;
 
-    /* Special instructions do their own operand decoding. */
-    if ( (d & DstMask) == ImplicitOps )
-        goto special_insn;
-
     /* Decode and fetch the source operand: register, memory or immediate. */
     switch ( d & SrcMask )
     {
-    case SrcNone:
+    case SrcNone: /* case SrcImplicit: */
+        src.type = OP_NONE;
         break;
     case SrcReg:
         src.type = OP_REG;
@@ -1479,7 +1478,21 @@ x86_emulate(
     /* Decode and fetch the destination operand: register or memory. */
     switch ( d & DstMask )
     {
+    case DstNone: /* case DstImplicit: */
+        /*
+         * The only implicit-operands instructions allowed a LOCK prefix are
+         * CMPXCHG{8,16}B, MOV CRn, MOV DRn.
+         */
+        generate_exception_if(
+            lock_prefix &&
+            ((b < 0x20) || (b > 0x23)) && /* MOV CRn/DRn */
+            (b != 0xc7),                  /* CMPXCHG{8,16}B */
+            EXC_GP, 0);
+        dst.type = OP_NONE;
+        break;
+
     case DstReg:
+        generate_exception_if(lock_prefix, EXC_GP, 0);
         dst.type = OP_REG;
         if ( d & ByteOp )
         {
@@ -1535,6 +1548,7 @@ x86_emulate(
         dst = ea;
         if ( dst.type == OP_REG )
         {
+            generate_exception_if(lock_prefix, EXC_GP, 0);
             switch ( dst.bytes )
             {
             case 1: dst.val = *(uint8_t  *)dst.reg; break;
@@ -1553,9 +1567,6 @@ x86_emulate(
         break;
     }
 
-    /* LOCK prefix allowed only on instructions with memory destination. */
-    generate_exception_if(lock_prefix && (dst.type != OP_MEM), EXC_GP, 0);
-
     if ( twobyte )
         goto twobyte_insn;
 
@@ -1618,583 +1629,6 @@ x86_emulate(
         dst.type = OP_NONE;
         break;
 
-    case 0x62: /* bound */ {
-        unsigned long src_val2;
-        int lb, ub, idx;
-        generate_exception_if(mode_64bit() || (src.type != OP_MEM),
-                              EXC_UD, -1);
-        if ( (rc = read_ulong(src.mem.seg, src.mem.off + op_bytes,
-                              &src_val2, op_bytes, ctxt, ops)) )
-            goto done;
-        ub  = (op_bytes == 2) ? (int16_t)src_val2 : (int32_t)src_val2;
-        lb  = (op_bytes == 2) ? (int16_t)src.val  : (int32_t)src.val;
-        idx = (op_bytes == 2) ? (int16_t)dst.val  : (int32_t)dst.val;
-        generate_exception_if((idx < lb) || (idx > ub), EXC_BR, -1);
-        dst.type = OP_NONE;
-        break;
-    }
-
-    case 0x63: /* movsxd (x86/64) / arpl (x86/32) */
-        if ( mode_64bit() )
-        {
-            /* movsxd */
-            if ( src.type == OP_REG )
-                src.val = *(int32_t *)src.reg;
-            else if ( (rc = read_ulong(src.mem.seg, src.mem.off,
-                                       &src.val, 4, ctxt, ops)) )
-                goto done;
-            dst.val = (int32_t)src.val;
-        }
-        else
-        {
-            /* arpl */
-            uint16_t src_val = dst.val;
-            dst = src;
-            _regs.eflags &= ~EFLG_ZF;
-            _regs.eflags |= ((src_val & 3) > (dst.val & 3)) ? EFLG_ZF : 0;
-            if ( _regs.eflags & EFLG_ZF )
-                dst.val  = (dst.val & ~3) | (src_val & 3);
-            else
-                dst.type = OP_NONE;
-            generate_exception_if(!in_protmode(ctxt, ops), EXC_UD, -1);
-        }
-        break;
-
-    case 0x69: /* imul imm16/32 */
-    case 0x6b: /* imul imm8 */ {
-        unsigned long src1; /* ModR/M source operand */
-        if ( ea.type == OP_REG )
-            src1 = *ea.reg;
-        else if ( (rc = read_ulong(ea.mem.seg, ea.mem.off,
-                                   &src1, op_bytes, ctxt, ops)) )
-            goto done;
-        _regs.eflags &= ~(EFLG_OF|EFLG_CF);
-        switch ( dst.bytes )
-        {
-        case 2:
-            dst.val = ((uint32_t)(int16_t)src.val *
-                       (uint32_t)(int16_t)src1);
-            if ( (int16_t)dst.val != (uint32_t)dst.val )
-                _regs.eflags |= EFLG_OF|EFLG_CF;
-            break;
-#ifdef __x86_64__
-        case 4:
-            dst.val = ((uint64_t)(int32_t)src.val *
-                       (uint64_t)(int32_t)src1);
-            if ( (int32_t)dst.val != dst.val )
-                _regs.eflags |= EFLG_OF|EFLG_CF;
-            break;
-#endif
-        default: {
-            unsigned long m[2] = { src.val, src1 };
-            if ( imul_dbl(m) )
-                _regs.eflags |= EFLG_OF|EFLG_CF;
-            dst.val = m[0];
-            break;
-        }
-        }
-        break;
-    }
-
-    case 0x82: /* Grp1 (x86/32 only) */
-        generate_exception_if(mode_64bit(), EXC_UD, -1);
-    case 0x80: case 0x81: case 0x83: /* Grp1 */
-        switch ( modrm_reg & 7 )
-        {
-        case 0: goto add;
-        case 1: goto or;
-        case 2: goto adc;
-        case 3: goto sbb;
-        case 4: goto and;
-        case 5: goto sub;
-        case 6: goto xor;
-        case 7: goto cmp;
-        }
-        break;
-
-    case 0xa8 ... 0xa9: /* test imm,%%eax */
-        dst.reg = (unsigned long *)&_regs.eax;
-        dst.val = _regs.eax;
-    case 0x84 ... 0x85: test: /* test */
-        emulate_2op_SrcV("test", src, dst, _regs.eflags);
-        dst.type = OP_NONE;
-        break;
-
-    case 0x86 ... 0x87: xchg: /* xchg */
-        /* Write back the register source. */
-        switch ( dst.bytes )
-        {
-        case 1: *(uint8_t  *)src.reg = (uint8_t)dst.val; break;
-        case 2: *(uint16_t *)src.reg = (uint16_t)dst.val; break;
-        case 4: *src.reg = (uint32_t)dst.val; break; /* 64b reg: zero-extend */
-        case 8: *src.reg = dst.val; break;
-        }
-        /* Write back the memory destination with implicit LOCK prefix. */
-        dst.val = src.val;
-        lock_prefix = 1;
-        break;
-
-    case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */
-        generate_exception_if((modrm_reg & 7) != 0, EXC_UD, -1);
-    case 0x88 ... 0x8b: /* mov */
-        dst.val = src.val;
-        break;
-
-    case 0x8c: /* mov Sreg,r/m */ {
-        struct segment_register reg;
-        enum x86_segment seg = decode_segment(modrm_reg);
-        generate_exception_if(seg == decode_segment_failed, EXC_UD, -1);
-        fail_if(ops->read_segment == NULL);
-        if ( (rc = ops->read_segment(seg, &reg, ctxt)) != 0 )
-            goto done;
-        dst.val = reg.sel;
-        if ( dst.type == OP_MEM )
-            dst.bytes = 2;
-        break;
-    }
-
-    case 0x8e: /* mov r/m,Sreg */ {
-        enum x86_segment seg = decode_segment(modrm_reg);
-        generate_exception_if(seg == decode_segment_failed, EXC_UD, -1);
-        if ( (rc = load_seg(seg, (uint16_t)src.val, ctxt, ops)) != 0 )
-            goto done;
-        if ( seg == x86_seg_ss )
-            ctxt->retire.flags.mov_ss = 1;
-        dst.type = OP_NONE;
-        break;
-    }
-
-    case 0x8d: /* lea */
-        dst.val = ea.mem.off;
-        break;
-
-    case 0x8f: /* pop (sole member of Grp1a) */
-        generate_exception_if((modrm_reg & 7) != 0, EXC_UD, -1);
-        /* 64-bit mode: POP defaults to a 64-bit operand. */
-        if ( mode_64bit() && (dst.bytes == 4) )
-            dst.bytes = 8;
-        if ( (rc = read_ulong(x86_seg_ss, sp_post_inc(dst.bytes),
-                              &dst.val, dst.bytes, ctxt, ops)) != 0 )
-            goto done;
-        break;
-
-    case 0xb0 ... 0xb7: /* mov imm8,r8 */
-        dst.reg = decode_register(
-            (b & 7) | ((rex_prefix & 1) << 3), &_regs, (rex_prefix == 0));
-        dst.val = src.val;
-        break;
-
-    case 0xb8 ... 0xbf: /* mov imm{16,32,64},r{16,32,64} */
-        if ( dst.bytes == 8 ) /* Fetch more bytes to obtain imm64 */
-            src.val = ((uint32_t)src.val |
-                       ((uint64_t)insn_fetch_type(uint32_t) << 32));
-        dst.reg = decode_register(
-            (b & 7) | ((rex_prefix & 1) << 3), &_regs, 0);
-        dst.val = src.val;
-        break;
-
-    case 0xc0 ... 0xc1: grp2: /* Grp2 */
-        switch ( modrm_reg & 7 )
-        {
-        case 0: /* rol */
-            emulate_2op_SrcB("rol", src, dst, _regs.eflags);
-            break;
-        case 1: /* ror */
-            emulate_2op_SrcB("ror", src, dst, _regs.eflags);
-            break;
-        case 2: /* rcl */
-            emulate_2op_SrcB("rcl", src, dst, _regs.eflags);
-            break;
-        case 3: /* rcr */
-            emulate_2op_SrcB("rcr", src, dst, _regs.eflags);
-            break;
-        case 4: /* sal/shl */
-        case 6: /* sal/shl */
-            emulate_2op_SrcB("sal", src, dst, _regs.eflags);
-            break;
-        case 5: /* shr */
-            emulate_2op_SrcB("shr", src, dst, _regs.eflags);
-            break;
-        case 7: /* sar */
-            emulate_2op_SrcB("sar", src, dst, _regs.eflags);
-            break;
-        }
-        break;
-
-    case 0xc4: /* les */ {
-        unsigned long sel;
-        dst.val = x86_seg_es;
-    les: /* dst.val identifies the segment */
-        generate_exception_if(src.type != OP_MEM, EXC_UD, -1);
-        if ( (rc = read_ulong(src.mem.seg, src.mem.off + src.bytes,
-                              &sel, 2, ctxt, ops)) != 0 )
-            goto done;
-        if ( (rc = load_seg(dst.val, (uint16_t)sel, ctxt, ops)) != 0 )
-            goto done;
-        dst.val = src.val;
-        break;
-    }
-
-    case 0xc5: /* lds */
-        dst.val = x86_seg_ds;
-        goto les;
-
-    case 0xd0 ... 0xd1: /* Grp2 */
-        src.val = 1;
-        goto grp2;
-
-    case 0xd2 ... 0xd3: /* Grp2 */
-        src.val = _regs.ecx;
-        goto grp2;
-
-    case 0xf6 ... 0xf7: /* Grp3 */
-        switch ( modrm_reg & 7 )
-        {
-        case 0 ... 1: /* test */
-            /* Special case in Grp3: test has an immediate source operand. */
-            src.type = OP_IMM;
-            src.bytes = (d & ByteOp) ? 1 : op_bytes;
-            if ( src.bytes == 8 ) src.bytes = 4;
-            switch ( src.bytes )
-            {
-            case 1: src.val = insn_fetch_type(int8_t);  break;
-            case 2: src.val = insn_fetch_type(int16_t); break;
-            case 4: src.val = insn_fetch_type(int32_t); break;
-            }
-            goto test;
-        case 2: /* not */
-            dst.val = ~dst.val;
-            break;
-        case 3: /* neg */
-            emulate_1op("neg", dst, _regs.eflags);
-            break;
-        case 4: /* mul */
-            src = dst;
-            dst.type = OP_REG;
-            dst.reg  = (unsigned long *)&_regs.eax;
-            dst.val  = *dst.reg;
-            _regs.eflags &= ~(EFLG_OF|EFLG_CF);
-            switch ( src.bytes )
-            {
-            case 1:
-                dst.val = (uint8_t)dst.val;
-                dst.val *= src.val;
-                if ( (uint8_t)dst.val != (uint16_t)dst.val )
-                    _regs.eflags |= EFLG_OF|EFLG_CF;
-                dst.bytes = 2;
-                break;
-            case 2:
-                dst.val = (uint16_t)dst.val;
-                dst.val *= src.val;
-                if ( (uint16_t)dst.val != (uint32_t)dst.val )
-                    _regs.eflags |= EFLG_OF|EFLG_CF;
-                *(uint16_t *)&_regs.edx = dst.val >> 16;
-                break;
-#ifdef __x86_64__
-            case 4:
-                dst.val = (uint32_t)dst.val;
-                dst.val *= src.val;
-                if ( (uint32_t)dst.val != dst.val )
-                    _regs.eflags |= EFLG_OF|EFLG_CF;
-                _regs.edx = (uint32_t)(dst.val >> 32);
-                break;
-#endif
-            default: {
-                unsigned long m[2] = { src.val, dst.val };
-                if ( mul_dbl(m) )
-                    _regs.eflags |= EFLG_OF|EFLG_CF;
-                _regs.edx = m[1];
-                dst.val  = m[0];
-                break;
-            }
-            }
-            break;
-        case 5: /* imul */
-            src = dst;
-            dst.type = OP_REG;
-            dst.reg  = (unsigned long *)&_regs.eax;
-            dst.val  = *dst.reg;
-            _regs.eflags &= ~(EFLG_OF|EFLG_CF);
-            switch ( src.bytes )
-            {
-            case 1:
-                dst.val = ((uint16_t)(int8_t)src.val *
-                           (uint16_t)(int8_t)dst.val);
-                if ( (int8_t)dst.val != (uint16_t)dst.val )
-                    _regs.eflags |= EFLG_OF|EFLG_CF;
-                dst.bytes = 2;
-                break;
-            case 2:
-                dst.val = ((uint32_t)(int16_t)src.val *
-                           (uint32_t)(int16_t)dst.val);
-                if ( (int16_t)dst.val != (uint32_t)dst.val )
-                    _regs.eflags |= EFLG_OF|EFLG_CF;
-                *(uint16_t *)&_regs.edx = dst.val >> 16;
-                break;
-#ifdef __x86_64__
-            case 4:
-                dst.val = ((uint64_t)(int32_t)src.val *
-                           (uint64_t)(int32_t)dst.val);
-                if ( (int32_t)dst.val != dst.val )
-                    _regs.eflags |= EFLG_OF|EFLG_CF;
-                _regs.edx = (uint32_t)(dst.val >> 32);
-                break;
-#endif
-            default: {
-                unsigned long m[2] = { src.val, dst.val };
-                if ( imul_dbl(m) )
-                    _regs.eflags |= EFLG_OF|EFLG_CF;
-                _regs.edx = m[1];
-                dst.val  = m[0];
-                break;
-            }
-            }
-            break;
-        case 6: /* div */ {
-            unsigned long u[2], v;
-            src = dst;
-            dst.type = OP_REG;
-            dst.reg  = (unsigned long *)&_regs.eax;
-            switch ( src.bytes )
-            {
-            case 1:
-                u[0] = (uint16_t)_regs.eax;
-                u[1] = 0;
-                v    = (uint8_t)src.val;
-                generate_exception_if(
-                    div_dbl(u, v) || ((uint8_t)u[0] != (uint16_t)u[0]),
-                    EXC_DE, -1);
-                dst.val = (uint8_t)u[0];
-                ((uint8_t *)&_regs.eax)[1] = u[1];
-                break;
-            case 2:
-                u[0] = ((uint32_t)_regs.edx << 16) | (uint16_t)_regs.eax;
-                u[1] = 0;
-                v    = (uint16_t)src.val;
-                generate_exception_if(
-                    div_dbl(u, v) || ((uint16_t)u[0] != (uint32_t)u[0]),
-                    EXC_DE, -1);
-                dst.val = (uint16_t)u[0];
-                *(uint16_t *)&_regs.edx = u[1];
-                break;
-#ifdef __x86_64__
-            case 4:
-                u[0] = (_regs.edx << 32) | (uint32_t)_regs.eax;
-                u[1] = 0;
-                v    = (uint32_t)src.val;
-                generate_exception_if(
-                    div_dbl(u, v) || ((uint32_t)u[0] != u[0]),
-                    EXC_DE, -1);
-                dst.val   = (uint32_t)u[0];
-                _regs.edx = (uint32_t)u[1];
-                break;
-#endif
-            default:
-                u[0] = _regs.eax;
-                u[1] = _regs.edx;
-                v    = src.val;
-                generate_exception_if(div_dbl(u, v), EXC_DE, -1);
-                dst.val   = u[0];
-                _regs.edx = u[1];
-                break;
-            }
-            break;
-        }
-        case 7: /* idiv */ {
-            unsigned long u[2], v;
-            src = dst;
-            dst.type = OP_REG;
-            dst.reg  = (unsigned long *)&_regs.eax;
-            switch ( src.bytes )
-            {
-            case 1:
-                u[0] = (int16_t)_regs.eax;
-                u[1] = ((long)u[0] < 0) ? ~0UL : 0UL;
-                v    = (int8_t)src.val;
-                generate_exception_if(
-                    idiv_dbl(u, v) || ((int8_t)u[0] != (int16_t)u[0]),
-                    EXC_DE, -1);
-                dst.val = (int8_t)u[0];
-                ((int8_t *)&_regs.eax)[1] = u[1];
-                break;
-            case 2:
-                u[0] = (int32_t)((_regs.edx << 16) | (uint16_t)_regs.eax);
-                u[1] = ((long)u[0] < 0) ? ~0UL : 0UL;
-                v    = (int16_t)src.val;
-                generate_exception_if(
-                    idiv_dbl(u, v) || ((int16_t)u[0] != (int32_t)u[0]),
-                    EXC_DE, -1);
-                dst.val = (int16_t)u[0];
-                *(int16_t *)&_regs.edx = u[1];
-                break;
-#ifdef __x86_64__
-            case 4:
-                u[0] = (_regs.edx << 32) | (uint32_t)_regs.eax;
-                u[1] = ((long)u[0] < 0) ? ~0UL : 0UL;
-                v    = (int32_t)src.val;
-                generate_exception_if(
-                    idiv_dbl(u, v) || ((int32_t)u[0] != u[0]),
-                    EXC_DE, -1);
-                dst.val   = (int32_t)u[0];
-                _regs.edx = (uint32_t)u[1];
-                break;
-#endif
-            default:
-                u[0] = _regs.eax;
-                u[1] = _regs.edx;
-                v    = src.val;
-                generate_exception_if(idiv_dbl(u, v), EXC_DE, -1);
-                dst.val   = u[0];
-                _regs.edx = u[1];
-                break;
-            }
-            break;
-        }
-        default:
-            goto cannot_emulate;
-        }
-        break;
-
-    case 0xfe: /* Grp4 */
-        generate_exception_if((modrm_reg & 7) >= 2, EXC_UD, -1);
-    case 0xff: /* Grp5 */
-        switch ( modrm_reg & 7 )
-        {
-        case 0: /* inc */
-            emulate_1op("inc", dst, _regs.eflags);
-            break;
-        case 1: /* dec */
-            emulate_1op("dec", dst, _regs.eflags);
-            break;
-        case 2: /* call (near) */
-        case 4: /* jmp (near) */
-            if ( (dst.bytes != 8) && mode_64bit() )
-            {
-                dst.bytes = op_bytes = 8;
-                if ( dst.type == OP_REG )
-                    dst.val = *dst.reg;
-                else if ( (rc = read_ulong(dst.mem.seg, dst.mem.off,
-                                           &dst.val, 8, ctxt, ops)) != 0 )
-                    goto done;
-            }
-            src.val = _regs.eip;
-            _regs.eip = dst.val;
-            if ( (modrm_reg & 7) == 2 )
-                goto push; /* call */
-            dst.type = OP_NONE;
-            break;
-        case 3: /* call (far, absolute indirect) */
-        case 5: /* jmp (far, absolute indirect) */ {
-            unsigned long sel;
-
-            generate_exception_if(dst.type != OP_MEM, EXC_UD, -1);
-
-            if ( (rc = read_ulong(dst.mem.seg, dst.mem.off+dst.bytes,
-                                  &sel, 2, ctxt, ops)) )
-                goto done;
-
-            if ( (modrm_reg & 7) == 3 ) /* call */
-            {
-                struct segment_register reg;
-                fail_if(ops->read_segment == NULL);
-                if ( (rc = ops->read_segment(x86_seg_cs, &reg, ctxt)) ||
-                     (rc = ops->write(x86_seg_ss, sp_pre_dec(op_bytes),
-                                      &reg.sel, op_bytes, ctxt)) ||
-                     (rc = ops->write(x86_seg_ss, sp_pre_dec(op_bytes),
-                                      &_regs.eip, op_bytes, ctxt)) )
-                    goto done;
-            }
-
-            if ( (rc = load_seg(x86_seg_cs, sel, ctxt, ops)) != 0 )
-                goto done;
-            _regs.eip = dst.val;
-
-            dst.type = OP_NONE;
-            break;
-        }
-        case 6: /* push */
-            /* 64-bit mode: PUSH defaults to a 64-bit operand. */
-            if ( mode_64bit() && (dst.bytes == 4) )
-            {
-                dst.bytes = 8;
-                if ( dst.type == OP_REG )
-                    dst.val = *dst.reg;
-                else if ( (rc = read_ulong(dst.mem.seg, dst.mem.off,
-                                           &dst.val, 8, ctxt, ops)) != 0 )
-                    goto done;
-            }
-            if ( (rc = ops->write(x86_seg_ss, sp_pre_dec(dst.bytes),
-                                  &dst.val, dst.bytes, ctxt)) != 0 )
-                goto done;
-            dst.type = OP_NONE;
-            break;
-        case 7:
-            generate_exception_if(1, EXC_UD, -1);
-        default:
-            goto cannot_emulate;
-        }
-        break;
-    }
-
- writeback:
-    switch ( dst.type )
-    {
-    case OP_REG:
-        /* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */
-        switch ( dst.bytes )
-        {
-        case 1: *(uint8_t  *)dst.reg = (uint8_t)dst.val; break;
-        case 2: *(uint16_t *)dst.reg = (uint16_t)dst.val; break;
-        case 4: *dst.reg = (uint32_t)dst.val; break; /* 64b: zero-ext */
-        case 8: *dst.reg = dst.val; break;
-        }
-        break;
-    case OP_MEM:
-        if ( !(d & Mov) && (dst.orig_val == dst.val) &&
-             !ctxt->force_writeback )
-            /* nothing to do */;
-        else if ( lock_prefix )
-            rc = ops->cmpxchg(
-                dst.mem.seg, dst.mem.off, &dst.orig_val,
-                &dst.val, dst.bytes, ctxt);
-        else
-            rc = ops->write(
-                dst.mem.seg, dst.mem.off, &dst.val, dst.bytes, ctxt);
-        if ( rc != 0 )
-            goto done;
-    default:
-        break;
-    }
-
-    /* Inject #DB if single-step tracing was enabled at instruction start. */
-    if ( (ctxt->regs->eflags & EFLG_TF) && (rc == X86EMUL_OKAY) &&
-         (ops->inject_hw_exception != NULL) )
-        rc = ops->inject_hw_exception(EXC_DB, -1, ctxt) ? : X86EMUL_EXCEPTION;
-
-    /* Commit shadow register state. */
-    _regs.eflags &= ~EFLG_RF;
-    *ctxt->regs = _regs;
-
- done:
-    return rc;
-
- special_insn:
-    dst.type = OP_NONE;
-
-    /*
-     * The only implicit-operands instructions allowed a LOCK prefix are
-     * CMPXCHG{8,16}B, MOV CRn, MOV DRn.
-     */
-    generate_exception_if(lock_prefix &&
-                          ((b < 0x20) || (b > 0x23)) && /* MOV CRn/DRn */
-                          (b != 0xc7),                  /* CMPXCHG{8,16}B */
-                          EXC_GP, 0);
-
-    if ( twobyte )
-        goto twobyte_special_insn;
-
-    switch ( b )
-    {
     case 0x06: /* push %%es */ {
         struct segment_register reg;
         src.val = x86_seg_es;
@@ -2370,11 +1804,89 @@ x86_emulate(
         break;
     }
 
+    case 0x62: /* bound */ {
+        unsigned long src_val2;
+        int lb, ub, idx;
+        generate_exception_if(mode_64bit() || (src.type != OP_MEM),
+                              EXC_UD, -1);
+        if ( (rc = read_ulong(src.mem.seg, src.mem.off + op_bytes,
+                              &src_val2, op_bytes, ctxt, ops)) )
+            goto done;
+        ub  = (op_bytes == 2) ? (int16_t)src_val2 : (int32_t)src_val2;
+        lb  = (op_bytes == 2) ? (int16_t)src.val  : (int32_t)src.val;
+        idx = (op_bytes == 2) ? (int16_t)dst.val  : (int32_t)dst.val;
+        generate_exception_if((idx < lb) || (idx > ub), EXC_BR, -1);
+        dst.type = OP_NONE;
+        break;
+    }
+
+    case 0x63: /* movsxd (x86/64) / arpl (x86/32) */
+        if ( mode_64bit() )
+        {
+            /* movsxd */
+            if ( src.type == OP_REG )
+                src.val = *(int32_t *)src.reg;
+            else if ( (rc = read_ulong(src.mem.seg, src.mem.off,
+                                       &src.val, 4, ctxt, ops)) )
+                goto done;
+            dst.val = (int32_t)src.val;
+        }
+        else
+        {
+            /* arpl */
+            uint16_t src_val = dst.val;
+            dst = src;
+            _regs.eflags &= ~EFLG_ZF;
+            _regs.eflags |= ((src_val & 3) > (dst.val & 3)) ? EFLG_ZF : 0;
+            if ( _regs.eflags & EFLG_ZF )
+                dst.val  = (dst.val & ~3) | (src_val & 3);
+            else
+                dst.type = OP_NONE;
+            generate_exception_if(!in_protmode(ctxt, ops), EXC_UD, -1);
+        }
+        break;
+
     case 0x68: /* push imm{16,32,64} */
         src.val = ((op_bytes == 2)
                    ? (int32_t)insn_fetch_type(int16_t)
                    : insn_fetch_type(int32_t));
         goto push;
+
+    case 0x69: /* imul imm16/32 */
+    case 0x6b: /* imul imm8 */ {
+        unsigned long src1; /* ModR/M source operand */
+        if ( ea.type == OP_REG )
+            src1 = *ea.reg;
+        else if ( (rc = read_ulong(ea.mem.seg, ea.mem.off,
+                                   &src1, op_bytes, ctxt, ops)) )
+            goto done;
+        _regs.eflags &= ~(EFLG_OF|EFLG_CF);
+        switch ( dst.bytes )
+        {
+        case 2:
+            dst.val = ((uint32_t)(int16_t)src.val *
+                       (uint32_t)(int16_t)src1);
+            if ( (int16_t)dst.val != (uint32_t)dst.val )
+                _regs.eflags |= EFLG_OF|EFLG_CF;
+            break;
+#ifdef __x86_64__
+        case 4:
+            dst.val = ((uint64_t)(int32_t)src.val *
+                       (uint64_t)(int32_t)src1);
+            if ( (int32_t)dst.val != dst.val )
+                _regs.eflags |= EFLG_OF|EFLG_CF;
+            break;
+#endif
+        default: {
+            unsigned long m[2] = { src.val, src1 };
+            if ( imul_dbl(m) )
+                _regs.eflags |= EFLG_OF|EFLG_CF;
+            dst.val = m[0];
+            break;
+        }
+        }
+        break;
+    }
 
     case 0x6a: /* push imm8 */
         src.val = insn_fetch_type(int8_t);
@@ -2457,6 +1969,88 @@ x86_emulate(
         break;
     }
 
+    case 0x82: /* Grp1 (x86/32 only) */
+        generate_exception_if(mode_64bit(), EXC_UD, -1);
+    case 0x80: case 0x81: case 0x83: /* Grp1 */
+        switch ( modrm_reg & 7 )
+        {
+        case 0: goto add;
+        case 1: goto or;
+        case 2: goto adc;
+        case 3: goto sbb;
+        case 4: goto and;
+        case 5: goto sub;
+        case 6: goto xor;
+        case 7: goto cmp;
+        }
+        break;
+
+    case 0xa8 ... 0xa9: /* test imm,%%eax */
+        dst.reg = (unsigned long *)&_regs.eax;
+        dst.val = _regs.eax;
+    case 0x84 ... 0x85: test: /* test */
+        emulate_2op_SrcV("test", src, dst, _regs.eflags);
+        dst.type = OP_NONE;
+        break;
+
+    case 0x86 ... 0x87: xchg: /* xchg */
+        /* Write back the register source. */
+        switch ( dst.bytes )
+        {
+        case 1: *(uint8_t  *)src.reg = (uint8_t)dst.val; break;
+        case 2: *(uint16_t *)src.reg = (uint16_t)dst.val; break;
+        case 4: *src.reg = (uint32_t)dst.val; break; /* 64b reg: zero-extend */
+        case 8: *src.reg = dst.val; break;
+        }
+        /* Write back the memory destination with implicit LOCK prefix. */
+        dst.val = src.val;
+        lock_prefix = 1;
+        break;
+
+    case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */
+        generate_exception_if((modrm_reg & 7) != 0, EXC_UD, -1);
+    case 0x88 ... 0x8b: /* mov */
+        dst.val = src.val;
+        break;
+
+    case 0x8c: /* mov Sreg,r/m */ {
+        struct segment_register reg;
+        enum x86_segment seg = decode_segment(modrm_reg);
+        generate_exception_if(seg == decode_segment_failed, EXC_UD, -1);
+        fail_if(ops->read_segment == NULL);
+        if ( (rc = ops->read_segment(seg, &reg, ctxt)) != 0 )
+            goto done;
+        dst.val = reg.sel;
+        if ( dst.type == OP_MEM )
+            dst.bytes = 2;
+        break;
+    }
+
+    case 0x8e: /* mov r/m,Sreg */ {
+        enum x86_segment seg = decode_segment(modrm_reg);
+        generate_exception_if(seg == decode_segment_failed, EXC_UD, -1);
+        if ( (rc = load_seg(seg, (uint16_t)src.val, ctxt, ops)) != 0 )
+            goto done;
+        if ( seg == x86_seg_ss )
+            ctxt->retire.flags.mov_ss = 1;
+        dst.type = OP_NONE;
+        break;
+    }
+
+    case 0x8d: /* lea */
+        dst.val = ea.mem.off;
+        break;
+
+    case 0x8f: /* pop (sole member of Grp1a) */
+        generate_exception_if((modrm_reg & 7) != 0, EXC_UD, -1);
+        /* 64-bit mode: POP defaults to a 64-bit operand. */
+        if ( mode_64bit() && (dst.bytes == 4) )
+            dst.bytes = 8;
+        if ( (rc = read_ulong(x86_seg_ss, sp_post_inc(dst.bytes),
+                              &dst.val, dst.bytes, ctxt, ops)) != 0 )
+            goto done;
+        break;
+
     case 0x90: /* nop / xchg %%r8,%%rax */
         if ( !(rex_prefix & 1) )
             break; /* nop */
@@ -2673,6 +2267,49 @@ x86_emulate(
         break;
     }
 
+    case 0xb0 ... 0xb7: /* mov imm8,r8 */
+        dst.reg = decode_register(
+            (b & 7) | ((rex_prefix & 1) << 3), &_regs, (rex_prefix == 0));
+        dst.val = src.val;
+        break;
+
+    case 0xb8 ... 0xbf: /* mov imm{16,32,64},r{16,32,64} */
+        if ( dst.bytes == 8 ) /* Fetch more bytes to obtain imm64 */
+            src.val = ((uint32_t)src.val |
+                       ((uint64_t)insn_fetch_type(uint32_t) << 32));
+        dst.reg = decode_register(
+            (b & 7) | ((rex_prefix & 1) << 3), &_regs, 0);
+        dst.val = src.val;
+        break;
+
+    case 0xc0 ... 0xc1: grp2: /* Grp2 */
+        switch ( modrm_reg & 7 )
+        {
+        case 0: /* rol */
+            emulate_2op_SrcB("rol", src, dst, _regs.eflags);
+            break;
+        case 1: /* ror */
+            emulate_2op_SrcB("ror", src, dst, _regs.eflags);
+            break;
+        case 2: /* rcl */
+            emulate_2op_SrcB("rcl", src, dst, _regs.eflags);
+            break;
+        case 3: /* rcr */
+            emulate_2op_SrcB("rcr", src, dst, _regs.eflags);
+            break;
+        case 4: /* sal/shl */
+        case 6: /* sal/shl */
+            emulate_2op_SrcB("sal", src, dst, _regs.eflags);
+            break;
+        case 5: /* shr */
+            emulate_2op_SrcB("shr", src, dst, _regs.eflags);
+            break;
+        case 7: /* sar */
+            emulate_2op_SrcB("sar", src, dst, _regs.eflags);
+            break;
+        }
+        break;
+
     case 0xc2: /* ret imm16 (near) */
     case 0xc3: /* ret (near) */ {
         int offset = (b == 0xc2) ? insn_fetch_type(uint16_t) : 0;
@@ -2683,6 +2320,24 @@ x86_emulate(
         _regs.eip = dst.val;
         break;
     }
+
+    case 0xc4: /* les */ {
+        unsigned long sel;
+        dst.val = x86_seg_es;
+    les: /* dst.val identifies the segment */
+        generate_exception_if(src.type != OP_MEM, EXC_UD, -1);
+        if ( (rc = read_ulong(src.mem.seg, src.mem.off + src.bytes,
+                              &sel, 2, ctxt, ops)) != 0 )
+            goto done;
+        if ( (rc = load_seg(dst.val, (uint16_t)sel, ctxt, ops)) != 0 )
+            goto done;
+        dst.val = src.val;
+        break;
+    }
+
+    case 0xc5: /* lds */
+        dst.val = x86_seg_ds;
+        goto les;
 
     case 0xc8: /* enter imm16,imm8 */ {
         uint16_t size = insn_fetch_type(uint16_t);
@@ -2799,6 +2454,14 @@ x86_emulate(
             goto done;
         break;
     }
+
+    case 0xd0 ... 0xd1: /* Grp2 */
+        src.val = 1;
+        goto grp2;
+
+    case 0xd2 ... 0xd3: /* Grp2 */
+        src.val = _regs.ecx;
+        goto grp2;
 
     case 0xd4: /* aam */ {
         unsigned int base = insn_fetch_type(uint8_t);
@@ -3436,6 +3099,214 @@ x86_emulate(
         _regs.eflags ^= EFLG_CF;
         break;
 
+    case 0xf6 ... 0xf7: /* Grp3 */
+        switch ( modrm_reg & 7 )
+        {
+        case 0 ... 1: /* test */
+            /* Special case in Grp3: test has an immediate source operand. */
+            src.type = OP_IMM;
+            src.bytes = (d & ByteOp) ? 1 : op_bytes;
+            if ( src.bytes == 8 ) src.bytes = 4;
+            switch ( src.bytes )
+            {
+            case 1: src.val = insn_fetch_type(int8_t);  break;
+            case 2: src.val = insn_fetch_type(int16_t); break;
+            case 4: src.val = insn_fetch_type(int32_t); break;
+            }
+            goto test;
+        case 2: /* not */
+            dst.val = ~dst.val;
+            break;
+        case 3: /* neg */
+            emulate_1op("neg", dst, _regs.eflags);
+            break;
+        case 4: /* mul */
+            src = dst;
+            dst.type = OP_REG;
+            dst.reg  = (unsigned long *)&_regs.eax;
+            dst.val  = *dst.reg;
+            _regs.eflags &= ~(EFLG_OF|EFLG_CF);
+            switch ( src.bytes )
+            {
+            case 1:
+                dst.val = (uint8_t)dst.val;
+                dst.val *= src.val;
+                if ( (uint8_t)dst.val != (uint16_t)dst.val )
+                    _regs.eflags |= EFLG_OF|EFLG_CF;
+                dst.bytes = 2;
+                break;
+            case 2:
+                dst.val = (uint16_t)dst.val;
+                dst.val *= src.val;
+                if ( (uint16_t)dst.val != (uint32_t)dst.val )
+                    _regs.eflags |= EFLG_OF|EFLG_CF;
+                *(uint16_t *)&_regs.edx = dst.val >> 16;
+                break;
+#ifdef __x86_64__
+            case 4:
+                dst.val = (uint32_t)dst.val;
+                dst.val *= src.val;
+                if ( (uint32_t)dst.val != dst.val )
+                    _regs.eflags |= EFLG_OF|EFLG_CF;
+                _regs.edx = (uint32_t)(dst.val >> 32);
+                break;
+#endif
+            default: {
+                unsigned long m[2] = { src.val, dst.val };
+                if ( mul_dbl(m) )
+                    _regs.eflags |= EFLG_OF|EFLG_CF;
+                _regs.edx = m[1];
+                dst.val  = m[0];
+                break;
+            }
+            }
+            break;
+        case 5: /* imul */
+            src = dst;
+            dst.type = OP_REG;
+            dst.reg  = (unsigned long *)&_regs.eax;
+            dst.val  = *dst.reg;
+            _regs.eflags &= ~(EFLG_OF|EFLG_CF);
+            switch ( src.bytes )
+            {
+            case 1:
+                dst.val = ((uint16_t)(int8_t)src.val *
+                           (uint16_t)(int8_t)dst.val);
+                if ( (int8_t)dst.val != (uint16_t)dst.val )
+                    _regs.eflags |= EFLG_OF|EFLG_CF;
+                dst.bytes = 2;
+                break;
+            case 2:
+                dst.val = ((uint32_t)(int16_t)src.val *
+                           (uint32_t)(int16_t)dst.val);
+                if ( (int16_t)dst.val != (uint32_t)dst.val )
+                    _regs.eflags |= EFLG_OF|EFLG_CF;
+                *(uint16_t *)&_regs.edx = dst.val >> 16;
+                break;
+#ifdef __x86_64__
+            case 4:
+                dst.val = ((uint64_t)(int32_t)src.val *
+                           (uint64_t)(int32_t)dst.val);
+                if ( (int32_t)dst.val != dst.val )
+                    _regs.eflags |= EFLG_OF|EFLG_CF;
+                _regs.edx = (uint32_t)(dst.val >> 32);
+                break;
+#endif
+            default: {
+                unsigned long m[2] = { src.val, dst.val };
+                if ( imul_dbl(m) )
+                    _regs.eflags |= EFLG_OF|EFLG_CF;
+                _regs.edx = m[1];
+                dst.val  = m[0];
+                break;
+            }
+            }
+            break;
+        case 6: /* div */ {
+            unsigned long u[2], v;
+            src = dst;
+            dst.type = OP_REG;
+            dst.reg  = (unsigned long *)&_regs.eax;
+            switch ( src.bytes )
+            {
+            case 1:
+                u[0] = (uint16_t)_regs.eax;
+                u[1] = 0;
+                v    = (uint8_t)src.val;
+                generate_exception_if(
+                    div_dbl(u, v) || ((uint8_t)u[0] != (uint16_t)u[0]),
+                    EXC_DE, -1);
+                dst.val = (uint8_t)u[0];
+                ((uint8_t *)&_regs.eax)[1] = u[1];
+                break;
+            case 2:
+                u[0] = ((uint32_t)_regs.edx << 16) | (uint16_t)_regs.eax;
+                u[1] = 0;
+                v    = (uint16_t)src.val;
+                generate_exception_if(
+                    div_dbl(u, v) || ((uint16_t)u[0] != (uint32_t)u[0]),
+                    EXC_DE, -1);
+                dst.val = (uint16_t)u[0];
+                *(uint16_t *)&_regs.edx = u[1];
+                break;
+#ifdef __x86_64__
+            case 4:
+                u[0] = (_regs.edx << 32) | (uint32_t)_regs.eax;
+                u[1] = 0;
+                v    = (uint32_t)src.val;
+                generate_exception_if(
+                    div_dbl(u, v) || ((uint32_t)u[0] != u[0]),
+                    EXC_DE, -1);
+                dst.val   = (uint32_t)u[0];
+                _regs.edx = (uint32_t)u[1];
+                break;
+#endif
+            default:
+                u[0] = _regs.eax;
+                u[1] = _regs.edx;
+                v    = src.val;
+                generate_exception_if(div_dbl(u, v), EXC_DE, -1);
+                dst.val   = u[0];
+                _regs.edx = u[1];
+                break;
+            }
+            break;
+        }
+        case 7: /* idiv */ {
+            unsigned long u[2], v;
+            src = dst;
+            dst.type = OP_REG;
+            dst.reg  = (unsigned long *)&_regs.eax;
+            switch ( src.bytes )
+            {
+            case 1:
+                u[0] = (int16_t)_regs.eax;
+                u[1] = ((long)u[0] < 0) ? ~0UL : 0UL;
+                v    = (int8_t)src.val;
+                generate_exception_if(
+                    idiv_dbl(u, v) || ((int8_t)u[0] != (int16_t)u[0]),
+                    EXC_DE, -1);
+                dst.val = (int8_t)u[0];
+                ((int8_t *)&_regs.eax)[1] = u[1];
+                break;
+            case 2:
+                u[0] = (int32_t)((_regs.edx << 16) | (uint16_t)_regs.eax);
+                u[1] = ((long)u[0] < 0) ? ~0UL : 0UL;
+                v    = (int16_t)src.val;
+                generate_exception_if(
+                    idiv_dbl(u, v) || ((int16_t)u[0] != (int32_t)u[0]),
+                    EXC_DE, -1);
+                dst.val = (int16_t)u[0];
+                *(int16_t *)&_regs.edx = u[1];
+                break;
+#ifdef __x86_64__
+            case 4:
+                u[0] = (_regs.edx << 32) | (uint32_t)_regs.eax;
+                u[1] = ((long)u[0] < 0) ? ~0UL : 0UL;
+                v    = (int32_t)src.val;
+                generate_exception_if(
+                    idiv_dbl(u, v) || ((int32_t)u[0] != u[0]),
+                    EXC_DE, -1);
+                dst.val   = (int32_t)u[0];
+                _regs.edx = (uint32_t)u[1];
+                break;
+#endif
+            default:
+                u[0] = _regs.eax;
+                u[1] = _regs.edx;
+                v    = src.val;
+                generate_exception_if(idiv_dbl(u, v), EXC_DE, -1);
+                dst.val   = u[0];
+                _regs.edx = u[1];
+                break;
+            }
+            break;
+        }
+        default:
+            goto cannot_emulate;
+        }
+        break;
+
     case 0xf8: /* clc */
         _regs.eflags &= ~EFLG_CF;
         break;
@@ -3465,21 +3336,402 @@ x86_emulate(
     case 0xfd: /* std */
         _regs.eflags |= EFLG_DF;
         break;
-    }
-    goto writeback;
+
+    case 0xfe: /* Grp4 */
+        generate_exception_if((modrm_reg & 7) >= 2, EXC_UD, -1);
+    case 0xff: /* Grp5 */
+        switch ( modrm_reg & 7 )
+        {
+        case 0: /* inc */
+            emulate_1op("inc", dst, _regs.eflags);
+            break;
+        case 1: /* dec */
+            emulate_1op("dec", dst, _regs.eflags);
+            break;
+        case 2: /* call (near) */
+        case 4: /* jmp (near) */
+            if ( (dst.bytes != 8) && mode_64bit() )
+            {
+                dst.bytes = op_bytes = 8;
+                if ( dst.type == OP_REG )
+                    dst.val = *dst.reg;
+                else if ( (rc = read_ulong(dst.mem.seg, dst.mem.off,
+                                           &dst.val, 8, ctxt, ops)) != 0 )
+                    goto done;
+            }
+            src.val = _regs.eip;
+            _regs.eip = dst.val;
+            if ( (modrm_reg & 7) == 2 )
+                goto push; /* call */
+            dst.type = OP_NONE;
+            break;
+        case 3: /* call (far, absolute indirect) */
+        case 5: /* jmp (far, absolute indirect) */ {
+            unsigned long sel;
+
+            generate_exception_if(dst.type != OP_MEM, EXC_UD, -1);
+
+            if ( (rc = read_ulong(dst.mem.seg, dst.mem.off+dst.bytes,
+                                  &sel, 2, ctxt, ops)) )
+                goto done;
+
+            if ( (modrm_reg & 7) == 3 ) /* call */
+            {
+                struct segment_register reg;
+                fail_if(ops->read_segment == NULL);
+                if ( (rc = ops->read_segment(x86_seg_cs, &reg, ctxt)) ||
+                     (rc = ops->write(x86_seg_ss, sp_pre_dec(op_bytes),
+                                      &reg.sel, op_bytes, ctxt)) ||
+                     (rc = ops->write(x86_seg_ss, sp_pre_dec(op_bytes),
+                                      &_regs.eip, op_bytes, ctxt)) )
+                    goto done;
+            }
+
+            if ( (rc = load_seg(x86_seg_cs, sel, ctxt, ops)) != 0 )
+                goto done;
+            _regs.eip = dst.val;
+
+            dst.type = OP_NONE;
+            break;
+        }
+        case 6: /* push */
+            /* 64-bit mode: PUSH defaults to a 64-bit operand. */
+            if ( mode_64bit() && (dst.bytes == 4) )
+            {
+                dst.bytes = 8;
+                if ( dst.type == OP_REG )
+                    dst.val = *dst.reg;
+                else if ( (rc = read_ulong(dst.mem.seg, dst.mem.off,
+                                           &dst.val, 8, ctxt, ops)) != 0 )
+                    goto done;
+            }
+            if ( (rc = ops->write(x86_seg_ss, sp_pre_dec(dst.bytes),
+                                  &dst.val, dst.bytes, ctxt)) != 0 )
+                goto done;
+            dst.type = OP_NONE;
+            break;
+        case 7:
+            generate_exception_if(1, EXC_UD, -1);
+        default:
+            goto cannot_emulate;
+        }
+        break;
+    }
+
+ writeback:
+    switch ( dst.type )
+    {
+    case OP_REG:
+        /* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */
+        switch ( dst.bytes )
+        {
+        case 1: *(uint8_t  *)dst.reg = (uint8_t)dst.val; break;
+        case 2: *(uint16_t *)dst.reg = (uint16_t)dst.val; break;
+        case 4: *dst.reg = (uint32_t)dst.val; break; /* 64b: zero-ext */
+        case 8: *dst.reg = dst.val; break;
+        }
+        break;
+    case OP_MEM:
+        if ( !(d & Mov) && (dst.orig_val == dst.val) &&
+             !ctxt->force_writeback )
+            /* nothing to do */;
+        else if ( lock_prefix )
+            rc = ops->cmpxchg(
+                dst.mem.seg, dst.mem.off, &dst.orig_val,
+                &dst.val, dst.bytes, ctxt);
+        else
+            rc = ops->write(
+                dst.mem.seg, dst.mem.off, &dst.val, dst.bytes, ctxt);
+        if ( rc != 0 )
+            goto done;
+    default:
+        break;
+    }
+
+    /* Inject #DB if single-step tracing was enabled at instruction start. */
+    if ( (ctxt->regs->eflags & EFLG_TF) && (rc == X86EMUL_OKAY) &&
+         (ops->inject_hw_exception != NULL) )
+        rc = ops->inject_hw_exception(EXC_DB, -1, ctxt) ? : X86EMUL_EXCEPTION;
+
+    /* Commit shadow register state. */
+    _regs.eflags &= ~EFLG_RF;
+    *ctxt->regs = _regs;
+
+ done:
+    return rc;
 
  twobyte_insn:
     switch ( b )
     {
+    case 0x01: /* Grp7 */ {
+        struct segment_register reg;
+        unsigned long base, limit, cr0, cr0w;
+
+        if ( modrm == 0xdf ) /* invlpga */
+        {
+            generate_exception_if(!in_protmode(ctxt, ops), EXC_UD, -1);
+            generate_exception_if(!mode_ring0(), EXC_GP, 0);
+            fail_if(ops->invlpg == NULL);
+            if ( (rc = ops->invlpg(x86_seg_none, truncate_ea(_regs.eax),
+                                   ctxt)) )
+                goto done;
+            break;
+        }
+
+        switch ( modrm_reg & 7 )
+        {
+        case 0: /* sgdt */
+        case 1: /* sidt */
+            generate_exception_if(ea.type != OP_MEM, EXC_UD, -1);
+            fail_if(ops->read_segment == NULL);
+            if ( (rc = ops->read_segment((modrm_reg & 1) ?
+                                         x86_seg_idtr : x86_seg_gdtr,
+                                         &reg, ctxt)) )
+                goto done;
+            if ( op_bytes == 2 )
+                reg.base &= 0xffffff;
+            if ( (rc = ops->write(ea.mem.seg, ea.mem.off+0,
+                                  &reg.limit, 2, ctxt)) ||
+                 (rc = ops->write(ea.mem.seg, ea.mem.off+2,
+                                  &reg.base, mode_64bit() ? 8 : 4, ctxt)) )
+                goto done;
+            break;
+        case 2: /* lgdt */
+        case 3: /* lidt */
+            generate_exception_if(ea.type != OP_MEM, EXC_UD, -1);
+            fail_if(ops->write_segment == NULL);
+            memset(&reg, 0, sizeof(reg));
+            if ( (rc = read_ulong(ea.mem.seg, ea.mem.off+0,
+                                  &limit, 2, ctxt, ops)) ||
+                 (rc = read_ulong(ea.mem.seg, ea.mem.off+2,
+                                  &base, mode_64bit() ? 8 : 4, ctxt, ops)) )
+                goto done;
+            reg.base = base;
+            reg.limit = limit;
+            if ( op_bytes == 2 )
+                reg.base &= 0xffffff;
+            if ( (rc = ops->write_segment((modrm_reg & 1) ?
+                                          x86_seg_idtr : x86_seg_gdtr,
+                                          &reg, ctxt)) )
+                goto done;
+            break;
+        case 4: /* smsw */
+            if ( ea.type == OP_MEM )
+                ea.bytes = 2;
+            dst = ea;
+            fail_if(ops->read_cr == NULL);
+            if ( (rc = ops->read_cr(0, &dst.val, ctxt)) )
+                goto done;
+            d |= Mov; /* force writeback */
+            break;
+        case 6: /* lmsw */
+            fail_if(ops->read_cr == NULL);
+            fail_if(ops->write_cr == NULL);
+            if ( (rc = ops->read_cr(0, &cr0, ctxt)) )
+                goto done;
+            if ( ea.type == OP_REG )
+                cr0w = *ea.reg;
+            else if ( (rc = read_ulong(ea.mem.seg, ea.mem.off,
+                                       &cr0w, 2, ctxt, ops)) )
+                goto done;
+            /* LMSW can: (1) set bits 0-3; (2) clear bits 1-3. */
+            cr0 = (cr0 & ~0xe) | (cr0w & 0xf);
+            if ( (rc = ops->write_cr(0, cr0, ctxt)) )
+                goto done;
+            break;
+        case 7: /* invlpg */
+            generate_exception_if(!mode_ring0(), EXC_GP, 0);
+            generate_exception_if(ea.type != OP_MEM, EXC_UD, -1);
+            fail_if(ops->invlpg == NULL);
+            if ( (rc = ops->invlpg(ea.mem.seg, ea.mem.off, ctxt)) )
+                goto done;
+            break;
+        default:
+            goto cannot_emulate;
+        }
+        break;
+    }
+
+    case 0x06: /* clts */
+        generate_exception_if(!mode_ring0(), EXC_GP, 0);
+        fail_if((ops->read_cr == NULL) || (ops->write_cr == NULL));
+        if ( (rc = ops->read_cr(0, &dst.val, ctxt)) ||
+             (rc = ops->write_cr(0, dst.val&~8, ctxt)) )
+            goto done;
+        break;
+
+    case 0x08: /* invd */
+    case 0x09: /* wbinvd */
+        generate_exception_if(!mode_ring0(), EXC_GP, 0);
+        fail_if(ops->wbinvd == NULL);
+        if ( (rc = ops->wbinvd(ctxt)) != 0 )
+            goto done;
+        break;
+
+    case 0x0d: /* GrpP (prefetch) */
+    case 0x18: /* Grp16 (prefetch/nop) */
+    case 0x19 ... 0x1f: /* nop (amd-defined) */
+        break;
+
+    case 0x20: /* mov cr,reg */
+    case 0x21: /* mov dr,reg */
+    case 0x22: /* mov reg,cr */
+    case 0x23: /* mov reg,dr */
+        generate_exception_if(ea.type != OP_REG, EXC_UD, -1);
+        generate_exception_if(!mode_ring0(), EXC_GP, 0);
+        modrm_reg |= lock_prefix << 3;
+        if ( b & 2 )
+        {
+            /* Write to CR/DR. */
+            src.val = *(unsigned long *)decode_register(modrm_rm, &_regs, 0);
+            if ( !mode_64bit() )
+                src.val = (uint32_t)src.val;
+            rc = ((b & 1)
+                  ? (ops->write_dr
+                     ? ops->write_dr(modrm_reg, src.val, ctxt)
+                     : X86EMUL_UNHANDLEABLE)
+                  : (ops->write_cr
+                     ? ops->write_cr(modrm_reg, src.val, ctxt)
+                     : X86EMUL_UNHANDLEABLE));
+        }
+        else
+        {
+            /* Read from CR/DR. */
+            dst.type  = OP_REG;
+            dst.bytes = mode_64bit() ? 8 : 4;
+            dst.reg   = decode_register(modrm_rm, &_regs, 0);
+            rc = ((b & 1)
+                  ? (ops->read_dr
+                     ? ops->read_dr(modrm_reg, &dst.val, ctxt)
+                     : X86EMUL_UNHANDLEABLE)
+                  : (ops->read_cr
+                     ? ops->read_cr(modrm_reg, &dst.val, ctxt)
+                     : X86EMUL_UNHANDLEABLE));
+        }
+        if ( rc != 0 )
+            goto done;
+        break;
+
+    case 0x30: /* wrmsr */ {
+        uint64_t val = ((uint64_t)_regs.edx << 32) | (uint32_t)_regs.eax;
+        generate_exception_if(!mode_ring0(), EXC_GP, 0);
+        fail_if(ops->write_msr == NULL);
+        if ( (rc = ops->write_msr((uint32_t)_regs.ecx, val, ctxt)) != 0 )
+            goto done;
+        break;
+    }
+
+    case 0x31: /* rdtsc */ {
+        unsigned long cr4;
+        uint64_t val;
+        fail_if(ops->read_cr == NULL);
+        if ( (rc = ops->read_cr(4, &cr4, ctxt)) )
+            goto done;
+        generate_exception_if((cr4 & CR4_TSD) && !mode_ring0(), EXC_GP, 0);
+        fail_if(ops->read_msr == NULL);
+        if ( (rc = ops->read_msr(MSR_TSC, &val, ctxt)) != 0 )
+            goto done;
+        _regs.edx = (uint32_t)(val >> 32);
+        _regs.eax = (uint32_t)(val >>  0);
+        break;
+    }
+
+    case 0x32: /* rdmsr */ {
+        uint64_t val;
+        generate_exception_if(!mode_ring0(), EXC_GP, 0);
+        fail_if(ops->read_msr == NULL);
+        if ( (rc = ops->read_msr((uint32_t)_regs.ecx, &val, ctxt)) != 0 )
+            goto done;
+        _regs.edx = (uint32_t)(val >> 32);
+        _regs.eax = (uint32_t)(val >>  0);
+        break;
+    }
+
     case 0x40 ... 0x4f: /* cmovcc */
         dst.val = src.val;
         if ( !test_cc(b, _regs.eflags) )
             dst.type = OP_NONE;
         break;
 
+    case 0x6f: /* movq mm/m64,mm */ {
+        uint8_t stub[] = { 0x0f, 0x6f, modrm, 0xc3 };
+        struct fpu_insn_ctxt fic = { .insn_bytes = sizeof(stub)-1 };
+        uint64_t val;
+        if ( ea.type == OP_MEM )
+        {
+            unsigned long lval, hval;
+            if ( (rc = read_ulong(ea.mem.seg, ea.mem.off+0,
+                                  &lval, 4, ctxt, ops)) ||
+                 (rc = read_ulong(ea.mem.seg, ea.mem.off+4,
+                                  &hval, 4, ctxt, ops)) )
+                goto done;
+            val = ((uint64_t)hval << 32) | (uint32_t)lval;
+            stub[2] = modrm & 0x38; /* movq (%eax),%mmN */
+        }
+        get_fpu(X86EMUL_FPU_mmx, &fic);
+        asm volatile ( "call *%0" : : "r" (stub), "a" (&val) : "memory" );
+        put_fpu(&fic);
+        break;
+    }
+
+    case 0x7f: /* movq mm,mm/m64 */ {
+        uint8_t stub[] = { 0x0f, 0x7f, modrm, 0xc3 };
+        struct fpu_insn_ctxt fic = { .insn_bytes = sizeof(stub)-1 };
+        uint64_t val;
+        if ( ea.type == OP_MEM )
+            stub[2] = modrm & 0x38; /* movq %mmN,(%eax) */
+        get_fpu(X86EMUL_FPU_mmx, &fic);
+        asm volatile ( "call *%0" : : "r" (stub), "a" (&val) : "memory" );
+        put_fpu(&fic);
+        if ( ea.type == OP_MEM )
+        {
+            unsigned long lval = (uint32_t)val, hval = (uint32_t)(val >> 32);
+            if ( (rc = ops->write(ea.mem.seg, ea.mem.off+0, &lval, 4, ctxt)) ||
+                 (rc = ops->write(ea.mem.seg, ea.mem.off+4, &hval, 4, ctxt)) )
+                goto done;
+        }
+        break;
+    }
+
+    case 0x80 ... 0x8f: /* jcc (near) */ {
+        int rel = (((op_bytes == 2) && !mode_64bit())
+                   ? (int32_t)insn_fetch_type(int16_t)
+                   : insn_fetch_type(int32_t));
+        if ( test_cc(b, _regs.eflags) )
+            jmp_rel(rel);
+        break;
+    }
+
     case 0x90 ... 0x9f: /* setcc */
         dst.val = test_cc(b, _regs.eflags);
         break;
+
+    case 0xa0: /* push %%fs */
+        src.val = x86_seg_fs;
+        goto push_seg;
+
+    case 0xa1: /* pop %%fs */
+        src.val = x86_seg_fs;
+        goto pop_seg;
+
+    case 0xa2: /* cpuid */ {
+        unsigned int eax = _regs.eax, ebx = _regs.ebx;
+        unsigned int ecx = _regs.ecx, edx = _regs.edx;
+        fail_if(ops->cpuid == NULL);
+        if ( (rc = ops->cpuid(&eax, &ebx, &ecx, &edx, ctxt)) != 0 )
+            goto done;
+        _regs.eax = eax; _regs.ebx = ebx;
+        _regs.ecx = ecx; _regs.edx = edx;
+        break;
+    }
+
+    case 0xa8: /* push %%gs */
+        src.val = x86_seg_gs;
+        goto push_seg;
+
+    case 0xa9: /* pop %%gs */
+        src.val = x86_seg_gs;
+        goto pop_seg;
 
     case 0xb0 ... 0xb1: /* cmpxchg */
         /* Save real source value, then compare EAX against destination. */
@@ -3656,271 +3908,6 @@ x86_emulate(
         case 8: *src.reg = dst.val; break;
         }
         goto add;
-    }
-    goto writeback;
-
- twobyte_special_insn:
-    switch ( b )
-    {
-    case 0x01: /* Grp7 */ {
-        struct segment_register reg;
-        unsigned long base, limit, cr0, cr0w;
-
-        if ( modrm == 0xdf ) /* invlpga */
-        {
-            generate_exception_if(!in_protmode(ctxt, ops), EXC_UD, -1);
-            generate_exception_if(!mode_ring0(), EXC_GP, 0);
-            fail_if(ops->invlpg == NULL);
-            if ( (rc = ops->invlpg(x86_seg_none, truncate_ea(_regs.eax),
-                                   ctxt)) )
-                goto done;
-            break;
-        }
-
-        switch ( modrm_reg & 7 )
-        {
-        case 0: /* sgdt */
-        case 1: /* sidt */
-            generate_exception_if(ea.type != OP_MEM, EXC_UD, -1);
-            fail_if(ops->read_segment == NULL);
-            if ( (rc = ops->read_segment((modrm_reg & 1) ?
-                                         x86_seg_idtr : x86_seg_gdtr,
-                                         &reg, ctxt)) )
-                goto done;
-            if ( op_bytes == 2 )
-                reg.base &= 0xffffff;
-            if ( (rc = ops->write(ea.mem.seg, ea.mem.off+0,
-                                  &reg.limit, 2, ctxt)) ||
-                 (rc = ops->write(ea.mem.seg, ea.mem.off+2,
-                                  &reg.base, mode_64bit() ? 8 : 4, ctxt)) )
-                goto done;
-            break;
-        case 2: /* lgdt */
-        case 3: /* lidt */
-            generate_exception_if(ea.type != OP_MEM, EXC_UD, -1);
-            fail_if(ops->write_segment == NULL);
-            memset(&reg, 0, sizeof(reg));
-            if ( (rc = read_ulong(ea.mem.seg, ea.mem.off+0,
-                                  &limit, 2, ctxt, ops)) ||
-                 (rc = read_ulong(ea.mem.seg, ea.mem.off+2,
-                                  &base, mode_64bit() ? 8 : 4, ctxt, ops)) )
-                goto done;
-            reg.base = base;
-            reg.limit = limit;
-            if ( op_bytes == 2 )
-                reg.base &= 0xffffff;
-            if ( (rc = ops->write_segment((modrm_reg & 1) ?
-                                          x86_seg_idtr : x86_seg_gdtr,
-                                          &reg, ctxt)) )
-                goto done;
-            break;
-        case 4: /* smsw */
-            if ( ea.type == OP_MEM )
-                ea.bytes = 2;
-            dst = ea;
-            fail_if(ops->read_cr == NULL);
-            if ( (rc = ops->read_cr(0, &dst.val, ctxt)) )
-                goto done;
-            d |= Mov; /* force writeback */
-            break;
-        case 6: /* lmsw */
-            fail_if(ops->read_cr == NULL);
-            fail_if(ops->write_cr == NULL);
-            if ( (rc = ops->read_cr(0, &cr0, ctxt)) )
-                goto done;
-            if ( ea.type == OP_REG )
-                cr0w = *ea.reg;
-            else if ( (rc = read_ulong(ea.mem.seg, ea.mem.off,
-                                       &cr0w, 2, ctxt, ops)) )
-                goto done;
-            /* LMSW can: (1) set bits 0-3; (2) clear bits 1-3. */
-            cr0 = (cr0 & ~0xe) | (cr0w & 0xf);
-            if ( (rc = ops->write_cr(0, cr0, ctxt)) )
-                goto done;
-            break;
-        case 7: /* invlpg */
-            generate_exception_if(!mode_ring0(), EXC_GP, 0);
-            generate_exception_if(ea.type != OP_MEM, EXC_UD, -1);
-            fail_if(ops->invlpg == NULL);
-            if ( (rc = ops->invlpg(ea.mem.seg, ea.mem.off, ctxt)) )
-                goto done;
-            break;
-        default:
-            goto cannot_emulate;
-        }
-        break;
-    }
-
-    case 0x06: /* clts */
-        generate_exception_if(!mode_ring0(), EXC_GP, 0);
-        fail_if((ops->read_cr == NULL) || (ops->write_cr == NULL));
-        if ( (rc = ops->read_cr(0, &dst.val, ctxt)) ||
-             (rc = ops->write_cr(0, dst.val&~8, ctxt)) )
-            goto done;
-        break;
-
-    case 0x08: /* invd */
-    case 0x09: /* wbinvd */
-        generate_exception_if(!mode_ring0(), EXC_GP, 0);
-        fail_if(ops->wbinvd == NULL);
-        if ( (rc = ops->wbinvd(ctxt)) != 0 )
-            goto done;
-        break;
-
-    case 0x0d: /* GrpP (prefetch) */
-    case 0x18: /* Grp16 (prefetch/nop) */
-    case 0x19 ... 0x1f: /* nop (amd-defined) */
-        break;
-
-    case 0x20: /* mov cr,reg */
-    case 0x21: /* mov dr,reg */
-    case 0x22: /* mov reg,cr */
-    case 0x23: /* mov reg,dr */
-        generate_exception_if(ea.type != OP_REG, EXC_UD, -1);
-        generate_exception_if(!mode_ring0(), EXC_GP, 0);
-        modrm_reg |= lock_prefix << 3;
-        if ( b & 2 )
-        {
-            /* Write to CR/DR. */
-            src.val = *(unsigned long *)decode_register(modrm_rm, &_regs, 0);
-            if ( !mode_64bit() )
-                src.val = (uint32_t)src.val;
-            rc = ((b & 1)
-                  ? (ops->write_dr
-                     ? ops->write_dr(modrm_reg, src.val, ctxt)
-                     : X86EMUL_UNHANDLEABLE)
-                  : (ops->write_cr
-                     ? ops->write_cr(modrm_reg, src.val, ctxt)
-                     : X86EMUL_UNHANDLEABLE));
-        }
-        else
-        {
-            /* Read from CR/DR. */
-            dst.type  = OP_REG;
-            dst.bytes = mode_64bit() ? 8 : 4;
-            dst.reg   = decode_register(modrm_rm, &_regs, 0);
-            rc = ((b & 1)
-                  ? (ops->read_dr
-                     ? ops->read_dr(modrm_reg, &dst.val, ctxt)
-                     : X86EMUL_UNHANDLEABLE)
-                  : (ops->read_cr
-                     ? ops->read_cr(modrm_reg, &dst.val, ctxt)
-                     : X86EMUL_UNHANDLEABLE));
-        }
-        if ( rc != 0 )
-            goto done;
-        break;
-
-    case 0x30: /* wrmsr */ {
-        uint64_t val = ((uint64_t)_regs.edx << 32) | (uint32_t)_regs.eax;
-        generate_exception_if(!mode_ring0(), EXC_GP, 0);
-        fail_if(ops->write_msr == NULL);
-        if ( (rc = ops->write_msr((uint32_t)_regs.ecx, val, ctxt)) != 0 )
-            goto done;
-        break;
-    }
-
-    case 0x31: /* rdtsc */ {
-        unsigned long cr4;
-        uint64_t val;
-        fail_if(ops->read_cr == NULL);
-        if ( (rc = ops->read_cr(4, &cr4, ctxt)) )
-            goto done;
-        generate_exception_if((cr4 & CR4_TSD) && !mode_ring0(), EXC_GP, 0);
-        fail_if(ops->read_msr == NULL);
-        if ( (rc = ops->read_msr(MSR_TSC, &val, ctxt)) != 0 )
-            goto done;
-        _regs.edx = (uint32_t)(val >> 32);
-        _regs.eax = (uint32_t)(val >>  0);
-        break;
-    }
-
-    case 0x32: /* rdmsr */ {
-        uint64_t val;
-        generate_exception_if(!mode_ring0(), EXC_GP, 0);
-        fail_if(ops->read_msr == NULL);
-        if ( (rc = ops->read_msr((uint32_t)_regs.ecx, &val, ctxt)) != 0 )
-            goto done;
-        _regs.edx = (uint32_t)(val >> 32);
-        _regs.eax = (uint32_t)(val >>  0);
-        break;
-    }
-
-    case 0x6f: /* movq mm/m64,mm */ {
-        uint8_t stub[] = { 0x0f, 0x6f, modrm, 0xc3 };
-        struct fpu_insn_ctxt fic = { .insn_bytes = sizeof(stub)-1 };
-        uint64_t val;
-        if ( ea.type == OP_MEM )
-        {
-            unsigned long lval, hval;
-            if ( (rc = read_ulong(ea.mem.seg, ea.mem.off+0,
-                                  &lval, 4, ctxt, ops)) ||
-                 (rc = read_ulong(ea.mem.seg, ea.mem.off+4,
-                                  &hval, 4, ctxt, ops)) )
-                goto done;
-            val = ((uint64_t)hval << 32) | (uint32_t)lval;
-            stub[2] = modrm & 0x38; /* movq (%eax),%mmN */
-        }
-        get_fpu(X86EMUL_FPU_mmx, &fic);
-        asm volatile ( "call *%0" : : "r" (stub), "a" (&val) : "memory" );
-        put_fpu(&fic);
-        break;
-    }
-
-    case 0x7f: /* movq mm,mm/m64 */ {
-        uint8_t stub[] = { 0x0f, 0x7f, modrm, 0xc3 };
-        struct fpu_insn_ctxt fic = { .insn_bytes = sizeof(stub)-1 };
-        uint64_t val;
-        if ( ea.type == OP_MEM )
-            stub[2] = modrm & 0x38; /* movq %mmN,(%eax) */
-        get_fpu(X86EMUL_FPU_mmx, &fic);
-        asm volatile ( "call *%0" : : "r" (stub), "a" (&val) : "memory" );
-        put_fpu(&fic);
-        if ( ea.type == OP_MEM )
-        {
-            unsigned long lval = (uint32_t)val, hval = (uint32_t)(val >> 32);
-            if ( (rc = ops->write(ea.mem.seg, ea.mem.off+0, &lval, 4, ctxt)) ||
-                 (rc = ops->write(ea.mem.seg, ea.mem.off+4, &hval, 4, ctxt)) )
-                goto done;
-        }
-        break;
-    }
-
-    case 0x80 ... 0x8f: /* jcc (near) */ {
-        int rel = (((op_bytes == 2) && !mode_64bit())
-                   ? (int32_t)insn_fetch_type(int16_t)
-                   : insn_fetch_type(int32_t));
-        if ( test_cc(b, _regs.eflags) )
-            jmp_rel(rel);
-        break;
-    }
-
-    case 0xa0: /* push %%fs */
-        src.val = x86_seg_fs;
-        goto push_seg;
-
-    case 0xa1: /* pop %%fs */
-        src.val = x86_seg_fs;
-        goto pop_seg;
-
-    case 0xa2: /* cpuid */ {
-        unsigned int eax = _regs.eax, ebx = _regs.ebx;
-        unsigned int ecx = _regs.ecx, edx = _regs.edx;
-        fail_if(ops->cpuid == NULL);
-        if ( (rc = ops->cpuid(&eax, &ebx, &ecx, &edx, ctxt)) != 0 )
-            goto done;
-        _regs.eax = eax; _regs.ebx = ebx;
-        _regs.ecx = ecx; _regs.edx = edx;
-        break;
-    }
-
-    case 0xa8: /* push %%gs */
-        src.val = x86_seg_gs;
-        goto push_seg;
-
-    case 0xa9: /* pop %%gs */
-        src.val = x86_seg_gs;
-        goto pop_seg;
 
     case 0xc7: /* Grp9 (cmpxchg8b/cmpxchg16b) */ {
         unsigned long old[2], exp[2], new[2];
diff -r a26194601c8f -r 8d993552673a xen/include/asm-x86/hvm/domain.h
--- a/xen/include/asm-x86/hvm/domain.h  Mon Oct 13 13:15:20 2008 +0100
+++ b/xen/include/asm-x86/hvm/domain.h  Tue Oct 14 10:45:29 2008 +0100
@@ -28,6 +28,7 @@
 #include <asm/hvm/vioapic.h>
 #include <asm/hvm/io.h>
 #include <xen/hvm/iommu.h>
+#include <asm/hvm/viridian.h>
 #include <asm/hvm/vmx/vmcs.h>
 #include <asm/hvm/svm/vmcb.h>
 #include <public/hvm/params.h>
@@ -74,6 +75,8 @@ struct hvm_domain {
     /* Pass-through */
     struct hvm_iommu       hvm_iommu;
 
+    struct viridian_domain viridian;
+
     bool_t                 hap_enabled;
     bool_t                 qemu_mapcache_invalidate;
     bool_t                 is_s3_suspended;
diff -r a26194601c8f -r 8d993552673a xen/include/asm-x86/hvm/hvm.h
--- a/xen/include/asm-x86/hvm/hvm.h     Mon Oct 13 13:15:20 2008 +0100
+++ b/xen/include/asm-x86/hvm/hvm.h     Tue Oct 14 10:45:29 2008 +0100
@@ -219,6 +219,9 @@ hvm_set_segment_register(struct vcpu *v,
     hvm_funcs.set_segment_register(v, seg, reg);
 }
 
+#define is_viridian_domain(_d)                                             \
+ (is_hvm_domain(_d) && ((_d)->arch.hvm_domain.params[HVM_PARAM_VIRIDIAN]))
+
 void hvm_cpuid(unsigned int input, unsigned int *eax, unsigned int *ebx,
                                    unsigned int *ecx, unsigned int *edx);
 void hvm_migrate_timers(struct vcpu *v);
diff -r a26194601c8f -r 8d993552673a xen/include/asm-x86/hvm/viridian.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/asm-x86/hvm/viridian.h        Tue Oct 14 10:45:29 2008 +0100
@@ -0,0 +1,65 @@
+/*****************************************************************************
+ *
+ * include/xen/viridian.h
+ *
+ * Copyright (c) 2008 Citrix Corp.
+ *
+ */
+
+#ifndef __ASM_X86_HVM_VIRIDIAN_H__
+#define __ASM_X86_HVM_VIRIDIAN_H__
+
+union viridian_guest_os_id
+{
+    uint64_t raw;
+    struct
+    {
+        uint64_t build_number:16;
+        uint64_t service_pack:8;
+        uint64_t minor:8;
+        uint64_t major:8;
+        uint64_t os:8;
+        uint64_t vendor:16;
+    } fields;
+};
+
+union viridian_hypercall_gpa
+{   uint64_t raw;
+    struct
+    {
+        uint64_t enabled:1;
+        uint64_t reserved_preserved:11;
+        uint64_t pfn:48;
+    } fields;
+};
+
+struct viridian_domain
+{
+    union viridian_guest_os_id guest_os_id;
+    union viridian_hypercall_gpa hypercall_gpa;
+};
+
+int
+cpuid_viridian_leaves(
+    unsigned int leaf,
+    unsigned int *eax,
+    unsigned int *ebx,
+    unsigned int *ecx,
+    unsigned int *edx);
+
+int
+wrmsr_viridian_regs(
+    uint32_t idx,
+    uint32_t eax,
+    uint32_t edx);
+
+int
+rdmsr_viridian_regs(
+    uint32_t idx,
+    uint32_t *eax,
+    uint32_t *edx);
+
+int
+viridian_hypercall(struct cpu_user_regs *regs);
+
+#endif /* __ASM_X86_HVM_VIRIDIAN_H__ */
diff -r a26194601c8f -r 8d993552673a xen/include/asm-x86/hvm/vlapic.h
--- a/xen/include/asm-x86/hvm/vlapic.h  Mon Oct 13 13:15:20 2008 +0100
+++ b/xen/include/asm-x86/hvm/vlapic.h  Tue Oct 14 10:45:29 2008 +0100
@@ -98,4 +98,8 @@ struct vlapic *apic_round_robin(
 
 int vlapic_match_logical_addr(struct vlapic *vlapic, uint8_t mda);
 
+void vlapic_EOI_set(struct vlapic *vlapic);
+
+int vlapic_ipi(struct vlapic *vlapic, uint32_t icr_low, uint32_t icr_high);
+
 #endif /* __ASM_X86_HVM_VLAPIC_H__ */
diff -r a26194601c8f -r 8d993552673a xen/include/asm-x86/perfc_defn.h
--- a/xen/include/asm-x86/perfc_defn.h  Mon Oct 13 13:15:20 2008 +0100
+++ b/xen/include/asm-x86/perfc_defn.h  Tue Oct 14 10:45:29 2008 +0100
@@ -111,4 +111,20 @@ PERFCOUNTER(shadow_unsync_evict,   "shad
 PERFCOUNTER(shadow_unsync_evict,   "shadow OOS evictions")
 PERFCOUNTER(shadow_resync,         "shadow OOS resyncs")
 
+PERFCOUNTER(mshv_call_sw_addr_space,    "MS Hv Switch Address Space")
+PERFCOUNTER(mshv_call_flush_tlb_list,   "MS Hv Flush TLB list")
+PERFCOUNTER(mshv_call_flush_tlb_all,    "MS Hv Flush TLB all")
+PERFCOUNTER(mshv_call_long_wait,        "MS Hv Notify long wait")
+PERFCOUNTER(mshv_rdmsr_osid,            "MS Hv rdmsr Guest OS ID")
+PERFCOUNTER(mshv_rdmsr_hc_page,         "MS Hv rdmsr hypercall page")
+PERFCOUNTER(mshv_rdmsr_vp_index,        "MS Hv rdmsr vp index")
+PERFCOUNTER(mshv_rdmsr_icr,             "MS Hv rdmsr icr")
+PERFCOUNTER(mshv_rdmsr_tpr,             "MS Hv rdmsr tpr")
+PERFCOUNTER(mshv_wrmsr_osid,            "MS Hv wrmsr Guest OS ID")
+PERFCOUNTER(mshv_wrmsr_hc_page,         "MS Hv wrmsr hypercall page")
+PERFCOUNTER(mshv_wrmsr_vp_index,        "MS Hv wrmsr vp index")
+PERFCOUNTER(mshv_wrmsr_icr,             "MS Hv wrmsr icr")
+PERFCOUNTER(mshv_wrmsr_tpr,             "MS Hv wrmsr tpr")
+PERFCOUNTER(mshv_wrmsr_eoi,             "MS Hv wrmsr eoi")
+
 /*#endif*/ /* __XEN_PERFC_DEFN_H__ */
diff -r a26194601c8f -r 8d993552673a xen/include/public/arch-x86/hvm/save.h
--- a/xen/include/public/arch-x86/hvm/save.h    Mon Oct 13 13:15:20 2008 +0100
+++ b/xen/include/public/arch-x86/hvm/save.h    Tue Oct 14 10:45:29 2008 +0100
@@ -421,9 +421,20 @@ struct hvm_hw_mtrr {
 
 DECLARE_HVM_SAVE_TYPE(MTRR, 14, struct hvm_hw_mtrr);
 
+/*
+ * Viridian hypervisor context.
+ */
+
+struct hvm_viridian_context {
+    uint64_t hypercall_gpa;
+    uint64_t guest_os_id;
+};
+
+DECLARE_HVM_SAVE_TYPE(VIRIDIAN, 15, struct hvm_viridian_context);
+
 /* 
  * Largest type-code in use
  */
-#define HVM_SAVE_CODE_MAX 14
+#define HVM_SAVE_CODE_MAX 15
 
 #endif /* __XEN_PUBLIC_HVM_SAVE_X86_H__ */
diff -r a26194601c8f -r 8d993552673a xen/include/public/hvm/params.h
--- a/xen/include/public/hvm/params.h   Mon Oct 13 13:15:20 2008 +0100
+++ b/xen/include/public/hvm/params.h   Tue Oct 14 10:45:29 2008 +0100
@@ -51,9 +51,16 @@
 #define HVM_PARAM_BUFIOREQ_PFN 6
 
 #ifdef __ia64__
+
 #define HVM_PARAM_NVRAM_FD     7
 #define HVM_PARAM_VHPT_SIZE    8
 #define HVM_PARAM_BUFPIOREQ_PFN        9
+
+#elif defined(__i386__) || defined(__x86_64__)
+
+/* Expose Viridian interfaces to this HVM guest? */
+#define HVM_PARAM_VIRIDIAN     9
+
 #endif
 
 /*

_______________________________________________
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®.