From 3d5de35b1b36744b84bf3213745d2f7b42485ff5 Mon Sep 17 00:00:00 2001 Message-Id: <3d5de35b1b36744b84bf3213745d2f7b42485ff5.1353592948.git.minovotn@redhat.com> From: Vadim Rozenfeld Date: Tue, 20 Nov 2012 11:35:29 +0100 Subject: [PATCH] hyper-v: Minimal hyper-v support. RH-Author: Vadim Rozenfeld Message-id: <1353411329-10018-1-git-send-email-vrozenfe@redhat.com> Patchwork-id: 44312 O-Subject: [RHEL6.4 qemu-kvm PATCH v4] hyper-v: Minimal hyper-v support. Bugzilla: 801196 RH-Acked-by: Gleb Natapov RH-Acked-by: Marcelo Tosatti RH-Acked-by: Michael S. Tsirkin Add minimal hyper-v support to qemu to support relaxed timing feature. Signed-off-by: Marcelo Tosatti Signed-off-by: Vadim Rozenfeld Bug: 801196 Upstream Status: 28f52cc04d341045e810bd487a478fa9ec5f40be Brew build: http://download.devel.redhat.com/brewroot/work/tasks/5729 /4975729/qemu-kvm-0.12.1.2-2.323.el6.bz801196.relaxed.x86_64.rpm This patch is a slightly modified version of the upstream commit. Current patch is a slightly modified version of the original patch, submitted to upstream. It provides reduced number of supported Hyper-V features. v0 -> v1 Hyper-V hypercall MSR subsection v1 -> v2 rollback unnecessary changes in vmstate_cpu v2 -> v3 add hyperv_guest_os_id MSR to subsection v3 -> v4 check hyperv_guest_os_id MSR instead of hyperv_hypercall MSR inside of hyperv_hypercall_needed routine. Signed-off-by: Vadim Rozenfeld --- Makefile.target | 2 +- qemu-kvm-x86.c | 26 ++++++++++++++++++++++++++ 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, 99 insertions(+), 1 deletions(-) create mode 100644 target-i386/hyperv.c create mode 100644 target-i386/hyperv.h Signed-off-by: Michal Novotny --- Makefile.target | 2 +- qemu-kvm-x86.c | 26 ++++++++++++++++++++++++++ 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, 99 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..a225116 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,9 @@ 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); + 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 +1353,8 @@ void kvm_arch_save_regs(CPUState *env) #endif msrs[n++].index = MSR_KVM_SYSTEM_TIME; msrs[n++].index = MSR_KVM_WALL_CLOCK; + 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 +1446,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 +1458,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 264b6bc..c7d9374 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -722,6 +722,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 e187242..bcc7452 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 @@ -1030,6 +1031,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