1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include "qemu/osdep.h"
25#include "libqtest.h"
26#include "qemu/module.h"
27#include "standard-headers/linux/virtio_ids.h"
28#include "virtio-9p.h"
29#include "qgraph.h"
30
31static QGuestAllocator *alloc;
32static char *local_test_path;
33
34
35static char *concat_path(const char* a, const char* b)
36{
37 return g_build_filename(a, b, NULL);
38}
39
40static void init_local_test_path(void)
41{
42 char *pwd = g_get_current_dir();
43 char *template = concat_path(pwd, "qtest-9p-local-XXXXXX");
44 local_test_path = mkdtemp(template);
45 if (!local_test_path) {
46 g_test_message("mkdtemp('%s') failed: %s", template, strerror(errno));
47 }
48 g_assert(local_test_path);
49 g_free(pwd);
50}
51
52void virtio_9p_create_local_test_dir(void)
53{
54 struct stat st;
55 int res;
56
57 init_local_test_path();
58
59 g_assert(local_test_path != NULL);
60 res = mkdir(local_test_path, 0777);
61 if (res < 0) {
62 g_test_message("mkdir('%s') failed: %s", local_test_path,
63 strerror(errno));
64 }
65
66
67 g_assert(stat(local_test_path, &st) == 0);
68
69 g_assert((st.st_mode & S_IFMT) == S_IFDIR);
70}
71
72void virtio_9p_remove_local_test_dir(void)
73{
74 g_assert(local_test_path != NULL);
75 char *cmd = g_strdup_printf("rm -fr '%s'\n", local_test_path);
76 int res = system(cmd);
77 if (res < 0) {
78
79 }
80 g_free(cmd);
81}
82
83char *virtio_9p_test_path(const char *path)
84{
85 g_assert(local_test_path);
86 return concat_path(local_test_path, path);
87}
88
89static void virtio_9p_cleanup(QVirtio9P *interface)
90{
91 qvirtqueue_cleanup(interface->vdev->bus, interface->vq, alloc);
92}
93
94static void virtio_9p_setup(QVirtio9P *interface)
95{
96 uint64_t features;
97
98 features = qvirtio_get_features(interface->vdev);
99 features &= ~(QVIRTIO_F_BAD_FEATURE | (1ull << VIRTIO_RING_F_EVENT_IDX));
100 qvirtio_set_features(interface->vdev, features);
101
102 interface->vq = qvirtqueue_setup(interface->vdev, alloc, 0);
103 qvirtio_set_driver_ok(interface->vdev);
104}
105
106
107static void virtio_9p_device_destructor(QOSGraphObject *obj)
108{
109 QVirtio9PDevice *v_9p = (QVirtio9PDevice *) obj;
110 QVirtio9P *v9p = &v_9p->v9p;
111
112 virtio_9p_cleanup(v9p);
113}
114
115static void virtio_9p_device_start_hw(QOSGraphObject *obj)
116{
117 QVirtio9PDevice *v_9p = (QVirtio9PDevice *) obj;
118 QVirtio9P *v9p = &v_9p->v9p;
119
120 virtio_9p_setup(v9p);
121}
122
123static void *virtio_9p_get_driver(QVirtio9P *v_9p,
124 const char *interface)
125{
126 if (!g_strcmp0(interface, "virtio-9p")) {
127 return v_9p;
128 }
129 if (!g_strcmp0(interface, "virtio")) {
130 return v_9p->vdev;
131 }
132
133 fprintf(stderr, "%s not present in virtio-9p-device\n", interface);
134 g_assert_not_reached();
135}
136
137static void *virtio_9p_device_get_driver(void *object, const char *interface)
138{
139 QVirtio9PDevice *v_9p = object;
140 return virtio_9p_get_driver(&v_9p->v9p, interface);
141}
142
143static void *virtio_9p_device_create(void *virtio_dev,
144 QGuestAllocator *t_alloc,
145 void *addr)
146{
147 QVirtio9PDevice *virtio_device = g_new0(QVirtio9PDevice, 1);
148 QVirtio9P *interface = &virtio_device->v9p;
149
150 interface->vdev = virtio_dev;
151 alloc = t_alloc;
152
153 virtio_device->obj.destructor = virtio_9p_device_destructor;
154 virtio_device->obj.get_driver = virtio_9p_device_get_driver;
155 virtio_device->obj.start_hw = virtio_9p_device_start_hw;
156
157 return &virtio_device->obj;
158}
159
160
161static void virtio_9p_pci_destructor(QOSGraphObject *obj)
162{
163 QVirtio9PPCI *v9_pci = (QVirtio9PPCI *) obj;
164 QVirtio9P *interface = &v9_pci->v9p;
165 QOSGraphObject *pci_vobj = &v9_pci->pci_vdev.obj;
166
167 virtio_9p_cleanup(interface);
168 qvirtio_pci_destructor(pci_vobj);
169}
170
171static void virtio_9p_pci_start_hw(QOSGraphObject *obj)
172{
173 QVirtio9PPCI *v9_pci = (QVirtio9PPCI *) obj;
174 QVirtio9P *interface = &v9_pci->v9p;
175 QOSGraphObject *pci_vobj = &v9_pci->pci_vdev.obj;
176
177 qvirtio_pci_start_hw(pci_vobj);
178 virtio_9p_setup(interface);
179}
180
181static void *virtio_9p_pci_get_driver(void *object, const char *interface)
182{
183 QVirtio9PPCI *v_9p = object;
184 if (!g_strcmp0(interface, "pci-device")) {
185 return v_9p->pci_vdev.pdev;
186 }
187 return virtio_9p_get_driver(&v_9p->v9p, interface);
188}
189
190static void *virtio_9p_pci_create(void *pci_bus, QGuestAllocator *t_alloc,
191 void *addr)
192{
193 QVirtio9PPCI *v9_pci = g_new0(QVirtio9PPCI, 1);
194 QVirtio9P *interface = &v9_pci->v9p;
195 QOSGraphObject *obj = &v9_pci->pci_vdev.obj;
196
197 virtio_pci_init(&v9_pci->pci_vdev, pci_bus, addr);
198 interface->vdev = &v9_pci->pci_vdev.vdev;
199 alloc = t_alloc;
200
201 g_assert_cmphex(interface->vdev->device_type, ==, VIRTIO_ID_9P);
202
203 obj->destructor = virtio_9p_pci_destructor;
204 obj->start_hw = virtio_9p_pci_start_hw;
205 obj->get_driver = virtio_9p_pci_get_driver;
206
207 return obj;
208}
209
210
211
212
213
214
215
216
217
218
219
220
221static void regex_replace(GString *haystack, const char *pattern,
222 const char *replace_fmt, ...)
223{
224 GRegex *regex;
225 char *replace, *s;
226 va_list argp;
227
228 va_start(argp, replace_fmt);
229 replace = g_strdup_vprintf(replace_fmt, argp);
230 va_end(argp);
231
232 regex = g_regex_new(pattern, 0, 0, NULL);
233 s = g_regex_replace(regex, haystack->str, -1, 0, replace, 0, NULL);
234 g_string_assign(haystack, s);
235 g_free(s);
236 g_regex_unref(regex);
237 g_free(replace);
238}
239
240void virtio_9p_assign_local_driver(GString *cmd_line, const char *args)
241{
242 g_assert_nonnull(local_test_path);
243
244
245 regex_replace(cmd_line, "-fsdev synth,", "-fsdev local,");
246
247
248 regex_replace(cmd_line, "(-fsdev \\w[^ ]*)", "\\1,path='%s'",
249 local_test_path);
250
251 if (!args) {
252 return;
253 }
254
255
256 regex_replace(cmd_line, "(-fsdev \\w[^ ]*)", "\\1,%s", args);
257}
258
259static void virtio_9p_register_nodes(void)
260{
261 const char *str_simple = "fsdev=fsdev0,mount_tag=" MOUNT_TAG;
262 const char *str_addr = "fsdev=fsdev0,addr=04.0,mount_tag=" MOUNT_TAG;
263
264 QPCIAddress addr = {
265 .devfn = QPCI_DEVFN(4, 0),
266 };
267
268 QOSGraphEdgeOptions opts = {
269 .before_cmd_line = "-fsdev synth,id=fsdev0",
270 };
271
272
273 opts.extra_device_opts = str_simple,
274 qos_node_create_driver("virtio-9p-device", virtio_9p_device_create);
275 qos_node_consumes("virtio-9p-device", "virtio-bus", &opts);
276 qos_node_produces("virtio-9p-device", "virtio");
277 qos_node_produces("virtio-9p-device", "virtio-9p");
278
279
280 opts.extra_device_opts = str_addr;
281 add_qpci_address(&opts, &addr);
282 qos_node_create_driver("virtio-9p-pci", virtio_9p_pci_create);
283 qos_node_consumes("virtio-9p-pci", "pci-bus", &opts);
284 qos_node_produces("virtio-9p-pci", "pci-device");
285 qos_node_produces("virtio-9p-pci", "virtio");
286 qos_node_produces("virtio-9p-pci", "virtio-9p");
287
288}
289
290libqos_init(virtio_9p_register_nodes);
291