summary refs log tree commit diff stats
path: root/target-i386
diff options
context:
space:
mode:
Diffstat (limited to 'target-i386')
-rw-r--r--target-i386/cpu-qom.h15
-rw-r--r--target-i386/cpu.c311
-rw-r--r--target-i386/cpu.h26
-rw-r--r--target-i386/excp_helper.c6
-rw-r--r--target-i386/helper.c77
-rw-r--r--target-i386/kvm.c8
-rw-r--r--target-i386/machine.c7
-rw-r--r--target-i386/mem_helper.c16
-rw-r--r--target-i386/misc_helper.c20
-rw-r--r--target-i386/seg_helper.c20
-rw-r--r--target-i386/smm_helper.c2
-rw-r--r--target-i386/svm_helper.c41
-rw-r--r--target-i386/translate.c4
13 files changed, 341 insertions, 212 deletions
diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h
index 722f11a04f..e9b3d577b3 100644
--- a/target-i386/cpu-qom.h
+++ b/target-i386/cpu-qom.h
@@ -38,7 +38,17 @@
     OBJECT_GET_CLASS(X86CPUClass, (obj), TYPE_X86_CPU)
 
 /**
+ * X86CPUDefinition:
+ *
+ * CPU model definition data that was not converted to QOM per-subclass
+ * property defaults yet.
+ */
+typedef struct X86CPUDefinition X86CPUDefinition;
+
+/**
  * X86CPUClass:
+ * @cpu_def: CPU model definition
+ * @kvm_required: Whether CPU model requires KVM to be enabled.
  * @parent_realize: The parent class' realize handler.
  * @parent_reset: The parent class' reset handler.
  *
@@ -49,6 +59,11 @@ typedef struct X86CPUClass {
     CPUClass parent_class;
     /*< public >*/
 
+    /* Should be eventually replaced by subclass-specific property defaults. */
+    X86CPUDefinition *cpu_def;
+
+    bool kvm_required;
+
     DeviceRealize parent_realize;
     void (*parent_reset)(CPUState *cpu);
 } X86CPUClass;
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 0e8812a11d..e7e62c5897 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -315,7 +315,7 @@ typedef struct X86RegisterInfo32 {
 } X86RegisterInfo32;
 
 #define REGISTER(reg) \
-    [R_##reg] = { .name = #reg, .qapi_enum = X86_C_P_U_REGISTER32_##reg }
+    [R_##reg] = { .name = #reg, .qapi_enum = X86_CPU_REGISTER32_##reg }
 X86RegisterInfo32 x86_reg_info_32[CPU_NB_REGS32] = {
     REGISTER(EAX),
     REGISTER(ECX),
@@ -339,7 +339,7 @@ static const ExtSaveArea ext_save_areas[] = {
     [3] = { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX,
             .offset = 0x3c0, .size = 0x40  },
     [4] = { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX,
-            .offset = 0x400, .size = 0x10  },
+            .offset = 0x400, .size = 0x40  },
 };
 
 const char *get_register_name_32(unsigned int reg)
@@ -358,17 +358,23 @@ typedef struct model_features_t {
     FeatureWord feat_word;
 } model_features_t;
 
-static uint32_t kvm_default_features = (1 << KVM_FEATURE_CLOCKSOURCE) |
+/* KVM-specific features that are automatically added to all CPU models
+ * when KVM is enabled.
+ */
+static uint32_t kvm_default_features[FEATURE_WORDS] = {
+    [FEAT_KVM] = (1 << KVM_FEATURE_CLOCKSOURCE) |
         (1 << KVM_FEATURE_NOP_IO_DELAY) |
         (1 << KVM_FEATURE_CLOCKSOURCE2) |
         (1 << KVM_FEATURE_ASYNC_PF) |
         (1 << KVM_FEATURE_STEAL_TIME) |
         (1 << KVM_FEATURE_PV_EOI) |
-        (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT);
+        (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT),
+    [FEAT_1_ECX] = CPUID_EXT_X2APIC,
+};
 
-void disable_kvm_pv_eoi(void)
+void x86_cpu_compat_disable_kvm_features(FeatureWord w, uint32_t features)
 {
-    kvm_default_features &= ~(1UL << KVM_FEATURE_PV_EOI);
+    kvm_default_features[w] &= ~features;
 }
 
 void host_cpuid(uint32_t function, uint32_t count,
@@ -484,7 +490,35 @@ static void add_flagname_to_bitmaps(const char *flagname,
     }
 }
 
-typedef struct x86_def_t {
+/* CPU class name definitions: */
+
+#define X86_CPU_TYPE_SUFFIX "-" TYPE_X86_CPU
+#define X86_CPU_TYPE_NAME(name) (name X86_CPU_TYPE_SUFFIX)
+
+/* Return type name for a given CPU model name
+ * Caller is responsible for freeing the returned string.
+ */
+static char *x86_cpu_type_name(const char *model_name)
+{
+    return g_strdup_printf(X86_CPU_TYPE_NAME("%s"), model_name);
+}
+
+static ObjectClass *x86_cpu_class_by_name(const char *cpu_model)
+{
+    ObjectClass *oc;
+    char *typename;
+
+    if (cpu_model == NULL) {
+        return NULL;
+    }
+
+    typename = x86_cpu_type_name(cpu_model);
+    oc = object_class_by_name(typename);
+    g_free(typename);
+    return oc;
+}
+
+struct X86CPUDefinition {
     const char *name;
     uint32_t level;
     uint32_t xlevel;
@@ -497,7 +531,7 @@ typedef struct x86_def_t {
     FeatureWordArray features;
     char model_id[48];
     bool cache_info_passthrough;
-} x86_def_t;
+};
 
 #define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
 #define PENTIUM_FEATURES (I486_FEATURES | CPUID_DE | CPUID_TSC | \
@@ -547,9 +581,7 @@ typedef struct x86_def_t {
           CPUID_7_0_EBX_ERMS, CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM,
           CPUID_7_0_EBX_RDSEED */
 
-/* built-in CPU model definitions
- */
-static x86_def_t builtin_x86_defs[] = {
+static X86CPUDefinition builtin_x86_defs[] = {
     {
         .name = "qemu64",
         .level = 4,
@@ -1108,7 +1140,7 @@ static x86_def_t builtin_x86_defs[] = {
 void x86_cpu_compat_set_features(const char *cpu_model, FeatureWord w,
                                  uint32_t feat_add, uint32_t feat_remove)
 {
-    x86_def_t *def;
+    X86CPUDefinition *def;
     int i;
     for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
         def = &builtin_x86_defs[i];
@@ -1119,6 +1151,8 @@ void x86_cpu_compat_set_features(const char *cpu_model, FeatureWord w,
     }
 }
 
+#ifdef CONFIG_KVM
+
 static int cpu_x86_fill_model_id(char *str)
 {
     uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
@@ -1134,44 +1168,68 @@ static int cpu_x86_fill_model_id(char *str)
     return 0;
 }
 
-/* Fill a x86_def_t struct with information about the host CPU, and
- * the CPU features supported by the host hardware + host kernel
+static X86CPUDefinition host_cpudef;
+
+/* class_init for the "host" CPU model
  *
- * This function may be called only if KVM is enabled.
+ * This function may be called before KVM is initialized.
  */
-static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def)
+static void host_x86_cpu_class_init(ObjectClass *oc, void *data)
 {
-    KVMState *s = kvm_state;
+    X86CPUClass *xcc = X86_CPU_CLASS(oc);
     uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
 
-    assert(kvm_enabled());
+    xcc->kvm_required = true;
 
-    x86_cpu_def->name = "host";
-    x86_cpu_def->cache_info_passthrough = true;
     host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
-    x86_cpu_vendor_words2str(x86_cpu_def->vendor, ebx, edx, ecx);
+    x86_cpu_vendor_words2str(host_cpudef.vendor, ebx, edx, ecx);
 
     host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
-    x86_cpu_def->family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
-    x86_cpu_def->model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12);
-    x86_cpu_def->stepping = eax & 0x0F;
+    host_cpudef.family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
+    host_cpudef.model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12);
+    host_cpudef.stepping = eax & 0x0F;
 
-    x86_cpu_def->level = kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX);
-    x86_cpu_def->xlevel = kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX);
-    x86_cpu_def->xlevel2 =
-        kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX);
+    cpu_x86_fill_model_id(host_cpudef.model_id);
 
-    cpu_x86_fill_model_id(x86_cpu_def->model_id);
+    xcc->cpu_def = &host_cpudef;
+    host_cpudef.cache_info_passthrough = true;
 
+    /* level, xlevel, xlevel2, and the feature words are initialized on
+     * instance_init, because they require KVM to be initialized.
+     */
+}
+
+static void host_x86_cpu_initfn(Object *obj)
+{
+    X86CPU *cpu = X86_CPU(obj);
+    CPUX86State *env = &cpu->env;
+    KVMState *s = kvm_state;
     FeatureWord w;
+
+    assert(kvm_enabled());
+
+    env->cpuid_level = kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX);
+    env->cpuid_xlevel = kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX);
+    env->cpuid_xlevel2 = kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX);
+
     for (w = 0; w < FEATURE_WORDS; w++) {
         FeatureWordInfo *wi = &feature_word_info[w];
-        x86_cpu_def->features[w] =
+        env->features[w] =
             kvm_arch_get_supported_cpuid(s, wi->cpuid_eax, wi->cpuid_ecx,
                                          wi->cpuid_reg);
     }
+    object_property_set_bool(OBJECT(cpu), true, "pmu", &error_abort);
 }
 
+static const TypeInfo host_x86_cpu_type_info = {
+    .name = X86_CPU_TYPE_NAME("host"),
+    .parent = TYPE_X86_CPU,
+    .instance_init = host_x86_cpu_initfn,
+    .class_init = host_x86_cpu_class_init,
+};
+
+#endif
+
 static int unavailable_host_feature(FeatureWordInfo *f, uint32_t mask)
 {
     int i;
@@ -1582,32 +1640,6 @@ static PropertyInfo qdev_prop_spinlocks = {
     .set   = x86_set_hv_spinlocks,
 };
 
-static int cpu_x86_find_by_name(X86CPU *cpu, x86_def_t *x86_cpu_def,
-                                const char *name)
-{
-    x86_def_t *def;
-    int i;
-
-    if (name == NULL) {
-        return -1;
-    }
-    if (kvm_enabled() && strcmp(name, "host") == 0) {
-        kvm_cpu_fill_host(x86_cpu_def);
-        object_property_set_bool(OBJECT(cpu), true, "pmu", &error_abort);
-        return 0;
-    }
-
-    for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
-        def = &builtin_x86_defs[i];
-        if (strcmp(name, def->name) == 0) {
-            memcpy(x86_cpu_def, def, sizeof(*def));
-            return 0;
-        }
-    }
-
-    return -1;
-}
-
 /* Convert all '_' in a feature string option name to '-', to make feature
  * name conform to QOM property naming rule, which uses '-' instead of '_'.
  */
@@ -1620,8 +1652,10 @@ static inline void feat2prop(char *s)
 
 /* Parse "+feature,-feature,feature=foo" CPU feature string
  */
-static void cpu_x86_parse_featurestr(X86CPU *cpu, char *features, Error **errp)
+static void x86_cpu_parse_featurestr(CPUState *cs, char *features,
+                                     Error **errp)
 {
+    X86CPU *cpu = X86_CPU(cs);
     char *featurestr; /* Single 'key=value" string being parsed */
     /* Features to be added */
     FeatureWordArray plus_features = { 0 };
@@ -1629,6 +1663,7 @@ static void cpu_x86_parse_featurestr(X86CPU *cpu, char *features, Error **errp)
     FeatureWordArray minus_features = { 0 };
     uint32_t numvalue;
     CPUX86State *env = &cpu->env;
+    Error *local_err = NULL;
 
     featurestr = features ? strtok(features, ",") : NULL;
 
@@ -1647,16 +1682,16 @@ static void cpu_x86_parse_featurestr(X86CPU *cpu, char *features, Error **errp)
 
                 numvalue = strtoul(val, &err, 0);
                 if (!*val || *err) {
-                    error_setg(errp, "bad numerical value %s", val);
+                    error_setg(&local_err, "bad numerical value %s", val);
                     goto out;
                 }
                 if (numvalue < 0x80000000) {
-                    fprintf(stderr, "xlevel value shall always be >= 0x80000000"
-                            ", fixup will be removed in future versions\n");
+                    error_report("xlevel value shall always be >= 0x80000000"
+                                 ", fixup will be removed in future versions");
                     numvalue += 0x80000000;
                 }
                 snprintf(num, sizeof(num), "%" PRIu32, numvalue);
-                object_property_parse(OBJECT(cpu), num, featurestr, errp);
+                object_property_parse(OBJECT(cpu), num, featurestr, &local_err);
             } else if (!strcmp(featurestr, "tsc-freq")) {
                 int64_t tsc_freq;
                 char *err;
@@ -1665,36 +1700,38 @@ static void cpu_x86_parse_featurestr(X86CPU *cpu, char *features, Error **errp)
                 tsc_freq = strtosz_suffix_unit(val, &err,
                                                STRTOSZ_DEFSUFFIX_B, 1000);
                 if (tsc_freq < 0 || *err) {
-                    error_setg(errp, "bad numerical value %s", val);
+                    error_setg(&local_err, "bad numerical value %s", val);
                     goto out;
                 }
                 snprintf(num, sizeof(num), "%" PRId64, tsc_freq);
-                object_property_parse(OBJECT(cpu), num, "tsc-frequency", errp);
+                object_property_parse(OBJECT(cpu), num, "tsc-frequency",
+                                      &local_err);
             } else if (!strcmp(featurestr, "hv-spinlocks")) {
                 char *err;
                 const int min = 0xFFF;
                 char num[32];
                 numvalue = strtoul(val, &err, 0);
                 if (!*val || *err) {
-                    error_setg(errp, "bad numerical value %s", val);
+                    error_setg(&local_err, "bad numerical value %s", val);
                     goto out;
                 }
                 if (numvalue < min) {
-                    fprintf(stderr, "hv-spinlocks value shall always be >= 0x%x"
-                            ", fixup will be removed in future versions\n",
+                    error_report("hv-spinlocks value shall always be >= 0x%x"
+                            ", fixup will be removed in future versions",
                             min);
                     numvalue = min;
                 }
                 snprintf(num, sizeof(num), "%" PRId32, numvalue);
-                object_property_parse(OBJECT(cpu), num, featurestr, errp);
+                object_property_parse(OBJECT(cpu), num, featurestr, &local_err);
             } else {
-                object_property_parse(OBJECT(cpu), val, featurestr, errp);
+                object_property_parse(OBJECT(cpu), val, featurestr, &local_err);
             }
         } else {
             feat2prop(featurestr);
-            object_property_parse(OBJECT(cpu), "on", featurestr, errp);
+            object_property_parse(OBJECT(cpu), "on", featurestr, &local_err);
         }
-        if (error_is_set(errp)) {
+        if (local_err) {
+            error_propagate(errp, local_err);
             goto out;
         }
         featurestr = strtok(NULL, ",");
@@ -1753,7 +1790,7 @@ static void listflags(char *buf, int bufsize, uint32_t fbits,
 /* generate CPU information. */
 void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf)
 {
-    x86_def_t *def;
+    X86CPUDefinition *def;
     char buf[256];
     int i;
 
@@ -1780,7 +1817,7 @@ void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf)
 CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
 {
     CpuDefinitionInfoList *cpu_list = NULL;
-    x86_def_t *def;
+    X86CPUDefinition *def;
     int i;
 
     for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
@@ -1817,17 +1854,13 @@ static void filter_features_for_kvm(X86CPU *cpu)
     }
 }
 
-static void cpu_x86_register(X86CPU *cpu, const char *name, Error **errp)
+/* Load data from X86CPUDefinition
+ */
+static void x86_cpu_load_def(X86CPU *cpu, X86CPUDefinition *def, Error **errp)
 {
     CPUX86State *env = &cpu->env;
-    x86_def_t def1, *def = &def1;
-
-    memset(def, 0, sizeof(*def));
-
-    if (cpu_x86_find_by_name(cpu, def, name) < 0) {
-        error_setg(errp, "Unable to find CPU definition: %s", name);
-        return;
-    }
+    const char *vendor;
+    char host_vendor[CPUID_VENDOR_SZ + 1];
 
     object_property_set_int(OBJECT(cpu), def->level, "level", errp);
     object_property_set_int(OBJECT(cpu), def->family, "family", errp);
@@ -1847,10 +1880,14 @@ static void cpu_x86_register(X86CPU *cpu, const char *name, Error **errp)
 
     object_property_set_str(OBJECT(cpu), def->model_id, "model-id", errp);
 
-    /* Special cases not set in the x86_def_t structs: */
+    /* Special cases not set in the X86CPUDefinition structs: */
     if (kvm_enabled()) {
-        env->features[FEAT_KVM] |= kvm_default_features;
+        FeatureWord w;
+        for (w = 0; w < FEATURE_WORDS; w++) {
+            env->features[w] |= kvm_default_features[w];
+        }
     }
+
     env->features[FEAT_1_ECX] |= CPUID_EXT_HYPERVISOR;
 
     /* sysenter isn't supported in compatibility mode on AMD,
@@ -1860,8 +1897,7 @@ static void cpu_x86_register(X86CPU *cpu, const char *name, Error **errp)
      * KVM's sysenter/syscall emulation in compatibility mode and
      * when doing cross vendor migration
      */
-    const char *vendor = def->vendor;
-    char host_vendor[CPUID_VENDOR_SZ + 1];
+    vendor = def->vendor;
     if (kvm_enabled()) {
         uint32_t  ebx = 0, ecx = 0, edx = 0;
         host_cpuid(0, 0, NULL, &ebx, &ecx, &edx);
@@ -1877,9 +1913,10 @@ X86CPU *cpu_x86_create(const char *cpu_model, DeviceState *icc_bridge,
                        Error **errp)
 {
     X86CPU *cpu = NULL;
+    X86CPUClass *xcc;
+    ObjectClass *oc;
     gchar **model_pieces;
     char *name, *features;
-    char *typename;
     Error *error = NULL;
 
     model_pieces = g_strsplit(cpu_model, ",", 2);
@@ -1890,30 +1927,30 @@ X86CPU *cpu_x86_create(const char *cpu_model, DeviceState *icc_bridge,
     name = model_pieces[0];
     features = model_pieces[1];
 
-    cpu = X86_CPU(object_new(TYPE_X86_CPU));
-#ifndef CONFIG_USER_ONLY
-    if (icc_bridge == NULL) {
-        error_setg(&error, "Invalid icc-bridge value");
+    oc = x86_cpu_class_by_name(name);
+    if (oc == NULL) {
+        error_setg(&error, "Unable to find CPU definition: %s", name);
         goto out;
     }
-    qdev_set_parent_bus(DEVICE(cpu), qdev_get_child_bus(icc_bridge, "icc"));
-    object_unref(OBJECT(cpu));
-#endif
+    xcc = X86_CPU_CLASS(oc);
 
-    cpu_x86_register(cpu, name, &error);
-    if (error) {
+    if (xcc->kvm_required && !kvm_enabled()) {
+        error_setg(&error, "CPU model '%s' requires KVM", name);
         goto out;
     }
 
-    /* Emulate per-model subclasses for global properties */
-    typename = g_strdup_printf("%s-" TYPE_X86_CPU, name);
-    qdev_prop_set_globals_for_type(DEVICE(cpu), typename, &error);
-    g_free(typename);
-    if (error) {
+    cpu = X86_CPU(object_new(object_class_get_name(oc)));
+
+#ifndef CONFIG_USER_ONLY
+    if (icc_bridge == NULL) {
+        error_setg(&error, "Invalid icc-bridge value");
         goto out;
     }
+    qdev_set_parent_bus(DEVICE(cpu), qdev_get_child_bus(icc_bridge, "icc"));
+    object_unref(OBJECT(cpu));
+#endif
 
-    cpu_x86_parse_featurestr(cpu, features, &error);
+    x86_cpu_parse_featurestr(CPU(cpu), features, &error);
     if (error) {
         goto out;
     }
@@ -1921,8 +1958,10 @@ X86CPU *cpu_x86_create(const char *cpu_model, DeviceState *icc_bridge,
 out:
     if (error != NULL) {
         error_propagate(errp, error);
-        object_unref(OBJECT(cpu));
-        cpu = NULL;
+        if (cpu) {
+            object_unref(OBJECT(cpu));
+            cpu = NULL;
+        }
     }
     g_strfreev(model_pieces);
     return cpu;
@@ -1952,6 +1991,28 @@ out:
     return cpu;
 }
 
+static void x86_cpu_cpudef_class_init(ObjectClass *oc, void *data)
+{
+    X86CPUDefinition *cpudef = data;
+    X86CPUClass *xcc = X86_CPU_CLASS(oc);
+
+    xcc->cpu_def = cpudef;
+}
+
+static void x86_register_cpudef_type(X86CPUDefinition *def)
+{
+    char *typename = x86_cpu_type_name(def->name);
+    TypeInfo ti = {
+        .name = typename,
+        .parent = TYPE_X86_CPU,
+        .class_init = x86_cpu_cpudef_class_init,
+        .class_data = def,
+    };
+
+    type_register(&ti);
+    g_free(typename);
+}
+
 #if !defined(CONFIG_USER_ONLY)
 
 void cpu_clear_apic_feature(CPUX86State *env)
@@ -1969,7 +2030,7 @@ void x86_cpudef_setup(void)
     static const char *model_with_versions[] = { "qemu32", "qemu64", "athlon" };
 
     for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); ++i) {
-        x86_def_t *def = &builtin_x86_defs[i];
+        X86CPUDefinition *def = &builtin_x86_defs[i];
 
         /* Look for specific "cpudef" models that */
         /* have the QEMU version in .model_id */
@@ -2349,9 +2410,9 @@ static void x86_cpu_reset(CPUState *s)
     xcc->parent_reset(s);
 
 
-    memset(env, 0, offsetof(CPUX86State, breakpoints));
+    memset(env, 0, offsetof(CPUX86State, pat));
 
-    tlb_flush(env, 1);
+    tlb_flush(s, 1);
 
     env->old_exception = -1;
 
@@ -2412,8 +2473,8 @@ static void x86_cpu_reset(CPUState *s)
     memset(env->dr, 0, sizeof(env->dr));
     env->dr[6] = DR6_FIXED_1;
     env->dr[7] = DR7_FIXED_1;
-    cpu_breakpoint_remove_all(env, BP_CPU);
-    cpu_watchpoint_remove_all(env, BP_CPU);
+    cpu_breakpoint_remove_all(s, BP_CPU);
+    cpu_watchpoint_remove_all(s, BP_CPU);
 
     env->tsc_adjust = 0;
     env->tsc = 0;
@@ -2613,6 +2674,7 @@ static void x86_cpu_initfn(Object *obj)
 {
     CPUState *cs = CPU(obj);
     X86CPU *cpu = X86_CPU(obj);
+    X86CPUClass *xcc = X86_CPU_GET_CLASS(obj);
     CPUX86State *env = &cpu->env;
     static int inited;
 
@@ -2656,6 +2718,8 @@ static void x86_cpu_initfn(Object *obj)
     cpu->hyperv_spinlock_attempts = HYPERV_SPINLOCK_NEVER_RETRY;
     env->cpuid_apic_id = x86_cpu_apic_id_from_index(cs->cpu_index);
 
+    x86_cpu_load_def(cpu, xcc->cpu_def, &error_abort);
+
     /* init various static tables used in TCG mode */
     if (tcg_enabled() && !inited) {
         inited = 1;
@@ -2695,6 +2759,20 @@ static void x86_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
     cpu->env.eip = tb->pc - tb->cs_base;
 }
 
+static bool x86_cpu_has_work(CPUState *cs)
+{
+    X86CPU *cpu = X86_CPU(cs);
+    CPUX86State *env = &cpu->env;
+
+    return ((cs->interrupt_request & (CPU_INTERRUPT_HARD |
+                                      CPU_INTERRUPT_POLL)) &&
+            (env->eflags & IF_MASK)) ||
+           (cs->interrupt_request & (CPU_INTERRUPT_NMI |
+                                     CPU_INTERRUPT_INIT |
+                                     CPU_INTERRUPT_SIPI |
+                                     CPU_INTERRUPT_MCE));
+}
+
 static Property x86_cpu_properties[] = {
     DEFINE_PROP_BOOL("pmu", X86CPU, enable_pmu, false),
     { .name  = "hv-spinlocks", .info  = &qdev_prop_spinlocks },
@@ -2721,6 +2799,9 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
     cc->reset = x86_cpu_reset;
     cc->reset_dump_flags = CPU_DUMP_FPU | CPU_DUMP_CCOP;
 
+    cc->class_by_name = x86_cpu_class_by_name;
+    cc->parse_features = x86_cpu_parse_featurestr;
+    cc->has_work = x86_cpu_has_work;
     cc->do_interrupt = x86_cpu_do_interrupt;
     cc->dump_state = x86_cpu_dump_state;
     cc->set_pc = x86_cpu_set_pc;
@@ -2729,7 +2810,9 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
     cc->gdb_write_register = x86_cpu_gdb_write_register;
     cc->get_arch_id = x86_cpu_get_arch_id;
     cc->get_paging_enabled = x86_cpu_get_paging_enabled;
-#ifndef CONFIG_USER_ONLY
+#ifdef CONFIG_USER_ONLY
+    cc->handle_mmu_fault = x86_cpu_handle_mmu_fault;
+#else
     cc->get_memory_mapping = x86_cpu_get_memory_mapping;
     cc->get_phys_page_debug = x86_cpu_get_phys_page_debug;
     cc->write_elf64_note = x86_cpu_write_elf64_note;
@@ -2746,14 +2829,22 @@ static const TypeInfo x86_cpu_type_info = {
     .parent = TYPE_CPU,
     .instance_size = sizeof(X86CPU),
     .instance_init = x86_cpu_initfn,
-    .abstract = false,
+    .abstract = true,
     .class_size = sizeof(X86CPUClass),
     .class_init = x86_cpu_common_class_init,
 };
 
 static void x86_cpu_register_types(void)
 {
+    int i;
+
     type_register_static(&x86_cpu_type_info);
+    for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
+        x86_register_cpudef_type(&builtin_x86_defs[i]);
+    }
+#ifdef CONFIG_KVM
+    type_register_static(&host_x86_cpu_type_info);
+#endif
 }
 
 type_init(x86_cpu_register_types)
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 0014acca7b..4d1374c6cc 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -875,8 +875,8 @@ typedef struct CPUX86State {
     target_ulong exception_next_eip;
     target_ulong dr[8]; /* debug registers */
     union {
-        CPUBreakpoint *cpu_breakpoint[4];
-        CPUWatchpoint *cpu_watchpoint[4];
+        struct CPUBreakpoint *cpu_breakpoint[4];
+        struct CPUWatchpoint *cpu_watchpoint[4];
     }; /* break/watchpoints for dr[0..3] */
     uint32_t smbase;
     int old_exception;  /* exception in flight */
@@ -887,6 +887,7 @@ typedef struct CPUX86State {
 
     CPU_COMMON
 
+    /* Fields from here on are preserved across CPU reset. */
     uint64_t pat;
 
     /* processor features (e.g. for CPUID insn) */
@@ -1067,9 +1068,8 @@ void host_cpuid(uint32_t function, uint32_t count,
                 uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
 
 /* helper.c */
-int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
+int x86_cpu_handle_mmu_fault(CPUState *cpu, vaddr addr,
                              int is_write, int mmu_idx);
-#define cpu_handle_mmu_fault cpu_x86_handle_mmu_fault
 void x86_cpu_set_a20(X86CPU *cpu, int a20_state);
 
 static inline bool hw_local_breakpoint_enabled(unsigned long dr7, int index)
@@ -1186,20 +1186,6 @@ void optimize_flags_init(void);
 #include "hw/i386/apic.h"
 #endif
 
-static inline bool cpu_has_work(CPUState *cs)
-{
-    X86CPU *cpu = X86_CPU(cs);
-    CPUX86State *env = &cpu->env;
-
-    return ((cs->interrupt_request & (CPU_INTERRUPT_HARD |
-                                      CPU_INTERRUPT_POLL)) &&
-            (env->eflags & IF_MASK)) ||
-           (cs->interrupt_request & (CPU_INTERRUPT_NMI |
-                                     CPU_INTERRUPT_INIT |
-                                     CPU_INTERRUPT_SIPI |
-                                     CPU_INTERRUPT_MCE));
-}
-
 #include "exec/exec-all.h"
 
 static inline void cpu_get_tb_cpu_state(CPUX86State *env, target_ulong *pc,
@@ -1276,11 +1262,11 @@ void do_smm_enter(X86CPU *cpu);
 
 void cpu_report_tpr_access(CPUX86State *env, TPRAccess access);
 
-void disable_kvm_pv_eoi(void);
-
 void x86_cpu_compat_set_features(const char *cpu_model, FeatureWord w,
                                  uint32_t feat_add, uint32_t feat_remove);
 
+void x86_cpu_compat_disable_kvm_features(FeatureWord w, uint32_t features);
+
 
 /* Return name of 32-bit register, from a R_* constant */
 const char *get_register_name_32(unsigned int reg);
diff --git a/target-i386/excp_helper.c b/target-i386/excp_helper.c
index 5319aef7df..f337fd20fb 100644
--- a/target-i386/excp_helper.c
+++ b/target-i386/excp_helper.c
@@ -94,6 +94,8 @@ static void QEMU_NORETURN raise_interrupt2(CPUX86State *env, int intno,
                                            int is_int, int error_code,
                                            int next_eip_addend)
 {
+    CPUState *cs = CPU(x86_env_get_cpu(env));
+
     if (!is_int) {
         cpu_svm_check_intercept_param(env, SVM_EXIT_EXCP_BASE + intno,
                                       error_code);
@@ -102,11 +104,11 @@ static void QEMU_NORETURN raise_interrupt2(CPUX86State *env, int intno,
         cpu_svm_check_intercept_param(env, SVM_EXIT_SWINT, 0);
     }
 
-    env->exception_index = intno;
+    cs->exception_index = intno;
     env->error_code = error_code;
     env->exception_is_int = is_int;
     env->exception_next_eip = env->eip + next_eip_addend;
-    cpu_loop_exit(env);
+    cpu_loop_exit(cs);
 }
 
 /* shortcuts to generate exceptions */
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 55c04577dc..4f447b8cf9 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -385,22 +385,25 @@ void x86_cpu_set_a20(X86CPU *cpu, int a20_state)
 
     a20_state = (a20_state != 0);
     if (a20_state != ((env->a20_mask >> 20) & 1)) {
+        CPUState *cs = CPU(cpu);
+
 #if defined(DEBUG_MMU)
         printf("A20 update: a20=%d\n", a20_state);
 #endif
         /* if the cpu is currently executing code, we must unlink it and
            all the potentially executing TB */
-        cpu_interrupt(CPU(cpu), CPU_INTERRUPT_EXITTB);
+        cpu_interrupt(cs, CPU_INTERRUPT_EXITTB);
 
         /* when a20 is changed, all the MMU mappings are invalid, so
            we must flush everything */
-        tlb_flush(env, 1);
+        tlb_flush(cs, 1);
         env->a20_mask = ~(1 << 20) | (a20_state << 20);
     }
 }
 
 void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0)
 {
+    X86CPU *cpu = x86_env_get_cpu(env);
     int pe_state;
 
 #if defined(DEBUG_MMU)
@@ -408,7 +411,7 @@ void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0)
 #endif
     if ((new_cr0 & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK)) !=
         (env->cr[0] & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK))) {
-        tlb_flush(env, 1);
+        tlb_flush(CPU(cpu), 1);
     }
 
 #ifdef TARGET_X86_64
@@ -444,24 +447,28 @@ void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0)
    the PDPT */
 void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3)
 {
+    X86CPU *cpu = x86_env_get_cpu(env);
+
     env->cr[3] = new_cr3;
     if (env->cr[0] & CR0_PG_MASK) {
 #if defined(DEBUG_MMU)
         printf("CR3 update: CR3=" TARGET_FMT_lx "\n", new_cr3);
 #endif
-        tlb_flush(env, 0);
+        tlb_flush(CPU(cpu), 0);
     }
 }
 
 void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
 {
+    X86CPU *cpu = x86_env_get_cpu(env);
+
 #if defined(DEBUG_MMU)
     printf("CR4 update: CR4=%08x\n", (uint32_t)env->cr[4]);
 #endif
     if ((new_cr4 ^ env->cr[4]) &
         (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK |
          CR4_SMEP_MASK | CR4_SMAP_MASK)) {
-        tlb_flush(env, 1);
+        tlb_flush(CPU(cpu), 1);
     }
     /* SSE handling */
     if (!(env->features[FEAT_1_EDX] & CPUID_SSE)) {
@@ -485,15 +492,18 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
 
 #if defined(CONFIG_USER_ONLY)
 
-int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
+int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr,
                              int is_write, int mmu_idx)
 {
+    X86CPU *cpu = X86_CPU(cs);
+    CPUX86State *env = &cpu->env;
+
     /* user mode only emulation */
     is_write &= 1;
     env->cr[2] = addr;
     env->error_code = (is_write << PG_ERROR_W_BIT);
     env->error_code |= PG_ERROR_U_MASK;
-    env->exception_index = EXCP0E_PAGE;
+    cs->exception_index = EXCP0E_PAGE;
     return 1;
 }
 
@@ -508,14 +518,15 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
 # endif
 
 /* return value:
-   -1 = cannot handle fault
-   0  = nothing more to do
-   1  = generate PF fault
-*/
-int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
+ * -1 = cannot handle fault
+ * 0  = nothing more to do
+ * 1  = generate PF fault
+ */
+int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr,
                              int is_write1, int mmu_idx)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    X86CPU *cpu = X86_CPU(cs);
+    CPUX86State *env = &cpu->env;
     uint64_t ptep, pte;
     target_ulong pde_addr, pte_addr;
     int error_code, is_dirty, prot, page_size, is_write, is_user;
@@ -525,7 +536,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
 
     is_user = mmu_idx == MMU_USER_IDX;
 #if defined(DEBUG_MMU)
-    printf("MMU fault: addr=" TARGET_FMT_lx " w=%d u=%d eip=" TARGET_FMT_lx "\n",
+    printf("MMU fault: addr=%" VADDR_PRIx " w=%d u=%d eip=" TARGET_FMT_lx "\n",
            addr, is_write1, is_user, env->eip);
 #endif
     is_write = is_write1 & 1;
@@ -557,7 +568,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
             sext = (int64_t)addr >> 47;
             if (sext != 0 && sext != -1) {
                 env->error_code = 0;
-                env->exception_index = EXCP0D_GPF;
+                cs->exception_index = EXCP0D_GPF;
                 return 1;
             }
 
@@ -866,7 +877,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
     paddr = (pte & TARGET_PAGE_MASK) + page_offset;
     vaddr = virt_addr + page_offset;
 
-    tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
+    tlb_set_page(cs, vaddr, paddr, prot, mmu_idx, page_size);
     return 0;
  do_fault_protect:
     error_code = PG_ERROR_P_MASK;
@@ -888,7 +899,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
         env->cr[2] = addr;
     }
     env->error_code = error_code;
-    env->exception_index = EXCP0E_PAGE;
+    cs->exception_index = EXCP0E_PAGE;
     return 1;
 }
 
@@ -989,12 +1000,13 @@ hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
 
 void hw_breakpoint_insert(CPUX86State *env, int index)
 {
+    CPUState *cs = CPU(x86_env_get_cpu(env));
     int type = 0, err = 0;
 
     switch (hw_breakpoint_type(env->dr[7], index)) {
     case DR7_TYPE_BP_INST:
         if (hw_breakpoint_enabled(env->dr[7], index)) {
-            err = cpu_breakpoint_insert(env, env->dr[index], BP_CPU,
+            err = cpu_breakpoint_insert(cs, env->dr[index], BP_CPU,
                                         &env->cpu_breakpoint[index]);
         }
         break;
@@ -1010,7 +1022,7 @@ void hw_breakpoint_insert(CPUX86State *env, int index)
     }
 
     if (type != 0) {
-        err = cpu_watchpoint_insert(env, env->dr[index],
+        err = cpu_watchpoint_insert(cs, env->dr[index],
                                     hw_breakpoint_len(env->dr[7], index),
                                     type, &env->cpu_watchpoint[index]);
     }
@@ -1022,17 +1034,21 @@ void hw_breakpoint_insert(CPUX86State *env, int index)
 
 void hw_breakpoint_remove(CPUX86State *env, int index)
 {
-    if (!env->cpu_breakpoint[index])
+    CPUState *cs;
+
+    if (!env->cpu_breakpoint[index]) {
         return;
+    }
+    cs = CPU(x86_env_get_cpu(env));
     switch (hw_breakpoint_type(env->dr[7], index)) {
     case DR7_TYPE_BP_INST:
         if (hw_breakpoint_enabled(env->dr[7], index)) {
-            cpu_breakpoint_remove_by_ref(env, env->cpu_breakpoint[index]);
+            cpu_breakpoint_remove_by_ref(cs, env->cpu_breakpoint[index]);
         }
         break;
     case DR7_TYPE_DATA_WR:
     case DR7_TYPE_DATA_RW:
-        cpu_watchpoint_remove_by_ref(env, env->cpu_watchpoint[index]);
+        cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[index]);
         break;
     case DR7_TYPE_IO_RW:
         /* No support for I/O watchpoints yet */
@@ -1084,19 +1100,20 @@ bool check_hw_breakpoints(CPUX86State *env, bool force_dr6_update)
 
 void breakpoint_handler(CPUX86State *env)
 {
+    CPUState *cs = CPU(x86_env_get_cpu(env));
     CPUBreakpoint *bp;
 
-    if (env->watchpoint_hit) {
-        if (env->watchpoint_hit->flags & BP_CPU) {
-            env->watchpoint_hit = NULL;
+    if (cs->watchpoint_hit) {
+        if (cs->watchpoint_hit->flags & BP_CPU) {
+            cs->watchpoint_hit = NULL;
             if (check_hw_breakpoints(env, false)) {
                 raise_exception(env, EXCP01_DB);
             } else {
-                cpu_resume_from_signal(env, NULL);
+                cpu_resume_from_signal(cs, NULL);
             }
         }
     } else {
-        QTAILQ_FOREACH(bp, &env->breakpoints, entry)
+        QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
             if (bp->pc == env->eip) {
                 if (bp->flags & BP_CPU) {
                     check_hw_breakpoints(env, true);
@@ -1104,6 +1121,7 @@ void breakpoint_handler(CPUX86State *env)
                 }
                 break;
             }
+        }
     }
 }
 
@@ -1250,13 +1268,14 @@ void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank,
 void cpu_report_tpr_access(CPUX86State *env, TPRAccess access)
 {
     X86CPU *cpu = x86_env_get_cpu(env);
+    CPUState *cs = CPU(cpu);
 
     if (kvm_enabled()) {
         env->tpr_access_type = access;
 
-        cpu_interrupt(CPU(cpu), CPU_INTERRUPT_TPR);
+        cpu_interrupt(cs, CPU_INTERRUPT_TPR);
     } else {
-        cpu_restore_state(env, env->mem_io_pc);
+        cpu_restore_state(cs, cs->mem_io_pc);
 
         apic_handle_tpr_access_report(cpu->apic_state, env->eip, access);
     }
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index e555040a97..7a295f6f20 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -2277,13 +2277,13 @@ static int kvm_handle_debug(X86CPU *cpu,
                         break;
                     case 0x1:
                         ret = EXCP_DEBUG;
-                        env->watchpoint_hit = &hw_watchpoint;
+                        cs->watchpoint_hit = &hw_watchpoint;
                         hw_watchpoint.vaddr = hw_breakpoint[n].addr;
                         hw_watchpoint.flags = BP_MEM_WRITE;
                         break;
                     case 0x3:
                         ret = EXCP_DEBUG;
-                        env->watchpoint_hit = &hw_watchpoint;
+                        cs->watchpoint_hit = &hw_watchpoint;
                         hw_watchpoint.vaddr = hw_breakpoint[n].addr;
                         hw_watchpoint.flags = BP_MEM_ACCESS;
                         break;
@@ -2291,11 +2291,11 @@ static int kvm_handle_debug(X86CPU *cpu,
                 }
             }
         }
-    } else if (kvm_find_sw_breakpoint(CPU(cpu), arch_info->pc)) {
+    } else if (kvm_find_sw_breakpoint(cs, arch_info->pc)) {
         ret = EXCP_DEBUG;
     }
     if (ret == 0) {
-        cpu_synchronize_state(CPU(cpu));
+        cpu_synchronize_state(cs);
         assert(env->exception_injected == -1);
 
         /* pass to guest */
diff --git a/target-i386/machine.c b/target-i386/machine.c
index d548c055a9..24bc373b9c 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -290,6 +290,7 @@ static void cpu_pre_save(void *opaque)
 static int cpu_post_load(void *opaque, int version_id)
 {
     X86CPU *cpu = opaque;
+    CPUState *cs = CPU(cpu);
     CPUX86State *env = &cpu->env;
     int i;
 
@@ -319,12 +320,12 @@ static int cpu_post_load(void *opaque, int version_id)
         env->fptags[i] = (env->fptag_vmstate >> i) & 1;
     }
 
-    cpu_breakpoint_remove_all(env, BP_CPU);
-    cpu_watchpoint_remove_all(env, BP_CPU);
+    cpu_breakpoint_remove_all(cs, BP_CPU);
+    cpu_watchpoint_remove_all(cs, BP_CPU);
     for (i = 0; i < DR7_MAX_BP; i++) {
         hw_breakpoint_insert(env, i);
     }
-    tlb_flush(env, 1);
+    tlb_flush(cs, 1);
 
     return 0;
 }
diff --git a/target-i386/mem_helper.c b/target-i386/mem_helper.c
index 319a219f8a..b3b811bc8c 100644
--- a/target-i386/mem_helper.c
+++ b/target-i386/mem_helper.c
@@ -129,21 +129,25 @@ void helper_boundl(CPUX86State *env, target_ulong a0, int v)
 
 #if !defined(CONFIG_USER_ONLY)
 /* try to fill the TLB and return an exception if error. If retaddr is
-   NULL, it means that the function was called in C code (i.e. not
-   from generated code or from helper.c) */
+ * NULL, it means that the function was called in C code (i.e. not
+ * from generated code or from helper.c)
+ */
 /* XXX: fix it to restore all registers */
-void tlb_fill(CPUX86State *env, target_ulong addr, int is_write, int mmu_idx,
+void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
               uintptr_t retaddr)
 {
     int ret;
 
-    ret = cpu_x86_handle_mmu_fault(env, addr, is_write, mmu_idx);
+    ret = x86_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
     if (ret) {
+        X86CPU *cpu = X86_CPU(cs);
+        CPUX86State *env = &cpu->env;
+
         if (retaddr) {
             /* now we have a real cpu fault */
-            cpu_restore_state(env, retaddr);
+            cpu_restore_state(cs, retaddr);
         }
-        raise_exception_err(env, env->exception_index, env->error_code);
+        raise_exception_err(env, cs->exception_index, env->error_code);
     }
 }
 #endif
diff --git a/target-i386/misc_helper.c b/target-i386/misc_helper.c
index 47f6a2f7c1..1e2da1ed68 100644
--- a/target-i386/misc_helper.c
+++ b/target-i386/misc_helper.c
@@ -221,8 +221,10 @@ void helper_lmsw(CPUX86State *env, target_ulong t0)
 
 void helper_invlpg(CPUX86State *env, target_ulong addr)
 {
+    X86CPU *cpu = x86_env_get_cpu(env);
+
     cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPG, 0);
-    tlb_flush_page(env, addr);
+    tlb_flush_page(CPU(cpu), addr);
 }
 
 void helper_rdtsc(CPUX86State *env)
@@ -568,11 +570,11 @@ void helper_rdmsr(CPUX86State *env)
 
 static void do_pause(X86CPU *cpu)
 {
-    CPUX86State *env = &cpu->env;
+    CPUState *cs = CPU(cpu);
 
     /* Just let another CPU run.  */
-    env->exception_index = EXCP_INTERRUPT;
-    cpu_loop_exit(env);
+    cs->exception_index = EXCP_INTERRUPT;
+    cpu_loop_exit(cs);
 }
 
 static void do_hlt(X86CPU *cpu)
@@ -582,8 +584,8 @@ static void do_hlt(X86CPU *cpu)
 
     env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
     cs->halted = 1;
-    env->exception_index = EXCP_HLT;
-    cpu_loop_exit(env);
+    cs->exception_index = EXCP_HLT;
+    cpu_loop_exit(cs);
 }
 
 void helper_hlt(CPUX86State *env, int next_eip_addend)
@@ -638,6 +640,8 @@ void helper_pause(CPUX86State *env, int next_eip_addend)
 
 void helper_debug(CPUX86State *env)
 {
-    env->exception_index = EXCP_DEBUG;
-    cpu_loop_exit(env);
+    CPUState *cs = CPU(x86_env_get_cpu(env));
+
+    cs->exception_index = EXCP_DEBUG;
+    cpu_loop_exit(cs);
 }
diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c
index 959212bfe3..8c3f92c22b 100644
--- a/target-i386/seg_helper.c
+++ b/target-i386/seg_helper.c
@@ -95,6 +95,7 @@ static inline void load_seg_vm(CPUX86State *env, int seg, int selector)
 static inline void get_ss_esp_from_tss(CPUX86State *env, uint32_t *ss_ptr,
                                        uint32_t *esp_ptr, int dpl)
 {
+    X86CPU *cpu = x86_env_get_cpu(env);
     int type, index, shift;
 
 #if 0
@@ -112,11 +113,11 @@ static inline void get_ss_esp_from_tss(CPUX86State *env, uint32_t *ss_ptr,
 #endif
 
     if (!(env->tr.flags & DESC_P_MASK)) {
-        cpu_abort(env, "invalid tss");
+        cpu_abort(CPU(cpu), "invalid tss");
     }
     type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
     if ((type & 7) != 1) {
-        cpu_abort(env, "invalid tss type");
+        cpu_abort(CPU(cpu), "invalid tss type");
     }
     shift = type >> 3;
     index = (dpl * 4 + 2) << shift;
@@ -782,6 +783,7 @@ static void do_interrupt_protected(CPUX86State *env, int intno, int is_int,
 
 static inline target_ulong get_rsp_from_tss(CPUX86State *env, int level)
 {
+    X86CPU *cpu = x86_env_get_cpu(env);
     int index;
 
 #if 0
@@ -790,7 +792,7 @@ static inline target_ulong get_rsp_from_tss(CPUX86State *env, int level)
 #endif
 
     if (!(env->tr.flags & DESC_P_MASK)) {
-        cpu_abort(env, "invalid tss");
+        cpu_abort(CPU(cpu), "invalid tss");
     }
     index = 8 * level + 4;
     if ((index + 7) > env->tr.limit) {
@@ -935,9 +937,11 @@ static void do_interrupt64(CPUX86State *env, int intno, int is_int,
 #if defined(CONFIG_USER_ONLY)
 void helper_syscall(CPUX86State *env, int next_eip_addend)
 {
-    env->exception_index = EXCP_SYSCALL;
+    CPUState *cs = CPU(x86_env_get_cpu(env));
+
+    cs->exception_index = EXCP_SYSCALL;
     env->exception_next_eip = env->eip + next_eip_addend;
-    cpu_loop_exit(env);
+    cpu_loop_exit(cs);
 }
 #else
 void helper_syscall(CPUX86State *env, int next_eip_addend)
@@ -1131,7 +1135,7 @@ static void do_interrupt_user(CPUX86State *env, int intno, int is_int,
 static void handle_even_inj(CPUX86State *env, int intno, int is_int,
                             int error_code, int is_hw, int rm)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(x86_env_get_cpu(env));
     uint32_t event_inj = ldl_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb,
                                                           control.event_inj));
 
@@ -1248,7 +1252,7 @@ void x86_cpu_do_interrupt(CPUState *cs)
     /* if user mode only, we simulate a fake exception
        which will be handled outside the cpu execution
        loop */
-    do_interrupt_user(env, env->exception_index,
+    do_interrupt_user(env, cs->exception_index,
                       env->exception_is_int,
                       env->error_code,
                       env->exception_next_eip);
@@ -1258,7 +1262,7 @@ void x86_cpu_do_interrupt(CPUState *cs)
     /* simulate a real cpu exception. On i386, it can
        trigger new exceptions, but we do not handle
        double or triple faults yet. */
-    do_interrupt_all(cpu, env->exception_index,
+    do_interrupt_all(cpu, cs->exception_index,
                      env->exception_is_int,
                      env->error_code,
                      env->exception_next_eip, 0);
diff --git a/target-i386/smm_helper.c b/target-i386/smm_helper.c
index 71c64b2479..35901c9e89 100644
--- a/target-i386/smm_helper.c
+++ b/target-i386/smm_helper.c
@@ -181,8 +181,8 @@ void do_smm_enter(X86CPU *cpu)
 
 void helper_rsm(CPUX86State *env)
 {
-    CPUState *cs = ENV_GET_CPU(env);
     X86CPU *cpu = x86_env_get_cpu(env);
+    CPUState *cs = CPU(cpu);
     target_ulong sm_state;
     int i, offset;
     uint32_t val;
diff --git a/target-i386/svm_helper.c b/target-i386/svm_helper.c
index b38d45002f..aa17ecdece 100644
--- a/target-i386/svm_helper.c
+++ b/target-i386/svm_helper.c
@@ -88,7 +88,8 @@ void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param,
 static inline void svm_save_seg(CPUX86State *env, hwaddr addr,
                                 const SegmentCache *sc)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(x86_env_get_cpu(env));
+
     stw_phys(cs->as, addr + offsetof(struct vmcb_seg, selector),
              sc->selector);
     stq_phys(cs->as, addr + offsetof(struct vmcb_seg, base),
@@ -102,7 +103,7 @@ static inline void svm_save_seg(CPUX86State *env, hwaddr addr,
 static inline void svm_load_seg(CPUX86State *env, hwaddr addr,
                                 SegmentCache *sc)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(x86_env_get_cpu(env));
     unsigned int flags;
 
     sc->selector = lduw_phys(cs->as,
@@ -125,7 +126,7 @@ static inline void svm_load_seg_cache(CPUX86State *env, hwaddr addr,
 
 void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(x86_env_get_cpu(env));
     target_ulong addr;
     uint32_t event_inj;
     uint32_t int_ctl;
@@ -293,7 +294,7 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
         break;
     case TLB_CONTROL_FLUSH_ALL_ASID:
         /* FIXME: this is not 100% correct but should work for now */
-        tlb_flush(env, 1);
+        tlb_flush(cs, 1);
         break;
     }
 
@@ -319,7 +320,7 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
         /* FIXME: need to implement valid_err */
         switch (event_inj & SVM_EVTINJ_TYPE_MASK) {
         case SVM_EVTINJ_TYPE_INTR:
-            env->exception_index = vector;
+            cs->exception_index = vector;
             env->error_code = event_inj_err;
             env->exception_is_int = 0;
             env->exception_next_eip = -1;
@@ -328,31 +329,31 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
             do_interrupt_x86_hardirq(env, vector, 1);
             break;
         case SVM_EVTINJ_TYPE_NMI:
-            env->exception_index = EXCP02_NMI;
+            cs->exception_index = EXCP02_NMI;
             env->error_code = event_inj_err;
             env->exception_is_int = 0;
             env->exception_next_eip = env->eip;
             qemu_log_mask(CPU_LOG_TB_IN_ASM, "NMI");
-            cpu_loop_exit(env);
+            cpu_loop_exit(cs);
             break;
         case SVM_EVTINJ_TYPE_EXEPT:
-            env->exception_index = vector;
+            cs->exception_index = vector;
             env->error_code = event_inj_err;
             env->exception_is_int = 0;
             env->exception_next_eip = -1;
             qemu_log_mask(CPU_LOG_TB_IN_ASM, "EXEPT");
-            cpu_loop_exit(env);
+            cpu_loop_exit(cs);
             break;
         case SVM_EVTINJ_TYPE_SOFT:
-            env->exception_index = vector;
+            cs->exception_index = vector;
             env->error_code = event_inj_err;
             env->exception_is_int = 1;
             env->exception_next_eip = env->eip;
             qemu_log_mask(CPU_LOG_TB_IN_ASM, "SOFT");
-            cpu_loop_exit(env);
+            cpu_loop_exit(cs);
             break;
         }
-        qemu_log_mask(CPU_LOG_TB_IN_ASM, " %#x %#x\n", env->exception_index,
+        qemu_log_mask(CPU_LOG_TB_IN_ASM, " %#x %#x\n", cs->exception_index,
                       env->error_code);
     }
 }
@@ -365,7 +366,7 @@ void helper_vmmcall(CPUX86State *env)
 
 void helper_vmload(CPUX86State *env, int aflag)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(x86_env_get_cpu(env));
     target_ulong addr;
 
     cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0);
@@ -405,7 +406,7 @@ void helper_vmload(CPUX86State *env, int aflag)
 
 void helper_vmsave(CPUX86State *env, int aflag)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(x86_env_get_cpu(env));
     target_ulong addr;
 
     cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0);
@@ -468,6 +469,7 @@ void helper_skinit(CPUX86State *env)
 
 void helper_invlpga(CPUX86State *env, int aflag)
 {
+    X86CPU *cpu = x86_env_get_cpu(env);
     target_ulong addr;
 
     cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPGA, 0);
@@ -480,13 +482,13 @@ void helper_invlpga(CPUX86State *env, int aflag)
 
     /* XXX: could use the ASID to see if it is needed to do the
        flush */
-    tlb_flush_page(env, addr);
+    tlb_flush_page(CPU(cpu), addr);
 }
 
 void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type,
                                       uint64_t param)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(x86_env_get_cpu(env));
 
     if (likely(!(env->hflags & HF_SVMI_MASK))) {
         return;
@@ -568,7 +570,8 @@ void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type,
 void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param,
                          uint32_t next_eip_addend)
 {
-    CPUState *cs = ENV_GET_CPU(env);
+    CPUState *cs = CPU(x86_env_get_cpu(env));
+
     if (env->intercept & (1ULL << (SVM_EXIT_IOIO - SVM_EXIT_INTR))) {
         /* FIXME: this should be read in at vmrun (faster this way?) */
         uint64_t addr = ldq_phys(cs->as, env->vm_vmcb +
@@ -766,11 +769,11 @@ void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
        #GP fault is delivered inside the host. */
 
     /* remove any pending exception */
-    env->exception_index = -1;
+    cs->exception_index = -1;
     env->error_code = 0;
     env->old_exception = -1;
 
-    cpu_loop_exit(env);
+    cpu_loop_exit(cs);
 }
 
 void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 707ebd5ca0..02625e31c2 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -7965,8 +7965,8 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu,
 
     gen_tb_start();
     for(;;) {
-        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
-            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
+            QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
                 if (bp->pc == pc_ptr &&
                     !((bp->flags & BP_CPU) && (tb->flags & HF_RF_MASK))) {
                     gen_debug(dc, pc_ptr - dc->cs_base);