-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
hw/misc: Hyper-V test device 'hyperv-testdev'
'hyperv-testdev' will be used by kvm-unit-tests to setup Hyper-V SynIC SINT's routing and to inject Hyper-V SynIC SINT's. Hyper-V test device is ISA type device that creates 0x3000 IO memory region and catches write access into it. Every write operation data decoded into ctl code and parameters for Hyper-V test device. Signed-off-by: Andrey Smetanin <asmetanin@virtuozzo.com> Reviewed-by: Roman Kagan <rkagan@virtuozzo.com> Signed-off-by: Denis V. Lunev <den@openvz.org> CC: Paolo Bonzini <pbonzini@redhat.com> CC: Richard Henderson <rth@twiddle.net> CC: Eduardo Habkost <ehabkost@redhat.com> CC: "Andreas Färber" <afaerber@suse.de> CC: Marcelo Tosatti <mtosatti@redhat.com> CC: Roman Kagan <rkagan@virtuozzo.com> CC: Denis V. Lunev <den@openvz.org> CC: kvm@vger.kernel.org Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
- Loading branch information
Showing
4 changed files
with
170 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,3 +50,4 @@ CONFIG_XIO3130=y | |
CONFIG_IOH3420=y | ||
CONFIG_I82801B11=y | ||
CONFIG_SMBIOS=y | ||
CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,3 +50,4 @@ CONFIG_XIO3130=y | |
CONFIG_IOH3420=y | ||
CONFIG_I82801B11=y | ||
CONFIG_SMBIOS=y | ||
CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
/* | ||
* QEMU KVM Hyper-V test device to support Hyper-V kvm-unit-tests | ||
* | ||
* Copyright (C) 2015 Andrey Smetanin <asmetanin@virtuozzo.com> | ||
* | ||
* Authors: | ||
* Andrey Smetanin <asmetanin@virtuozzo.com> | ||
* | ||
* 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 "hw/hw.h" | ||
#include "hw/qdev.h" | ||
#include "hw/isa/isa.h" | ||
#include "sysemu/kvm.h" | ||
#include "linux/kvm.h" | ||
#include "target-i386/hyperv.h" | ||
#include "kvm_i386.h" | ||
|
||
#define HV_TEST_DEV_MAX_SINT_ROUTES 64 | ||
|
||
struct HypervTestDev { | ||
ISADevice parent_obj; | ||
MemoryRegion sint_control; | ||
HvSintRoute *sint_route[HV_TEST_DEV_MAX_SINT_ROUTES]; | ||
}; | ||
typedef struct HypervTestDev HypervTestDev; | ||
|
||
#define TYPE_HYPERV_TEST_DEV "hyperv-testdev" | ||
#define HYPERV_TEST_DEV(obj) \ | ||
OBJECT_CHECK(HypervTestDev, (obj), TYPE_HYPERV_TEST_DEV) | ||
|
||
enum { | ||
HV_TEST_DEV_SINT_ROUTE_CREATE = 1, | ||
HV_TEST_DEV_SINT_ROUTE_DESTROY, | ||
HV_TEST_DEV_SINT_ROUTE_SET_SINT | ||
}; | ||
|
||
static int alloc_sint_route_index(HypervTestDev *dev) | ||
{ | ||
int i; | ||
|
||
for (i = 0; i < ARRAY_SIZE(dev->sint_route); i++) { | ||
if (dev->sint_route[i] == NULL) { | ||
return i; | ||
} | ||
} | ||
return -1; | ||
} | ||
|
||
static void free_sint_route_index(HypervTestDev *dev, int i) | ||
{ | ||
assert(i >= 0 && i < ARRAY_SIZE(dev->sint_route)); | ||
dev->sint_route[i] = NULL; | ||
} | ||
|
||
static int find_sint_route_index(HypervTestDev *dev, uint32_t vcpu_id, | ||
uint32_t sint) | ||
{ | ||
HvSintRoute *sint_route; | ||
int i; | ||
|
||
for (i = 0; i < ARRAY_SIZE(dev->sint_route); i++) { | ||
sint_route = dev->sint_route[i]; | ||
if (sint_route && sint_route->vcpu_id == vcpu_id && | ||
sint_route->sint == sint) { | ||
return i; | ||
} | ||
} | ||
return -1; | ||
} | ||
|
||
static void hv_synic_test_dev_control(HypervTestDev *dev, uint32_t ctl, | ||
uint32_t vcpu_id, uint32_t sint) | ||
{ | ||
int i; | ||
HvSintRoute *sint_route; | ||
|
||
switch (ctl) { | ||
case HV_TEST_DEV_SINT_ROUTE_CREATE: | ||
i = alloc_sint_route_index(dev); | ||
assert(i >= 0); | ||
sint_route = kvm_hv_sint_route_create(vcpu_id, sint, NULL); | ||
assert(sint_route); | ||
dev->sint_route[i] = sint_route; | ||
break; | ||
case HV_TEST_DEV_SINT_ROUTE_DESTROY: | ||
i = find_sint_route_index(dev, vcpu_id, sint); | ||
assert(i >= 0); | ||
sint_route = dev->sint_route[i]; | ||
kvm_hv_sint_route_destroy(sint_route); | ||
free_sint_route_index(dev, i); | ||
break; | ||
case HV_TEST_DEV_SINT_ROUTE_SET_SINT: | ||
i = find_sint_route_index(dev, vcpu_id, sint); | ||
assert(i >= 0); | ||
sint_route = dev->sint_route[i]; | ||
kvm_hv_sint_route_set_sint(sint_route); | ||
break; | ||
default: | ||
break; | ||
} | ||
} | ||
|
||
static void hv_test_dev_control(void *opaque, hwaddr addr, uint64_t data, | ||
uint32_t len) | ||
{ | ||
HypervTestDev *dev = HYPERV_TEST_DEV(opaque); | ||
uint8_t ctl; | ||
|
||
ctl = (data >> 16ULL) & 0xFF; | ||
switch (ctl) { | ||
case HV_TEST_DEV_SINT_ROUTE_CREATE: | ||
case HV_TEST_DEV_SINT_ROUTE_DESTROY: | ||
case HV_TEST_DEV_SINT_ROUTE_SET_SINT: { | ||
uint8_t sint = data & 0xFF; | ||
uint8_t vcpu_id = (data >> 8ULL) & 0xFF; | ||
hv_synic_test_dev_control(dev, ctl, vcpu_id, sint); | ||
break; | ||
} | ||
default: | ||
break; | ||
} | ||
} | ||
|
||
static const MemoryRegionOps synic_test_sint_ops = { | ||
.write = hv_test_dev_control, | ||
.valid.min_access_size = 4, | ||
.valid.max_access_size = 4, | ||
.endianness = DEVICE_LITTLE_ENDIAN, | ||
}; | ||
|
||
static void hv_test_dev_realizefn(DeviceState *d, Error **errp) | ||
{ | ||
ISADevice *isa = ISA_DEVICE(d); | ||
HypervTestDev *dev = HYPERV_TEST_DEV(d); | ||
MemoryRegion *io = isa_address_space_io(isa); | ||
|
||
memset(dev->sint_route, 0, sizeof(dev->sint_route)); | ||
memory_region_init_io(&dev->sint_control, OBJECT(dev), | ||
&synic_test_sint_ops, dev, | ||
"hyperv-testdev-ctl", 4); | ||
memory_region_add_subregion(io, 0x3000, &dev->sint_control); | ||
} | ||
|
||
static void hv_test_dev_class_init(ObjectClass *klass, void *data) | ||
{ | ||
DeviceClass *dc = DEVICE_CLASS(klass); | ||
|
||
set_bit(DEVICE_CATEGORY_MISC, dc->categories); | ||
dc->realize = hv_test_dev_realizefn; | ||
} | ||
|
||
static const TypeInfo hv_test_dev_info = { | ||
.name = TYPE_HYPERV_TEST_DEV, | ||
.parent = TYPE_ISA_DEVICE, | ||
.instance_size = sizeof(HypervTestDev), | ||
.class_init = hv_test_dev_class_init, | ||
}; | ||
|
||
static void hv_test_dev_register_types(void) | ||
{ | ||
type_register_static(&hv_test_dev_info); | ||
} | ||
type_init(hv_test_dev_register_types); |