From d0f403175b8bc58517dea28f725a312ff61d05eb Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: References: From: Vadim Rozenfeld Date: Tue, 18 Dec 2012 08:14:29 +0200 Subject: [PATCH 2/9] hyper-v: Minimal hyper-v support. Signed-off-by: Michal Novotny --- Makefile.target | 2 +- qemu-kvm-x86.c | 29 +++++++++++++++++++++++++++++ target-i386/cpu.h | 3 +++ target-i386/cpuid.c | 3 +++ target-i386/hyperv.c | 14 ++++++++++++++ target-i386/hyperv.h | 30 ++++++++++++++++++++++++++++++ target-i386/machine.c | 22 ++++++++++++++++++++++ 7 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 target-i386/hyperv.c create mode 100644 target-i386/hyperv.h diff --git a/Makefile.target b/Makefile.target index 052a896..a094bbc 100644 --- a/Makefile.target +++ b/Makefile.target @@ -208,7 +208,7 @@ obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-pci.o virtio-serial-b obj-y += virtio-scsi.o event_notifier.o obj-y += vhost_net.o obj-$(CONFIG_VHOST_NET) += vhost.o -obj-$(CONFIG_KVM) += kvm.o kvm-all.o +obj-$(CONFIG_KVM) += kvm.o kvm-all.o hyperv.o # MSI-X depends on kvm for interrupt injection, # so moved it from Makefile.hw to Makefile.target for now obj-y += msix.o diff --git a/qemu-kvm-x86.c b/qemu-kvm-x86.c index eed3883..12bb873 100644 --- a/qemu-kvm-x86.c +++ b/qemu-kvm-x86.c @@ -23,6 +23,7 @@ #include "kvm.h" #include "hw/pc.h" +#include "hyperv.h" #define MSR_IA32_TSC 0x10 @@ -882,6 +883,12 @@ static int get_msr_entry(struct kvm_msr_entry *entry, CPUState *env) case MSR_KVM_WALL_CLOCK: env->wall_clock_msr = entry->data; break; + case HV_X64_MSR_GUEST_OS_ID: + env->hyperv_guest_os_id = entry->data; + break; + case HV_X64_MSR_HYPERCALL: + env->hyperv_hypercall = entry->data; + break; case MSR_KVM_PV_EOI_EN: env->pv_eoi_en_msr = entry->data; break; @@ -1103,6 +1110,10 @@ void kvm_arch_load_regs(CPUState *env) #endif set_msr_entry(&msrs[n++], MSR_KVM_SYSTEM_TIME, env->system_time_msr); set_msr_entry(&msrs[n++], MSR_KVM_WALL_CLOCK, env->wall_clock_msr); + if (kvm_check_extension(kvm_state, KVM_CAP_HYPERV)) { + set_msr_entry(&msrs[n++], HV_X64_MSR_GUEST_OS_ID, env->hyperv_guest_os_id); + set_msr_entry(&msrs[n++], HV_X64_MSR_HYPERCALL, env->hyperv_hypercall); + } if (has_msr_pv_eoi_en) { set_msr_entry(&msrs[n++], MSR_KVM_PV_EOI_EN, env->pv_eoi_en_msr); } @@ -1343,6 +1354,10 @@ void kvm_arch_save_regs(CPUState *env) #endif msrs[n++].index = MSR_KVM_SYSTEM_TIME; msrs[n++].index = MSR_KVM_WALL_CLOCK; + if (kvm_check_extension(kvm_state, KVM_CAP_HYPERV)) { + msrs[n++].index = HV_X64_MSR_GUEST_OS_ID; + msrs[n++].index = HV_X64_MSR_HYPERCALL; + } if (has_msr_pv_eoi_en) { msrs[n++].index = MSR_KVM_PV_EOI_EN; } @@ -1434,6 +1449,9 @@ int kvm_arch_init_vcpu(CPUState *cenv) memset(pv_ent, 0, sizeof(*pv_ent)); pv_ent->function = KVM_CPUID_SIGNATURE; pv_ent->eax = 0; + if (hyperv_relaxed_timing_enabled()) { + pv_ent->eax = HYPERV_CPUID_ENLIGHTMENT_INFO; + } pv_ent->ebx = signature[0]; pv_ent->ecx = signature[1]; pv_ent->edx = signature[2]; @@ -1443,6 +1461,17 @@ int kvm_arch_init_vcpu(CPUState *cenv) pv_ent->function = KVM_CPUID_FEATURES; pv_ent->eax = cenv->cpuid_kvm_features & kvm_arch_get_supported_cpuid(cenv->kvm_state, KVM_CPUID_FEATURES, 0, R_EAX); + + if (hyperv_relaxed_timing_enabled()) { + memcpy(signature, "Hv#1\0\0\0\0\0\0\0\0", 12); + pv_ent->eax = signature[0]; + + pv_ent = &cpuid_ent[cpuid_nent++]; + memset(pv_ent, 0, sizeof(*pv_ent)); + pv_ent->function = HYPERV_CPUID_ENLIGHTMENT_INFO; + pv_ent->eax |= HV_X64_RELAXED_TIMING_RECOMMENDED; + } + #endif kvm_trim_features(&cenv->cpuid_features, diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 60d649f..7415335 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -723,6 +723,9 @@ typedef struct CPUX86State { uint64_t wall_clock_msr; uint64_t pv_eoi_en_msr; + uint64_t hyperv_guest_os_id; + uint64_t hyperv_hypercall; + uint64_t tsc; uint64_t tsc_deadline; diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c index 00502ea..db99112 100644 --- a/target-i386/cpuid.c +++ b/target-i386/cpuid.c @@ -27,6 +27,7 @@ #include "qemu-option.h" #include "qemu-config.h" +#include "hyperv.h" /* feature flags taken from "Intel Processor Identification and the CPUID * Instruction" and AMD's "CPUID Specification". In cases of disagreement @@ -1031,6 +1032,8 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model) check_cpuid = 1; } else if (!strcmp(featurestr, "enforce")) { check_cpuid = enforce_cpuid = 1; + } else if (!strcmp(featurestr, "hv_relaxed")) { + hyperv_enable_relaxed_timing(true); } else { fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr); goto error; diff --git a/target-i386/hyperv.c b/target-i386/hyperv.c new file mode 100644 index 0000000..616a1b2 --- /dev/null +++ b/target-i386/hyperv.c @@ -0,0 +1,14 @@ +#include "hyperv.h" + +static bool hyperv_relaxed_timing; + +void hyperv_enable_relaxed_timing(bool val) +{ + hyperv_relaxed_timing = val; +} + +bool hyperv_relaxed_timing_enabled(void) +{ + return hyperv_relaxed_timing; +} + diff --git a/target-i386/hyperv.h b/target-i386/hyperv.h new file mode 100644 index 0000000..450ad97 --- /dev/null +++ b/target-i386/hyperv.h @@ -0,0 +1,30 @@ +#ifndef QEMU_HYPERV_H +#define QEMU_HYPERV_H + +#include "qemu-common.h" + +#ifndef HYPERV_CPUID_ENLIGHTMENT_INFO +#define HYPERV_CPUID_ENLIGHTMENT_INFO 0x40000004 +#endif + +#ifndef HV_X64_RELAXED_TIMING_RECOMMENDED +#define HV_X64_RELAXED_TIMING_RECOMMENDED (1 << 5) +#endif + +#ifndef HV_X64_MSR_GUEST_OS_ID +#define HV_X64_MSR_GUEST_OS_ID 0x40000000 +#endif + +#ifndef HV_X64_MSR_HYPERCALL +#define HV_X64_MSR_HYPERCALL 0x40000001 +#endif + +#if defined(CONFIG_KVM) +void hyperv_enable_relaxed_timing(bool val); +#else +static inline void hyperv_enable_relaxed_timing(bool val) { } +#endif + +bool hyperv_relaxed_timing_enabled(void); + +#endif /* QEMU_HYPERV_H */ diff --git a/target-i386/machine.c b/target-i386/machine.c index eb4576e..3b092f9 100644 --- a/target-i386/machine.c +++ b/target-i386/machine.c @@ -455,6 +455,25 @@ static const VMStateDescription vmstate_msr_tscdeadline = { } }; +static bool hyperv_hypercall_needed(void *opaque) +{ + CPUState *env = opaque; + + return env->hyperv_guest_os_id != 0; +} + +static const VMStateDescription vmstate_msr_hyperv_hypercall = { + .name = "cpu/msr_hyperv_hypercall", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT64(hyperv_guest_os_id, CPUState), + VMSTATE_UINT64(hyperv_hypercall, CPUState), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_cpu = { .name = "cpu", .version_id = CPU_SAVE_VERSION, @@ -570,6 +589,9 @@ static const VMStateDescription vmstate_cpu = { .vmsd = &vmstate_msr_tscdeadline, .needed = tscdeadline_needed, }, { + .vmsd = &vmstate_msr_hyperv_hypercall, + .needed = hyperv_hypercall_needed, + }, { /* empty */ } } -- 1.7.11.7