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 "exec/address-spaces.h"
14 #include "sysemu/kvm.h"
15 #include "hw/hyperv/hyperv.h"
17 typedef struct SynICState
{
18 DeviceState parent_obj
;
24 hwaddr event_page_addr
;
25 MemoryRegion msg_page_mr
;
26 MemoryRegion event_page_mr
;
27 struct hyperv_message_page
*msg_page
;
28 struct hyperv_event_flags_page
*event_page
;
31 #define TYPE_SYNIC "hyperv-synic"
32 #define SYNIC(obj) OBJECT_CHECK(SynICState, (obj), TYPE_SYNIC)
34 static SynICState
*get_synic(CPUState
*cs
)
36 return SYNIC(object_resolve_path_component(OBJECT(cs
), "synic"));
39 static void synic_update(SynICState
*synic
, bool enable
,
40 hwaddr msg_page_addr
, hwaddr event_page_addr
)
43 synic
->enabled
= enable
;
44 if (synic
->msg_page_addr
!= msg_page_addr
) {
45 if (synic
->msg_page_addr
) {
46 memory_region_del_subregion(get_system_memory(),
50 memory_region_add_subregion(get_system_memory(), msg_page_addr
,
53 synic
->msg_page_addr
= msg_page_addr
;
55 if (synic
->event_page_addr
!= event_page_addr
) {
56 if (synic
->event_page_addr
) {
57 memory_region_del_subregion(get_system_memory(),
58 &synic
->event_page_mr
);
60 if (event_page_addr
) {
61 memory_region_add_subregion(get_system_memory(), event_page_addr
,
62 &synic
->event_page_mr
);
64 synic
->event_page_addr
= event_page_addr
;
68 void hyperv_synic_update(CPUState
*cs
, bool enable
,
69 hwaddr msg_page_addr
, hwaddr event_page_addr
)
71 SynICState
*synic
= get_synic(cs
);
77 synic_update(synic
, enable
, msg_page_addr
, event_page_addr
);
80 static void synic_realize(DeviceState
*dev
, Error
**errp
)
82 Object
*obj
= OBJECT(dev
);
83 SynICState
*synic
= SYNIC(dev
);
84 char *msgp_name
, *eventp_name
;
87 /* memory region names have to be globally unique */
88 vp_index
= hyperv_vp_index(synic
->cs
);
89 msgp_name
= g_strdup_printf("synic-%u-msg-page", vp_index
);
90 eventp_name
= g_strdup_printf("synic-%u-event-page", vp_index
);
92 memory_region_init_ram(&synic
->msg_page_mr
, obj
, msgp_name
,
93 sizeof(*synic
->msg_page
), &error_abort
);
94 memory_region_init_ram(&synic
->event_page_mr
, obj
, eventp_name
,
95 sizeof(*synic
->event_page
), &error_abort
);
96 synic
->msg_page
= memory_region_get_ram_ptr(&synic
->msg_page_mr
);
97 synic
->event_page
= memory_region_get_ram_ptr(&synic
->event_page_mr
);
102 static void synic_reset(DeviceState
*dev
)
104 SynICState
*synic
= SYNIC(dev
);
105 memset(synic
->msg_page
, 0, sizeof(*synic
->msg_page
));
106 memset(synic
->event_page
, 0, sizeof(*synic
->event_page
));
107 synic_update(synic
, false, 0, 0);
110 static void synic_class_init(ObjectClass
*klass
, void *data
)
112 DeviceClass
*dc
= DEVICE_CLASS(klass
);
114 dc
->realize
= synic_realize
;
115 dc
->reset
= synic_reset
;
116 dc
->user_creatable
= false;
119 void hyperv_synic_add(CPUState
*cs
)
124 obj
= object_new(TYPE_SYNIC
);
127 object_property_add_child(OBJECT(cs
), "synic", obj
, &error_abort
);
129 object_property_set_bool(obj
, true, "realized", &error_abort
);
132 void hyperv_synic_reset(CPUState
*cs
)
134 device_reset(DEVICE(get_synic(cs
)));
137 static const TypeInfo synic_type_info
= {
139 .parent
= TYPE_DEVICE
,
140 .instance_size
= sizeof(SynICState
),
141 .class_init
= synic_class_init
,
144 static void synic_register_types(void)
146 type_register_static(&synic_type_info
);
149 type_init(synic_register_types
)
155 EventNotifier sint_set_notifier
;
156 EventNotifier sint_ack_notifier
;
157 HvSintAckClb sint_ack_clb
;
158 void *sint_ack_clb_data
;
162 static CPUState
*hyperv_find_vcpu(uint32_t vp_index
)
164 CPUState
*cs
= qemu_get_cpu(vp_index
);
165 assert(hyperv_vp_index(cs
) == vp_index
);
169 static void kvm_hv_sint_ack_handler(EventNotifier
*notifier
)
171 HvSintRoute
*sint_route
= container_of(notifier
, HvSintRoute
,
173 event_notifier_test_and_clear(notifier
);
174 sint_route
->sint_ack_clb(sint_route
->sint_ack_clb_data
);
177 HvSintRoute
*hyperv_sint_route_new(uint32_t vp_index
, uint32_t sint
,
178 HvSintAckClb sint_ack_clb
,
179 void *sint_ack_clb_data
)
181 HvSintRoute
*sint_route
;
182 EventNotifier
*ack_notifier
;
187 cs
= hyperv_find_vcpu(vp_index
);
192 synic
= get_synic(cs
);
197 sint_route
= g_new0(HvSintRoute
, 1);
198 r
= event_notifier_init(&sint_route
->sint_set_notifier
, false);
203 ack_notifier
= sint_ack_clb
? &sint_route
->sint_ack_notifier
: NULL
;
205 r
= event_notifier_init(ack_notifier
, false);
207 goto err_sint_set_notifier
;
210 event_notifier_set_handler(ack_notifier
, kvm_hv_sint_ack_handler
);
213 gsi
= kvm_irqchip_add_hv_sint_route(kvm_state
, vp_index
, sint
);
218 r
= kvm_irqchip_add_irqfd_notifier_gsi(kvm_state
,
219 &sint_route
->sint_set_notifier
,
224 sint_route
->gsi
= gsi
;
225 sint_route
->sint_ack_clb
= sint_ack_clb
;
226 sint_route
->sint_ack_clb_data
= sint_ack_clb_data
;
227 sint_route
->synic
= synic
;
228 sint_route
->sint
= sint
;
229 sint_route
->refcount
= 1;
234 kvm_irqchip_release_virq(kvm_state
, gsi
);
237 event_notifier_set_handler(ack_notifier
, NULL
);
238 event_notifier_cleanup(ack_notifier
);
240 err_sint_set_notifier
:
241 event_notifier_cleanup(&sint_route
->sint_set_notifier
);
248 void hyperv_sint_route_ref(HvSintRoute
*sint_route
)
250 sint_route
->refcount
++;
253 void hyperv_sint_route_unref(HvSintRoute
*sint_route
)
259 assert(sint_route
->refcount
> 0);
261 if (--sint_route
->refcount
) {
265 kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state
,
266 &sint_route
->sint_set_notifier
,
268 kvm_irqchip_release_virq(kvm_state
, sint_route
->gsi
);
269 if (sint_route
->sint_ack_clb
) {
270 event_notifier_set_handler(&sint_route
->sint_ack_notifier
, NULL
);
271 event_notifier_cleanup(&sint_route
->sint_ack_notifier
);
273 event_notifier_cleanup(&sint_route
->sint_set_notifier
);
277 int hyperv_sint_route_set_sint(HvSintRoute
*sint_route
)
279 return event_notifier_set(&sint_route
->sint_set_notifier
);