diff mbox

[1/3] Add cpudef option to GPF on unknown MSRs

Message ID 97b7217405af678e1dda6836b25b38e0cf0bbcf2.1326641605.git.josh@joshtriplett.org
State New
Headers show

Commit Message

Josh Triplett Jan. 15, 2012, 3:39 p.m. UTC
qemu normally returns 0 for rdmsr of an unknown MSR, and silently
ignores wrmsr of an unknown MSR.  Add a new msr_gpf option to cpudef,
which when enabled causes qemu to generate a GPF on any access to an
unknown MSR.

This option allows qemu to better support software which detects the
availability of MSRs and their associated features by handling GPFs.

Signed-off-by: Josh Triplet <josh@joshtriplett.org>
---
 qemu-config.c           |    3 +++
 target-i386/cpu.h       |    1 +
 target-i386/cpuid.c     |    9 +++++++++
 target-i386/op_helper.c |   16 ++++++++++++----
 4 files changed, 25 insertions(+), 4 deletions(-)
diff mbox

Patch

diff --git a/qemu-config.c b/qemu-config.c
index ecc88e8..8f9f16e 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -416,6 +416,9 @@  static QemuOptsList qemu_cpudef_opts = {
         },{
             .name = "vendor_override",
             .type = QEMU_OPT_NUMBER,
+        },{
+            .name = "msr_gpf",
+            .type = QEMU_OPT_BOOL,
         },
         { /* end of list */ }
     },
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 37dde79..c37cb30 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -734,6 +734,7 @@  typedef struct CPUX86State {
     /* Store the results of Centaur's CPUID instructions */
     uint32_t cpuid_xlevel2;
     uint32_t cpuid_ext4_features;
+    bool msr_gpf;
 
     /* MTRRs */
     uint64_t mtrr_fixed[11];
diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c
index 91a104b..8cbbe9b 100644
--- a/target-i386/cpuid.c
+++ b/target-i386/cpuid.c
@@ -234,6 +234,7 @@  typedef struct x86_def_t {
     /* Store the results of Centaur's CPUID instructions */
     uint32_t ext4_features;
     uint32_t xlevel2;
+    bool msr_gpf;
 } x86_def_t;
 
 #define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
@@ -547,6 +548,8 @@  static int cpu_x86_fill_host(x86_def_t *x86_cpu_def)
      */
     x86_cpu_def->svm_features = -1;
 
+    x86_cpu_def->msr_gpf = false;
+
     return 0;
 }
 
@@ -842,6 +845,8 @@  void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf, const char *optarg)
                 0);
             (*cpu_fprintf)(f, "  extfeature_ecx %08x (%s)\n",
                 def->ext3_features, buf);
+            if (def->msr_gpf)
+                (*cpu_fprintf)(f, "  GPF on unknown MSRs\n");
             (*cpu_fprintf)(f, "\n");
         }
     }
@@ -884,6 +889,7 @@  int cpu_x86_register (CPUX86State *env, const char *cpu_model)
     env->cpuid_svm_features = def->svm_features;
     env->cpuid_ext4_features = def->ext4_features;
     env->cpuid_xlevel2 = def->xlevel2;
+    env->msr_gpf = def->msr_gpf;
     env->tsc_khz = def->tsc_khz;
     if (!kvm_enabled()) {
         env->cpuid_features &= TCG_FEATURES;
@@ -995,6 +1001,8 @@  static int cpudef_setfield(const char *name, const char *str, void *opaque)
         setfeatures(&def->ext3_features, str, ext3_feature_name, &err);
     } else if (!strcmp(name, "xlevel")) {
         setscalar(&def->xlevel, str, &err)
+    } else if (!strcmp(name, "msr_gpf")) {
+        /* Handled in cpudef_register */
     } else {
         fprintf(stderr, "error: unknown option [%s = %s]\n", name, str);
         return (1);
@@ -1013,6 +1021,7 @@  static int cpudef_register(QemuOpts *opts, void *opaque)
     x86_def_t *def = g_malloc0(sizeof (x86_def_t));
 
     qemu_opt_foreach(opts, cpudef_setfield, def, 1);
+    def->msr_gpf = qemu_opt_get_bool(opts, "msr_gpf", false);
     def->next = x86_defs;
     x86_defs = def;
     return (0);
diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c
index 2aea71b..f782f03 100644
--- a/target-i386/op_helper.c
+++ b/target-i386/op_helper.c
@@ -3292,7 +3292,10 @@  void helper_wrmsr(void)
                 env->mce_banks[offset] = val;
             break;
         }
-        /* XXX: exception ? */
+        if (env->msr_gpf) {
+            raise_exception(EXCP0D_GPF);
+            return;
+        }
         break;
     }
 }
@@ -3400,8 +3403,10 @@  void helper_rdmsr(void)
     case MSR_MTRRcap:
         if (env->cpuid_features & CPUID_MTRR)
             val = MSR_MTRRcap_VCNT | MSR_MTRRcap_FIXRANGE_SUPPORT | MSR_MTRRcap_WC_SUPPORTED;
-        else
-            /* XXX: exception ? */
+        else if (env->msr_gpf) {
+            raise_exception(EXCP0D_GPF);
+            return;
+        } else
             val = 0;
         break;
     case MSR_MCG_CAP:
@@ -3426,7 +3431,10 @@  void helper_rdmsr(void)
             val = env->mce_banks[offset];
             break;
         }
-        /* XXX: exception ? */
+        if (env->msr_gpf) {
+            raise_exception(EXCP0D_GPF);
+            return;
+        }
         val = 0;
         break;
     }