From 3d5de35b1b36744b84bf3213745d2f7b42485ff5 Mon Sep 17 00:00:00 2001
Message-Id: <3d5de35b1b36744b84bf3213745d2f7b42485ff5.1353592948.git.minovotn@redhat.com>
From: Vadim Rozenfeld <vrozenfe@redhat.com>
Date: Tue, 20 Nov 2012 11:35:29 +0100
Subject: [PATCH] hyper-v: Minimal hyper-v support.

RH-Author: Vadim Rozenfeld <vrozenfe@redhat.com>
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 <gleb@redhat.com>
RH-Acked-by: Marcelo Tosatti <mtosatti@redhat.com>
RH-Acked-by: Michael S. Tsirkin <mst@redhat.com>

Add minimal hyper-v support to qemu to support relaxed timing
feature.

Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Vadim Rozenfeld <vrozenfe@redhat.com>

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 <vrozenfe@redhat.com>

---
 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 <minovotn@redhat.com>
---
 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

