2 * QEMU KVM Hyper-V test device to support Hyper-V kvm-unit-tests
4 * Copyright (C) 2015 Andrey Smetanin <asmetanin@virtuozzo.com>
7 * Andrey Smetanin <asmetanin@virtuozzo.com>
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
14 #include "qemu/osdep.h"
15 #include <linux/kvm.h>
18 #include "hw/isa/isa.h"
19 #include "sysemu/kvm.h"
20 #include "target/i386/hyperv.h"
23 #define HV_TEST_DEV_MAX_SINT_ROUTES 64
25 struct HypervTestDev
{
27 MemoryRegion sint_control
;
28 HvSintRoute
*sint_route
[HV_TEST_DEV_MAX_SINT_ROUTES
];
30 typedef struct HypervTestDev HypervTestDev
;
32 #define TYPE_HYPERV_TEST_DEV "hyperv-testdev"
33 #define HYPERV_TEST_DEV(obj) \
34 OBJECT_CHECK(HypervTestDev, (obj), TYPE_HYPERV_TEST_DEV)
37 HV_TEST_DEV_SINT_ROUTE_CREATE
= 1,
38 HV_TEST_DEV_SINT_ROUTE_DESTROY
,
39 HV_TEST_DEV_SINT_ROUTE_SET_SINT
42 static int alloc_sint_route_index(HypervTestDev
*dev
)
46 for (i
= 0; i
< ARRAY_SIZE(dev
->sint_route
); i
++) {
47 if (dev
->sint_route
[i
] == NULL
) {
54 static void free_sint_route_index(HypervTestDev
*dev
, int i
)
56 assert(i
>= 0 && i
< ARRAY_SIZE(dev
->sint_route
));
57 dev
->sint_route
[i
] = NULL
;
60 static int find_sint_route_index(HypervTestDev
*dev
, uint32_t vcpu_id
,
63 HvSintRoute
*sint_route
;
66 for (i
= 0; i
< ARRAY_SIZE(dev
->sint_route
); i
++) {
67 sint_route
= dev
->sint_route
[i
];
68 if (sint_route
&& sint_route
->vcpu_id
== vcpu_id
&&
69 sint_route
->sint
== sint
) {
76 static void hv_synic_test_dev_control(HypervTestDev
*dev
, uint32_t ctl
,
77 uint32_t vcpu_id
, uint32_t sint
)
80 HvSintRoute
*sint_route
;
83 case HV_TEST_DEV_SINT_ROUTE_CREATE
:
84 i
= alloc_sint_route_index(dev
);
86 sint_route
= kvm_hv_sint_route_create(vcpu_id
, sint
, NULL
);
88 dev
->sint_route
[i
] = sint_route
;
90 case HV_TEST_DEV_SINT_ROUTE_DESTROY
:
91 i
= find_sint_route_index(dev
, vcpu_id
, sint
);
93 sint_route
= dev
->sint_route
[i
];
94 kvm_hv_sint_route_destroy(sint_route
);
95 free_sint_route_index(dev
, i
);
97 case HV_TEST_DEV_SINT_ROUTE_SET_SINT
:
98 i
= find_sint_route_index(dev
, vcpu_id
, sint
);
100 sint_route
= dev
->sint_route
[i
];
101 kvm_hv_sint_route_set_sint(sint_route
);
108 static void hv_test_dev_control(void *opaque
, hwaddr addr
, uint64_t data
,
111 HypervTestDev
*dev
= HYPERV_TEST_DEV(opaque
);
114 ctl
= (data
>> 16ULL) & 0xFF;
116 case HV_TEST_DEV_SINT_ROUTE_CREATE
:
117 case HV_TEST_DEV_SINT_ROUTE_DESTROY
:
118 case HV_TEST_DEV_SINT_ROUTE_SET_SINT
: {
119 uint8_t sint
= data
& 0xFF;
120 uint8_t vcpu_id
= (data
>> 8ULL) & 0xFF;
121 hv_synic_test_dev_control(dev
, ctl
, vcpu_id
, sint
);
129 static const MemoryRegionOps synic_test_sint_ops
= {
130 .write
= hv_test_dev_control
,
131 .valid
.min_access_size
= 4,
132 .valid
.max_access_size
= 4,
133 .endianness
= DEVICE_LITTLE_ENDIAN
,
136 static void hv_test_dev_realizefn(DeviceState
*d
, Error
**errp
)
138 ISADevice
*isa
= ISA_DEVICE(d
);
139 HypervTestDev
*dev
= HYPERV_TEST_DEV(d
);
140 MemoryRegion
*io
= isa_address_space_io(isa
);
142 memset(dev
->sint_route
, 0, sizeof(dev
->sint_route
));
143 memory_region_init_io(&dev
->sint_control
, OBJECT(dev
),
144 &synic_test_sint_ops
, dev
,
145 "hyperv-testdev-ctl", 4);
146 memory_region_add_subregion(io
, 0x3000, &dev
->sint_control
);
149 static void hv_test_dev_class_init(ObjectClass
*klass
, void *data
)
151 DeviceClass
*dc
= DEVICE_CLASS(klass
);
153 set_bit(DEVICE_CATEGORY_MISC
, dc
->categories
);
154 dc
->realize
= hv_test_dev_realizefn
;
157 static const TypeInfo hv_test_dev_info
= {
158 .name
= TYPE_HYPERV_TEST_DEV
,
159 .parent
= TYPE_ISA_DEVICE
,
160 .instance_size
= sizeof(HypervTestDev
),
161 .class_init
= hv_test_dev_class_init
,
164 static void hv_test_dev_register_types(void)
166 type_register_static(&hv_test_dev_info
);
168 type_init(hv_test_dev_register_types
);