diff mbox

[2/3] Support arbitrary additional MSRs in cpu definitions

Message ID 61ad8602bfd32ab635862fd406e1b4bba4e7fa89.1326641605.git.josh@joshtriplett.org
State New
Headers show

Commit Message

Josh Triplett Jan. 15, 2012, 3:39 p.m. UTC
CPU definitions can now define arbitrary additional MSRs, and rdmsr will
support those MSRs and return the corresponding values.

Signed-off-by: Josh Triplett <josh@joshtriplett.org>
---
 qemu-config.c           |    3 +++
 target-i386/cpu.h       |    5 +++++
 target-i386/cpuid.c     |   45 +++++++++++++++++++++++++++++++++++++++++++++
 target-i386/op_helper.c |   20 ++++++++++++++++++++
 4 files changed, 73 insertions(+), 0 deletions(-)
diff mbox

Patch

diff --git a/qemu-config.c b/qemu-config.c
index 8f9f16e..a675ba7 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -419,6 +419,9 @@  static QemuOptsList qemu_cpudef_opts = {
         },{
             .name = "msr_gpf",
             .type = QEMU_OPT_BOOL,
+        },{
+            .name = "msr",
+            .type = QEMU_OPT_STRING,
         },
         { /* end of list */ }
     },
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index c37cb30..3c0f8f1 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -613,6 +613,8 @@  typedef struct {
 
 #define NB_MMU_MODES 2
 
+struct QDict;
+
 typedef struct CPUX86State {
     /* standard registers */
     target_ulong regs[CPU_NB_REGS];
@@ -735,6 +737,9 @@  typedef struct CPUX86State {
     uint32_t cpuid_xlevel2;
     uint32_t cpuid_ext4_features;
     bool msr_gpf;
+#ifdef CONFIG_SOFTMMU
+    struct QDict *msr_dict;
+#endif
 
     /* MTRRs */
     uint64_t mtrr_fixed[11];
diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c
index 8cbbe9b..ea55f69 100644
--- a/target-i386/cpuid.c
+++ b/target-i386/cpuid.c
@@ -26,6 +26,10 @@ 
 
 #include "qemu-option.h"
 #include "qemu-config.h"
+#ifdef CONFIG_SOFTMMU
+#include "qdict.h"
+#include "qint.h"
+#endif
 
 /* feature flags taken from "Intel Processor Identification and the CPUID
  * Instruction" and AMD's "CPUID Specification".  In cases of disagreement
@@ -235,6 +239,9 @@  typedef struct x86_def_t {
     uint32_t ext4_features;
     uint32_t xlevel2;
     bool msr_gpf;
+#ifdef CONFIG_SOFTMMU
+    QDict *msr_dict;
+#endif
 } x86_def_t;
 
 #define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
@@ -624,6 +631,9 @@  static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
         goto error;
     } else {
         memcpy(x86_cpu_def, def, sizeof(*def));
+#ifdef CONFIG_SOFTMMU
+        QINCREF(def->msr_dict);
+#endif
     }
 
     plus_kvm_features = ~0; /* not supported bits will be filtered out later */
@@ -847,6 +857,17 @@  void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf, const char *optarg)
                 def->ext3_features, buf);
             if (def->msr_gpf)
                 (*cpu_fprintf)(f, "  GPF on unknown MSRs\n");
+#ifdef CONFIG_SOFTMMU
+            if (def->msr_dict) {
+                const QDictEntry *entry;
+                (*cpu_fprintf)(f, "  Additional MSRs:\n");
+                for (entry = qdict_first(def->msr_dict); entry;
+                     entry = qdict_next(def->msr_dict, entry))
+                    (*cpu_fprintf)(f, "    MSR 0x%s = 0x%" PRIx64 "\n",
+                        qdict_entry_key(entry),
+                        (uint64_t)qint_get_int(qobject_to_qint(qdict_entry_value(entry))));
+            }
+#endif
             (*cpu_fprintf)(f, "\n");
         }
     }
@@ -890,6 +911,10 @@  int cpu_x86_register (CPUX86State *env, const char *cpu_model)
     env->cpuid_ext4_features = def->ext4_features;
     env->cpuid_xlevel2 = def->xlevel2;
     env->msr_gpf = def->msr_gpf;
+#ifdef CONFIG_SOFTMMU
+    env->msr_dict = def->msr_dict;
+    QINCREF(def->msr_dict);
+#endif
     env->tsc_khz = def->tsc_khz;
     if (!kvm_enabled()) {
         env->cpuid_features &= TCG_FEATURES;
@@ -1003,6 +1028,26 @@  static int cpudef_setfield(const char *name, const char *str, void *opaque)
         setscalar(&def->xlevel, str, &err)
     } else if (!strcmp(name, "msr_gpf")) {
         /* Handled in cpudef_register */
+    } else if (!strcmp(name, "msr")) {
+#ifdef CONFIG_SOFTMMU
+        int chars;
+        def->msr_dict = qdict_new();
+        /* Skip initial whitespace */
+        sscanf(str, " %n", &chars);
+        str += chars;
+        while (*str) {
+            int32_t num;
+            int64_t value;
+            char key[9];
+            if (sscanf(str, " %" SCNi32 " = %" SCNi64 " %n", &num, &value, &chars) < 2) {
+                fprintf(stderr, "error: bad value for msr option; failed to parse \"%s\"\n", str);
+                return 1;
+            }
+            str += chars;
+            snprintf(key, sizeof(key), "%x", (uint32_t)num);
+            qdict_put(def->msr_dict, key, qint_from_int(value));
+        }
+#endif
     } else {
         fprintf(stderr, "error: unknown option [%s = %s]\n", name, str);
         return (1);
diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c
index f782f03..c7d5dab 100644
--- a/target-i386/op_helper.c
+++ b/target-i386/op_helper.c
@@ -27,6 +27,11 @@ 
 #include "cpu-defs.h"
 #include "helper.h"
 
+#ifdef CONFIG_SOFTMMU
+#include "qdict.h"
+#include "qint.h"
+#endif
+
 #if !defined(CONFIG_USER_ONLY)
 #include "softmmu_exec.h"
 #endif /* !defined(CONFIG_USER_ONLY) */
@@ -3306,6 +3311,21 @@  void helper_rdmsr(void)
 
     helper_svm_check_intercept_param(SVM_EXIT_MSR, 0);
 
+#ifdef CONFIG_SOFTMMU
+    if (env->msr_dict) {
+        char key[9];
+        QObject *obj;
+        snprintf(key, sizeof(key), "%x", (uint32_t)ECX);
+        obj = qdict_get(env->msr_dict, key);
+        if (obj) {
+            val = (uint64_t)qint_get_int(qobject_to_qint(obj));
+            EAX = (uint32_t)(val);
+            EDX = (uint32_t)(val >> 32);
+            return;
+        }
+    }
+#endif
+
     switch((uint32_t)ECX) {
     case MSR_IA32_SYSENTER_CS:
         val = env->sysenter_cs;