2 * Hyper-V guest/hypervisor interaction
4 * Copyright (c) 2015-2018 Virtuozzo International GmbH.
6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
7 * See the COPYING file in the top-level directory.
10 #include "qemu/osdep.h"
11 #include "qemu/main-loop.h"
12 #include "qapi/error.h"
13 #include "sysemu/kvm.h"
14 #include "hw/hyperv/hyperv.h"
16 typedef struct SynICState
{
17 DeviceState parent_obj
;
23 hwaddr event_page_addr
;
26 #define TYPE_SYNIC "hyperv-synic"
27 #define SYNIC(obj) OBJECT_CHECK(SynICState, (obj), TYPE_SYNIC)
29 static SynICState
*get_synic(CPUState
*cs
)
31 return SYNIC(object_resolve_path_component(OBJECT(cs
), "synic"));
34 static void synic_update(SynICState
*synic
, bool enable
,
35 hwaddr msg_page_addr
, hwaddr event_page_addr
)
38 synic
->enabled
= enable
;
39 synic
->msg_page_addr
= msg_page_addr
;
40 synic
->event_page_addr
= event_page_addr
;
43 void hyperv_synic_update(CPUState
*cs
, bool enable
,
44 hwaddr msg_page_addr
, hwaddr event_page_addr
)
46 SynICState
*synic
= get_synic(cs
);
52 synic_update(synic
, enable
, msg_page_addr
, event_page_addr
);
55 static void synic_realize(DeviceState
*dev
, Error
**errp
)
59 static void synic_reset(DeviceState
*dev
)
61 SynICState
*synic
= SYNIC(dev
);
62 synic_update(synic
, false, 0, 0);
65 static void synic_class_init(ObjectClass
*klass
, void *data
)
67 DeviceClass
*dc
= DEVICE_CLASS(klass
);
69 dc
->realize
= synic_realize
;
70 dc
->reset
= synic_reset
;
71 dc
->user_creatable
= false;
74 void hyperv_synic_add(CPUState
*cs
)
79 obj
= object_new(TYPE_SYNIC
);
82 object_property_add_child(OBJECT(cs
), "synic", obj
, &error_abort
);
84 object_property_set_bool(obj
, true, "realized", &error_abort
);
87 void hyperv_synic_reset(CPUState
*cs
)
89 device_reset(DEVICE(get_synic(cs
)));
92 static const TypeInfo synic_type_info
= {
94 .parent
= TYPE_DEVICE
,
95 .instance_size
= sizeof(SynICState
),
96 .class_init
= synic_class_init
,
99 static void synic_register_types(void)
101 type_register_static(&synic_type_info
);
104 type_init(synic_register_types
)
110 EventNotifier sint_set_notifier
;
111 EventNotifier sint_ack_notifier
;
112 HvSintAckClb sint_ack_clb
;
113 void *sint_ack_clb_data
;
117 static CPUState
*hyperv_find_vcpu(uint32_t vp_index
)
119 CPUState
*cs
= qemu_get_cpu(vp_index
);
120 assert(hyperv_vp_index(cs
) == vp_index
);
124 static void kvm_hv_sint_ack_handler(EventNotifier
*notifier
)
126 HvSintRoute
*sint_route
= container_of(notifier
, HvSintRoute
,
128 event_notifier_test_and_clear(notifier
);
129 sint_route
->sint_ack_clb(sint_route
->sint_ack_clb_data
);
132 HvSintRoute
*hyperv_sint_route_new(uint32_t vp_index
, uint32_t sint
,
133 HvSintAckClb sint_ack_clb
,
134 void *sint_ack_clb_data
)
136 HvSintRoute
*sint_route
;
137 EventNotifier
*ack_notifier
;
142 cs
= hyperv_find_vcpu(vp_index
);
147 synic
= get_synic(cs
);
152 sint_route
= g_new0(HvSintRoute
, 1);
153 r
= event_notifier_init(&sint_route
->sint_set_notifier
, false);
158 ack_notifier
= sint_ack_clb
? &sint_route
->sint_ack_notifier
: NULL
;
160 r
= event_notifier_init(ack_notifier
, false);
162 goto err_sint_set_notifier
;
165 event_notifier_set_handler(ack_notifier
, kvm_hv_sint_ack_handler
);
168 gsi
= kvm_irqchip_add_hv_sint_route(kvm_state
, vp_index
, sint
);
173 r
= kvm_irqchip_add_irqfd_notifier_gsi(kvm_state
,
174 &sint_route
->sint_set_notifier
,
179 sint_route
->gsi
= gsi
;
180 sint_route
->sint_ack_clb
= sint_ack_clb
;
181 sint_route
->sint_ack_clb_data
= sint_ack_clb_data
;
182 sint_route
->synic
= synic
;
183 sint_route
->sint
= sint
;
184 sint_route
->refcount
= 1;
189 kvm_irqchip_release_virq(kvm_state
, gsi
);
192 event_notifier_set_handler(ack_notifier
, NULL
);
193 event_notifier_cleanup(ack_notifier
);
195 err_sint_set_notifier
:
196 event_notifier_cleanup(&sint_route
->sint_set_notifier
);
203 void hyperv_sint_route_ref(HvSintRoute
*sint_route
)
205 sint_route
->refcount
++;
208 void hyperv_sint_route_unref(HvSintRoute
*sint_route
)
214 assert(sint_route
->refcount
> 0);
216 if (--sint_route
->refcount
) {
220 kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state
,
221 &sint_route
->sint_set_notifier
,
223 kvm_irqchip_release_virq(kvm_state
, sint_route
->gsi
);
224 if (sint_route
->sint_ack_clb
) {
225 event_notifier_set_handler(&sint_route
->sint_ack_notifier
, NULL
);
226 event_notifier_cleanup(&sint_route
->sint_ack_notifier
);
228 event_notifier_cleanup(&sint_route
->sint_set_notifier
);
232 int hyperv_sint_route_set_sint(HvSintRoute
*sint_route
)
234 return event_notifier_set(&sint_route
->sint_set_notifier
);