]> git.ipfire.org Git - thirdparty/qemu.git/blame - hw/xen/xen-bus.c
Include hw/qdev-properties.h less
[thirdparty/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
160static XenWatch *xen_bus_add_watch(XenBus *xenbus, const char *node,
161 const char *key, XenWatchHandler handler,
162 void *opaque, Error **errp)
163{
164 XenWatch *watch = new_watch(node, key, handler, opaque);
165 Error *local_err = NULL;
166
167 trace_xen_bus_add_watch(watch->node, watch->key, watch->token);
168
169 notifier_list_add(&xenbus->watch_notifiers, &watch->notifier);
170
171 xs_node_watch(xenbus->xsh, node, key, watch->token, &local_err);
172 if (local_err) {
173 error_propagate(errp, local_err);
174
175 notifier_remove(&watch->notifier);
176 free_watch(watch);
177
178 return NULL;
179 }
180
181 return watch;
182}
183
184static void xen_bus_remove_watch(XenBus *xenbus, XenWatch *watch,
185 Error **errp)
186{
187 trace_xen_bus_remove_watch(watch->node, watch->key, watch->token);
188
189 xs_node_unwatch(xenbus->xsh, watch->node, watch->key, watch->token,
190 errp);
191
192 notifier_remove(&watch->notifier);
193 free_watch(watch);
194}
195
a783f8ad
PD
196static void xen_bus_backend_create(XenBus *xenbus, const char *type,
197 const char *name, char *path,
198 Error **errp)
199{
200 xs_transaction_t tid;
201 char **key;
202 QDict *opts;
203 unsigned int i, n;
204 Error *local_err = NULL;
205
206 trace_xen_bus_backend_create(type, path);
207
208again:
209 tid = xs_transaction_start(xenbus->xsh);
210 if (tid == XBT_NULL) {
211 error_setg(errp, "failed xs_transaction_start");
212 return;
213 }
214
215 key = xs_directory(xenbus->xsh, tid, path, &n);
216 if (!key) {
217 if (!xs_transaction_end(xenbus->xsh, tid, true)) {
218 error_setg_errno(errp, errno, "failed xs_transaction_end");
219 }
220 return;
221 }
222
223 opts = qdict_new();
224 for (i = 0; i < n; i++) {
225 char *val;
226
227 /*
228 * Assume anything found in the xenstore backend area, other than
229 * the keys created for a generic XenDevice, are parameters
230 * to be used to configure the backend.
231 */
232 if (!strcmp(key[i], "state") ||
233 !strcmp(key[i], "online") ||
234 !strcmp(key[i], "frontend") ||
235 !strcmp(key[i], "frontend-id") ||
236 !strcmp(key[i], "hotplug-status"))
237 continue;
238
239 if (xs_node_scanf(xenbus->xsh, tid, path, key[i], NULL, "%ms",
240 &val) == 1) {
241 qdict_put_str(opts, key[i], val);
242 free(val);
243 }
244 }
245
246 free(key);
247
248 if (!xs_transaction_end(xenbus->xsh, tid, false)) {
249 qobject_unref(opts);
250
251 if (errno == EAGAIN) {
252 goto again;
253 }
254
255 error_setg_errno(errp, errno, "failed xs_transaction_end");
256 return;
257 }
258
259 xen_backend_device_create(xenbus, type, name, opts, &local_err);
260 qobject_unref(opts);
261
262 if (local_err) {
263 error_propagate_prepend(errp, local_err,
264 "failed to create '%s' device '%s': ",
265 type, name);
266 }
267}
268
269static void xen_bus_type_enumerate(XenBus *xenbus, const char *type)
270{
271 char *domain_path = g_strdup_printf("backend/%s/%u", type, xen_domid);
272 char **backend;
273 unsigned int i, n;
274
275 trace_xen_bus_type_enumerate(type);
276
277 backend = xs_directory(xenbus->xsh, XBT_NULL, domain_path, &n);
278 if (!backend) {
279 goto out;
280 }
281
282 for (i = 0; i < n; i++) {
283 char *backend_path = g_strdup_printf("%s/%s", domain_path,
284 backend[i]);
285 enum xenbus_state backend_state;
286
287 if (xs_node_scanf(xenbus->xsh, XBT_NULL, backend_path, "state",
288 NULL, "%u", &backend_state) != 1)
289 backend_state = XenbusStateUnknown;
290
291 if (backend_state == XenbusStateInitialising) {
292 Error *local_err = NULL;
293
294 xen_bus_backend_create(xenbus, type, backend[i], backend_path,
295 &local_err);
296 if (local_err) {
297 error_report_err(local_err);
298 }
299 }
300
301 g_free(backend_path);
302 }
303
304 free(backend);
305
306out:
307 g_free(domain_path);
308}
309
310static void xen_bus_enumerate(void *opaque)
311{
312 XenBus *xenbus = opaque;
313 char **type;
314 unsigned int i, n;
315
316 trace_xen_bus_enumerate();
317
318 type = xs_directory(xenbus->xsh, XBT_NULL, "backend", &n);
319 if (!type) {
320 return;
321 }
322
323 for (i = 0; i < n; i++) {
324 xen_bus_type_enumerate(xenbus, type[i]);
325 }
326
327 free(type);
328}
329
108f7bba
PD
330static void xen_bus_unrealize(BusState *bus, Error **errp)
331{
094a2239
PD
332 XenBus *xenbus = XEN_BUS(bus);
333
108f7bba 334 trace_xen_bus_unrealize();
094a2239 335
a783f8ad
PD
336 if (xenbus->backend_watch) {
337 xen_bus_remove_watch(xenbus, xenbus->backend_watch, NULL);
338 xenbus->backend_watch = NULL;
339 }
340
094a2239
PD
341 if (!xenbus->xsh) {
342 return;
343 }
344
82a29e30
PD
345 qemu_set_fd_handler(xs_fileno(xenbus->xsh), NULL, NULL, NULL);
346
094a2239 347 xs_close(xenbus->xsh);
108f7bba
PD
348}
349
82a29e30
PD
350static void xen_bus_watch(void *opaque)
351{
352 XenBus *xenbus = opaque;
353 char **v;
354 const char *token;
355
356 g_assert(xenbus->xsh);
357
358 v = xs_check_watch(xenbus->xsh);
359 if (!v) {
360 return;
361 }
362
363 token = v[XS_WATCH_TOKEN];
364
365 trace_xen_bus_watch(token);
366
367 notifier_list_notify(&xenbus->watch_notifiers, (void *)token);
368
369 free(v);
370}
371
108f7bba
PD
372static void xen_bus_realize(BusState *bus, Error **errp)
373{
094a2239
PD
374 XenBus *xenbus = XEN_BUS(bus);
375 unsigned int domid;
a783f8ad 376 Error *local_err = NULL;
094a2239 377
108f7bba 378 trace_xen_bus_realize();
094a2239
PD
379
380 xenbus->xsh = xs_open(0);
381 if (!xenbus->xsh) {
382 error_setg_errno(errp, errno, "failed xs_open");
383 goto fail;
384 }
385
386 if (xs_node_scanf(xenbus->xsh, XBT_NULL, "", /* domain root node */
387 "domid", NULL, "%u", &domid) == 1) {
388 xenbus->backend_id = domid;
389 } else {
390 xenbus->backend_id = 0; /* Assume lack of node means dom0 */
391 }
392
82a29e30
PD
393 notifier_list_init(&xenbus->watch_notifiers);
394 qemu_set_fd_handler(xs_fileno(xenbus->xsh), xen_bus_watch, NULL,
395 xenbus);
a783f8ad
PD
396
397 module_call_init(MODULE_INIT_XEN_BACKEND);
398
399 xenbus->backend_watch =
400 xen_bus_add_watch(xenbus, "", /* domain root node */
401 "backend", xen_bus_enumerate, xenbus, &local_err);
402 if (local_err) {
403 /* This need not be treated as a hard error so don't propagate */
404 error_reportf_err(local_err,
405 "failed to set up enumeration watch: ");
406 }
407
094a2239
PD
408 return;
409
410fail:
411 xen_bus_unrealize(bus, &error_abort);
108f7bba
PD
412}
413
b6af8926
PD
414static void xen_bus_unplug_request(HotplugHandler *hotplug,
415 DeviceState *dev,
416 Error **errp)
417{
418 XenDevice *xendev = XEN_DEVICE(dev);
419
420 xen_device_unplug(xendev, errp);
421}
422
108f7bba
PD
423static void xen_bus_class_init(ObjectClass *class, void *data)
424{
425 BusClass *bus_class = BUS_CLASS(class);
b6af8926 426 HotplugHandlerClass *hotplug_class = HOTPLUG_HANDLER_CLASS(class);
108f7bba 427
094a2239
PD
428 bus_class->print_dev = xen_bus_print_dev;
429 bus_class->get_dev_path = xen_bus_get_dev_path;
108f7bba
PD
430 bus_class->realize = xen_bus_realize;
431 bus_class->unrealize = xen_bus_unrealize;
b6af8926
PD
432
433 hotplug_class->unplug_request = xen_bus_unplug_request;
108f7bba
PD
434}
435
436static const TypeInfo xen_bus_type_info = {
437 .name = TYPE_XEN_BUS,
438 .parent = TYPE_BUS,
439 .instance_size = sizeof(XenBus),
440 .class_size = sizeof(XenBusClass),
441 .class_init = xen_bus_class_init,
442 .interfaces = (InterfaceInfo[]) {
443 { TYPE_HOTPLUG_HANDLER },
444 { }
445 },
446};
447
b6af8926
PD
448void xen_device_backend_printf(XenDevice *xendev, const char *key,
449 const char *fmt, ...)
094a2239
PD
450{
451 XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
452 Error *local_err = NULL;
453 va_list ap;
454
455 g_assert(xenbus->xsh);
456
457 va_start(ap, fmt);
458 xs_node_vprintf(xenbus->xsh, XBT_NULL, xendev->backend_path, key,
459 &local_err, fmt, ap);
460 va_end(ap);
461
462 if (local_err) {
463 error_report_err(local_err);
464 }
465}
466
82a29e30
PD
467static int xen_device_backend_scanf(XenDevice *xendev, const char *key,
468 const char *fmt, ...)
469{
470 XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
471 va_list ap;
472 int rc;
473
474 g_assert(xenbus->xsh);
475
476 va_start(ap, fmt);
477 rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->backend_path, key,
478 NULL, fmt, ap);
479 va_end(ap);
480
481 return rc;
482}
483
484void xen_device_backend_set_state(XenDevice *xendev,
485 enum xenbus_state state)
094a2239
PD
486{
487 const char *type = object_get_typename(OBJECT(xendev));
488
489 if (xendev->backend_state == state) {
490 return;
491 }
492
493 trace_xen_device_backend_state(type, xendev->name,
494 xs_strstate(state));
495
496 xendev->backend_state = state;
497 xen_device_backend_printf(xendev, "state", "%u", state);
498}
499
82a29e30
PD
500enum xenbus_state xen_device_backend_get_state(XenDevice *xendev)
501{
502 return xendev->backend_state;
503}
504
b6af8926
PD
505static void xen_device_backend_set_online(XenDevice *xendev, bool online)
506{
507 const char *type = object_get_typename(OBJECT(xendev));
508
509 if (xendev->backend_online == online) {
510 return;
511 }
512
513 trace_xen_device_backend_online(type, xendev->name, online);
514
515 xendev->backend_online = online;
516 xen_device_backend_printf(xendev, "online", "%u", online);
517}
518
519static void xen_device_backend_changed(void *opaque)
520{
521 XenDevice *xendev = opaque;
522 const char *type = object_get_typename(OBJECT(xendev));
523 enum xenbus_state state;
524 unsigned int online;
525
526 trace_xen_device_backend_changed(type, xendev->name);
527
528 if (xen_device_backend_scanf(xendev, "state", "%u", &state) != 1) {
529 state = XenbusStateUnknown;
530 }
531
532 xen_device_backend_set_state(xendev, state);
533
534 if (xen_device_backend_scanf(xendev, "online", "%u", &online) != 1) {
535 online = 0;
536 }
537
538 xen_device_backend_set_online(xendev, !!online);
539
540 /*
541 * If the toolstack (or unplug request callback) has set the backend
542 * state to Closing, but there is no active frontend (i.e. the
543 * state is not Connected) then set the backend state to Closed.
544 */
545 if (xendev->backend_state == XenbusStateClosing &&
546 xendev->frontend_state != XenbusStateConnected) {
547 xen_device_backend_set_state(xendev, XenbusStateClosed);
548 }
549
550 /*
67bc8e00
PD
551 * If a backend is still 'online' then we should leave it alone but,
552 * if a backend is not 'online', then the device should be destroyed
553 * once the state is Closed.
b6af8926 554 */
67bc8e00
PD
555 if (!xendev->backend_online &&
556 (xendev->backend_state == XenbusStateClosed ||
557 xendev->backend_state == XenbusStateInitialising ||
558 xendev->backend_state == XenbusStateInitWait ||
559 xendev->backend_state == XenbusStateUnknown)) {
a783f8ad
PD
560 Error *local_err = NULL;
561
562 if (!xen_backend_try_device_destroy(xendev, &local_err)) {
563 object_unparent(OBJECT(xendev));
564 }
565
566 if (local_err) {
567 error_report_err(local_err);
568 }
b6af8926
PD
569 }
570}
571
094a2239
PD
572static void xen_device_backend_create(XenDevice *xendev, Error **errp)
573{
574 XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
575 struct xs_permissions perms[2];
576 Error *local_err = NULL;
577
578 xendev->backend_path = xen_device_get_backend_path(xendev);
579
580 perms[0].id = xenbus->backend_id;
581 perms[0].perms = XS_PERM_NONE;
582 perms[1].id = xendev->frontend_id;
583 perms[1].perms = XS_PERM_READ;
584
585 g_assert(xenbus->xsh);
586
587 xs_node_create(xenbus->xsh, XBT_NULL, xendev->backend_path, perms,
588 ARRAY_SIZE(perms), &local_err);
589 if (local_err) {
590 error_propagate_prepend(errp, local_err,
591 "failed to create backend: ");
b6af8926
PD
592 return;
593 }
594
595 xendev->backend_state_watch =
596 xen_bus_add_watch(xenbus, xendev->backend_path,
597 "state", xen_device_backend_changed,
598 xendev, &local_err);
599 if (local_err) {
600 error_propagate_prepend(errp, local_err,
601 "failed to watch backend state: ");
602 return;
603 }
604
605 xendev->backend_online_watch =
606 xen_bus_add_watch(xenbus, xendev->backend_path,
607 "online", xen_device_backend_changed,
608 xendev, &local_err);
609 if (local_err) {
610 error_propagate_prepend(errp, local_err,
611 "failed to watch backend online: ");
612 return;
094a2239
PD
613 }
614}
615
616static void xen_device_backend_destroy(XenDevice *xendev)
617{
618 XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
619 Error *local_err = NULL;
620
b6af8926
PD
621 if (xendev->backend_online_watch) {
622 xen_bus_remove_watch(xenbus, xendev->backend_online_watch, NULL);
623 xendev->backend_online_watch = NULL;
624 }
625
626 if (xendev->backend_state_watch) {
627 xen_bus_remove_watch(xenbus, xendev->backend_state_watch, NULL);
628 xendev->backend_state_watch = NULL;
629 }
630
094a2239
PD
631 if (!xendev->backend_path) {
632 return;
633 }
634
635 g_assert(xenbus->xsh);
636
637 xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->backend_path,
638 &local_err);
639 g_free(xendev->backend_path);
640 xendev->backend_path = NULL;
641
642 if (local_err) {
643 error_report_err(local_err);
644 }
645}
646
b6af8926
PD
647void xen_device_frontend_printf(XenDevice *xendev, const char *key,
648 const char *fmt, ...)
094a2239
PD
649{
650 XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
651 Error *local_err = NULL;
652 va_list ap;
653
654 g_assert(xenbus->xsh);
655
656 va_start(ap, fmt);
657 xs_node_vprintf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key,
658 &local_err, fmt, ap);
659 va_end(ap);
660
661 if (local_err) {
662 error_report_err(local_err);
663 }
664}
665
b6af8926
PD
666int xen_device_frontend_scanf(XenDevice *xendev, const char *key,
667 const char *fmt, ...)
82a29e30
PD
668{
669 XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
670 va_list ap;
671 int rc;
672
673 g_assert(xenbus->xsh);
674
675 va_start(ap, fmt);
676 rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key,
677 NULL, fmt, ap);
678 va_end(ap);
679
680 return rc;
681}
682
094a2239
PD
683static void xen_device_frontend_set_state(XenDevice *xendev,
684 enum xenbus_state state)
685{
686 const char *type = object_get_typename(OBJECT(xendev));
687
688 if (xendev->frontend_state == state) {
689 return;
690 }
691
692 trace_xen_device_frontend_state(type, xendev->name,
693 xs_strstate(state));
694
695 xendev->frontend_state = state;
696 xen_device_frontend_printf(xendev, "state", "%u", state);
697}
698
82a29e30
PD
699static void xen_device_frontend_changed(void *opaque)
700{
701 XenDevice *xendev = opaque;
702 XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
703 const char *type = object_get_typename(OBJECT(xendev));
704 enum xenbus_state state;
705
706 trace_xen_device_frontend_changed(type, xendev->name);
707
708 if (xen_device_frontend_scanf(xendev, "state", "%u", &state) != 1) {
709 state = XenbusStateUnknown;
710 }
711
712 xen_device_frontend_set_state(xendev, state);
713
67bc8e00
PD
714 if (state == XenbusStateInitialising &&
715 xendev->backend_state == XenbusStateClosed &&
716 xendev->backend_online) {
717 /*
718 * The frontend is re-initializing so switch back to
719 * InitWait.
720 */
721 xen_device_backend_set_state(xendev, XenbusStateInitWait);
722 return;
723 }
724
82a29e30
PD
725 if (xendev_class->frontend_changed) {
726 Error *local_err = NULL;
727
728 xendev_class->frontend_changed(xendev, state, &local_err);
729
730 if (local_err) {
731 error_reportf_err(local_err, "frontend change error: ");
732 }
733 }
82a29e30
PD
734}
735
094a2239
PD
736static void xen_device_frontend_create(XenDevice *xendev, Error **errp)
737{
738 XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
739 struct xs_permissions perms[2];
740 Error *local_err = NULL;
741
742 xendev->frontend_path = xen_device_get_frontend_path(xendev);
743
744 perms[0].id = xendev->frontend_id;
745 perms[0].perms = XS_PERM_NONE;
746 perms[1].id = xenbus->backend_id;
747 perms[1].perms = XS_PERM_READ | XS_PERM_WRITE;
748
749 g_assert(xenbus->xsh);
750
751 xs_node_create(xenbus->xsh, XBT_NULL, xendev->frontend_path, perms,
752 ARRAY_SIZE(perms), &local_err);
753 if (local_err) {
754 error_propagate_prepend(errp, local_err,
755 "failed to create frontend: ");
82a29e30
PD
756 return;
757 }
758
759 xendev->frontend_state_watch =
760 xen_bus_add_watch(xenbus, xendev->frontend_path, "state",
761 xen_device_frontend_changed, xendev, &local_err);
762 if (local_err) {
763 error_propagate_prepend(errp, local_err,
764 "failed to watch frontend state: ");
094a2239
PD
765 }
766}
767
768static void xen_device_frontend_destroy(XenDevice *xendev)
769{
770 XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
771 Error *local_err = NULL;
772
82a29e30
PD
773 if (xendev->frontend_state_watch) {
774 xen_bus_remove_watch(xenbus, xendev->frontend_state_watch, NULL);
775 xendev->frontend_state_watch = NULL;
776 }
777
094a2239
PD
778 if (!xendev->frontend_path) {
779 return;
780 }
781
782 g_assert(xenbus->xsh);
783
784 xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->frontend_path,
785 &local_err);
786 g_free(xendev->frontend_path);
787 xendev->frontend_path = NULL;
788
789 if (local_err) {
790 error_report_err(local_err);
791 }
792}
793
4b34b5b1
PD
794void xen_device_set_max_grant_refs(XenDevice *xendev, unsigned int nr_refs,
795 Error **errp)
796{
797 if (xengnttab_set_max_grants(xendev->xgth, nr_refs)) {
798 error_setg_errno(errp, errno, "xengnttab_set_max_grants failed");
799 }
800}
801
802void *xen_device_map_grant_refs(XenDevice *xendev, uint32_t *refs,
803 unsigned int nr_refs, int prot,
804 Error **errp)
805{
806 void *map = xengnttab_map_domain_grant_refs(xendev->xgth, nr_refs,
807 xendev->frontend_id, refs,
808 prot);
809
810 if (!map) {
811 error_setg_errno(errp, errno,
812 "xengnttab_map_domain_grant_refs failed");
813 }
814
815 return map;
816}
817
818void xen_device_unmap_grant_refs(XenDevice *xendev, void *map,
819 unsigned int nr_refs, Error **errp)
820{
821 if (xengnttab_unmap(xendev->xgth, map, nr_refs)) {
822 error_setg_errno(errp, errno, "xengnttab_unmap failed");
823 }
824}
825
826static void compat_copy_grant_refs(XenDevice *xendev, bool to_domain,
827 XenDeviceGrantCopySegment segs[],
828 unsigned int nr_segs, Error **errp)
829{
830 uint32_t *refs = g_new(uint32_t, nr_segs);
831 int prot = to_domain ? PROT_WRITE : PROT_READ;
832 void *map;
833 unsigned int i;
834
835 for (i = 0; i < nr_segs; i++) {
836 XenDeviceGrantCopySegment *seg = &segs[i];
837
838 refs[i] = to_domain ? seg->dest.foreign.ref :
839 seg->source.foreign.ref;
840 }
841
842 map = xengnttab_map_domain_grant_refs(xendev->xgth, nr_segs,
843 xendev->frontend_id, refs,
844 prot);
845 if (!map) {
846 error_setg_errno(errp, errno,
847 "xengnttab_map_domain_grant_refs failed");
848 goto done;
849 }
850
851 for (i = 0; i < nr_segs; i++) {
852 XenDeviceGrantCopySegment *seg = &segs[i];
853 void *page = map + (i * XC_PAGE_SIZE);
854
855 if (to_domain) {
856 memcpy(page + seg->dest.foreign.offset, seg->source.virt,
857 seg->len);
858 } else {
859 memcpy(seg->dest.virt, page + seg->source.foreign.offset,
860 seg->len);
861 }
862 }
863
864 if (xengnttab_unmap(xendev->xgth, map, nr_segs)) {
865 error_setg_errno(errp, errno, "xengnttab_unmap failed");
866 }
867
868done:
869 g_free(refs);
870}
871
872void xen_device_copy_grant_refs(XenDevice *xendev, bool to_domain,
873 XenDeviceGrantCopySegment segs[],
874 unsigned int nr_segs, Error **errp)
875{
876 xengnttab_grant_copy_segment_t *xengnttab_segs;
877 unsigned int i;
878
879 if (!xendev->feature_grant_copy) {
880 compat_copy_grant_refs(xendev, to_domain, segs, nr_segs, errp);
881 return;
882 }
883
884 xengnttab_segs = g_new0(xengnttab_grant_copy_segment_t, nr_segs);
885
886 for (i = 0; i < nr_segs; i++) {
887 XenDeviceGrantCopySegment *seg = &segs[i];
888 xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i];
889
890 if (to_domain) {
891 xengnttab_seg->flags = GNTCOPY_dest_gref;
892 xengnttab_seg->dest.foreign.domid = xendev->frontend_id;
893 xengnttab_seg->dest.foreign.ref = seg->dest.foreign.ref;
894 xengnttab_seg->dest.foreign.offset = seg->dest.foreign.offset;
895 xengnttab_seg->source.virt = seg->source.virt;
896 } else {
897 xengnttab_seg->flags = GNTCOPY_source_gref;
898 xengnttab_seg->source.foreign.domid = xendev->frontend_id;
899 xengnttab_seg->source.foreign.ref = seg->source.foreign.ref;
900 xengnttab_seg->source.foreign.offset =
901 seg->source.foreign.offset;
902 xengnttab_seg->dest.virt = seg->dest.virt;
903 }
904
905 xengnttab_seg->len = seg->len;
906 }
907
908 if (xengnttab_grant_copy(xendev->xgth, nr_segs, xengnttab_segs)) {
909 error_setg_errno(errp, errno, "xengnttab_grant_copy failed");
910 goto done;
911 }
912
913 for (i = 0; i < nr_segs; i++) {
914 xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i];
915
916 if (xengnttab_seg->status != GNTST_okay) {
917 error_setg(errp, "xengnttab_grant_copy seg[%u] failed", i);
918 break;
919 }
920 }
921
922done:
923 g_free(xengnttab_segs);
924}
925
a3d669c8 926struct XenEventChannel {
c0b336ea 927 QLIST_ENTRY(XenEventChannel) list;
83361a8a 928 AioContext *ctx;
c0b336ea 929 xenevtchn_handle *xeh;
a3d669c8
PD
930 evtchn_port_t local_port;
931 XenEventHandler handler;
932 void *opaque;
a3d669c8
PD
933};
934
345f42b4
PD
935static bool xen_device_poll(void *opaque)
936{
937 XenEventChannel *channel = opaque;
938
939 return channel->handler(channel->opaque);
940}
941
c0b336ea 942static void xen_device_event(void *opaque)
a3d669c8 943{
c0b336ea
PD
944 XenEventChannel *channel = opaque;
945 unsigned long port = xenevtchn_pending(channel->xeh);
a3d669c8
PD
946
947 if (port == channel->local_port) {
345f42b4 948 xen_device_poll(channel);
c0b336ea
PD
949
950 xenevtchn_unmask(channel->xeh, port);
a3d669c8
PD
951 }
952}
953
954XenEventChannel *xen_device_bind_event_channel(XenDevice *xendev,
83361a8a 955 AioContext *ctx,
a3d669c8
PD
956 unsigned int port,
957 XenEventHandler handler,
958 void *opaque, Error **errp)
959{
960 XenEventChannel *channel = g_new0(XenEventChannel, 1);
961 xenevtchn_port_or_error_t local_port;
962
c0b336ea
PD
963 channel->xeh = xenevtchn_open(NULL, 0);
964 if (!channel->xeh) {
965 error_setg_errno(errp, errno, "failed xenevtchn_open");
966 goto fail;
967 }
968
969 local_port = xenevtchn_bind_interdomain(channel->xeh,
a3d669c8
PD
970 xendev->frontend_id,
971 port);
972 if (local_port < 0) {
973 error_setg_errno(errp, errno, "xenevtchn_bind_interdomain failed");
c0b336ea 974 goto fail;
a3d669c8
PD
975 }
976
977 channel->local_port = local_port;
978 channel->handler = handler;
979 channel->opaque = opaque;
a3d669c8 980
83361a8a
PD
981 channel->ctx = ctx;
982 aio_set_fd_handler(channel->ctx, xenevtchn_fd(channel->xeh), true,
345f42b4 983 xen_device_event, NULL, xen_device_poll, channel);
c0b336ea
PD
984
985 QLIST_INSERT_HEAD(&xendev->event_channels, channel, list);
a3d669c8
PD
986
987 return channel;
c0b336ea
PD
988
989fail:
990 if (channel->xeh) {
991 xenevtchn_close(channel->xeh);
992 }
993
994 g_free(channel);
995
996 return NULL;
a3d669c8
PD
997}
998
999void xen_device_notify_event_channel(XenDevice *xendev,
1000 XenEventChannel *channel,
1001 Error **errp)
1002{
1003 if (!channel) {
1004 error_setg(errp, "bad channel");
1005 return;
1006 }
1007
c0b336ea 1008 if (xenevtchn_notify(channel->xeh, channel->local_port) < 0) {
a3d669c8
PD
1009 error_setg_errno(errp, errno, "xenevtchn_notify failed");
1010 }
1011}
1012
1013void xen_device_unbind_event_channel(XenDevice *xendev,
1014 XenEventChannel *channel,
1015 Error **errp)
1016{
1017 if (!channel) {
1018 error_setg(errp, "bad channel");
1019 return;
1020 }
1021
c0b336ea 1022 QLIST_REMOVE(channel, list);
a3d669c8 1023
83361a8a
PD
1024 aio_set_fd_handler(channel->ctx, xenevtchn_fd(channel->xeh), true,
1025 NULL, NULL, NULL, NULL);
c0b336ea
PD
1026
1027 if (xenevtchn_unbind(channel->xeh, channel->local_port) < 0) {
a3d669c8
PD
1028 error_setg_errno(errp, errno, "xenevtchn_unbind failed");
1029 }
1030
c0b336ea 1031 xenevtchn_close(channel->xeh);
a3d669c8
PD
1032 g_free(channel);
1033}
1034
108f7bba
PD
1035static void xen_device_unrealize(DeviceState *dev, Error **errp)
1036{
1037 XenDevice *xendev = XEN_DEVICE(dev);
1038 XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
1039 const char *type = object_get_typename(OBJECT(xendev));
c0b336ea 1040 XenEventChannel *channel, *next;
108f7bba 1041
094a2239
PD
1042 if (!xendev->name) {
1043 return;
1044 }
1045
1046 trace_xen_device_unrealize(type, xendev->name);
1047
1048 if (xendev->exit.notify) {
1049 qemu_remove_exit_notifier(&xendev->exit);
1050 xendev->exit.notify = NULL;
1051 }
108f7bba
PD
1052
1053 if (xendev_class->unrealize) {
1054 xendev_class->unrealize(xendev, errp);
1055 }
094a2239 1056
c0b336ea
PD
1057 /* Make sure all event channels are cleaned up */
1058 QLIST_FOREACH_SAFE(channel, &xendev->event_channels, list, next) {
1059 xen_device_unbind_event_channel(xendev, channel, NULL);
1060 }
1061
094a2239
PD
1062 xen_device_frontend_destroy(xendev);
1063 xen_device_backend_destroy(xendev);
1064
4b34b5b1
PD
1065 if (xendev->xgth) {
1066 xengnttab_close(xendev->xgth);
1067 xendev->xgth = NULL;
1068 }
1069
094a2239
PD
1070 g_free(xendev->name);
1071 xendev->name = NULL;
1072}
1073
1074static void xen_device_exit(Notifier *n, void *data)
1075{
1076 XenDevice *xendev = container_of(n, XenDevice, exit);
1077
1078 xen_device_unrealize(DEVICE(xendev), &error_abort);
108f7bba
PD
1079}
1080
1081static void xen_device_realize(DeviceState *dev, Error **errp)
1082{
1083 XenDevice *xendev = XEN_DEVICE(dev);
1084 XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
094a2239 1085 XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
108f7bba
PD
1086 const char *type = object_get_typename(OBJECT(xendev));
1087 Error *local_err = NULL;
1088
094a2239
PD
1089 if (xendev->frontend_id == DOMID_INVALID) {
1090 xendev->frontend_id = xen_domid;
1091 }
1092
1093 if (xendev->frontend_id >= DOMID_FIRST_RESERVED) {
1094 error_setg(errp, "invalid frontend-id");
1095 goto unrealize;
1096 }
1097
1098 if (!xendev_class->get_name) {
1099 error_setg(errp, "get_name method not implemented");
1100 goto unrealize;
1101 }
1102
1103 xendev->name = xendev_class->get_name(xendev, &local_err);
1104 if (local_err) {
1105 error_propagate_prepend(errp, local_err,
1106 "failed to get device name: ");
1107 goto unrealize;
1108 }
1109
1110 trace_xen_device_realize(type, xendev->name);
1111
4b34b5b1
PD
1112 xendev->xgth = xengnttab_open(NULL, 0);
1113 if (!xendev->xgth) {
1114 error_setg_errno(errp, errno, "failed xengnttab_open");
1115 goto unrealize;
1116 }
1117
1118 xendev->feature_grant_copy =
1119 (xengnttab_grant_copy(xendev->xgth, 0, NULL) == 0);
1120
094a2239
PD
1121 xen_device_backend_create(xendev, &local_err);
1122 if (local_err) {
1123 error_propagate(errp, local_err);
1124 goto unrealize;
1125 }
1126
1127 xen_device_frontend_create(xendev, &local_err);
1128 if (local_err) {
1129 error_propagate(errp, local_err);
1130 goto unrealize;
1131 }
108f7bba
PD
1132
1133 if (xendev_class->realize) {
1134 xendev_class->realize(xendev, &local_err);
1135 if (local_err) {
1136 error_propagate(errp, local_err);
1137 goto unrealize;
1138 }
1139 }
1140
094a2239
PD
1141 xen_device_backend_printf(xendev, "frontend", "%s",
1142 xendev->frontend_path);
1143 xen_device_backend_printf(xendev, "frontend-id", "%u",
1144 xendev->frontend_id);
094a2239
PD
1145 xen_device_backend_printf(xendev, "hotplug-status", "connected");
1146
b6af8926 1147 xen_device_backend_set_online(xendev, true);
094a2239
PD
1148 xen_device_backend_set_state(xendev, XenbusStateInitWait);
1149
1150 xen_device_frontend_printf(xendev, "backend", "%s",
1151 xendev->backend_path);
1152 xen_device_frontend_printf(xendev, "backend-id", "%u",
1153 xenbus->backend_id);
1154
1155 xen_device_frontend_set_state(xendev, XenbusStateInitialising);
1156
1157 xendev->exit.notify = xen_device_exit;
1158 qemu_add_exit_notifier(&xendev->exit);
108f7bba
PD
1159 return;
1160
1161unrealize:
1162 xen_device_unrealize(dev, &error_abort);
1163}
1164
094a2239
PD
1165static Property xen_device_props[] = {
1166 DEFINE_PROP_UINT16("frontend-id", XenDevice, frontend_id,
1167 DOMID_INVALID),
1168 DEFINE_PROP_END_OF_LIST()
1169};
1170
108f7bba
PD
1171static void xen_device_class_init(ObjectClass *class, void *data)
1172{
1173 DeviceClass *dev_class = DEVICE_CLASS(class);
1174
1175 dev_class->realize = xen_device_realize;
1176 dev_class->unrealize = xen_device_unrealize;
094a2239 1177 dev_class->props = xen_device_props;
108f7bba
PD
1178 dev_class->bus_type = TYPE_XEN_BUS;
1179}
1180
1181static const TypeInfo xen_device_type_info = {
1182 .name = TYPE_XEN_DEVICE,
1183 .parent = TYPE_DEVICE,
1184 .instance_size = sizeof(XenDevice),
1185 .abstract = true,
1186 .class_size = sizeof(XenDeviceClass),
1187 .class_init = xen_device_class_init,
1188};
1189
1190typedef struct XenBridge {
1191 SysBusDevice busdev;
1192} XenBridge;
1193
1194#define TYPE_XEN_BRIDGE "xen-bridge"
1195
1196static const TypeInfo xen_bridge_type_info = {
1197 .name = TYPE_XEN_BRIDGE,
1198 .parent = TYPE_SYS_BUS_DEVICE,
1199 .instance_size = sizeof(XenBridge),
1200};
1201
1202static void xen_register_types(void)
1203{
1204 type_register_static(&xen_bridge_type_info);
1205 type_register_static(&xen_bus_type_info);
1206 type_register_static(&xen_device_type_info);
1207}
1208
1209type_init(xen_register_types)
1210
1211void xen_bus_init(void)
1212{
1213 DeviceState *dev = qdev_create(NULL, TYPE_XEN_BRIDGE);
1214 BusState *bus = qbus_create(TYPE_XEN_BUS, dev, NULL);
1215
1216 qdev_init_nofail(dev);
1217 qbus_set_bus_hotplug_handler(bus, &error_abort);
1218}