提交 bc1c7217 编写于 作者: P Peter Maydell

Merge remote-tracking branch 'remotes/kvm/uq/master' into staging

* remotes/kvm/uq/master:
  target-i386: Move KVM default-vendor hack to instance_init
  target-i386: Don't change x86_def_t struct on cpu_x86_register()
  target-i386: Eliminate CONFIG_KVM #ifdefs
  kvm: add support for hyper-v timers
  kvm: make hyperv vapic assist page migratable
  kvm: make hyperv hypercall and guest os id MSRs migratable.
  kvm: make availability of Hyper-V enlightenments dependent on KVM_CAP_HYPERV
  KVM: fix coexistence of KVM and Hyper-V leaves
  kvm: print suberror on all internal errors
  target-i386: kvm_check_features_against_host(): Kill feature word array
  target-i386: kvm_cpu_fill_host(): Fill feature words in a loop
  target-i386: kvm_cpu_fill_host(): Set all feature words at end of function
  target-i386: kvm_cpu_fill_host(): No need to check xlevel2
  target-i386: kvm_cpu_fill_host(): No need to check CPU vendor
  target-i386: kvm_cpu_fill_host(): No need to check level
  target-i386: kvm_cpu_fill_host(): Kill unused code
Signed-off-by: NPeter Maydell <peter.maydell@linaro.org>
......@@ -1546,17 +1546,16 @@ static void kvm_handle_io(uint16_t port, void *data, int direction, int size,
static int kvm_handle_internal_error(CPUState *cpu, struct kvm_run *run)
{
fprintf(stderr, "KVM internal error.");
fprintf(stderr, "KVM internal error. Suberror: %d\n",
run->internal.suberror);
if (kvm_check_extension(kvm_state, KVM_CAP_INTERNAL_ERROR_DATA)) {
int i;
fprintf(stderr, " Suberror: %d\n", run->internal.suberror);
for (i = 0; i < run->internal.ndata; ++i) {
fprintf(stderr, "extra data[%d]: %"PRIx64"\n",
i, (uint64_t)run->internal.data[i]);
}
} else {
fprintf(stderr, "\n");
}
if (run->internal.suberror == KVM_INTERNAL_ERROR_EMULATION) {
fprintf(stderr, "emulation failure\n");
......
......@@ -149,6 +149,9 @@
/* MSR used to read the per-partition time reference counter */
#define HV_X64_MSR_TIME_REF_COUNT 0x40000020
/* A partition's reference time stamp counter (TSC) page */
#define HV_X64_MSR_REFERENCE_TSC 0x40000021
/* MSR used to retrieve the TSC frequency */
#define HV_X64_MSR_TSC_FREQUENCY 0x40000022
......
......@@ -674,6 +674,7 @@ struct kvm_ppc_smmu_info {
#define KVM_CAP_ARM_EL1_32BIT 93
#define KVM_CAP_SPAPR_MULTITCE 94
#define KVM_CAP_EXT_EMUL_CPUID 95
#define KVM_CAP_HYPERV_TIME 96
#ifdef KVM_CAP_IRQ_ROUTING
......
......@@ -69,6 +69,7 @@ typedef struct X86CPU {
bool hyperv_vapic;
bool hyperv_relaxed_timing;
int hyperv_spinlock_attempts;
bool hyperv_time;
bool check_cpuid;
bool enforce_cpuid;
......
......@@ -374,7 +374,6 @@ void disable_kvm_pv_eoi(void)
void host_cpuid(uint32_t function, uint32_t count,
uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
{
#if defined(CONFIG_KVM)
uint32_t vec[4];
#ifdef __x86_64__
......@@ -382,7 +381,7 @@ void host_cpuid(uint32_t function, uint32_t count,
: "=a"(vec[0]), "=b"(vec[1]),
"=c"(vec[2]), "=d"(vec[3])
: "0"(function), "c"(count) : "cc");
#else
#elif defined(__i386__)
asm volatile("pusha \n\t"
"cpuid \n\t"
"mov %%eax, 0(%2) \n\t"
......@@ -392,6 +391,8 @@ void host_cpuid(uint32_t function, uint32_t count,
"popa"
: : "a"(function), "c"(count), "S"(vec)
: "memory", "cc");
#else
abort();
#endif
if (eax)
......@@ -402,7 +403,6 @@ void host_cpuid(uint32_t function, uint32_t count,
*ecx = vec[2];
if (edx)
*edx = vec[3];
#endif
}
#define iswhite(c) ((c) && ((c) <= ' ' || '~' < (c)))
......@@ -1119,7 +1119,6 @@ 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,7 +1133,6 @@ static int cpu_x86_fill_model_id(char *str)
}
return 0;
}
#endif
/* Fill a x86_def_t struct with information about the host CPU, and
* the CPU features supported by the host hardware + host kernel
......@@ -1143,7 +1141,6 @@ static int cpu_x86_fill_model_id(char *str)
*/
static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def)
{
#ifdef CONFIG_KVM
KVMState *s = kvm_state;
uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
......@@ -1160,46 +1157,19 @@ static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def)
x86_cpu_def->stepping = eax & 0x0F;
x86_cpu_def->level = kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX);
x86_cpu_def->features[FEAT_1_EDX] =
kvm_arch_get_supported_cpuid(s, 0x1, 0, R_EDX);
x86_cpu_def->features[FEAT_1_ECX] =
kvm_arch_get_supported_cpuid(s, 0x1, 0, R_ECX);
if (x86_cpu_def->level >= 7) {
x86_cpu_def->features[FEAT_7_0_EBX] =
kvm_arch_get_supported_cpuid(s, 0x7, 0, R_EBX);
} else {
x86_cpu_def->features[FEAT_7_0_EBX] = 0;
}
x86_cpu_def->xlevel = kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX);
x86_cpu_def->features[FEAT_8000_0001_EDX] =
kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_EDX);
x86_cpu_def->features[FEAT_8000_0001_ECX] =
kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_ECX);
x86_cpu_def->xlevel2 =
kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX);
cpu_x86_fill_model_id(x86_cpu_def->model_id);
/* Call Centaur's CPUID instruction. */
if (!strcmp(x86_cpu_def->vendor, CPUID_VENDOR_VIA)) {
host_cpuid(0xC0000000, 0, &eax, &ebx, &ecx, &edx);
eax = kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX);
if (eax >= 0xC0000001) {
/* Support VIA max extended level */
x86_cpu_def->xlevel2 = eax;
host_cpuid(0xC0000001, 0, &eax, &ebx, &ecx, &edx);
x86_cpu_def->features[FEAT_C000_0001_EDX] =
kvm_arch_get_supported_cpuid(s, 0xC0000001, 0, R_EDX);
}
FeatureWord w;
for (w = 0; w < FEATURE_WORDS; w++) {
FeatureWordInfo *wi = &feature_word_info[w];
x86_cpu_def->features[w] =
kvm_arch_get_supported_cpuid(s, wi->cpuid_eax, wi->cpuid_ecx,
wi->cpuid_reg);
}
/* Other KVM-specific feature fields: */
x86_cpu_def->features[FEAT_SVM] =
kvm_arch_get_supported_cpuid(s, 0x8000000A, 0, R_EDX);
x86_cpu_def->features[FEAT_KVM] =
kvm_arch_get_supported_cpuid(s, KVM_CPUID_FEATURES, 0, R_EAX);
#endif /* CONFIG_KVM */
}
static int unavailable_host_feature(FeatureWordInfo *f, uint32_t mask)
......@@ -1226,48 +1196,23 @@ static int unavailable_host_feature(FeatureWordInfo *f, uint32_t mask)
*
* This function may be called only if KVM is enabled.
*/
static int kvm_check_features_against_host(X86CPU *cpu)
static int kvm_check_features_against_host(KVMState *s, X86CPU *cpu)
{
CPUX86State *env = &cpu->env;
x86_def_t host_def;
uint32_t mask;
int rv, i;
struct model_features_t ft[] = {
{&env->features[FEAT_1_EDX],
&host_def.features[FEAT_1_EDX],
FEAT_1_EDX },
{&env->features[FEAT_1_ECX],
&host_def.features[FEAT_1_ECX],
FEAT_1_ECX },
{&env->features[FEAT_8000_0001_EDX],
&host_def.features[FEAT_8000_0001_EDX],
FEAT_8000_0001_EDX },
{&env->features[FEAT_8000_0001_ECX],
&host_def.features[FEAT_8000_0001_ECX],
FEAT_8000_0001_ECX },
{&env->features[FEAT_C000_0001_EDX],
&host_def.features[FEAT_C000_0001_EDX],
FEAT_C000_0001_EDX },
{&env->features[FEAT_7_0_EBX],
&host_def.features[FEAT_7_0_EBX],
FEAT_7_0_EBX },
{&env->features[FEAT_SVM],
&host_def.features[FEAT_SVM],
FEAT_SVM },
{&env->features[FEAT_KVM],
&host_def.features[FEAT_KVM],
FEAT_KVM },
};
int rv = 0;
FeatureWord w;
assert(kvm_enabled());
kvm_cpu_fill_host(&host_def);
for (rv = 0, i = 0; i < ARRAY_SIZE(ft); ++i) {
FeatureWord w = ft[i].feat_word;
for (w = 0; w < FEATURE_WORDS; w++) {
FeatureWordInfo *wi = &feature_word_info[w];
uint32_t guest_feat = env->features[w];
uint32_t host_feat = kvm_arch_get_supported_cpuid(s, wi->cpuid_eax,
wi->cpuid_ecx,
wi->cpuid_reg);
uint32_t mask;
for (mask = 1; mask; mask <<= 1) {
if (*ft[i].guest_feat & mask &&
!(*ft[i].host_feat & mask)) {
if (guest_feat & mask && !(host_feat & mask)) {
unavailable_host_feature(wi, mask);
rv = 1;
}
......@@ -1656,18 +1601,6 @@ static int cpu_x86_find_by_name(X86CPU *cpu, x86_def_t *x86_cpu_def,
def = &builtin_x86_defs[i];
if (strcmp(name, def->name) == 0) {
memcpy(x86_cpu_def, def, sizeof(*def));
/* sysenter isn't supported in compatibility mode on AMD,
* syscall isn't supported in compatibility mode on Intel.
* Normally we advertise the actual CPU vendor, but you can
* override this using the 'vendor' property if you want to use
* KVM's sysenter/syscall emulation in compatibility mode and
* when doing cross vendor migration
*/
if (kvm_enabled()) {
uint32_t ebx = 0, ecx = 0, edx = 0;
host_cpuid(0, 0, NULL, &ebx, &ecx, &edx);
x86_cpu_vendor_words2str(x86_cpu_def->vendor, ebx, edx, ecx);
}
return 0;
}
}
......@@ -1867,7 +1800,6 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
return cpu_list;
}
#ifdef CONFIG_KVM
static void filter_features_for_kvm(X86CPU *cpu)
{
CPUX86State *env = &cpu->env;
......@@ -1884,7 +1816,6 @@ static void filter_features_for_kvm(X86CPU *cpu)
cpu->filtered_features[w] = requested_features & ~env->features[w];
}
}
#endif
static void cpu_x86_register(X86CPU *cpu, const char *name, Error **errp)
{
......@@ -1898,12 +1829,6 @@ static void cpu_x86_register(X86CPU *cpu, const char *name, Error **errp)
return;
}
if (kvm_enabled()) {
def->features[FEAT_KVM] |= kvm_default_features;
}
def->features[FEAT_1_ECX] |= CPUID_EXT_HYPERVISOR;
object_property_set_str(OBJECT(cpu), def->vendor, "vendor", errp);
object_property_set_int(OBJECT(cpu), def->level, "level", errp);
object_property_set_int(OBJECT(cpu), def->family, "family", errp);
object_property_set_int(OBJECT(cpu), def->model, "model", errp);
......@@ -1921,6 +1846,31 @@ static void cpu_x86_register(X86CPU *cpu, const char *name, Error **errp)
cpu->cache_info_passthrough = def->cache_info_passthrough;
object_property_set_str(OBJECT(cpu), def->model_id, "model-id", errp);
/* Special cases not set in the x86_def_t structs: */
if (kvm_enabled()) {
env->features[FEAT_KVM] |= kvm_default_features;
}
env->features[FEAT_1_ECX] |= CPUID_EXT_HYPERVISOR;
/* sysenter isn't supported in compatibility mode on AMD,
* syscall isn't supported in compatibility mode on Intel.
* Normally we advertise the actual CPU vendor, but you can
* override this using the 'vendor' property if you want to use
* 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];
if (kvm_enabled()) {
uint32_t ebx = 0, ecx = 0, edx = 0;
host_cpuid(0, 0, NULL, &ebx, &ecx, &edx);
x86_cpu_vendor_words2str(host_vendor, ebx, edx, ecx);
vendor = host_vendor;
}
object_property_set_str(OBJECT(cpu), vendor, "vendor", errp);
}
X86CPU *cpu_x86_create(const char *cpu_model, DeviceState *icc_bridge,
......@@ -2588,15 +2538,14 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
env->features[FEAT_8000_0001_ECX] &= TCG_EXT3_FEATURES;
env->features[FEAT_SVM] &= TCG_SVM_FEATURES;
} else {
KVMState *s = kvm_state;
if ((cpu->check_cpuid || cpu->enforce_cpuid)
&& kvm_check_features_against_host(cpu) && cpu->enforce_cpuid) {
&& kvm_check_features_against_host(s, cpu) && cpu->enforce_cpuid) {
error_setg(&local_err,
"Host's CPU doesn't support requested features");
goto out;
}
#ifdef CONFIG_KVM
filter_features_for_kvm(cpu);
#endif
}
#ifndef CONFIG_USER_ONLY
......@@ -2751,6 +2700,7 @@ static Property x86_cpu_properties[] = {
{ .name = "hv-spinlocks", .info = &qdev_prop_spinlocks },
DEFINE_PROP_BOOL("hv-relaxed", X86CPU, hyperv_relaxed_timing, false),
DEFINE_PROP_BOOL("hv-vapic", X86CPU, hyperv_vapic, false),
DEFINE_PROP_BOOL("hv-time", X86CPU, hyperv_time, false),
DEFINE_PROP_BOOL("check", X86CPU, check_cpuid, false),
DEFINE_PROP_BOOL("enforce", X86CPU, enforce_cpuid, false),
DEFINE_PROP_END_OF_LIST()
......
......@@ -862,6 +862,10 @@ typedef struct CPUX86State {
uint64_t msr_fixed_counters[MAX_FIXED_COUNTERS];
uint64_t msr_gp_counters[MAX_GP_COUNTERS];
uint64_t msr_gp_evtsel[MAX_GP_COUNTERS];
uint64_t msr_hv_hypercall;
uint64_t msr_hv_guest_os_id;
uint64_t msr_hv_vapic;
uint64_t msr_hv_tsc;
/* exception/interrupt handling */
int error_code;
......
......@@ -72,6 +72,9 @@ static bool has_msr_misc_enable;
static bool has_msr_bndcfgs;
static bool has_msr_kvm_steal_time;
static int lm_capable_kernel;
static bool has_msr_hv_hypercall;
static bool has_msr_hv_vapic;
static bool has_msr_hv_tsc;
static bool has_msr_architectural_pmu;
static uint32_t num_architectural_pmu_counters;
......@@ -437,8 +440,11 @@ static bool hyperv_hypercall_available(X86CPU *cpu)
static bool hyperv_enabled(X86CPU *cpu)
{
return hyperv_hypercall_available(cpu) ||
cpu->hyperv_relaxed_timing;
CPUState *cs = CPU(cpu);
return kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV) > 0 &&
(hyperv_hypercall_available(cpu) ||
cpu->hyperv_time ||
cpu->hyperv_relaxed_timing);
}
#define KVM_MAX_CPUID_ENTRIES 100
......@@ -455,6 +461,7 @@ int kvm_arch_init_vcpu(CPUState *cs)
uint32_t unused;
struct kvm_cpuid_entry2 *c;
uint32_t signature[3];
int kvm_base = KVM_CPUID_SIGNATURE;
int r;
memset(&cpuid_data, 0, sizeof(cpuid_data));
......@@ -462,26 +469,22 @@ int kvm_arch_init_vcpu(CPUState *cs)
cpuid_i = 0;
/* Paravirtualization CPUIDs */
c = &cpuid_data.entries[cpuid_i++];
c->function = KVM_CPUID_SIGNATURE;
if (!hyperv_enabled(cpu)) {
memcpy(signature, "KVMKVMKVM\0\0\0", 12);
c->eax = 0;
} else {
if (hyperv_enabled(cpu)) {
c = &cpuid_data.entries[cpuid_i++];
c->function = HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS;
memcpy(signature, "Microsoft Hv", 12);
c->eax = HYPERV_CPUID_MIN;
}
c->ebx = signature[0];
c->ecx = signature[1];
c->edx = signature[2];
c = &cpuid_data.entries[cpuid_i++];
c->function = KVM_CPUID_FEATURES;
c->eax = env->features[FEAT_KVM];
c->ebx = signature[0];
c->ecx = signature[1];
c->edx = signature[2];
if (hyperv_enabled(cpu)) {
c = &cpuid_data.entries[cpuid_i++];
c->function = HYPERV_CPUID_INTERFACE;
memcpy(signature, "Hv#1\0\0\0\0\0\0\0\0", 12);
c->eax = signature[0];
c->ebx = 0;
c->ecx = 0;
c->edx = 0;
c = &cpuid_data.entries[cpuid_i++];
c->function = HYPERV_CPUID_VERSION;
......@@ -496,14 +499,21 @@ int kvm_arch_init_vcpu(CPUState *cs)
if (cpu->hyperv_vapic) {
c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE;
c->eax |= HV_X64_MSR_APIC_ACCESS_AVAILABLE;
has_msr_hv_vapic = true;
}
if (cpu->hyperv_time &&
kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV_TIME) > 0) {
c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE;
c->eax |= HV_X64_MSR_TIME_REF_COUNT_AVAILABLE;
c->eax |= 0x200;
has_msr_hv_tsc = true;
}
c = &cpuid_data.entries[cpuid_i++];
c->function = HYPERV_CPUID_ENLIGHTMENT_INFO;
if (cpu->hyperv_relaxed_timing) {
c->eax |= HV_X64_RELAXED_TIMING_RECOMMENDED;
}
if (cpu->hyperv_vapic) {
if (has_msr_hv_vapic) {
c->eax |= HV_X64_APIC_ACCESS_RECOMMENDED;
}
c->ebx = cpu->hyperv_spinlock_attempts;
......@@ -513,15 +523,22 @@ int kvm_arch_init_vcpu(CPUState *cs)
c->eax = 0x40;
c->ebx = 0x40;
c = &cpuid_data.entries[cpuid_i++];
c->function = KVM_CPUID_SIGNATURE_NEXT;
memcpy(signature, "KVMKVMKVM\0\0\0", 12);
c->eax = 0;
c->ebx = signature[0];
c->ecx = signature[1];
c->edx = signature[2];
kvm_base = KVM_CPUID_SIGNATURE_NEXT;
has_msr_hv_hypercall = true;
}
memcpy(signature, "KVMKVMKVM\0\0\0", 12);
c = &cpuid_data.entries[cpuid_i++];
c->function = KVM_CPUID_SIGNATURE | kvm_base;
c->eax = 0;
c->ebx = signature[0];
c->ecx = signature[1];
c->edx = signature[2];
c = &cpuid_data.entries[cpuid_i++];
c->function = KVM_CPUID_FEATURES | kvm_base;
c->eax = env->features[FEAT_KVM];
has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF);
has_msr_pv_eoi_en = c->eax & (1 << KVM_FEATURE_PV_EOI);
......@@ -1220,12 +1237,19 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
kvm_msr_entry_set(&msrs[n++], MSR_CORE_PERF_GLOBAL_CTRL,
env->msr_global_ctrl);
}
if (hyperv_hypercall_available(cpu)) {
kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_GUEST_OS_ID, 0);
kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_HYPERCALL, 0);
if (has_msr_hv_hypercall) {
kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_GUEST_OS_ID,
env->msr_hv_guest_os_id);
kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_HYPERCALL,
env->msr_hv_hypercall);
}
if (cpu->hyperv_vapic) {
kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_APIC_ASSIST_PAGE, 0);
if (has_msr_hv_vapic) {
kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_APIC_ASSIST_PAGE,
env->msr_hv_vapic);
}
if (has_msr_hv_tsc) {
kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_REFERENCE_TSC,
env->msr_hv_tsc);
}
/* Note: MSR_IA32_FEATURE_CONTROL is written separately, see
......@@ -1511,6 +1535,17 @@ static int kvm_get_msrs(X86CPU *cpu)
}
}
if (has_msr_hv_hypercall) {
msrs[n++].index = HV_X64_MSR_HYPERCALL;
msrs[n++].index = HV_X64_MSR_GUEST_OS_ID;
}
if (has_msr_hv_vapic) {
msrs[n++].index = HV_X64_MSR_APIC_ASSIST_PAGE;
}
if (has_msr_hv_tsc) {
msrs[n++].index = HV_X64_MSR_REFERENCE_TSC;
}
msr_data.info.nmsrs = n;
ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, &msr_data);
if (ret < 0) {
......@@ -1618,6 +1653,18 @@ static int kvm_get_msrs(X86CPU *cpu)
case MSR_P6_EVNTSEL0 ... MSR_P6_EVNTSEL0 + MAX_GP_COUNTERS - 1:
env->msr_gp_evtsel[index - MSR_P6_EVNTSEL0] = msrs[i].data;
break;
case HV_X64_MSR_HYPERCALL:
env->msr_hv_hypercall = msrs[i].data;
break;
case HV_X64_MSR_GUEST_OS_ID:
env->msr_hv_guest_os_id = msrs[i].data;
break;
case HV_X64_MSR_APIC_ASSIST_PAGE:
env->msr_hv_vapic = msrs[i].data;
break;
case HV_X64_MSR_REFERENCE_TSC:
env->msr_hv_tsc = msrs[i].data;
break;
}
}
......
......@@ -554,6 +554,64 @@ static const VMStateDescription vmstate_mpx = {
}
};
static bool hyperv_hypercall_enable_needed(void *opaque)
{
X86CPU *cpu = opaque;
CPUX86State *env = &cpu->env;
return env->msr_hv_hypercall != 0 || env->msr_hv_guest_os_id != 0;
}
static const VMStateDescription vmstate_msr_hypercall_hypercall = {
.name = "cpu/msr_hyperv_hypercall",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField []) {
VMSTATE_UINT64(env.msr_hv_hypercall, X86CPU),
VMSTATE_UINT64(env.msr_hv_guest_os_id, X86CPU),
VMSTATE_END_OF_LIST()
}
};
static bool hyperv_vapic_enable_needed(void *opaque)
{
X86CPU *cpu = opaque;
CPUX86State *env = &cpu->env;
return env->msr_hv_vapic != 0;
}
static const VMStateDescription vmstate_msr_hyperv_vapic = {
.name = "cpu/msr_hyperv_vapic",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField []) {
VMSTATE_UINT64(env.msr_hv_vapic, X86CPU),
VMSTATE_END_OF_LIST()
}
};
static bool hyperv_time_enable_needed(void *opaque)
{
X86CPU *cpu = opaque;
CPUX86State *env = &cpu->env;
return env->msr_hv_tsc != 0;
}
static const VMStateDescription vmstate_msr_hyperv_time = {
.name = "cpu/msr_hyperv_time",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField []) {
VMSTATE_UINT64(env.msr_hv_tsc, X86CPU),
VMSTATE_END_OF_LIST()
}
};
const VMStateDescription vmstate_x86_cpu = {
.name = "cpu",
.version_id = 12,
......@@ -688,6 +746,15 @@ const VMStateDescription vmstate_x86_cpu = {
} , {
.vmsd = &vmstate_mpx,
.needed = mpx_needed,
}, {
.vmsd = &vmstate_msr_hypercall_hypercall,
.needed = hyperv_hypercall_enable_needed,
}, {
.vmsd = &vmstate_msr_hyperv_vapic,
.needed = hyperv_vapic_enable_needed,
}, {
.vmsd = &vmstate_msr_hyperv_time,
.needed = hyperv_time_enable_needed,
} , {
/* empty */
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册