CPU definitions can now define arbitrary additional MSRs, and rdmsr will support those MSRs and return the corresponding values.
Signed-off-by: Josh Triplett <j...@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 --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; -- 1.7.8.3