xref: /openbmc/qemu/hw/hyperv/hyperv_testdev.c (revision 701189e31140a7c82ec02a7f4ca632cfd6a8559d)
1 /*
2  * QEMU KVM Hyper-V test device to support Hyper-V kvm-unit-tests
3  *
4  * Copyright (C) 2015 Andrey Smetanin <asmetanin@virtuozzo.com>
5  *
6  * Authors:
7  *  Andrey Smetanin <asmetanin@virtuozzo.com>
8  *
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.
11  *
12  */
13 
14 #include "qemu/osdep.h"
15 #include "qemu/queue.h"
16 #include "hw/qdev.h"
17 #include "hw/isa/isa.h"
18 #include "hw/hyperv/hyperv.h"
19 
20 typedef struct TestSintRoute {
21     QLIST_ENTRY(TestSintRoute) le;
22     uint8_t vp_index;
23     uint8_t sint;
24     HvSintRoute *sint_route;
25 } TestSintRoute;
26 
27 struct HypervTestDev {
28     ISADevice parent_obj;
29     MemoryRegion sint_control;
30     QLIST_HEAD(, TestSintRoute) sint_routes;
31 };
32 typedef struct HypervTestDev HypervTestDev;
33 
34 #define TYPE_HYPERV_TEST_DEV "hyperv-testdev"
35 #define HYPERV_TEST_DEV(obj) \
36         OBJECT_CHECK(HypervTestDev, (obj), TYPE_HYPERV_TEST_DEV)
37 
38 enum {
39     HV_TEST_DEV_SINT_ROUTE_CREATE = 1,
40     HV_TEST_DEV_SINT_ROUTE_DESTROY,
41     HV_TEST_DEV_SINT_ROUTE_SET_SINT
42 };
43 
44 static void sint_route_create(HypervTestDev *dev,
45                               uint8_t vp_index, uint8_t sint)
46 {
47     TestSintRoute *sint_route;
48 
49     sint_route = g_new0(TestSintRoute, 1);
50     assert(sint_route);
51 
52     sint_route->vp_index = vp_index;
53     sint_route->sint = sint;
54 
55     sint_route->sint_route = hyperv_sint_route_new(vp_index, sint, NULL, NULL);
56     assert(sint_route->sint_route);
57 
58     QLIST_INSERT_HEAD(&dev->sint_routes, sint_route, le);
59 }
60 
61 static TestSintRoute *sint_route_find(HypervTestDev *dev,
62                                       uint8_t vp_index, uint8_t sint)
63 {
64     TestSintRoute *sint_route;
65 
66     QLIST_FOREACH(sint_route, &dev->sint_routes, le) {
67         if (sint_route->vp_index == vp_index && sint_route->sint == sint) {
68             return sint_route;
69         }
70     }
71     assert(false);
72     return NULL;
73 }
74 
75 static void sint_route_destroy(HypervTestDev *dev,
76                                uint8_t vp_index, uint8_t sint)
77 {
78     TestSintRoute *sint_route;
79 
80     sint_route = sint_route_find(dev, vp_index, sint);
81     QLIST_REMOVE(sint_route, le);
82     hyperv_sint_route_unref(sint_route->sint_route);
83     g_free(sint_route);
84 }
85 
86 static void sint_route_set_sint(HypervTestDev *dev,
87                                 uint8_t vp_index, uint8_t sint)
88 {
89     TestSintRoute *sint_route;
90 
91     sint_route = sint_route_find(dev, vp_index, sint);
92 
93     hyperv_sint_route_set_sint(sint_route->sint_route);
94 }
95 
96 static uint64_t hv_test_dev_read(void *opaque, hwaddr addr, unsigned size)
97 {
98     return 0;
99 }
100 
101 static void hv_test_dev_write(void *opaque, hwaddr addr, uint64_t data,
102                                 uint32_t len)
103 {
104     HypervTestDev *dev = HYPERV_TEST_DEV(opaque);
105     uint8_t sint = data & 0xFF;
106     uint8_t vp_index = (data >> 8ULL) & 0xFF;
107     uint8_t ctl = (data >> 16ULL) & 0xFF;
108 
109     switch (ctl) {
110     case HV_TEST_DEV_SINT_ROUTE_CREATE:
111         sint_route_create(dev, vp_index, sint);
112         break;
113     case HV_TEST_DEV_SINT_ROUTE_DESTROY:
114         sint_route_destroy(dev, vp_index, sint);
115         break;
116     case HV_TEST_DEV_SINT_ROUTE_SET_SINT:
117         sint_route_set_sint(dev, vp_index, sint);
118         break;
119     default:
120         break;
121     }
122 }
123 
124 static const MemoryRegionOps synic_test_sint_ops = {
125     .read = hv_test_dev_read,
126     .write = hv_test_dev_write,
127     .valid.min_access_size = 4,
128     .valid.max_access_size = 4,
129     .endianness = DEVICE_LITTLE_ENDIAN,
130 };
131 
132 static void hv_test_dev_realizefn(DeviceState *d, Error **errp)
133 {
134     ISADevice *isa = ISA_DEVICE(d);
135     HypervTestDev *dev = HYPERV_TEST_DEV(d);
136     MemoryRegion *io = isa_address_space_io(isa);
137 
138     QLIST_INIT(&dev->sint_routes);
139     memory_region_init_io(&dev->sint_control, OBJECT(dev),
140                           &synic_test_sint_ops, dev,
141                           "hyperv-testdev-ctl", 4);
142     memory_region_add_subregion(io, 0x3000, &dev->sint_control);
143 }
144 
145 static void hv_test_dev_class_init(ObjectClass *klass, void *data)
146 {
147     DeviceClass *dc = DEVICE_CLASS(klass);
148 
149     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
150     dc->realize = hv_test_dev_realizefn;
151 }
152 
153 static const TypeInfo hv_test_dev_info = {
154     .name           = TYPE_HYPERV_TEST_DEV,
155     .parent         = TYPE_ISA_DEVICE,
156     .instance_size  = sizeof(HypervTestDev),
157     .class_init     = hv_test_dev_class_init,
158 };
159 
160 static void hv_test_dev_register_types(void)
161 {
162     type_register_static(&hv_test_dev_info);
163 }
164 type_init(hv_test_dev_register_types);
165