Browse Source
A significant part of hyperv.c is not actually tied to x86, and can be moved to hw/. This will allow to maintain most of Hyper-V and VMBus target-independent, and to avoid conflicts with inclusion of arch-specific headers down the road in VMBus implementation. Also this stuff can now be opt-out with CONFIG_HYPERV. Signed-off-by: Roman Kagan <rkagan@virtuozzo.com> Message-Id: <20180921082041.29380-4-rkagan@virtuozzo.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>pull/76/head
committed by
Paolo Bonzini
9 changed files with 178 additions and 146 deletions
@ -0,0 +1,2 @@ |
|||
obj-y += hyperv.o |
|||
obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o |
|||
@ -0,0 +1,138 @@ |
|||
/*
|
|||
* Hyper-V guest/hypervisor interaction |
|||
* |
|||
* Copyright (c) 2015-2018 Virtuozzo International GmbH. |
|||
* |
|||
* This work is licensed under the terms of the GNU GPL, version 2 or later. |
|||
* See the COPYING file in the top-level directory. |
|||
*/ |
|||
|
|||
#include "qemu/osdep.h" |
|||
#include "qemu/main-loop.h" |
|||
#include "sysemu/kvm.h" |
|||
#include "hw/hyperv/hyperv.h" |
|||
|
|||
struct HvSintRoute { |
|||
uint32_t sint; |
|||
CPUState *cs; |
|||
int gsi; |
|||
EventNotifier sint_set_notifier; |
|||
EventNotifier sint_ack_notifier; |
|||
HvSintAckClb sint_ack_clb; |
|||
void *sint_ack_clb_data; |
|||
unsigned refcount; |
|||
}; |
|||
|
|||
static CPUState *hyperv_find_vcpu(uint32_t vp_index) |
|||
{ |
|||
CPUState *cs = qemu_get_cpu(vp_index); |
|||
assert(hyperv_vp_index(cs) == vp_index); |
|||
return cs; |
|||
} |
|||
|
|||
static void kvm_hv_sint_ack_handler(EventNotifier *notifier) |
|||
{ |
|||
HvSintRoute *sint_route = container_of(notifier, HvSintRoute, |
|||
sint_ack_notifier); |
|||
event_notifier_test_and_clear(notifier); |
|||
sint_route->sint_ack_clb(sint_route->sint_ack_clb_data); |
|||
} |
|||
|
|||
HvSintRoute *hyperv_sint_route_new(uint32_t vp_index, uint32_t sint, |
|||
HvSintAckClb sint_ack_clb, |
|||
void *sint_ack_clb_data) |
|||
{ |
|||
HvSintRoute *sint_route; |
|||
EventNotifier *ack_notifier; |
|||
int r, gsi; |
|||
CPUState *cs; |
|||
|
|||
cs = hyperv_find_vcpu(vp_index); |
|||
if (!cs) { |
|||
return NULL; |
|||
} |
|||
|
|||
sint_route = g_new0(HvSintRoute, 1); |
|||
r = event_notifier_init(&sint_route->sint_set_notifier, false); |
|||
if (r) { |
|||
goto err; |
|||
} |
|||
|
|||
ack_notifier = sint_ack_clb ? &sint_route->sint_ack_notifier : NULL; |
|||
if (ack_notifier) { |
|||
r = event_notifier_init(ack_notifier, false); |
|||
if (r) { |
|||
goto err_sint_set_notifier; |
|||
} |
|||
|
|||
event_notifier_set_handler(ack_notifier, kvm_hv_sint_ack_handler); |
|||
} |
|||
|
|||
gsi = kvm_irqchip_add_hv_sint_route(kvm_state, vp_index, sint); |
|||
if (gsi < 0) { |
|||
goto err_gsi; |
|||
} |
|||
|
|||
r = kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, |
|||
&sint_route->sint_set_notifier, |
|||
ack_notifier, gsi); |
|||
if (r) { |
|||
goto err_irqfd; |
|||
} |
|||
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->sint = sint; |
|||
sint_route->refcount = 1; |
|||
|
|||
return sint_route; |
|||
|
|||
err_irqfd: |
|||
kvm_irqchip_release_virq(kvm_state, gsi); |
|||
err_gsi: |
|||
if (ack_notifier) { |
|||
event_notifier_set_handler(ack_notifier, NULL); |
|||
event_notifier_cleanup(ack_notifier); |
|||
} |
|||
err_sint_set_notifier: |
|||
event_notifier_cleanup(&sint_route->sint_set_notifier); |
|||
err: |
|||
g_free(sint_route); |
|||
|
|||
return NULL; |
|||
} |
|||
|
|||
void hyperv_sint_route_ref(HvSintRoute *sint_route) |
|||
{ |
|||
sint_route->refcount++; |
|||
} |
|||
|
|||
void hyperv_sint_route_unref(HvSintRoute *sint_route) |
|||
{ |
|||
if (!sint_route) { |
|||
return; |
|||
} |
|||
|
|||
assert(sint_route->refcount > 0); |
|||
|
|||
if (--sint_route->refcount) { |
|||
return; |
|||
} |
|||
|
|||
kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, |
|||
&sint_route->sint_set_notifier, |
|||
sint_route->gsi); |
|||
kvm_irqchip_release_virq(kvm_state, sint_route->gsi); |
|||
if (sint_route->sint_ack_clb) { |
|||
event_notifier_set_handler(&sint_route->sint_ack_notifier, NULL); |
|||
event_notifier_cleanup(&sint_route->sint_ack_notifier); |
|||
} |
|||
event_notifier_cleanup(&sint_route->sint_set_notifier); |
|||
g_free(sint_route); |
|||
} |
|||
|
|||
int hyperv_sint_route_set_sint(HvSintRoute *sint_route) |
|||
{ |
|||
return event_notifier_set(&sint_route->sint_set_notifier); |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
/*
|
|||
* Hyper-V guest/hypervisor interaction |
|||
* |
|||
* Copyright (c) 2015-2018 Virtuozzo International GmbH. |
|||
* |
|||
* This work is licensed under the terms of the GNU GPL, version 2 or later. |
|||
* See the COPYING file in the top-level directory. |
|||
*/ |
|||
|
|||
#ifndef HW_HYPERV_HYPERV_H |
|||
#define HW_HYPERV_HYPERV_H |
|||
|
|||
#include "cpu-qom.h" |
|||
|
|||
typedef struct HvSintRoute HvSintRoute; |
|||
typedef void (*HvSintAckClb)(void *data); |
|||
|
|||
HvSintRoute *hyperv_sint_route_new(uint32_t vp_index, uint32_t sint, |
|||
HvSintAckClb sint_ack_clb, |
|||
void *sint_ack_clb_data); |
|||
void hyperv_sint_route_ref(HvSintRoute *sint_route); |
|||
void hyperv_sint_route_unref(HvSintRoute *sint_route); |
|||
|
|||
int hyperv_sint_route_set_sint(HvSintRoute *sint_route); |
|||
|
|||
static inline uint32_t hyperv_vp_index(CPUState *cs) |
|||
{ |
|||
return cs->cpu_index; |
|||
} |
|||
|
|||
#endif |
|||
Loading…
Reference in new issue