]> git.proxmox.com Git - mirror_qemu.git/blame - hw/xen/xen-bus.c
Merge remote-tracking branch 'remotes/thibault/tags/samuel-thibault' into staging
[mirror_qemu.git] / hw / xen / xen-bus.c
CommitLineData
108f7bba
PD
1/*
2 * Copyright (c) 2018 Citrix Systems Inc.
3 *
4 * This work is licensed under the terms of the GNU GPL, version 2 or later.
5 * See the COPYING file in the top-level directory.
6 */
7
8#include "qemu/osdep.h"
82a29e30 9#include "qemu/main-loop.h"
0b8fa32f 10#include "qemu/module.h"
82a29e30 11#include "qemu/uuid.h"
a27bd6c7 12#include "hw/qdev-properties.h"
108f7bba 13#include "hw/sysbus.h"
094a2239 14#include "hw/xen/xen.h"
a783f8ad 15#include "hw/xen/xen-backend.h"
108f7bba 16#include "hw/xen/xen-bus.h"
094a2239
PD
17#include "hw/xen/xen-bus-helper.h"
18#include "monitor/monitor.h"
108f7bba 19#include "qapi/error.h"
a783f8ad 20#include "qapi/qmp/qdict.h"
094a2239 21#include "sysemu/sysemu.h"
108f7bba
PD
22#include "trace.h"
23
094a2239
PD
24static char *xen_device_get_backend_path(XenDevice *xendev)
25{
26 XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
27 XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
28 const char *type = object_get_typename(OBJECT(xendev));
29 const char *backend = xendev_class->backend;
30
31 if (!backend) {
32 backend = type;
33 }
34
35 return g_strdup_printf("/local/domain/%u/backend/%s/%u/%s",
36 xenbus->backend_id, backend, xendev->frontend_id,
37 xendev->name);
38}
39
40static char *xen_device_get_frontend_path(XenDevice *xendev)
41{
42 XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
43 const char *type = object_get_typename(OBJECT(xendev));
44 const char *device = xendev_class->device;
45
46 if (!device) {
47 device = type;
48 }
49
50 return g_strdup_printf("/local/domain/%u/device/%s/%s",
51 xendev->frontend_id, device, xendev->name);
52}
53
b6af8926
PD
54static void xen_device_unplug(XenDevice *xendev, Error **errp)
55{
56 XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
57 const char *type = object_get_typename(OBJECT(xendev));
58 Error *local_err = NULL;
59 xs_transaction_t tid;
60
61 trace_xen_device_unplug(type, xendev->name);
62
63 /* Mimic the way the Xen toolstack does an unplug */
64again:
65 tid = xs_transaction_start(xenbus->xsh);
66 if (tid == XBT_NULL) {
67 error_setg_errno(errp, errno, "failed xs_transaction_start");
68 return;
69 }
70
71 xs_node_printf(xenbus->xsh, tid, xendev->backend_path, "online",
72 &local_err, "%u", 0);
73 if (local_err) {
74 goto abort;
75 }
76
77 xs_node_printf(xenbus->xsh, tid, xendev->backend_path, "state",
78 &local_err, "%u", XenbusStateClosing);
79 if (local_err) {
80 goto abort;
81 }
82
83 if (!xs_transaction_end(xenbus->xsh, tid, false)) {
84 if (errno == EAGAIN) {
85 goto again;
86 }
87
88 error_setg_errno(errp, errno, "failed xs_transaction_end");
89 }
90
91 return;
92
93abort:
94 /*
95 * We only abort if there is already a failure so ignore any error
96 * from ending the transaction.
97 */
98 xs_transaction_end(xenbus->xsh, tid, true);
99 error_propagate(errp, local_err);
100}
101
094a2239
PD
102static void xen_bus_print_dev(Monitor *mon, DeviceState *dev, int indent)
103{
104 XenDevice *xendev = XEN_DEVICE(dev);
105
106 monitor_printf(mon, "%*sname = '%s' frontend_id = %u\n",
107 indent, "", xendev->name, xendev->frontend_id);
108}
109
110static char *xen_bus_get_dev_path(DeviceState *dev)
111{
112 return xen_device_get_backend_path(XEN_DEVICE(dev));
113}
114
82a29e30
PD
115struct XenWatch {
116 char *node, *key;
117 char *token;
118 XenWatchHandler handler;
119 void *opaque;
120 Notifier notifier;
121};
122
123static void watch_notify(Notifier *n, void *data)
124{
125 XenWatch *watch = container_of(n, XenWatch, notifier);
126 const char *token = data;
127
128 if (!strcmp(watch->token, token)) {
129 watch->handler(watch->opaque);
130 }
131}
132
133static XenWatch *new_watch(const char *node, const char *key,
134 XenWatchHandler handler, void *opaque)
135{
136 XenWatch *watch = g_new0(XenWatch, 1);
137 QemuUUID uuid;
138
139 qemu_uuid_generate(&uuid);
140
141 watch->token = qemu_uuid_unparse_strdup(&uuid);
142 watch->node = g_strdup(node);
143 watch->key = g_strdup(key);
144 watch->handler = handler;
145 watch->opaque = opaque;
146 watch->notifier.notify = watch_notify;
147
148 return watch;
149}
150
151static void free_watch(XenWatch *watch)
152{
153 g_free(watch->token);
154 g_free(watch->key);
155 g_free(watch->node);
156
157 g_free(watch);
158}
159
374752a2
PD
160struct XenWatchList {
161 struct xs_handle *xsh;
162 NotifierList notifiers;
163};
164
165static void watch_list_event(void *opaque)
166{
167 XenWatchList *watch_list = opaque;
168 char **v;
169 const char *token;
170
171 v = xs_check_watch(watch_list->xsh);
172 if (!v) {
173 return;
174 }
175
176 token = v[XS_WATCH_TOKEN];
177
178 notifier_list_notify(&watch_list->notifiers, (void *)token);
179
180 free(v);
181}
182
183static XenWatchList *watch_list_create(struct xs_handle *xsh)
184{
185 XenWatchList *watch_list = g_new0(XenWatchList, 1);
186
187 g_assert(xsh);
188
189 watch_list->xsh = xsh;
190 notifier_list_init(&watch_list->notifiers);
191 qemu_set_fd_handler(xs_fileno(watch_list->xsh), watch_list_event, NULL,
192 watch_list);
193
194 return watch_list;
195}
196
197static void watch_list_destroy(XenWatchList *watch_list)
198{
199 g_assert(notifier_list_empty(&watch_list->notifiers));
200 qemu_set_fd_handler(xs_fileno(watch_list->xsh), NULL, NULL, NULL);
201 g_free(watch_list);
202}
203
204static XenWatch *watch_list_add(XenWatchList *watch_list, const char *node,
205 const char *key, XenWatchHandler handler,
206 void *opaque, Error **errp)
82a29e30
PD
207{
208 XenWatch *watch = new_watch(node, key, handler, opaque);
209 Error *local_err = NULL;
210
374752a2 211 notifier_list_add(&watch_list->notifiers, &watch->notifier);
82a29e30 212
374752a2 213 xs_node_watch(watch_list->xsh, node, key, watch->token, &local_err);
82a29e30
PD
214 if (local_err) {
215 error_propagate(errp, local_err);
216
217 notifier_remove(&watch->notifier);
218 free_watch(watch);
219
220 return NULL;
221 }
222
223 return watch;
224}
225
374752a2
PD
226static void watch_list_remove(XenWatchList *watch_list, XenWatch *watch,
227 Error **errp)
82a29e30 228{
374752a2 229 xs_node_unwatch(watch_list->xsh, watch->node, watch->key, watch->token,
82a29e30
PD
230 errp);
231
232 notifier_remove(&watch->notifier);
233 free_watch(watch);
234}
235
374752a2
PD
236static XenWatch *xen_bus_add_watch(XenBus *xenbus, const char *node,
237 const char *key, XenWatchHandler handler,
d198b711 238 Error **errp)
374752a2
PD
239{
240 trace_xen_bus_add_watch(node, key);
241
d198b711 242 return watch_list_add(xenbus->watch_list, node, key, handler, xenbus,
374752a2
PD
243 errp);
244}
245
246static void xen_bus_remove_watch(XenBus *xenbus, XenWatch *watch,
247 Error **errp)
248{
249 trace_xen_bus_remove_watch(watch->node, watch->key);
250
251 watch_list_remove(xenbus->watch_list, watch, errp);
252}
253
a783f8ad
PD
254static void xen_bus_backend_create(XenBus *xenbus, const char *type,
255 const char *name, char *path,
256 Error **errp)
257{
258 xs_transaction_t tid;
259 char **key;
260 QDict *opts;
261 unsigned int i, n;
262 Error *local_err = NULL;
263
264 trace_xen_bus_backend_create(type, path);
265
266again:
267 tid = xs_transaction_start(xenbus->xsh);
268 if (tid == XBT_NULL) {
269 error_setg(errp, "failed xs_transaction_start");
270 return;
271 }
272
273 key = xs_directory(xenbus->xsh, tid, path, &n);
274 if (!key) {
275 if (!xs_transaction_end(xenbus->xsh, tid, true)) {
276 error_setg_errno(errp, errno, "failed xs_transaction_end");
277 }
278 return;
279 }
280
281 opts = qdict_new();
282 for (i = 0; i < n; i++) {
283 char *val;
284
285 /*
286 * Assume anything found in the xenstore backend area, other than
287 * the keys created for a generic XenDevice, are parameters
288 * to be used to configure the backend.
289 */
290 if (!strcmp(key[i], "state") ||
291 !strcmp(key[i], "online") ||
292 !strcmp(key[i], "frontend") ||
293 !strcmp(key[i], "frontend-id") ||
294 !strcmp(key[i], "hotplug-status"))
295 continue;
296
297 if (xs_node_scanf(xenbus->xsh, tid, path, key[i], NULL, "%ms",
298 &val) == 1) {
299 qdict_put_str(opts, key[i], val);
300 free(val);
301 }
302 }
303
304 free(key);
305
306 if (!xs_transaction_end(xenbus->xsh, tid, false)) {
307 qobject_unref(opts);
308
309 if (errno == EAGAIN) {
310 goto again;
311 }
312
313 error_setg_errno(errp, errno, "failed xs_transaction_end");
314 return;
315 }
316
317 xen_backend_device_create(xenbus, type, name, opts, &local_err);
318 qobject_unref(opts);
319
320 if (local_err) {
321 error_propagate_prepend(errp, local_err,
322 "failed to create '%s' device '%s': ",
323 type, name);
324 }
325}
326
327static void xen_bus_type_enumerate(XenBus *xenbus, const char *type)
328{
329 char *domain_path = g_strdup_printf("backend/%s/%u", type, xen_domid);
330 char **backend;
331 unsigned int i, n;
332
333 trace_xen_bus_type_enumerate(type);
334
335 backend = xs_directory(xenbus->xsh, XBT_NULL, domain_path, &n);
336 if (!backend) {
337 goto out;
338 }
339
340 for (i = 0; i < n; i++) {
341 char *backend_path = g_strdup_printf("%s/%s", domain_path,
342 backend[i]);
3809f758
PD
343 enum xenbus_state state;
344 unsigned int online;
a783f8ad
PD
345
346 if (xs_node_scanf(xenbus->xsh, XBT_NULL, backend_path, "state",
3809f758
PD
347 NULL, "%u", &state) != 1)
348 state = XenbusStateUnknown;
a783f8ad 349
3809f758
PD
350 if (xs_node_scanf(xenbus->xsh, XBT_NULL, backend_path, "online",
351 NULL, "%u", &online) != 1)
352 online = 0;
353
354 if (online && state == XenbusStateInitialising) {
a783f8ad
PD
355 Error *local_err = NULL;
356
357 xen_bus_backend_create(xenbus, type, backend[i], backend_path,
358 &local_err);
359 if (local_err) {
360 error_report_err(local_err);
361 }
362 }
363
364 g_free(backend_path);
365 }
366
367 free(backend);
368
369out:
370 g_free(domain_path);
371}
372
3809f758 373static void xen_bus_enumerate(XenBus *xenbus)
a783f8ad 374{
a783f8ad
PD
375 char **type;
376 unsigned int i, n;
377
378 trace_xen_bus_enumerate();
379
380 type = xs_directory(xenbus->xsh, XBT_NULL, "backend", &n);
381 if (!type) {
382 return;
383 }
384
385 for (i = 0; i < n; i++) {
386 xen_bus_type_enumerate(xenbus, type[i]);
387 }
388
389 free(type);
390}
391
3809f758
PD
392static void xen_bus_device_cleanup(XenDevice *xendev)
393{
394 const char *type = object_get_typename(OBJECT(xendev));
395 Error *local_err = NULL;
396
397 trace_xen_bus_device_cleanup(type, xendev->name);
398
399 g_assert(!xendev->backend_online);
400
401 if (!xen_backend_try_device_destroy(xendev, &local_err)) {
402 object_unparent(OBJECT(xendev));
403 }
404
405 if (local_err) {
406 error_report_err(local_err);
407 }
408}
409
410static void xen_bus_cleanup(XenBus *xenbus)
411{
412 XenDevice *xendev, *next;
413
414 trace_xen_bus_cleanup();
415
416 QLIST_FOREACH_SAFE(xendev, &xenbus->inactive_devices, list, next) {
417 g_assert(xendev->inactive);
418 QLIST_REMOVE(xendev, list);
419 xen_bus_device_cleanup(xendev);
420 }
421}
422
423static void xen_bus_backend_changed(void *opaque)
424{
425 XenBus *xenbus = opaque;
426
427 xen_bus_enumerate(xenbus);
428 xen_bus_cleanup(xenbus);
429}
430
108f7bba
PD
431static void xen_bus_unrealize(BusState *bus, Error **errp)
432{
094a2239
PD
433 XenBus *xenbus = XEN_BUS(bus);
434
108f7bba 435 trace_xen_bus_unrealize();
094a2239 436
a783f8ad
PD
437 if (xenbus->backend_watch) {
438 xen_bus_remove_watch(xenbus, xenbus->backend_watch, NULL);
439 xenbus->backend_watch = NULL;
440 }
441
374752a2
PD
442 if (xenbus->watch_list) {
443 watch_list_destroy(xenbus->watch_list);
444 xenbus->watch_list = NULL;
094a2239
PD
445 }
446
374752a2
PD
447 if (xenbus->xsh) {
448 xs_close(xenbus->xsh);
82a29e30 449 }
82a29e30
PD
450}
451
108f7bba
PD
452static void xen_bus_realize(BusState *bus, Error **errp)
453{
094a2239
PD
454 XenBus *xenbus = XEN_BUS(bus);
455 unsigned int domid;
a783f8ad 456 Error *local_err = NULL;
094a2239 457
108f7bba 458 trace_xen_bus_realize();
094a2239
PD
459
460 xenbus->xsh = xs_open(0);
461 if (!xenbus->xsh) {
462 error_setg_errno(errp, errno, "failed xs_open");
463 goto fail;
464 }
465
466 if (xs_node_scanf(xenbus->xsh, XBT_NULL, "", /* domain root node */
467 "domid", NULL, "%u", &domid) == 1) {
468 xenbus->backend_id = domid;
469 } else {
470 xenbus->backend_id = 0; /* Assume lack of node means dom0 */
471 }
472
374752a2 473 xenbus->watch_list = watch_list_create(xenbus->xsh);
a783f8ad
PD
474
475 module_call_init(MODULE_INIT_XEN_BACKEND);
476
477 xenbus->backend_watch =
478 xen_bus_add_watch(xenbus, "", /* domain root node */
3809f758 479 "backend", xen_bus_backend_changed, &local_err);
a783f8ad
PD
480 if (local_err) {
481 /* This need not be treated as a hard error so don't propagate */
482 error_reportf_err(local_err,
483 "failed to set up enumeration watch: ");
484 }
485
094a2239
PD
486 return;
487
488fail:
489 xen_bus_unrealize(bus, &error_abort);
108f7bba
PD
490}
491
b6af8926
PD
492static void xen_bus_unplug_request(HotplugHandler *hotplug,
493 DeviceState *dev,
494 Error **errp)
495{
496 XenDevice *xendev = XEN_DEVICE(dev);
497
498 xen_device_unplug(xendev, errp);
499}
500
108f7bba
PD
501static void xen_bus_class_init(ObjectClass *class, void *data)
502{
503 BusClass *bus_class = BUS_CLASS(class);
b6af8926 504 HotplugHandlerClass *hotplug_class = HOTPLUG_HANDLER_CLASS(class);
108f7bba 505
094a2239
PD
506 bus_class->print_dev = xen_bus_print_dev;
507 bus_class->get_dev_path = xen_bus_get_dev_path;
108f7bba
PD
508 bus_class->realize = xen_bus_realize;
509 bus_class->unrealize = xen_bus_unrealize;
b6af8926
PD
510
511 hotplug_class->unplug_request = xen_bus_unplug_request;
108f7bba
PD
512}
513
514static const TypeInfo xen_bus_type_info = {
515 .name = TYPE_XEN_BUS,
516 .parent = TYPE_BUS,
517 .instance_size = sizeof(XenBus),
518 .class_size = sizeof(XenBusClass),
519 .class_init = xen_bus_class_init,
520 .interfaces = (InterfaceInfo[]) {
521 { TYPE_HOTPLUG_HANDLER },
522 { }
523 },
524};
525
b6af8926
PD
526void xen_device_backend_printf(XenDevice *xendev, const char *key,
527 const char *fmt, ...)
094a2239
PD
528{
529 XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
530 Error *local_err = NULL;
531 va_list ap;
532
533 g_assert(xenbus->xsh);
534
535 va_start(ap, fmt);
536 xs_node_vprintf(xenbus->xsh, XBT_NULL, xendev->backend_path, key,
537 &local_err, fmt, ap);
538 va_end(ap);
539
540 if (local_err) {
541 error_report_err(local_err);
542 }
543}
544
82a29e30
PD
545static int xen_device_backend_scanf(XenDevice *xendev, const char *key,
546 const char *fmt, ...)
547{
548 XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
549 va_list ap;
550 int rc;
551
552 g_assert(xenbus->xsh);
553
554 va_start(ap, fmt);
555 rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->backend_path, key,
556 NULL, fmt, ap);
557 va_end(ap);
558
559 return rc;
560}
561
562void xen_device_backend_set_state(XenDevice *xendev,
563 enum xenbus_state state)
094a2239
PD
564{
565 const char *type = object_get_typename(OBJECT(xendev));
566
567 if (xendev->backend_state == state) {
568 return;
569 }
570
571 trace_xen_device_backend_state(type, xendev->name,
572 xs_strstate(state));
573
574 xendev->backend_state = state;
575 xen_device_backend_printf(xendev, "state", "%u", state);
576}
577
82a29e30
PD
578enum xenbus_state xen_device_backend_get_state(XenDevice *xendev)
579{
580 return xendev->backend_state;
581}
582
b6af8926
PD
583static void xen_device_backend_set_online(XenDevice *xendev, bool online)
584{
585 const char *type = object_get_typename(OBJECT(xendev));
586
587 if (xendev->backend_online == online) {
588 return;
589 }
590
591 trace_xen_device_backend_online(type, xendev->name, online);
592
593 xendev->backend_online = online;
594 xen_device_backend_printf(xendev, "online", "%u", online);
595}
596
cb323146
AP
597/*
598 * Tell from the state whether the frontend is likely alive,
599 * i.e. it will react to a change of state of the backend.
600 */
3809f758 601static bool xen_device_frontend_is_active(XenDevice *xendev)
cb323146 602{
3809f758 603 switch (xendev->frontend_state) {
cb323146
AP
604 case XenbusStateInitWait:
605 case XenbusStateInitialised:
606 case XenbusStateConnected:
607 case XenbusStateClosing:
608 return true;
609 default:
610 return false;
611 }
612}
613
b6af8926
PD
614static void xen_device_backend_changed(void *opaque)
615{
616 XenDevice *xendev = opaque;
617 const char *type = object_get_typename(OBJECT(xendev));
618 enum xenbus_state state;
619 unsigned int online;
620
621 trace_xen_device_backend_changed(type, xendev->name);
622
623 if (xen_device_backend_scanf(xendev, "state", "%u", &state) != 1) {
624 state = XenbusStateUnknown;
625 }
626
627 xen_device_backend_set_state(xendev, state);
628
629 if (xen_device_backend_scanf(xendev, "online", "%u", &online) != 1) {
630 online = 0;
631 }
632
633 xen_device_backend_set_online(xendev, !!online);
634
635 /*
636 * If the toolstack (or unplug request callback) has set the backend
cb323146
AP
637 * state to Closing, but there is no active frontend then set the
638 * backend state to Closed.
b6af8926 639 */
3809f758
PD
640 if (state == XenbusStateClosing &&
641 !xen_device_frontend_is_active(xendev)) {
b6af8926
PD
642 xen_device_backend_set_state(xendev, XenbusStateClosed);
643 }
644
645 /*
67bc8e00 646 * If a backend is still 'online' then we should leave it alone but,
3809f758
PD
647 * if a backend is not 'online', then the device is a candidate
648 * for destruction. Hence add it to the 'inactive' list to be cleaned
649 * by xen_bus_cleanup().
b6af8926 650 */
3809f758
PD
651 if (!online &&
652 (state == XenbusStateClosed || state == XenbusStateInitialising ||
653 state == XenbusStateInitWait || state == XenbusStateUnknown) &&
654 !xendev->inactive) {
655 XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
a783f8ad 656
3809f758
PD
657 xendev->inactive = true;
658 QLIST_INSERT_HEAD(&xenbus->inactive_devices, xendev, list);
659
660 /*
661 * Re-write the state to cause a XenBus backend_watch notification,
662 * resulting in a call to xen_bus_cleanup().
663 */
664 xen_device_backend_printf(xendev, "state", "%u", state);
b6af8926
PD
665 }
666}
667
d198b711
PD
668static XenWatch *xen_device_add_watch(XenDevice *xendev, const char *node,
669 const char *key,
670 XenWatchHandler handler,
671 Error **errp)
672{
673 const char *type = object_get_typename(OBJECT(xendev));
674
675 trace_xen_device_add_watch(type, xendev->name, node, key);
676
677 return watch_list_add(xendev->watch_list, node, key, handler, xendev,
678 errp);
679}
680
681static void xen_device_remove_watch(XenDevice *xendev, XenWatch *watch,
682 Error **errp)
683{
684 const char *type = object_get_typename(OBJECT(xendev));
685
686 trace_xen_device_remove_watch(type, xendev->name, watch->node,
687 watch->key);
688
689 watch_list_remove(xendev->watch_list, watch, errp);
690}
691
692
094a2239
PD
693static void xen_device_backend_create(XenDevice *xendev, Error **errp)
694{
695 XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
696 struct xs_permissions perms[2];
697 Error *local_err = NULL;
698
699 xendev->backend_path = xen_device_get_backend_path(xendev);
700
701 perms[0].id = xenbus->backend_id;
702 perms[0].perms = XS_PERM_NONE;
703 perms[1].id = xendev->frontend_id;
704 perms[1].perms = XS_PERM_READ;
705
706 g_assert(xenbus->xsh);
707
708 xs_node_create(xenbus->xsh, XBT_NULL, xendev->backend_path, perms,
709 ARRAY_SIZE(perms), &local_err);
710 if (local_err) {
711 error_propagate_prepend(errp, local_err,
712 "failed to create backend: ");
b6af8926
PD
713 return;
714 }
715
716 xendev->backend_state_watch =
d198b711
PD
717 xen_device_add_watch(xendev, xendev->backend_path,
718 "state", xen_device_backend_changed,
719 &local_err);
b6af8926
PD
720 if (local_err) {
721 error_propagate_prepend(errp, local_err,
722 "failed to watch backend state: ");
723 return;
724 }
725
726 xendev->backend_online_watch =
d198b711
PD
727 xen_device_add_watch(xendev, xendev->backend_path,
728 "online", xen_device_backend_changed,
729 &local_err);
b6af8926
PD
730 if (local_err) {
731 error_propagate_prepend(errp, local_err,
732 "failed to watch backend online: ");
733 return;
094a2239
PD
734 }
735}
736
737static void xen_device_backend_destroy(XenDevice *xendev)
738{
739 XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
740 Error *local_err = NULL;
741
b6af8926 742 if (xendev->backend_online_watch) {
d198b711 743 xen_device_remove_watch(xendev, xendev->backend_online_watch, NULL);
b6af8926
PD
744 xendev->backend_online_watch = NULL;
745 }
746
747 if (xendev->backend_state_watch) {
d198b711 748 xen_device_remove_watch(xendev, xendev->backend_state_watch, NULL);
b6af8926
PD
749 xendev->backend_state_watch = NULL;
750 }
751
094a2239
PD
752 if (!xendev->backend_path) {
753 return;
754 }
755
756 g_assert(xenbus->xsh);
757
758 xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->backend_path,
759 &local_err);
760 g_free(xendev->backend_path);
761 xendev->backend_path = NULL;
762
763 if (local_err) {
764 error_report_err(local_err);
765 }
766}
767
b6af8926
PD
768void xen_device_frontend_printf(XenDevice *xendev, const char *key,
769 const char *fmt, ...)
094a2239
PD
770{
771 XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
772 Error *local_err = NULL;
773 va_list ap;
774
775 g_assert(xenbus->xsh);
776
777 va_start(ap, fmt);
778 xs_node_vprintf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key,
779 &local_err, fmt, ap);
780 va_end(ap);
781
782 if (local_err) {
783 error_report_err(local_err);
784 }
785}
786
b6af8926
PD
787int xen_device_frontend_scanf(XenDevice *xendev, const char *key,
788 const char *fmt, ...)
82a29e30
PD
789{
790 XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
791 va_list ap;
792 int rc;
793
794 g_assert(xenbus->xsh);
795
796 va_start(ap, fmt);
797 rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key,
798 NULL, fmt, ap);
799 va_end(ap);
800
801 return rc;
802}
803
094a2239 804static void xen_device_frontend_set_state(XenDevice *xendev,
705be570
AP
805 enum xenbus_state state,
806 bool publish)
094a2239
PD
807{
808 const char *type = object_get_typename(OBJECT(xendev));
809
810 if (xendev->frontend_state == state) {
811 return;
812 }
813
814 trace_xen_device_frontend_state(type, xendev->name,
815 xs_strstate(state));
816
817 xendev->frontend_state = state;
705be570
AP
818 if (publish) {
819 xen_device_frontend_printf(xendev, "state", "%u", state);
820 }
094a2239
PD
821}
822
82a29e30
PD
823static void xen_device_frontend_changed(void *opaque)
824{
825 XenDevice *xendev = opaque;
826 XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
827 const char *type = object_get_typename(OBJECT(xendev));
828 enum xenbus_state state;
829
830 trace_xen_device_frontend_changed(type, xendev->name);
831
832 if (xen_device_frontend_scanf(xendev, "state", "%u", &state) != 1) {
833 state = XenbusStateUnknown;
834 }
835
705be570 836 xen_device_frontend_set_state(xendev, state, false);
82a29e30 837
67bc8e00
PD
838 if (state == XenbusStateInitialising &&
839 xendev->backend_state == XenbusStateClosed &&
840 xendev->backend_online) {
841 /*
842 * The frontend is re-initializing so switch back to
843 * InitWait.
844 */
845 xen_device_backend_set_state(xendev, XenbusStateInitWait);
846 return;
847 }
848
82a29e30
PD
849 if (xendev_class->frontend_changed) {
850 Error *local_err = NULL;
851
852 xendev_class->frontend_changed(xendev, state, &local_err);
853
854 if (local_err) {
855 error_reportf_err(local_err, "frontend change error: ");
856 }
857 }
82a29e30
PD
858}
859
6bd6b955
MS
860static bool xen_device_frontend_exists(XenDevice *xendev)
861{
862 enum xenbus_state state;
863
864 return (xen_device_frontend_scanf(xendev, "state", "%u", &state) == 1);
865}
866
094a2239
PD
867static void xen_device_frontend_create(XenDevice *xendev, Error **errp)
868{
869 XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
870 struct xs_permissions perms[2];
871 Error *local_err = NULL;
872
873 xendev->frontend_path = xen_device_get_frontend_path(xendev);
874
6bd6b955
MS
875 /*
876 * The frontend area may have already been created by a legacy
877 * toolstack.
878 */
879 if (!xen_device_frontend_exists(xendev)) {
880 perms[0].id = xendev->frontend_id;
881 perms[0].perms = XS_PERM_NONE;
882 perms[1].id = xenbus->backend_id;
883 perms[1].perms = XS_PERM_READ | XS_PERM_WRITE;
094a2239 884
6bd6b955 885 g_assert(xenbus->xsh);
094a2239 886
6bd6b955
MS
887 xs_node_create(xenbus->xsh, XBT_NULL, xendev->frontend_path, perms,
888 ARRAY_SIZE(perms), &local_err);
889 if (local_err) {
890 error_propagate_prepend(errp, local_err,
891 "failed to create frontend: ");
892 return;
893 }
82a29e30
PD
894 }
895
896 xendev->frontend_state_watch =
d198b711
PD
897 xen_device_add_watch(xendev, xendev->frontend_path, "state",
898 xen_device_frontend_changed, &local_err);
82a29e30
PD
899 if (local_err) {
900 error_propagate_prepend(errp, local_err,
901 "failed to watch frontend state: ");
094a2239
PD
902 }
903}
904
905static void xen_device_frontend_destroy(XenDevice *xendev)
906{
907 XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
908 Error *local_err = NULL;
909
82a29e30 910 if (xendev->frontend_state_watch) {
d198b711
PD
911 xen_device_remove_watch(xendev, xendev->frontend_state_watch,
912 NULL);
82a29e30
PD
913 xendev->frontend_state_watch = NULL;
914 }
915
094a2239
PD
916 if (!xendev->frontend_path) {
917 return;
918 }
919
920 g_assert(xenbus->xsh);
921
922 xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->frontend_path,
923 &local_err);
924 g_free(xendev->frontend_path);
925 xendev->frontend_path = NULL;
926
927 if (local_err) {
928 error_report_err(local_err);
929 }
930}
931
4b34b5b1
PD
932void xen_device_set_max_grant_refs(XenDevice *xendev, unsigned int nr_refs,
933 Error **errp)
934{
935 if (xengnttab_set_max_grants(xendev->xgth, nr_refs)) {
936 error_setg_errno(errp, errno, "xengnttab_set_max_grants failed");
937 }
938}
939
940void *xen_device_map_grant_refs(XenDevice *xendev, uint32_t *refs,
941 unsigned int nr_refs, int prot,
942 Error **errp)
943{
944 void *map = xengnttab_map_domain_grant_refs(xendev->xgth, nr_refs,
945 xendev->frontend_id, refs,
946 prot);
947
948 if (!map) {
949 error_setg_errno(errp, errno,
950 "xengnttab_map_domain_grant_refs failed");
951 }
952
953 return map;
954}
955
956void xen_device_unmap_grant_refs(XenDevice *xendev, void *map,
957 unsigned int nr_refs, Error **errp)
958{
959 if (xengnttab_unmap(xendev->xgth, map, nr_refs)) {
960 error_setg_errno(errp, errno, "xengnttab_unmap failed");
961 }
962}
963
964static void compat_copy_grant_refs(XenDevice *xendev, bool to_domain,
965 XenDeviceGrantCopySegment segs[],
966 unsigned int nr_segs, Error **errp)
967{
968 uint32_t *refs = g_new(uint32_t, nr_segs);
969 int prot = to_domain ? PROT_WRITE : PROT_READ;
970 void *map;
971 unsigned int i;
972
973 for (i = 0; i < nr_segs; i++) {
974 XenDeviceGrantCopySegment *seg = &segs[i];
975
976 refs[i] = to_domain ? seg->dest.foreign.ref :
977 seg->source.foreign.ref;
978 }
979
980 map = xengnttab_map_domain_grant_refs(xendev->xgth, nr_segs,
981 xendev->frontend_id, refs,
982 prot);
983 if (!map) {
984 error_setg_errno(errp, errno,
985 "xengnttab_map_domain_grant_refs failed");
986 goto done;
987 }
988
989 for (i = 0; i < nr_segs; i++) {
990 XenDeviceGrantCopySegment *seg = &segs[i];
991 void *page = map + (i * XC_PAGE_SIZE);
992
993 if (to_domain) {
994 memcpy(page + seg->dest.foreign.offset, seg->source.virt,
995 seg->len);
996 } else {
997 memcpy(seg->dest.virt, page + seg->source.foreign.offset,
998 seg->len);
999 }
1000 }
1001
1002 if (xengnttab_unmap(xendev->xgth, map, nr_segs)) {
1003 error_setg_errno(errp, errno, "xengnttab_unmap failed");
1004 }
1005
1006done:
1007 g_free(refs);
1008}
1009
1010void xen_device_copy_grant_refs(XenDevice *xendev, bool to_domain,
1011 XenDeviceGrantCopySegment segs[],
1012 unsigned int nr_segs, Error **errp)
1013{
1014 xengnttab_grant_copy_segment_t *xengnttab_segs;
1015 unsigned int i;
1016
1017 if (!xendev->feature_grant_copy) {
1018 compat_copy_grant_refs(xendev, to_domain, segs, nr_segs, errp);
1019 return;
1020 }
1021
1022 xengnttab_segs = g_new0(xengnttab_grant_copy_segment_t, nr_segs);
1023
1024 for (i = 0; i < nr_segs; i++) {
1025 XenDeviceGrantCopySegment *seg = &segs[i];
1026 xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i];
1027
1028 if (to_domain) {
1029 xengnttab_seg->flags = GNTCOPY_dest_gref;
1030 xengnttab_seg->dest.foreign.domid = xendev->frontend_id;
1031 xengnttab_seg->dest.foreign.ref = seg->dest.foreign.ref;
1032 xengnttab_seg->dest.foreign.offset = seg->dest.foreign.offset;
1033 xengnttab_seg->source.virt = seg->source.virt;
1034 } else {
1035 xengnttab_seg->flags = GNTCOPY_source_gref;
1036 xengnttab_seg->source.foreign.domid = xendev->frontend_id;
1037 xengnttab_seg->source.foreign.ref = seg->source.foreign.ref;
1038 xengnttab_seg->source.foreign.offset =
1039 seg->source.foreign.offset;
1040 xengnttab_seg->dest.virt = seg->dest.virt;
1041 }
1042
1043 xengnttab_seg->len = seg->len;
1044 }
1045
1046 if (xengnttab_grant_copy(xendev->xgth, nr_segs, xengnttab_segs)) {
1047 error_setg_errno(errp, errno, "xengnttab_grant_copy failed");
1048 goto done;
1049 }
1050
1051 for (i = 0; i < nr_segs; i++) {
1052 xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i];
1053
1054 if (xengnttab_seg->status != GNTST_okay) {
1055 error_setg(errp, "xengnttab_grant_copy seg[%u] failed", i);
1056 break;
1057 }
1058 }
1059
1060done:
1061 g_free(xengnttab_segs);
1062}
1063
a3d669c8 1064struct XenEventChannel {
c0b336ea 1065 QLIST_ENTRY(XenEventChannel) list;
83361a8a 1066 AioContext *ctx;
c0b336ea 1067 xenevtchn_handle *xeh;
a3d669c8
PD
1068 evtchn_port_t local_port;
1069 XenEventHandler handler;
1070 void *opaque;
a3d669c8
PD
1071};
1072
345f42b4
PD
1073static bool xen_device_poll(void *opaque)
1074{
1075 XenEventChannel *channel = opaque;
1076
1077 return channel->handler(channel->opaque);
1078}
1079
c0b336ea 1080static void xen_device_event(void *opaque)
a3d669c8 1081{
c0b336ea
PD
1082 XenEventChannel *channel = opaque;
1083 unsigned long port = xenevtchn_pending(channel->xeh);
a3d669c8
PD
1084
1085 if (port == channel->local_port) {
345f42b4 1086 xen_device_poll(channel);
c0b336ea
PD
1087
1088 xenevtchn_unmask(channel->xeh, port);
a3d669c8
PD
1089 }
1090}
1091
1092XenEventChannel *xen_device_bind_event_channel(XenDevice *xendev,
83361a8a 1093 AioContext *ctx,
a3d669c8
PD
1094 unsigned int port,
1095 XenEventHandler handler,
1096 void *opaque, Error **errp)
1097{
1098 XenEventChannel *channel = g_new0(XenEventChannel, 1);
1099 xenevtchn_port_or_error_t local_port;
1100
c0b336ea
PD
1101 channel->xeh = xenevtchn_open(NULL, 0);
1102 if (!channel->xeh) {
1103 error_setg_errno(errp, errno, "failed xenevtchn_open");
1104 goto fail;
1105 }
1106
1107 local_port = xenevtchn_bind_interdomain(channel->xeh,
a3d669c8
PD
1108 xendev->frontend_id,
1109 port);
1110 if (local_port < 0) {
1111 error_setg_errno(errp, errno, "xenevtchn_bind_interdomain failed");
c0b336ea 1112 goto fail;
a3d669c8
PD
1113 }
1114
1115 channel->local_port = local_port;
1116 channel->handler = handler;
1117 channel->opaque = opaque;
a3d669c8 1118
83361a8a
PD
1119 channel->ctx = ctx;
1120 aio_set_fd_handler(channel->ctx, xenevtchn_fd(channel->xeh), true,
345f42b4 1121 xen_device_event, NULL, xen_device_poll, channel);
c0b336ea
PD
1122
1123 QLIST_INSERT_HEAD(&xendev->event_channels, channel, list);
a3d669c8
PD
1124
1125 return channel;
c0b336ea
PD
1126
1127fail:
1128 if (channel->xeh) {
1129 xenevtchn_close(channel->xeh);
1130 }
1131
1132 g_free(channel);
1133
1134 return NULL;
a3d669c8
PD
1135}
1136
1137void xen_device_notify_event_channel(XenDevice *xendev,
1138 XenEventChannel *channel,
1139 Error **errp)
1140{
1141 if (!channel) {
1142 error_setg(errp, "bad channel");
1143 return;
1144 }
1145
c0b336ea 1146 if (xenevtchn_notify(channel->xeh, channel->local_port) < 0) {
a3d669c8
PD
1147 error_setg_errno(errp, errno, "xenevtchn_notify failed");
1148 }
1149}
1150
1151void xen_device_unbind_event_channel(XenDevice *xendev,
1152 XenEventChannel *channel,
1153 Error **errp)
1154{
1155 if (!channel) {
1156 error_setg(errp, "bad channel");
1157 return;
1158 }
1159
c0b336ea 1160 QLIST_REMOVE(channel, list);
a3d669c8 1161
83361a8a
PD
1162 aio_set_fd_handler(channel->ctx, xenevtchn_fd(channel->xeh), true,
1163 NULL, NULL, NULL, NULL);
c0b336ea
PD
1164
1165 if (xenevtchn_unbind(channel->xeh, channel->local_port) < 0) {
a3d669c8
PD
1166 error_setg_errno(errp, errno, "xenevtchn_unbind failed");
1167 }
1168
c0b336ea 1169 xenevtchn_close(channel->xeh);
a3d669c8
PD
1170 g_free(channel);
1171}
1172
108f7bba
PD
1173static void xen_device_unrealize(DeviceState *dev, Error **errp)
1174{
1175 XenDevice *xendev = XEN_DEVICE(dev);
1176 XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
1177 const char *type = object_get_typename(OBJECT(xendev));
c0b336ea 1178 XenEventChannel *channel, *next;
108f7bba 1179
094a2239
PD
1180 if (!xendev->name) {
1181 return;
1182 }
1183
1184 trace_xen_device_unrealize(type, xendev->name);
1185
1186 if (xendev->exit.notify) {
1187 qemu_remove_exit_notifier(&xendev->exit);
1188 xendev->exit.notify = NULL;
1189 }
108f7bba
PD
1190
1191 if (xendev_class->unrealize) {
1192 xendev_class->unrealize(xendev, errp);
1193 }
094a2239 1194
c0b336ea
PD
1195 /* Make sure all event channels are cleaned up */
1196 QLIST_FOREACH_SAFE(channel, &xendev->event_channels, list, next) {
1197 xen_device_unbind_event_channel(xendev, channel, NULL);
1198 }
1199
094a2239
PD
1200 xen_device_frontend_destroy(xendev);
1201 xen_device_backend_destroy(xendev);
1202
4b34b5b1
PD
1203 if (xendev->xgth) {
1204 xengnttab_close(xendev->xgth);
1205 xendev->xgth = NULL;
1206 }
1207
d198b711
PD
1208 if (xendev->watch_list) {
1209 watch_list_destroy(xendev->watch_list);
1210 xendev->watch_list = NULL;
1211 }
1212
1213 if (xendev->xsh) {
1214 xs_close(xendev->xsh);
1215 xendev->xsh = NULL;
1216 }
1217
094a2239
PD
1218 g_free(xendev->name);
1219 xendev->name = NULL;
1220}
1221
1222static void xen_device_exit(Notifier *n, void *data)
1223{
1224 XenDevice *xendev = container_of(n, XenDevice, exit);
1225
1226 xen_device_unrealize(DEVICE(xendev), &error_abort);
108f7bba
PD
1227}
1228
1229static void xen_device_realize(DeviceState *dev, Error **errp)
1230{
1231 XenDevice *xendev = XEN_DEVICE(dev);
1232 XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
094a2239 1233 XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
108f7bba
PD
1234 const char *type = object_get_typename(OBJECT(xendev));
1235 Error *local_err = NULL;
1236
094a2239
PD
1237 if (xendev->frontend_id == DOMID_INVALID) {
1238 xendev->frontend_id = xen_domid;
1239 }
1240
1241 if (xendev->frontend_id >= DOMID_FIRST_RESERVED) {
1242 error_setg(errp, "invalid frontend-id");
1243 goto unrealize;
1244 }
1245
1246 if (!xendev_class->get_name) {
1247 error_setg(errp, "get_name method not implemented");
1248 goto unrealize;
1249 }
1250
1251 xendev->name = xendev_class->get_name(xendev, &local_err);
1252 if (local_err) {
1253 error_propagate_prepend(errp, local_err,
1254 "failed to get device name: ");
1255 goto unrealize;
1256 }
1257
1258 trace_xen_device_realize(type, xendev->name);
1259
d198b711
PD
1260 xendev->xsh = xs_open(0);
1261 if (!xendev->xsh) {
1262 error_setg_errno(errp, errno, "failed xs_open");
1263 goto unrealize;
1264 }
1265
1266 xendev->watch_list = watch_list_create(xendev->xsh);
1267
4b34b5b1
PD
1268 xendev->xgth = xengnttab_open(NULL, 0);
1269 if (!xendev->xgth) {
1270 error_setg_errno(errp, errno, "failed xengnttab_open");
1271 goto unrealize;
1272 }
1273
1274 xendev->feature_grant_copy =
1275 (xengnttab_grant_copy(xendev->xgth, 0, NULL) == 0);
1276
094a2239
PD
1277 xen_device_backend_create(xendev, &local_err);
1278 if (local_err) {
1279 error_propagate(errp, local_err);
1280 goto unrealize;
1281 }
1282
1283 xen_device_frontend_create(xendev, &local_err);
1284 if (local_err) {
1285 error_propagate(errp, local_err);
1286 goto unrealize;
1287 }
108f7bba
PD
1288
1289 if (xendev_class->realize) {
1290 xendev_class->realize(xendev, &local_err);
1291 if (local_err) {
1292 error_propagate(errp, local_err);
1293 goto unrealize;
1294 }
1295 }
1296
094a2239
PD
1297 xen_device_backend_printf(xendev, "frontend", "%s",
1298 xendev->frontend_path);
1299 xen_device_backend_printf(xendev, "frontend-id", "%u",
1300 xendev->frontend_id);
094a2239
PD
1301 xen_device_backend_printf(xendev, "hotplug-status", "connected");
1302
b6af8926 1303 xen_device_backend_set_online(xendev, true);
094a2239
PD
1304 xen_device_backend_set_state(xendev, XenbusStateInitWait);
1305
6bd6b955
MS
1306 if (!xen_device_frontend_exists(xendev)) {
1307 xen_device_frontend_printf(xendev, "backend", "%s",
1308 xendev->backend_path);
1309 xen_device_frontend_printf(xendev, "backend-id", "%u",
1310 xenbus->backend_id);
094a2239 1311
6bd6b955
MS
1312 xen_device_frontend_set_state(xendev, XenbusStateInitialising, true);
1313 }
094a2239
PD
1314
1315 xendev->exit.notify = xen_device_exit;
1316 qemu_add_exit_notifier(&xendev->exit);
108f7bba
PD
1317 return;
1318
1319unrealize:
1320 xen_device_unrealize(dev, &error_abort);
1321}
1322
094a2239
PD
1323static Property xen_device_props[] = {
1324 DEFINE_PROP_UINT16("frontend-id", XenDevice, frontend_id,
1325 DOMID_INVALID),
1326 DEFINE_PROP_END_OF_LIST()
1327};
1328
108f7bba
PD
1329static void xen_device_class_init(ObjectClass *class, void *data)
1330{
1331 DeviceClass *dev_class = DEVICE_CLASS(class);
1332
1333 dev_class->realize = xen_device_realize;
1334 dev_class->unrealize = xen_device_unrealize;
094a2239 1335 dev_class->props = xen_device_props;
108f7bba
PD
1336 dev_class->bus_type = TYPE_XEN_BUS;
1337}
1338
1339static const TypeInfo xen_device_type_info = {
1340 .name = TYPE_XEN_DEVICE,
1341 .parent = TYPE_DEVICE,
1342 .instance_size = sizeof(XenDevice),
1343 .abstract = true,
1344 .class_size = sizeof(XenDeviceClass),
1345 .class_init = xen_device_class_init,
1346};
1347
1348typedef struct XenBridge {
1349 SysBusDevice busdev;
1350} XenBridge;
1351
1352#define TYPE_XEN_BRIDGE "xen-bridge"
1353
1354static const TypeInfo xen_bridge_type_info = {
1355 .name = TYPE_XEN_BRIDGE,
1356 .parent = TYPE_SYS_BUS_DEVICE,
1357 .instance_size = sizeof(XenBridge),
1358};
1359
1360static void xen_register_types(void)
1361{
1362 type_register_static(&xen_bridge_type_info);
1363 type_register_static(&xen_bus_type_info);
1364 type_register_static(&xen_device_type_info);
1365}
1366
1367type_init(xen_register_types)
1368
1369void xen_bus_init(void)
1370{
1371 DeviceState *dev = qdev_create(NULL, TYPE_XEN_BRIDGE);
1372 BusState *bus = qbus_create(TYPE_XEN_BUS, dev, NULL);
1373
1374 qdev_init_nofail(dev);
1375 qbus_set_bus_hotplug_handler(bus, &error_abort);
1376}