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 vp_index
,
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
->vp_index
== vp_index
&&
69 sint_route
->sint
== sint
) {
76 static void hv_synic_test_dev_control(HypervTestDev
*dev
, uint32_t ctl
,
77 uint32_t vp_index
, 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(vp_index
, sint
, NULL
);
88 dev
->sint_route
[i
] = sint_route
;
90 case HV_TEST_DEV_SINT_ROUTE_DESTROY
:
91 i
= find_sint_route_index(dev
, vp_index
, 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
, vp_index
, sint
);
100 sint_route
= dev
->sint_route
[i
];
101 kvm_hv_sint_route_set_sint(sint_route
);
108 static uint64_t hv_test_dev_read(void *opaque
, hwaddr addr
, unsigned size
)
113 static void hv_test_dev_write(void *opaque
, hwaddr addr
, uint64_t data
,
116 HypervTestDev
*dev
= HYPERV_TEST_DEV(opaque
);
119 ctl
= (data
>> 16ULL) & 0xFF;
121 case HV_TEST_DEV_SINT_ROUTE_CREATE
:
122 case HV_TEST_DEV_SINT_ROUTE_DESTROY
:
123 case HV_TEST_DEV_SINT_ROUTE_SET_SINT
: {
124 uint8_t sint
= data
& 0xFF;
125 uint8_t vp_index
= (data
>> 8ULL) & 0xFF;
126 hv_synic_test_dev_control(dev
, ctl
, vp_index
, sint
);
134 static const MemoryRegionOps synic_test_sint_ops
= {
135 .read
= hv_test_dev_read
,
136 .write
= hv_test_dev_write
,
137 .valid
.min_access_size
= 4,
138 .valid
.max_access_size
= 4,
139 .endianness
= DEVICE_LITTLE_ENDIAN
,
142 static void hv_test_dev_realizefn(DeviceState
*d
, Error
**errp
)
144 ISADevice
*isa
= ISA_DEVICE(d
);
145 HypervTestDev
*dev
= HYPERV_TEST_DEV(d
);
146 MemoryRegion
*io
= isa_address_space_io(isa
);
148 memset(dev
->sint_route
, 0, sizeof(dev
->sint_route
));
149 memory_region_init_io(&dev
->sint_control
, OBJECT(dev
),
150 &synic_test_sint_ops
, dev
,
151 "hyperv-testdev-ctl", 4);
152 memory_region_add_subregion(io
, 0x3000, &dev
->sint_control
);
155 static void hv_test_dev_class_init(ObjectClass
*klass
, void *data
)
157 DeviceClass
*dc
= DEVICE_CLASS(klass
);
159 set_bit(DEVICE_CATEGORY_MISC
, dc
->categories
);
160 dc
->realize
= hv_test_dev_realizefn
;
163 static const TypeInfo hv_test_dev_info
= {
164 .name
= TYPE_HYPERV_TEST_DEV
,
165 .parent
= TYPE_ISA_DEVICE
,
166 .instance_size
= sizeof(HypervTestDev
),
167 .class_init
= hv_test_dev_class_init
,
170 static void hv_test_dev_register_types(void)
172 type_register_static(&hv_test_dev_info
);
174 type_init(hv_test_dev_register_types
);