These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / hw / misc / hyperv_testdev.c
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 "hw/hw.h"
16 #include "hw/qdev.h"
17 #include "hw/isa/isa.h"
18 #include "sysemu/kvm.h"
19 #include "linux/kvm.h"
20 #include "target-i386/hyperv.h"
21 #include "kvm_i386.h"
22
23 #define HV_TEST_DEV_MAX_SINT_ROUTES 64
24
25 struct HypervTestDev {
26     ISADevice parent_obj;
27     MemoryRegion sint_control;
28     HvSintRoute *sint_route[HV_TEST_DEV_MAX_SINT_ROUTES];
29 };
30 typedef struct HypervTestDev HypervTestDev;
31
32 #define TYPE_HYPERV_TEST_DEV "hyperv-testdev"
33 #define HYPERV_TEST_DEV(obj) \
34         OBJECT_CHECK(HypervTestDev, (obj), TYPE_HYPERV_TEST_DEV)
35
36 enum {
37     HV_TEST_DEV_SINT_ROUTE_CREATE = 1,
38     HV_TEST_DEV_SINT_ROUTE_DESTROY,
39     HV_TEST_DEV_SINT_ROUTE_SET_SINT
40 };
41
42 static int alloc_sint_route_index(HypervTestDev *dev)
43 {
44     int i;
45
46     for (i = 0; i < ARRAY_SIZE(dev->sint_route); i++) {
47         if (dev->sint_route[i] == NULL) {
48             return i;
49         }
50     }
51     return -1;
52 }
53
54 static void free_sint_route_index(HypervTestDev *dev, int i)
55 {
56     assert(i >= 0 && i < ARRAY_SIZE(dev->sint_route));
57     dev->sint_route[i] = NULL;
58 }
59
60 static int find_sint_route_index(HypervTestDev *dev, uint32_t vcpu_id,
61                                  uint32_t sint)
62 {
63     HvSintRoute *sint_route;
64     int i;
65
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) {
70             return i;
71         }
72     }
73     return -1;
74 }
75
76 static void hv_synic_test_dev_control(HypervTestDev *dev, uint32_t ctl,
77                                       uint32_t vcpu_id, uint32_t sint)
78 {
79     int i;
80     HvSintRoute *sint_route;
81
82     switch (ctl) {
83     case HV_TEST_DEV_SINT_ROUTE_CREATE:
84         i = alloc_sint_route_index(dev);
85         assert(i >= 0);
86         sint_route = kvm_hv_sint_route_create(vcpu_id, sint, NULL);
87         assert(sint_route);
88         dev->sint_route[i] = sint_route;
89         break;
90     case HV_TEST_DEV_SINT_ROUTE_DESTROY:
91         i = find_sint_route_index(dev, vcpu_id, sint);
92         assert(i >= 0);
93         sint_route = dev->sint_route[i];
94         kvm_hv_sint_route_destroy(sint_route);
95         free_sint_route_index(dev, i);
96         break;
97     case HV_TEST_DEV_SINT_ROUTE_SET_SINT:
98         i = find_sint_route_index(dev, vcpu_id, sint);
99         assert(i >= 0);
100         sint_route = dev->sint_route[i];
101         kvm_hv_sint_route_set_sint(sint_route);
102         break;
103     default:
104         break;
105     }
106 }
107
108 static void hv_test_dev_control(void *opaque, hwaddr addr, uint64_t data,
109                                 uint32_t len)
110 {
111     HypervTestDev *dev = HYPERV_TEST_DEV(opaque);
112     uint8_t ctl;
113
114     ctl = (data >> 16ULL) & 0xFF;
115     switch (ctl) {
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);
122         break;
123     }
124     default:
125         break;
126     }
127 }
128
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,
134 };
135
136 static void hv_test_dev_realizefn(DeviceState *d, Error **errp)
137 {
138     ISADevice *isa = ISA_DEVICE(d);
139     HypervTestDev *dev = HYPERV_TEST_DEV(d);
140     MemoryRegion *io = isa_address_space_io(isa);
141
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);
147 }
148
149 static void hv_test_dev_class_init(ObjectClass *klass, void *data)
150 {
151     DeviceClass *dc = DEVICE_CLASS(klass);
152
153     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
154     dc->realize = hv_test_dev_realizefn;
155 }
156
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,
162 };
163
164 static void hv_test_dev_register_types(void)
165 {
166     type_register_static(&hv_test_dev_info);
167 }
168 type_init(hv_test_dev_register_types);