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