Signed-off-by: Igor Mammedov <imamm...@redhat.com>
---
v2:
  * restore original behavior, check features against host before
    they might be filtered out by TCG masks. spotted-by: Eduardo Habkost
v3:
  * use static properties instead of feature name arrays
  * since "check" is becoming regular boolean property it would be
    possible to turn it off while "enforce=on", set check_cpuid=true
    if "enforce=on" after all properties set at realize time.
---
 target-i386/cpu.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 73 insertions(+), 12 deletions(-)

diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 44cbf9c..061ee01 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -237,6 +237,62 @@ PropertyInfo qdev_prop_hv_vapic = {
 #define DEFINE_PROP_HV_VAPIC(_n)                                               
\
     DEFINE_ABSTRACT_PROP(_n, qdev_prop_hv_vapic)
 
+static bool check_cpuid;
+
+static void x86_cpuid_get_check(Object *obj, Visitor *v, void *opaque,
+                                         const char *name, Error **errp)
+{
+    visit_type_bool(v, &check_cpuid, name, errp);
+}
+
+static void x86_cpuid_set_check(Object *obj, Visitor *v, void *opaque,
+                                         const char *name, Error **errp)
+{
+    bool value;
+
+    visit_type_bool(v, &value, name, errp);
+    if (error_is_set(errp)) {
+        return;
+    }
+    check_cpuid = value;
+}
+
+PropertyInfo qdev_prop_check = {
+    .name  = "bool",
+    .get   = x86_cpuid_get_check,
+    .set   = x86_cpuid_set_check,
+};
+#define DEFINE_PROP_CHECK(_n) \
+    DEFINE_ABSTRACT_PROP(_n, qdev_prop_check)
+
+static bool enforce_cpuid;
+
+static void x86_cpuid_get_enforce(Object *obj, Visitor *v, void *opaque,
+                                         const char *name, Error **errp)
+{
+    visit_type_bool(v, &enforce_cpuid, name, errp);
+}
+
+static void x86_cpuid_set_enforce(Object *obj, Visitor *v, void *opaque,
+                                         const char *name, Error **errp)
+{
+    bool value;
+
+    visit_type_bool(v, &value, name, errp);
+    if (error_is_set(errp)) {
+        return;
+    }
+    enforce_cpuid = value;
+}
+
+PropertyInfo qdev_prop_enforce = {
+    .name  = "boolean",
+    .get   = x86_cpuid_get_enforce,
+    .set   = x86_cpuid_set_enforce,
+};
+#define DEFINE_PROP_ENFORCE(_n)                                                
\
+    DEFINE_ABSTRACT_PROP(_n, qdev_prop_enforce)
+
 static Property cpu_x86_properties[] = {
     DEFINE_PROP_BIT("f-fpu", X86CPU, env.cpuid_features,  0, false),
     DEFINE_PROP_BIT("f-vme", X86CPU, env.cpuid_features,  1, false),
@@ -354,6 +410,8 @@ static Property cpu_x86_properties[] = {
     DEFINE_PROP_HV_SPINLOCKS("hv_spinlocks"),
     DEFINE_PROP_HV_RELAXED("hv_relaxed"),
     DEFINE_PROP_HV_VAPIC("hv_vapic"),
+    DEFINE_PROP_CHECK("check"),
+    DEFINE_PROP_ENFORCE("enforce"),
     DEFINE_PROP_END_OF_LIST(),
  };
 
@@ -367,9 +425,6 @@ typedef struct model_features_t {
     uint32_t cpuid;
     } model_features_t;
 
-int check_cpuid = 0;
-int enforce_cpuid = 0;
-
 void host_cpuid(uint32_t function, uint32_t count,
                 uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
 {
@@ -1064,19 +1119,20 @@ static int unavailable_host_feature(struct 
model_features_t *f, uint32_t mask)
  * their way to the guest.  Note: ft[].check_feat ideally should be
  * specified via a guest_def field to suppress report of extraneous flags.
  */
-static int check_features_against_host(x86_def_t *guest_def)
+static int check_features_against_host(X86CPU *cpu)
 {
+    CPUX86State *env = &cpu->env;
     x86_def_t host_def;
     uint32_t mask;
     int rv, i;
     struct model_features_t ft[] = {
-        {&guest_def->features, &host_def.features,
+        {&env->cpuid_features, &host_def.features,
             ~0, feature_name, 0x00000000},
-        {&guest_def->ext_features, &host_def.ext_features,
+        {&env->cpuid_ext_features, &host_def.ext_features,
             ~CPUID_EXT_HYPERVISOR, ext_feature_name, 0x00000001},
-        {&guest_def->ext2_features, &host_def.ext2_features,
+        {&env->cpuid_ext2_features, &host_def.ext2_features,
             ~PPRO_FEATURES, ext2_feature_name, 0x80000000},
-        {&guest_def->ext3_features, &host_def.ext3_features,
+        {&env->cpuid_ext3_features, &host_def.ext3_features,
             ~CPUID_EXT3_SVM, ext3_feature_name, 0x80000001}};
 
     cpu_x86_fill_host(&host_def);
@@ -1594,10 +1650,6 @@ static int cpu_x86_find_by_name(X86CPU *cpu, x86_def_t 
*x86_cpu_def,
     x86_cpu_def->kvm_features &= ~minus_kvm_features;
     x86_cpu_def->svm_features &= ~minus_svm_features;
     x86_cpu_def->cpuid_7_0_ebx_features &= ~minus_7_0_ebx_features;
-    if (check_cpuid) {
-        if (check_features_against_host(x86_cpu_def) && enforce_cpuid)
-            goto error;
-    }
     g_free(s);
     return 0;
 
@@ -2159,6 +2211,15 @@ void x86_cpu_realize(Object *obj, Error **errp)
         env->cpuid_level = 7;
     }
 
+    if (enforce_cpuid) {
+        check_cpuid = true;
+    }
+    if (check_cpuid && check_features_against_host(cpu)
+        && enforce_cpuid) {
+        error_set(errp, QERR_PERMISSION_DENIED);
+        return;
+    }
+
     if (!kvm_enabled()) {
         env->cpuid_features &= TCG_FEATURES;
         env->cpuid_ext_features &= TCG_EXT_FEATURES;
-- 
1.7.11.7


Reply via email to