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.
16 #include "hw/isa/isa.h"
17 #include "sysemu/kvm.h"
18 #include "linux/kvm.h"
19 #include "target-i386/hyperv.h"
22 #define HV_TEST_DEV_MAX_SINT_ROUTES 64
24 struct HypervTestDev
{
26 MemoryRegion sint_control
;
27 HvSintRoute
*sint_route
[HV_TEST_DEV_MAX_SINT_ROUTES
];
29 typedef struct HypervTestDev HypervTestDev
;
31 #define TYPE_HYPERV_TEST_DEV "hyperv-testdev"
32 #define HYPERV_TEST_DEV(obj) \
33 OBJECT_CHECK(HypervTestDev, (obj), TYPE_HYPERV_TEST_DEV)
36 HV_TEST_DEV_SINT_ROUTE_CREATE
= 1,
37 HV_TEST_DEV_SINT_ROUTE_DESTROY
,
38 HV_TEST_DEV_SINT_ROUTE_SET_SINT
41 static int alloc_sint_route_index(HypervTestDev
*dev
)
45 for (i
= 0; i
< ARRAY_SIZE(dev
->sint_route
); i
++) {
46 if (dev
->sint_route
[i
] == NULL
) {
53 static void free_sint_route_index(HypervTestDev
*dev
, int i
)
55 assert(i
>= 0 && i
< ARRAY_SIZE(dev
->sint_route
));
56 dev
->sint_route
[i
] = NULL
;
59 static int find_sint_route_index(HypervTestDev
*dev
, uint32_t vcpu_id
,
62 HvSintRoute
*sint_route
;
65 for (i
= 0; i
< ARRAY_SIZE(dev
->sint_route
); i
++) {
66 sint_route
= dev
->sint_route
[i
];
67 if (sint_route
&& sint_route
->vcpu_id
== vcpu_id
&&
68 sint_route
->sint
== sint
) {
75 static void hv_synic_test_dev_control(HypervTestDev
*dev
, uint32_t ctl
,
76 uint32_t vcpu_id
, uint32_t sint
)
79 HvSintRoute
*sint_route
;
82 case HV_TEST_DEV_SINT_ROUTE_CREATE
:
83 i
= alloc_sint_route_index(dev
);
85 sint_route
= kvm_hv_sint_route_create(vcpu_id
, sint
, NULL
);
87 dev
->sint_route
[i
] = sint_route
;
89 case HV_TEST_DEV_SINT_ROUTE_DESTROY
:
90 i
= find_sint_route_index(dev
, vcpu_id
, sint
);
92 sint_route
= dev
->sint_route
[i
];
93 kvm_hv_sint_route_destroy(sint_route
);
94 free_sint_route_index(dev
, i
);
96 case HV_TEST_DEV_SINT_ROUTE_SET_SINT
:
97 i
= find_sint_route_index(dev
, vcpu_id
, sint
);
99 sint_route
= dev
->sint_route
[i
];
100 kvm_hv_sint_route_set_sint(sint_route
);
107 static void hv_test_dev_control(void *opaque
, hwaddr addr
, uint64_t data
,
110 HypervTestDev
*dev
= HYPERV_TEST_DEV(opaque
);
113 ctl
= (data
>> 16ULL) & 0xFF;
115 case HV_TEST_DEV_SINT_ROUTE_CREATE
:
116 case HV_TEST_DEV_SINT_ROUTE_DESTROY
:
117 case HV_TEST_DEV_SINT_ROUTE_SET_SINT
: {
118 uint8_t sint
= data
& 0xFF;
119 uint8_t vcpu_id
= (data
>> 8ULL) & 0xFF;
120 hv_synic_test_dev_control(dev
, ctl
, vcpu_id
, sint
);
128 static const MemoryRegionOps synic_test_sint_ops
= {
129 .write
= hv_test_dev_control
,
130 .valid
.min_access_size
= 4,
131 .valid
.max_access_size
= 4,
132 .endianness
= DEVICE_LITTLE_ENDIAN
,
135 static void hv_test_dev_realizefn(DeviceState
*d
, Error
**errp
)
137 ISADevice
*isa
= ISA_DEVICE(d
);
138 HypervTestDev
*dev
= HYPERV_TEST_DEV(d
);
139 MemoryRegion
*io
= isa_address_space_io(isa
);
141 memset(dev
->sint_route
, 0, sizeof(dev
->sint_route
));
142 memory_region_init_io(&dev
->sint_control
, OBJECT(dev
),
143 &synic_test_sint_ops
, dev
,
144 "hyperv-testdev-ctl", 4);
145 memory_region_add_subregion(io
, 0x3000, &dev
->sint_control
);
148 static void hv_test_dev_class_init(ObjectClass
*klass
, void *data
)
150 DeviceClass
*dc
= DEVICE_CLASS(klass
);
152 set_bit(DEVICE_CATEGORY_MISC
, dc
->categories
);
153 dc
->realize
= hv_test_dev_realizefn
;
156 static const TypeInfo hv_test_dev_info
= {
157 .name
= TYPE_HYPERV_TEST_DEV
,
158 .parent
= TYPE_ISA_DEVICE
,
159 .instance_size
= sizeof(HypervTestDev
),
160 .class_init
= hv_test_dev_class_init
,
163 static void hv_test_dev_register_types(void)
165 type_register_static(&hv_test_dev_info
);
167 type_init(hv_test_dev_register_types
);