hyperv: qom-ify SynIC
authorRoman Kagan <rkagan@virtuozzo.com>
Fri, 21 Sep 2018 08:22:09 +0000 (11:22 +0300)
committerPaolo Bonzini <pbonzini@redhat.com>
Fri, 19 Oct 2018 11:44:14 +0000 (13:44 +0200)
Make Hyper-V SynIC a device which is attached as a child to a CPU.  For
now it only makes SynIC visibile in the qom hierarchy, and maintains its
internal fields in sync with the respecitve msrs of the parent cpu (the
fields will be used in followup patches).

Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>
Message-Id: <20180921082217.29481-3-rkagan@virtuozzo.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
hw/hyperv/hyperv.c
include/hw/hyperv/hyperv.h
target/i386/hyperv-stub.c
target/i386/hyperv.c
target/i386/hyperv.h
target/i386/kvm.c
target/i386/machine.c

index 97db87561e9c978e23bc26c063686742ad63e542..3d6f04428265ebf6bb308f62ac468f00ebe32242 100644 (file)
 
 #include "qemu/osdep.h"
 #include "qemu/main-loop.h"
+#include "qapi/error.h"
 #include "sysemu/kvm.h"
 #include "hw/hyperv/hyperv.h"
 
+typedef struct SynICState {
+    DeviceState parent_obj;
+
+    CPUState *cs;
+
+    bool enabled;
+    hwaddr msg_page_addr;
+    hwaddr event_page_addr;
+} SynICState;
+
+#define TYPE_SYNIC "hyperv-synic"
+#define SYNIC(obj) OBJECT_CHECK(SynICState, (obj), TYPE_SYNIC)
+
+static SynICState *get_synic(CPUState *cs)
+{
+    return SYNIC(object_resolve_path_component(OBJECT(cs), "synic"));
+}
+
+static void synic_update(SynICState *synic, bool enable,
+                         hwaddr msg_page_addr, hwaddr event_page_addr)
+{
+
+    synic->enabled = enable;
+    synic->msg_page_addr = msg_page_addr;
+    synic->event_page_addr = event_page_addr;
+}
+
+void hyperv_synic_update(CPUState *cs, bool enable,
+                         hwaddr msg_page_addr, hwaddr event_page_addr)
+{
+    SynICState *synic = get_synic(cs);
+
+    if (!synic) {
+        return;
+    }
+
+    synic_update(synic, enable, msg_page_addr, event_page_addr);
+}
+
+static void synic_realize(DeviceState *dev, Error **errp)
+{
+}
+
+static void synic_reset(DeviceState *dev)
+{
+    SynICState *synic = SYNIC(dev);
+    synic_update(synic, false, 0, 0);
+}
+
+static void synic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = synic_realize;
+    dc->reset = synic_reset;
+    dc->user_creatable = false;
+}
+
+void hyperv_synic_add(CPUState *cs)
+{
+    Object *obj;
+    SynICState *synic;
+
+    obj = object_new(TYPE_SYNIC);
+    synic = SYNIC(obj);
+    synic->cs = cs;
+    object_property_add_child(OBJECT(cs), "synic", obj, &error_abort);
+    object_unref(obj);
+    object_property_set_bool(obj, true, "realized", &error_abort);
+}
+
+void hyperv_synic_reset(CPUState *cs)
+{
+    device_reset(DEVICE(get_synic(cs)));
+}
+
+static const TypeInfo synic_type_info = {
+    .name = TYPE_SYNIC,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(SynICState),
+    .class_init = synic_class_init,
+};
+
+static void synic_register_types(void)
+{
+    type_register_static(&synic_type_info);
+}
+
+type_init(synic_register_types)
+
 struct HvSintRoute {
     uint32_t sint;
-    CPUState *cs;
+    SynICState *synic;
     int gsi;
     EventNotifier sint_set_notifier;
     EventNotifier sint_ack_notifier;
@@ -46,12 +137,18 @@ HvSintRoute *hyperv_sint_route_new(uint32_t vp_index, uint32_t sint,
     EventNotifier *ack_notifier;
     int r, gsi;
     CPUState *cs;
+    SynICState *synic;
 
     cs = hyperv_find_vcpu(vp_index);
     if (!cs) {
         return NULL;
     }
 
+    synic = get_synic(cs);
+    if (!synic) {
+        return NULL;
+    }
+
     sint_route = g_new0(HvSintRoute, 1);
     r = event_notifier_init(&sint_route->sint_set_notifier, false);
     if (r) {
@@ -82,7 +179,7 @@ HvSintRoute *hyperv_sint_route_new(uint32_t vp_index, uint32_t sint,
     sint_route->gsi = gsi;
     sint_route->sint_ack_clb = sint_ack_clb;
     sint_route->sint_ack_clb_data = sint_ack_clb_data;
-    sint_route->cs = cs;
+    sint_route->synic = synic;
     sint_route->sint = sint;
     sint_route->refcount = 1;
 
index d6c8d78353b046d82492f42f62d680584ba34523..6fba4762c89595586e8c0084591b069c74c4453d 100644 (file)
@@ -28,4 +28,9 @@ static inline uint32_t hyperv_vp_index(CPUState *cs)
     return cs->cpu_index;
 }
 
+void hyperv_synic_add(CPUState *cs);
+void hyperv_synic_reset(CPUState *cs);
+void hyperv_synic_update(CPUState *cs, bool enable,
+                         hwaddr msg_page_addr, hwaddr event_page_addr);
+
 #endif
index 5919ba851c63749f4fc685cede703235b12a5db7..fe548cbae2f1b51ffdcb881d13b41bf741ae61a8 100644 (file)
@@ -33,3 +33,16 @@ int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
     }
 }
 #endif
+
+int hyperv_x86_synic_add(X86CPU *cpu)
+{
+    return -ENOSYS;
+}
+
+void hyperv_x86_synic_reset(X86CPU *cpu)
+{
+}
+
+void hyperv_x86_synic_update(X86CPU *cpu)
+{
+}
index 1eac7277741c23c29031fa193dedb2b8e98dc6c7..0216735d67839fedd01e531dcfcb2b55e1b7d469 100644 (file)
 #include "hw/hyperv/hyperv.h"
 #include "hyperv-proto.h"
 
+int hyperv_x86_synic_add(X86CPU *cpu)
+{
+    hyperv_synic_add(CPU(cpu));
+    return 0;
+}
+
+void hyperv_x86_synic_reset(X86CPU *cpu)
+{
+    hyperv_synic_reset(CPU(cpu));
+}
+
+void hyperv_x86_synic_update(X86CPU *cpu)
+{
+    CPUX86State *env = &cpu->env;
+    bool enable = env->msr_hv_synic_control & HV_SYNIC_ENABLE;
+    hwaddr msg_page_addr = (env->msr_hv_synic_msg_page & HV_SIMP_ENABLE) ?
+        (env->msr_hv_synic_msg_page & TARGET_PAGE_MASK) : 0;
+    hwaddr event_page_addr = (env->msr_hv_synic_evt_page & HV_SIEFP_ENABLE) ?
+        (env->msr_hv_synic_evt_page & TARGET_PAGE_MASK) : 0;
+    hyperv_synic_update(CPU(cpu), enable, msg_page_addr, event_page_addr);
+}
+
 int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
 {
     CPUX86State *env = &cpu->env;
@@ -44,6 +66,9 @@ int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
         default:
             return -1;
         }
+
+        hyperv_x86_synic_update(cpu);
+
         return 0;
     case KVM_EXIT_HYPERV_HCALL: {
         uint16_t code;
index f0a27c3d73aa95ab5ddce1a8fad5160493088699..67543296c3a4e12bc382ea2177bb609c72aac1cb 100644 (file)
@@ -22,4 +22,8 @@
 int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit);
 #endif
 
+int hyperv_x86_synic_add(X86CPU *cpu);
+void hyperv_x86_synic_reset(X86CPU *cpu);
+void hyperv_x86_synic_update(X86CPU *cpu);
+
 #endif
index 2e5b9f63eb4506fc203982c32803cd53559bcee8..cf6270ae396e481145819247848ab2803f40b708 100644 (file)
@@ -790,6 +790,13 @@ static int hyperv_init_vcpu(X86CPU *cpu)
                          strerror(-ret));
             return ret;
         }
+
+        ret = hyperv_x86_synic_add(cpu);
+        if (ret < 0) {
+            error_report("failed to create HyperV SynIC: %s",
+                         strerror(-ret));
+            return ret;
+        }
     }
 
     return 0;
@@ -1250,6 +1257,8 @@ void kvm_arch_reset_vcpu(X86CPU *cpu)
         for (i = 0; i < ARRAY_SIZE(env->msr_hv_synic_sint); i++) {
             env->msr_hv_synic_sint[i] = HV_SINT_MASKED;
         }
+
+        hyperv_x86_synic_reset(cpu);
     }
 }
 
index 084c2c73a8f7cec93d421a484aa7625439de8e47..225b5d433bc446f8d81a9de5344cd4303373cadd 100644 (file)
@@ -7,6 +7,7 @@
 #include "hw/i386/pc.h"
 #include "hw/isa/isa.h"
 #include "migration/cpu.h"
+#include "hyperv.h"
 
 #include "sysemu/kvm.h"
 
@@ -672,11 +673,19 @@ static bool hyperv_synic_enable_needed(void *opaque)
     return false;
 }
 
+static int hyperv_synic_post_load(void *opaque, int version_id)
+{
+    X86CPU *cpu = opaque;
+    hyperv_x86_synic_update(cpu);
+    return 0;
+}
+
 static const VMStateDescription vmstate_msr_hyperv_synic = {
     .name = "cpu/msr_hyperv_synic",
     .version_id = 1,
     .minimum_version_id = 1,
     .needed = hyperv_synic_enable_needed,
+    .post_load = hyperv_synic_post_load,
     .fields = (VMStateField[]) {
         VMSTATE_UINT64(env.msr_hv_synic_control, X86CPU),
         VMSTATE_UINT64(env.msr_hv_synic_evt_page, X86CPU),