1108f7bbaSPaul Durrant /* 2108f7bbaSPaul Durrant * Copyright (c) 2018 Citrix Systems Inc. 3108f7bbaSPaul Durrant * 4108f7bbaSPaul Durrant * This work is licensed under the terms of the GNU GPL, version 2 or later. 5108f7bbaSPaul Durrant * See the COPYING file in the top-level directory. 6108f7bbaSPaul Durrant */ 7108f7bbaSPaul Durrant 8108f7bbaSPaul Durrant #include "qemu/osdep.h" 982a29e30SPaul Durrant #include "qemu/main-loop.h" 1082a29e30SPaul Durrant #include "qemu/uuid.h" 11108f7bbaSPaul Durrant #include "hw/hw.h" 12108f7bbaSPaul Durrant #include "hw/sysbus.h" 13094a2239SPaul Durrant #include "hw/xen/xen.h" 14108f7bbaSPaul Durrant #include "hw/xen/xen-bus.h" 15094a2239SPaul Durrant #include "hw/xen/xen-bus-helper.h" 16094a2239SPaul Durrant #include "monitor/monitor.h" 17108f7bbaSPaul Durrant #include "qapi/error.h" 18094a2239SPaul Durrant #include "sysemu/sysemu.h" 19108f7bbaSPaul Durrant #include "trace.h" 20108f7bbaSPaul Durrant 21094a2239SPaul Durrant static char *xen_device_get_backend_path(XenDevice *xendev) 22094a2239SPaul Durrant { 23094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 24094a2239SPaul Durrant XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); 25094a2239SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 26094a2239SPaul Durrant const char *backend = xendev_class->backend; 27094a2239SPaul Durrant 28094a2239SPaul Durrant if (!backend) { 29094a2239SPaul Durrant backend = type; 30094a2239SPaul Durrant } 31094a2239SPaul Durrant 32094a2239SPaul Durrant return g_strdup_printf("/local/domain/%u/backend/%s/%u/%s", 33094a2239SPaul Durrant xenbus->backend_id, backend, xendev->frontend_id, 34094a2239SPaul Durrant xendev->name); 35094a2239SPaul Durrant } 36094a2239SPaul Durrant 37094a2239SPaul Durrant static char *xen_device_get_frontend_path(XenDevice *xendev) 38094a2239SPaul Durrant { 39094a2239SPaul Durrant XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); 40094a2239SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 41094a2239SPaul Durrant const char *device = xendev_class->device; 42094a2239SPaul Durrant 43094a2239SPaul Durrant if (!device) { 44094a2239SPaul Durrant device = type; 45094a2239SPaul Durrant } 46094a2239SPaul Durrant 47094a2239SPaul Durrant return g_strdup_printf("/local/domain/%u/device/%s/%s", 48094a2239SPaul Durrant xendev->frontend_id, device, xendev->name); 49094a2239SPaul Durrant } 50094a2239SPaul Durrant 51094a2239SPaul Durrant static void xen_bus_print_dev(Monitor *mon, DeviceState *dev, int indent) 52094a2239SPaul Durrant { 53094a2239SPaul Durrant XenDevice *xendev = XEN_DEVICE(dev); 54094a2239SPaul Durrant 55094a2239SPaul Durrant monitor_printf(mon, "%*sname = '%s' frontend_id = %u\n", 56094a2239SPaul Durrant indent, "", xendev->name, xendev->frontend_id); 57094a2239SPaul Durrant } 58094a2239SPaul Durrant 59094a2239SPaul Durrant static char *xen_bus_get_dev_path(DeviceState *dev) 60094a2239SPaul Durrant { 61094a2239SPaul Durrant return xen_device_get_backend_path(XEN_DEVICE(dev)); 62094a2239SPaul Durrant } 63094a2239SPaul Durrant 6482a29e30SPaul Durrant struct XenWatch { 6582a29e30SPaul Durrant char *node, *key; 6682a29e30SPaul Durrant char *token; 6782a29e30SPaul Durrant XenWatchHandler handler; 6882a29e30SPaul Durrant void *opaque; 6982a29e30SPaul Durrant Notifier notifier; 7082a29e30SPaul Durrant }; 7182a29e30SPaul Durrant 7282a29e30SPaul Durrant static void watch_notify(Notifier *n, void *data) 7382a29e30SPaul Durrant { 7482a29e30SPaul Durrant XenWatch *watch = container_of(n, XenWatch, notifier); 7582a29e30SPaul Durrant const char *token = data; 7682a29e30SPaul Durrant 7782a29e30SPaul Durrant if (!strcmp(watch->token, token)) { 7882a29e30SPaul Durrant watch->handler(watch->opaque); 7982a29e30SPaul Durrant } 8082a29e30SPaul Durrant } 8182a29e30SPaul Durrant 8282a29e30SPaul Durrant static XenWatch *new_watch(const char *node, const char *key, 8382a29e30SPaul Durrant XenWatchHandler handler, void *opaque) 8482a29e30SPaul Durrant { 8582a29e30SPaul Durrant XenWatch *watch = g_new0(XenWatch, 1); 8682a29e30SPaul Durrant QemuUUID uuid; 8782a29e30SPaul Durrant 8882a29e30SPaul Durrant qemu_uuid_generate(&uuid); 8982a29e30SPaul Durrant 9082a29e30SPaul Durrant watch->token = qemu_uuid_unparse_strdup(&uuid); 9182a29e30SPaul Durrant watch->node = g_strdup(node); 9282a29e30SPaul Durrant watch->key = g_strdup(key); 9382a29e30SPaul Durrant watch->handler = handler; 9482a29e30SPaul Durrant watch->opaque = opaque; 9582a29e30SPaul Durrant watch->notifier.notify = watch_notify; 9682a29e30SPaul Durrant 9782a29e30SPaul Durrant return watch; 9882a29e30SPaul Durrant } 9982a29e30SPaul Durrant 10082a29e30SPaul Durrant static void free_watch(XenWatch *watch) 10182a29e30SPaul Durrant { 10282a29e30SPaul Durrant g_free(watch->token); 10382a29e30SPaul Durrant g_free(watch->key); 10482a29e30SPaul Durrant g_free(watch->node); 10582a29e30SPaul Durrant 10682a29e30SPaul Durrant g_free(watch); 10782a29e30SPaul Durrant } 10882a29e30SPaul Durrant 10982a29e30SPaul Durrant static XenWatch *xen_bus_add_watch(XenBus *xenbus, const char *node, 11082a29e30SPaul Durrant const char *key, XenWatchHandler handler, 11182a29e30SPaul Durrant void *opaque, Error **errp) 11282a29e30SPaul Durrant { 11382a29e30SPaul Durrant XenWatch *watch = new_watch(node, key, handler, opaque); 11482a29e30SPaul Durrant Error *local_err = NULL; 11582a29e30SPaul Durrant 11682a29e30SPaul Durrant trace_xen_bus_add_watch(watch->node, watch->key, watch->token); 11782a29e30SPaul Durrant 11882a29e30SPaul Durrant notifier_list_add(&xenbus->watch_notifiers, &watch->notifier); 11982a29e30SPaul Durrant 12082a29e30SPaul Durrant xs_node_watch(xenbus->xsh, node, key, watch->token, &local_err); 12182a29e30SPaul Durrant if (local_err) { 12282a29e30SPaul Durrant error_propagate(errp, local_err); 12382a29e30SPaul Durrant 12482a29e30SPaul Durrant notifier_remove(&watch->notifier); 12582a29e30SPaul Durrant free_watch(watch); 12682a29e30SPaul Durrant 12782a29e30SPaul Durrant return NULL; 12882a29e30SPaul Durrant } 12982a29e30SPaul Durrant 13082a29e30SPaul Durrant return watch; 13182a29e30SPaul Durrant } 13282a29e30SPaul Durrant 13382a29e30SPaul Durrant static void xen_bus_remove_watch(XenBus *xenbus, XenWatch *watch, 13482a29e30SPaul Durrant Error **errp) 13582a29e30SPaul Durrant { 13682a29e30SPaul Durrant trace_xen_bus_remove_watch(watch->node, watch->key, watch->token); 13782a29e30SPaul Durrant 13882a29e30SPaul Durrant xs_node_unwatch(xenbus->xsh, watch->node, watch->key, watch->token, 13982a29e30SPaul Durrant errp); 14082a29e30SPaul Durrant 14182a29e30SPaul Durrant notifier_remove(&watch->notifier); 14282a29e30SPaul Durrant free_watch(watch); 14382a29e30SPaul Durrant } 14482a29e30SPaul Durrant 145108f7bbaSPaul Durrant static void xen_bus_unrealize(BusState *bus, Error **errp) 146108f7bbaSPaul Durrant { 147094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(bus); 148094a2239SPaul Durrant 149108f7bbaSPaul Durrant trace_xen_bus_unrealize(); 150094a2239SPaul Durrant 151094a2239SPaul Durrant if (!xenbus->xsh) { 152094a2239SPaul Durrant return; 153094a2239SPaul Durrant } 154094a2239SPaul Durrant 15582a29e30SPaul Durrant qemu_set_fd_handler(xs_fileno(xenbus->xsh), NULL, NULL, NULL); 15682a29e30SPaul Durrant 157094a2239SPaul Durrant xs_close(xenbus->xsh); 158108f7bbaSPaul Durrant } 159108f7bbaSPaul Durrant 16082a29e30SPaul Durrant static void xen_bus_watch(void *opaque) 16182a29e30SPaul Durrant { 16282a29e30SPaul Durrant XenBus *xenbus = opaque; 16382a29e30SPaul Durrant char **v; 16482a29e30SPaul Durrant const char *token; 16582a29e30SPaul Durrant 16682a29e30SPaul Durrant g_assert(xenbus->xsh); 16782a29e30SPaul Durrant 16882a29e30SPaul Durrant v = xs_check_watch(xenbus->xsh); 16982a29e30SPaul Durrant if (!v) { 17082a29e30SPaul Durrant return; 17182a29e30SPaul Durrant } 17282a29e30SPaul Durrant 17382a29e30SPaul Durrant token = v[XS_WATCH_TOKEN]; 17482a29e30SPaul Durrant 17582a29e30SPaul Durrant trace_xen_bus_watch(token); 17682a29e30SPaul Durrant 17782a29e30SPaul Durrant notifier_list_notify(&xenbus->watch_notifiers, (void *)token); 17882a29e30SPaul Durrant 17982a29e30SPaul Durrant free(v); 18082a29e30SPaul Durrant } 18182a29e30SPaul Durrant 182108f7bbaSPaul Durrant static void xen_bus_realize(BusState *bus, Error **errp) 183108f7bbaSPaul Durrant { 184094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(bus); 185094a2239SPaul Durrant unsigned int domid; 186094a2239SPaul Durrant 187108f7bbaSPaul Durrant trace_xen_bus_realize(); 188094a2239SPaul Durrant 189094a2239SPaul Durrant xenbus->xsh = xs_open(0); 190094a2239SPaul Durrant if (!xenbus->xsh) { 191094a2239SPaul Durrant error_setg_errno(errp, errno, "failed xs_open"); 192094a2239SPaul Durrant goto fail; 193094a2239SPaul Durrant } 194094a2239SPaul Durrant 195094a2239SPaul Durrant if (xs_node_scanf(xenbus->xsh, XBT_NULL, "", /* domain root node */ 196094a2239SPaul Durrant "domid", NULL, "%u", &domid) == 1) { 197094a2239SPaul Durrant xenbus->backend_id = domid; 198094a2239SPaul Durrant } else { 199094a2239SPaul Durrant xenbus->backend_id = 0; /* Assume lack of node means dom0 */ 200094a2239SPaul Durrant } 201094a2239SPaul Durrant 20282a29e30SPaul Durrant notifier_list_init(&xenbus->watch_notifiers); 20382a29e30SPaul Durrant qemu_set_fd_handler(xs_fileno(xenbus->xsh), xen_bus_watch, NULL, 20482a29e30SPaul Durrant xenbus); 205094a2239SPaul Durrant return; 206094a2239SPaul Durrant 207094a2239SPaul Durrant fail: 208094a2239SPaul Durrant xen_bus_unrealize(bus, &error_abort); 209108f7bbaSPaul Durrant } 210108f7bbaSPaul Durrant 211108f7bbaSPaul Durrant static void xen_bus_class_init(ObjectClass *class, void *data) 212108f7bbaSPaul Durrant { 213108f7bbaSPaul Durrant BusClass *bus_class = BUS_CLASS(class); 214108f7bbaSPaul Durrant 215094a2239SPaul Durrant bus_class->print_dev = xen_bus_print_dev; 216094a2239SPaul Durrant bus_class->get_dev_path = xen_bus_get_dev_path; 217108f7bbaSPaul Durrant bus_class->realize = xen_bus_realize; 218108f7bbaSPaul Durrant bus_class->unrealize = xen_bus_unrealize; 219108f7bbaSPaul Durrant } 220108f7bbaSPaul Durrant 221108f7bbaSPaul Durrant static const TypeInfo xen_bus_type_info = { 222108f7bbaSPaul Durrant .name = TYPE_XEN_BUS, 223108f7bbaSPaul Durrant .parent = TYPE_BUS, 224108f7bbaSPaul Durrant .instance_size = sizeof(XenBus), 225108f7bbaSPaul Durrant .class_size = sizeof(XenBusClass), 226108f7bbaSPaul Durrant .class_init = xen_bus_class_init, 227108f7bbaSPaul Durrant .interfaces = (InterfaceInfo[]) { 228108f7bbaSPaul Durrant { TYPE_HOTPLUG_HANDLER }, 229108f7bbaSPaul Durrant { } 230108f7bbaSPaul Durrant }, 231108f7bbaSPaul Durrant }; 232108f7bbaSPaul Durrant 233094a2239SPaul Durrant static void xen_device_backend_printf(XenDevice *xendev, const char *key, 234094a2239SPaul Durrant const char *fmt, ...) 235094a2239SPaul Durrant { 236094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 237094a2239SPaul Durrant Error *local_err = NULL; 238094a2239SPaul Durrant va_list ap; 239094a2239SPaul Durrant 240094a2239SPaul Durrant g_assert(xenbus->xsh); 241094a2239SPaul Durrant 242094a2239SPaul Durrant va_start(ap, fmt); 243094a2239SPaul Durrant xs_node_vprintf(xenbus->xsh, XBT_NULL, xendev->backend_path, key, 244094a2239SPaul Durrant &local_err, fmt, ap); 245094a2239SPaul Durrant va_end(ap); 246094a2239SPaul Durrant 247094a2239SPaul Durrant if (local_err) { 248094a2239SPaul Durrant error_report_err(local_err); 249094a2239SPaul Durrant } 250094a2239SPaul Durrant } 251094a2239SPaul Durrant 25282a29e30SPaul Durrant static int xen_device_backend_scanf(XenDevice *xendev, const char *key, 25382a29e30SPaul Durrant const char *fmt, ...) 25482a29e30SPaul Durrant { 25582a29e30SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 25682a29e30SPaul Durrant va_list ap; 25782a29e30SPaul Durrant int rc; 25882a29e30SPaul Durrant 25982a29e30SPaul Durrant g_assert(xenbus->xsh); 26082a29e30SPaul Durrant 26182a29e30SPaul Durrant va_start(ap, fmt); 26282a29e30SPaul Durrant rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->backend_path, key, 26382a29e30SPaul Durrant NULL, fmt, ap); 26482a29e30SPaul Durrant va_end(ap); 26582a29e30SPaul Durrant 26682a29e30SPaul Durrant return rc; 26782a29e30SPaul Durrant } 26882a29e30SPaul Durrant 26982a29e30SPaul Durrant void xen_device_backend_set_state(XenDevice *xendev, 270094a2239SPaul Durrant enum xenbus_state state) 271094a2239SPaul Durrant { 272094a2239SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 273094a2239SPaul Durrant 274094a2239SPaul Durrant if (xendev->backend_state == state) { 275094a2239SPaul Durrant return; 276094a2239SPaul Durrant } 277094a2239SPaul Durrant 278094a2239SPaul Durrant trace_xen_device_backend_state(type, xendev->name, 279094a2239SPaul Durrant xs_strstate(state)); 280094a2239SPaul Durrant 281094a2239SPaul Durrant xendev->backend_state = state; 282094a2239SPaul Durrant xen_device_backend_printf(xendev, "state", "%u", state); 283094a2239SPaul Durrant } 284094a2239SPaul Durrant 28582a29e30SPaul Durrant enum xenbus_state xen_device_backend_get_state(XenDevice *xendev) 28682a29e30SPaul Durrant { 28782a29e30SPaul Durrant return xendev->backend_state; 28882a29e30SPaul Durrant } 28982a29e30SPaul Durrant 290094a2239SPaul Durrant static void xen_device_backend_create(XenDevice *xendev, Error **errp) 291094a2239SPaul Durrant { 292094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 293094a2239SPaul Durrant struct xs_permissions perms[2]; 294094a2239SPaul Durrant Error *local_err = NULL; 295094a2239SPaul Durrant 296094a2239SPaul Durrant xendev->backend_path = xen_device_get_backend_path(xendev); 297094a2239SPaul Durrant 298094a2239SPaul Durrant perms[0].id = xenbus->backend_id; 299094a2239SPaul Durrant perms[0].perms = XS_PERM_NONE; 300094a2239SPaul Durrant perms[1].id = xendev->frontend_id; 301094a2239SPaul Durrant perms[1].perms = XS_PERM_READ; 302094a2239SPaul Durrant 303094a2239SPaul Durrant g_assert(xenbus->xsh); 304094a2239SPaul Durrant 305094a2239SPaul Durrant xs_node_create(xenbus->xsh, XBT_NULL, xendev->backend_path, perms, 306094a2239SPaul Durrant ARRAY_SIZE(perms), &local_err); 307094a2239SPaul Durrant if (local_err) { 308094a2239SPaul Durrant error_propagate_prepend(errp, local_err, 309094a2239SPaul Durrant "failed to create backend: "); 310094a2239SPaul Durrant } 311094a2239SPaul Durrant } 312094a2239SPaul Durrant 313094a2239SPaul Durrant static void xen_device_backend_destroy(XenDevice *xendev) 314094a2239SPaul Durrant { 315094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 316094a2239SPaul Durrant Error *local_err = NULL; 317094a2239SPaul Durrant 318094a2239SPaul Durrant if (!xendev->backend_path) { 319094a2239SPaul Durrant return; 320094a2239SPaul Durrant } 321094a2239SPaul Durrant 322094a2239SPaul Durrant g_assert(xenbus->xsh); 323094a2239SPaul Durrant 324094a2239SPaul Durrant xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->backend_path, 325094a2239SPaul Durrant &local_err); 326094a2239SPaul Durrant g_free(xendev->backend_path); 327094a2239SPaul Durrant xendev->backend_path = NULL; 328094a2239SPaul Durrant 329094a2239SPaul Durrant if (local_err) { 330094a2239SPaul Durrant error_report_err(local_err); 331094a2239SPaul Durrant } 332094a2239SPaul Durrant } 333094a2239SPaul Durrant 334094a2239SPaul Durrant static void xen_device_frontend_printf(XenDevice *xendev, const char *key, 335094a2239SPaul Durrant const char *fmt, ...) 336094a2239SPaul Durrant { 337094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 338094a2239SPaul Durrant Error *local_err = NULL; 339094a2239SPaul Durrant va_list ap; 340094a2239SPaul Durrant 341094a2239SPaul Durrant g_assert(xenbus->xsh); 342094a2239SPaul Durrant 343094a2239SPaul Durrant va_start(ap, fmt); 344094a2239SPaul Durrant xs_node_vprintf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key, 345094a2239SPaul Durrant &local_err, fmt, ap); 346094a2239SPaul Durrant va_end(ap); 347094a2239SPaul Durrant 348094a2239SPaul Durrant if (local_err) { 349094a2239SPaul Durrant error_report_err(local_err); 350094a2239SPaul Durrant } 351094a2239SPaul Durrant } 352094a2239SPaul Durrant 35382a29e30SPaul Durrant static int xen_device_frontend_scanf(XenDevice *xendev, const char *key, 35482a29e30SPaul Durrant const char *fmt, ...) 35582a29e30SPaul Durrant { 35682a29e30SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 35782a29e30SPaul Durrant va_list ap; 35882a29e30SPaul Durrant int rc; 35982a29e30SPaul Durrant 36082a29e30SPaul Durrant g_assert(xenbus->xsh); 36182a29e30SPaul Durrant 36282a29e30SPaul Durrant va_start(ap, fmt); 36382a29e30SPaul Durrant rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key, 36482a29e30SPaul Durrant NULL, fmt, ap); 36582a29e30SPaul Durrant va_end(ap); 36682a29e30SPaul Durrant 36782a29e30SPaul Durrant return rc; 36882a29e30SPaul Durrant } 36982a29e30SPaul Durrant 370094a2239SPaul Durrant static void xen_device_frontend_set_state(XenDevice *xendev, 371094a2239SPaul Durrant enum xenbus_state state) 372094a2239SPaul Durrant { 373094a2239SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 374094a2239SPaul Durrant 375094a2239SPaul Durrant if (xendev->frontend_state == state) { 376094a2239SPaul Durrant return; 377094a2239SPaul Durrant } 378094a2239SPaul Durrant 379094a2239SPaul Durrant trace_xen_device_frontend_state(type, xendev->name, 380094a2239SPaul Durrant xs_strstate(state)); 381094a2239SPaul Durrant 382094a2239SPaul Durrant xendev->frontend_state = state; 383094a2239SPaul Durrant xen_device_frontend_printf(xendev, "state", "%u", state); 384094a2239SPaul Durrant } 385094a2239SPaul Durrant 38682a29e30SPaul Durrant static void xen_device_frontend_changed(void *opaque) 38782a29e30SPaul Durrant { 38882a29e30SPaul Durrant XenDevice *xendev = opaque; 38982a29e30SPaul Durrant XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); 39082a29e30SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 39182a29e30SPaul Durrant enum xenbus_state state; 39282a29e30SPaul Durrant 39382a29e30SPaul Durrant trace_xen_device_frontend_changed(type, xendev->name); 39482a29e30SPaul Durrant 39582a29e30SPaul Durrant if (xen_device_frontend_scanf(xendev, "state", "%u", &state) != 1) { 39682a29e30SPaul Durrant state = XenbusStateUnknown; 39782a29e30SPaul Durrant } 39882a29e30SPaul Durrant 39982a29e30SPaul Durrant xen_device_frontend_set_state(xendev, state); 40082a29e30SPaul Durrant 40182a29e30SPaul Durrant if (xendev_class->frontend_changed) { 40282a29e30SPaul Durrant Error *local_err = NULL; 40382a29e30SPaul Durrant 40482a29e30SPaul Durrant xendev_class->frontend_changed(xendev, state, &local_err); 40582a29e30SPaul Durrant 40682a29e30SPaul Durrant if (local_err) { 40782a29e30SPaul Durrant error_reportf_err(local_err, "frontend change error: "); 40882a29e30SPaul Durrant } 40982a29e30SPaul Durrant } 41082a29e30SPaul Durrant 41182a29e30SPaul Durrant /* 41282a29e30SPaul Durrant * If a backend is still 'online' then its state should be cycled 41382a29e30SPaul Durrant * back round to InitWait in order for a new frontend instance to 41482a29e30SPaul Durrant * connect. This may happen when, for example, a frontend driver is 41582a29e30SPaul Durrant * re-installed or updated. 41682a29e30SPaul Durrant */ 41782a29e30SPaul Durrant if (xendev->backend_state == XenbusStateClosed) { 41882a29e30SPaul Durrant unsigned int online; 41982a29e30SPaul Durrant 42082a29e30SPaul Durrant if (xen_device_backend_scanf(xendev, "online", "%u", &online) != 1) { 42182a29e30SPaul Durrant online = 0; 42282a29e30SPaul Durrant } 42382a29e30SPaul Durrant 42482a29e30SPaul Durrant if (online) { 42582a29e30SPaul Durrant xen_device_backend_set_state(xendev, XenbusStateInitWait); 42682a29e30SPaul Durrant } 42782a29e30SPaul Durrant } 42882a29e30SPaul Durrant } 42982a29e30SPaul Durrant 430094a2239SPaul Durrant static void xen_device_frontend_create(XenDevice *xendev, Error **errp) 431094a2239SPaul Durrant { 432094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 433094a2239SPaul Durrant struct xs_permissions perms[2]; 434094a2239SPaul Durrant Error *local_err = NULL; 435094a2239SPaul Durrant 436094a2239SPaul Durrant xendev->frontend_path = xen_device_get_frontend_path(xendev); 437094a2239SPaul Durrant 438094a2239SPaul Durrant perms[0].id = xendev->frontend_id; 439094a2239SPaul Durrant perms[0].perms = XS_PERM_NONE; 440094a2239SPaul Durrant perms[1].id = xenbus->backend_id; 441094a2239SPaul Durrant perms[1].perms = XS_PERM_READ | XS_PERM_WRITE; 442094a2239SPaul Durrant 443094a2239SPaul Durrant g_assert(xenbus->xsh); 444094a2239SPaul Durrant 445094a2239SPaul Durrant xs_node_create(xenbus->xsh, XBT_NULL, xendev->frontend_path, perms, 446094a2239SPaul Durrant ARRAY_SIZE(perms), &local_err); 447094a2239SPaul Durrant if (local_err) { 448094a2239SPaul Durrant error_propagate_prepend(errp, local_err, 449094a2239SPaul Durrant "failed to create frontend: "); 45082a29e30SPaul Durrant return; 45182a29e30SPaul Durrant } 45282a29e30SPaul Durrant 45382a29e30SPaul Durrant xendev->frontend_state_watch = 45482a29e30SPaul Durrant xen_bus_add_watch(xenbus, xendev->frontend_path, "state", 45582a29e30SPaul Durrant xen_device_frontend_changed, xendev, &local_err); 45682a29e30SPaul Durrant if (local_err) { 45782a29e30SPaul Durrant error_propagate_prepend(errp, local_err, 45882a29e30SPaul Durrant "failed to watch frontend state: "); 459094a2239SPaul Durrant } 460094a2239SPaul Durrant } 461094a2239SPaul Durrant 462094a2239SPaul Durrant static void xen_device_frontend_destroy(XenDevice *xendev) 463094a2239SPaul Durrant { 464094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 465094a2239SPaul Durrant Error *local_err = NULL; 466094a2239SPaul Durrant 46782a29e30SPaul Durrant if (xendev->frontend_state_watch) { 46882a29e30SPaul Durrant xen_bus_remove_watch(xenbus, xendev->frontend_state_watch, NULL); 46982a29e30SPaul Durrant xendev->frontend_state_watch = NULL; 47082a29e30SPaul Durrant } 47182a29e30SPaul Durrant 472094a2239SPaul Durrant if (!xendev->frontend_path) { 473094a2239SPaul Durrant return; 474094a2239SPaul Durrant } 475094a2239SPaul Durrant 476094a2239SPaul Durrant g_assert(xenbus->xsh); 477094a2239SPaul Durrant 478094a2239SPaul Durrant xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->frontend_path, 479094a2239SPaul Durrant &local_err); 480094a2239SPaul Durrant g_free(xendev->frontend_path); 481094a2239SPaul Durrant xendev->frontend_path = NULL; 482094a2239SPaul Durrant 483094a2239SPaul Durrant if (local_err) { 484094a2239SPaul Durrant error_report_err(local_err); 485094a2239SPaul Durrant } 486094a2239SPaul Durrant } 487094a2239SPaul Durrant 488*4b34b5b1SPaul Durrant void xen_device_set_max_grant_refs(XenDevice *xendev, unsigned int nr_refs, 489*4b34b5b1SPaul Durrant Error **errp) 490*4b34b5b1SPaul Durrant { 491*4b34b5b1SPaul Durrant if (xengnttab_set_max_grants(xendev->xgth, nr_refs)) { 492*4b34b5b1SPaul Durrant error_setg_errno(errp, errno, "xengnttab_set_max_grants failed"); 493*4b34b5b1SPaul Durrant } 494*4b34b5b1SPaul Durrant } 495*4b34b5b1SPaul Durrant 496*4b34b5b1SPaul Durrant void *xen_device_map_grant_refs(XenDevice *xendev, uint32_t *refs, 497*4b34b5b1SPaul Durrant unsigned int nr_refs, int prot, 498*4b34b5b1SPaul Durrant Error **errp) 499*4b34b5b1SPaul Durrant { 500*4b34b5b1SPaul Durrant void *map = xengnttab_map_domain_grant_refs(xendev->xgth, nr_refs, 501*4b34b5b1SPaul Durrant xendev->frontend_id, refs, 502*4b34b5b1SPaul Durrant prot); 503*4b34b5b1SPaul Durrant 504*4b34b5b1SPaul Durrant if (!map) { 505*4b34b5b1SPaul Durrant error_setg_errno(errp, errno, 506*4b34b5b1SPaul Durrant "xengnttab_map_domain_grant_refs failed"); 507*4b34b5b1SPaul Durrant } 508*4b34b5b1SPaul Durrant 509*4b34b5b1SPaul Durrant return map; 510*4b34b5b1SPaul Durrant } 511*4b34b5b1SPaul Durrant 512*4b34b5b1SPaul Durrant void xen_device_unmap_grant_refs(XenDevice *xendev, void *map, 513*4b34b5b1SPaul Durrant unsigned int nr_refs, Error **errp) 514*4b34b5b1SPaul Durrant { 515*4b34b5b1SPaul Durrant if (xengnttab_unmap(xendev->xgth, map, nr_refs)) { 516*4b34b5b1SPaul Durrant error_setg_errno(errp, errno, "xengnttab_unmap failed"); 517*4b34b5b1SPaul Durrant } 518*4b34b5b1SPaul Durrant } 519*4b34b5b1SPaul Durrant 520*4b34b5b1SPaul Durrant static void compat_copy_grant_refs(XenDevice *xendev, bool to_domain, 521*4b34b5b1SPaul Durrant XenDeviceGrantCopySegment segs[], 522*4b34b5b1SPaul Durrant unsigned int nr_segs, Error **errp) 523*4b34b5b1SPaul Durrant { 524*4b34b5b1SPaul Durrant uint32_t *refs = g_new(uint32_t, nr_segs); 525*4b34b5b1SPaul Durrant int prot = to_domain ? PROT_WRITE : PROT_READ; 526*4b34b5b1SPaul Durrant void *map; 527*4b34b5b1SPaul Durrant unsigned int i; 528*4b34b5b1SPaul Durrant 529*4b34b5b1SPaul Durrant for (i = 0; i < nr_segs; i++) { 530*4b34b5b1SPaul Durrant XenDeviceGrantCopySegment *seg = &segs[i]; 531*4b34b5b1SPaul Durrant 532*4b34b5b1SPaul Durrant refs[i] = to_domain ? seg->dest.foreign.ref : 533*4b34b5b1SPaul Durrant seg->source.foreign.ref; 534*4b34b5b1SPaul Durrant } 535*4b34b5b1SPaul Durrant 536*4b34b5b1SPaul Durrant map = xengnttab_map_domain_grant_refs(xendev->xgth, nr_segs, 537*4b34b5b1SPaul Durrant xendev->frontend_id, refs, 538*4b34b5b1SPaul Durrant prot); 539*4b34b5b1SPaul Durrant if (!map) { 540*4b34b5b1SPaul Durrant error_setg_errno(errp, errno, 541*4b34b5b1SPaul Durrant "xengnttab_map_domain_grant_refs failed"); 542*4b34b5b1SPaul Durrant goto done; 543*4b34b5b1SPaul Durrant } 544*4b34b5b1SPaul Durrant 545*4b34b5b1SPaul Durrant for (i = 0; i < nr_segs; i++) { 546*4b34b5b1SPaul Durrant XenDeviceGrantCopySegment *seg = &segs[i]; 547*4b34b5b1SPaul Durrant void *page = map + (i * XC_PAGE_SIZE); 548*4b34b5b1SPaul Durrant 549*4b34b5b1SPaul Durrant if (to_domain) { 550*4b34b5b1SPaul Durrant memcpy(page + seg->dest.foreign.offset, seg->source.virt, 551*4b34b5b1SPaul Durrant seg->len); 552*4b34b5b1SPaul Durrant } else { 553*4b34b5b1SPaul Durrant memcpy(seg->dest.virt, page + seg->source.foreign.offset, 554*4b34b5b1SPaul Durrant seg->len); 555*4b34b5b1SPaul Durrant } 556*4b34b5b1SPaul Durrant } 557*4b34b5b1SPaul Durrant 558*4b34b5b1SPaul Durrant if (xengnttab_unmap(xendev->xgth, map, nr_segs)) { 559*4b34b5b1SPaul Durrant error_setg_errno(errp, errno, "xengnttab_unmap failed"); 560*4b34b5b1SPaul Durrant } 561*4b34b5b1SPaul Durrant 562*4b34b5b1SPaul Durrant done: 563*4b34b5b1SPaul Durrant g_free(refs); 564*4b34b5b1SPaul Durrant } 565*4b34b5b1SPaul Durrant 566*4b34b5b1SPaul Durrant void xen_device_copy_grant_refs(XenDevice *xendev, bool to_domain, 567*4b34b5b1SPaul Durrant XenDeviceGrantCopySegment segs[], 568*4b34b5b1SPaul Durrant unsigned int nr_segs, Error **errp) 569*4b34b5b1SPaul Durrant { 570*4b34b5b1SPaul Durrant xengnttab_grant_copy_segment_t *xengnttab_segs; 571*4b34b5b1SPaul Durrant unsigned int i; 572*4b34b5b1SPaul Durrant 573*4b34b5b1SPaul Durrant if (!xendev->feature_grant_copy) { 574*4b34b5b1SPaul Durrant compat_copy_grant_refs(xendev, to_domain, segs, nr_segs, errp); 575*4b34b5b1SPaul Durrant return; 576*4b34b5b1SPaul Durrant } 577*4b34b5b1SPaul Durrant 578*4b34b5b1SPaul Durrant xengnttab_segs = g_new0(xengnttab_grant_copy_segment_t, nr_segs); 579*4b34b5b1SPaul Durrant 580*4b34b5b1SPaul Durrant for (i = 0; i < nr_segs; i++) { 581*4b34b5b1SPaul Durrant XenDeviceGrantCopySegment *seg = &segs[i]; 582*4b34b5b1SPaul Durrant xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i]; 583*4b34b5b1SPaul Durrant 584*4b34b5b1SPaul Durrant if (to_domain) { 585*4b34b5b1SPaul Durrant xengnttab_seg->flags = GNTCOPY_dest_gref; 586*4b34b5b1SPaul Durrant xengnttab_seg->dest.foreign.domid = xendev->frontend_id; 587*4b34b5b1SPaul Durrant xengnttab_seg->dest.foreign.ref = seg->dest.foreign.ref; 588*4b34b5b1SPaul Durrant xengnttab_seg->dest.foreign.offset = seg->dest.foreign.offset; 589*4b34b5b1SPaul Durrant xengnttab_seg->source.virt = seg->source.virt; 590*4b34b5b1SPaul Durrant } else { 591*4b34b5b1SPaul Durrant xengnttab_seg->flags = GNTCOPY_source_gref; 592*4b34b5b1SPaul Durrant xengnttab_seg->source.foreign.domid = xendev->frontend_id; 593*4b34b5b1SPaul Durrant xengnttab_seg->source.foreign.ref = seg->source.foreign.ref; 594*4b34b5b1SPaul Durrant xengnttab_seg->source.foreign.offset = 595*4b34b5b1SPaul Durrant seg->source.foreign.offset; 596*4b34b5b1SPaul Durrant xengnttab_seg->dest.virt = seg->dest.virt; 597*4b34b5b1SPaul Durrant } 598*4b34b5b1SPaul Durrant 599*4b34b5b1SPaul Durrant xengnttab_seg->len = seg->len; 600*4b34b5b1SPaul Durrant } 601*4b34b5b1SPaul Durrant 602*4b34b5b1SPaul Durrant if (xengnttab_grant_copy(xendev->xgth, nr_segs, xengnttab_segs)) { 603*4b34b5b1SPaul Durrant error_setg_errno(errp, errno, "xengnttab_grant_copy failed"); 604*4b34b5b1SPaul Durrant goto done; 605*4b34b5b1SPaul Durrant } 606*4b34b5b1SPaul Durrant 607*4b34b5b1SPaul Durrant for (i = 0; i < nr_segs; i++) { 608*4b34b5b1SPaul Durrant xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i]; 609*4b34b5b1SPaul Durrant 610*4b34b5b1SPaul Durrant if (xengnttab_seg->status != GNTST_okay) { 611*4b34b5b1SPaul Durrant error_setg(errp, "xengnttab_grant_copy seg[%u] failed", i); 612*4b34b5b1SPaul Durrant break; 613*4b34b5b1SPaul Durrant } 614*4b34b5b1SPaul Durrant } 615*4b34b5b1SPaul Durrant 616*4b34b5b1SPaul Durrant done: 617*4b34b5b1SPaul Durrant g_free(xengnttab_segs); 618*4b34b5b1SPaul Durrant } 619*4b34b5b1SPaul Durrant 620108f7bbaSPaul Durrant static void xen_device_unrealize(DeviceState *dev, Error **errp) 621108f7bbaSPaul Durrant { 622108f7bbaSPaul Durrant XenDevice *xendev = XEN_DEVICE(dev); 623108f7bbaSPaul Durrant XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); 624108f7bbaSPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 625108f7bbaSPaul Durrant 626094a2239SPaul Durrant if (!xendev->name) { 627094a2239SPaul Durrant return; 628094a2239SPaul Durrant } 629094a2239SPaul Durrant 630094a2239SPaul Durrant trace_xen_device_unrealize(type, xendev->name); 631094a2239SPaul Durrant 632094a2239SPaul Durrant if (xendev->exit.notify) { 633094a2239SPaul Durrant qemu_remove_exit_notifier(&xendev->exit); 634094a2239SPaul Durrant xendev->exit.notify = NULL; 635094a2239SPaul Durrant } 636108f7bbaSPaul Durrant 637108f7bbaSPaul Durrant if (xendev_class->unrealize) { 638108f7bbaSPaul Durrant xendev_class->unrealize(xendev, errp); 639108f7bbaSPaul Durrant } 640094a2239SPaul Durrant 641094a2239SPaul Durrant xen_device_frontend_destroy(xendev); 642094a2239SPaul Durrant xen_device_backend_destroy(xendev); 643094a2239SPaul Durrant 644*4b34b5b1SPaul Durrant if (xendev->xgth) { 645*4b34b5b1SPaul Durrant xengnttab_close(xendev->xgth); 646*4b34b5b1SPaul Durrant xendev->xgth = NULL; 647*4b34b5b1SPaul Durrant } 648*4b34b5b1SPaul Durrant 649094a2239SPaul Durrant g_free(xendev->name); 650094a2239SPaul Durrant xendev->name = NULL; 651094a2239SPaul Durrant } 652094a2239SPaul Durrant 653094a2239SPaul Durrant static void xen_device_exit(Notifier *n, void *data) 654094a2239SPaul Durrant { 655094a2239SPaul Durrant XenDevice *xendev = container_of(n, XenDevice, exit); 656094a2239SPaul Durrant 657094a2239SPaul Durrant xen_device_unrealize(DEVICE(xendev), &error_abort); 658108f7bbaSPaul Durrant } 659108f7bbaSPaul Durrant 660108f7bbaSPaul Durrant static void xen_device_realize(DeviceState *dev, Error **errp) 661108f7bbaSPaul Durrant { 662108f7bbaSPaul Durrant XenDevice *xendev = XEN_DEVICE(dev); 663108f7bbaSPaul Durrant XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); 664094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 665108f7bbaSPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 666108f7bbaSPaul Durrant Error *local_err = NULL; 667108f7bbaSPaul Durrant 668094a2239SPaul Durrant if (xendev->frontend_id == DOMID_INVALID) { 669094a2239SPaul Durrant xendev->frontend_id = xen_domid; 670094a2239SPaul Durrant } 671094a2239SPaul Durrant 672094a2239SPaul Durrant if (xendev->frontend_id >= DOMID_FIRST_RESERVED) { 673094a2239SPaul Durrant error_setg(errp, "invalid frontend-id"); 674094a2239SPaul Durrant goto unrealize; 675094a2239SPaul Durrant } 676094a2239SPaul Durrant 677094a2239SPaul Durrant if (!xendev_class->get_name) { 678094a2239SPaul Durrant error_setg(errp, "get_name method not implemented"); 679094a2239SPaul Durrant goto unrealize; 680094a2239SPaul Durrant } 681094a2239SPaul Durrant 682094a2239SPaul Durrant xendev->name = xendev_class->get_name(xendev, &local_err); 683094a2239SPaul Durrant if (local_err) { 684094a2239SPaul Durrant error_propagate_prepend(errp, local_err, 685094a2239SPaul Durrant "failed to get device name: "); 686094a2239SPaul Durrant goto unrealize; 687094a2239SPaul Durrant } 688094a2239SPaul Durrant 689094a2239SPaul Durrant trace_xen_device_realize(type, xendev->name); 690094a2239SPaul Durrant 691*4b34b5b1SPaul Durrant xendev->xgth = xengnttab_open(NULL, 0); 692*4b34b5b1SPaul Durrant if (!xendev->xgth) { 693*4b34b5b1SPaul Durrant error_setg_errno(errp, errno, "failed xengnttab_open"); 694*4b34b5b1SPaul Durrant goto unrealize; 695*4b34b5b1SPaul Durrant } 696*4b34b5b1SPaul Durrant 697*4b34b5b1SPaul Durrant xendev->feature_grant_copy = 698*4b34b5b1SPaul Durrant (xengnttab_grant_copy(xendev->xgth, 0, NULL) == 0); 699*4b34b5b1SPaul Durrant 700094a2239SPaul Durrant xen_device_backend_create(xendev, &local_err); 701094a2239SPaul Durrant if (local_err) { 702094a2239SPaul Durrant error_propagate(errp, local_err); 703094a2239SPaul Durrant goto unrealize; 704094a2239SPaul Durrant } 705094a2239SPaul Durrant 706094a2239SPaul Durrant xen_device_frontend_create(xendev, &local_err); 707094a2239SPaul Durrant if (local_err) { 708094a2239SPaul Durrant error_propagate(errp, local_err); 709094a2239SPaul Durrant goto unrealize; 710094a2239SPaul Durrant } 711108f7bbaSPaul Durrant 712108f7bbaSPaul Durrant if (xendev_class->realize) { 713108f7bbaSPaul Durrant xendev_class->realize(xendev, &local_err); 714108f7bbaSPaul Durrant if (local_err) { 715108f7bbaSPaul Durrant error_propagate(errp, local_err); 716108f7bbaSPaul Durrant goto unrealize; 717108f7bbaSPaul Durrant } 718108f7bbaSPaul Durrant } 719108f7bbaSPaul Durrant 720094a2239SPaul Durrant xen_device_backend_printf(xendev, "frontend", "%s", 721094a2239SPaul Durrant xendev->frontend_path); 722094a2239SPaul Durrant xen_device_backend_printf(xendev, "frontend-id", "%u", 723094a2239SPaul Durrant xendev->frontend_id); 724094a2239SPaul Durrant xen_device_backend_printf(xendev, "online", "%u", 1); 725094a2239SPaul Durrant xen_device_backend_printf(xendev, "hotplug-status", "connected"); 726094a2239SPaul Durrant 727094a2239SPaul Durrant xen_device_backend_set_state(xendev, XenbusStateInitWait); 728094a2239SPaul Durrant 729094a2239SPaul Durrant xen_device_frontend_printf(xendev, "backend", "%s", 730094a2239SPaul Durrant xendev->backend_path); 731094a2239SPaul Durrant xen_device_frontend_printf(xendev, "backend-id", "%u", 732094a2239SPaul Durrant xenbus->backend_id); 733094a2239SPaul Durrant 734094a2239SPaul Durrant xen_device_frontend_set_state(xendev, XenbusStateInitialising); 735094a2239SPaul Durrant 736094a2239SPaul Durrant xendev->exit.notify = xen_device_exit; 737094a2239SPaul Durrant qemu_add_exit_notifier(&xendev->exit); 738108f7bbaSPaul Durrant return; 739108f7bbaSPaul Durrant 740108f7bbaSPaul Durrant unrealize: 741108f7bbaSPaul Durrant xen_device_unrealize(dev, &error_abort); 742108f7bbaSPaul Durrant } 743108f7bbaSPaul Durrant 744094a2239SPaul Durrant static Property xen_device_props[] = { 745094a2239SPaul Durrant DEFINE_PROP_UINT16("frontend-id", XenDevice, frontend_id, 746094a2239SPaul Durrant DOMID_INVALID), 747094a2239SPaul Durrant DEFINE_PROP_END_OF_LIST() 748094a2239SPaul Durrant }; 749094a2239SPaul Durrant 750108f7bbaSPaul Durrant static void xen_device_class_init(ObjectClass *class, void *data) 751108f7bbaSPaul Durrant { 752108f7bbaSPaul Durrant DeviceClass *dev_class = DEVICE_CLASS(class); 753108f7bbaSPaul Durrant 754108f7bbaSPaul Durrant dev_class->realize = xen_device_realize; 755108f7bbaSPaul Durrant dev_class->unrealize = xen_device_unrealize; 756094a2239SPaul Durrant dev_class->props = xen_device_props; 757108f7bbaSPaul Durrant dev_class->bus_type = TYPE_XEN_BUS; 758108f7bbaSPaul Durrant } 759108f7bbaSPaul Durrant 760108f7bbaSPaul Durrant static const TypeInfo xen_device_type_info = { 761108f7bbaSPaul Durrant .name = TYPE_XEN_DEVICE, 762108f7bbaSPaul Durrant .parent = TYPE_DEVICE, 763108f7bbaSPaul Durrant .instance_size = sizeof(XenDevice), 764108f7bbaSPaul Durrant .abstract = true, 765108f7bbaSPaul Durrant .class_size = sizeof(XenDeviceClass), 766108f7bbaSPaul Durrant .class_init = xen_device_class_init, 767108f7bbaSPaul Durrant }; 768108f7bbaSPaul Durrant 769108f7bbaSPaul Durrant typedef struct XenBridge { 770108f7bbaSPaul Durrant SysBusDevice busdev; 771108f7bbaSPaul Durrant } XenBridge; 772108f7bbaSPaul Durrant 773108f7bbaSPaul Durrant #define TYPE_XEN_BRIDGE "xen-bridge" 774108f7bbaSPaul Durrant 775108f7bbaSPaul Durrant static const TypeInfo xen_bridge_type_info = { 776108f7bbaSPaul Durrant .name = TYPE_XEN_BRIDGE, 777108f7bbaSPaul Durrant .parent = TYPE_SYS_BUS_DEVICE, 778108f7bbaSPaul Durrant .instance_size = sizeof(XenBridge), 779108f7bbaSPaul Durrant }; 780108f7bbaSPaul Durrant 781108f7bbaSPaul Durrant static void xen_register_types(void) 782108f7bbaSPaul Durrant { 783108f7bbaSPaul Durrant type_register_static(&xen_bridge_type_info); 784108f7bbaSPaul Durrant type_register_static(&xen_bus_type_info); 785108f7bbaSPaul Durrant type_register_static(&xen_device_type_info); 786108f7bbaSPaul Durrant } 787108f7bbaSPaul Durrant 788108f7bbaSPaul Durrant type_init(xen_register_types) 789108f7bbaSPaul Durrant 790108f7bbaSPaul Durrant void xen_bus_init(void) 791108f7bbaSPaul Durrant { 792108f7bbaSPaul Durrant DeviceState *dev = qdev_create(NULL, TYPE_XEN_BRIDGE); 793108f7bbaSPaul Durrant BusState *bus = qbus_create(TYPE_XEN_BUS, dev, NULL); 794108f7bbaSPaul Durrant 795108f7bbaSPaul Durrant qdev_init_nofail(dev); 796108f7bbaSPaul Durrant qbus_set_bus_hotplug_handler(bus, &error_abort); 797108f7bbaSPaul Durrant } 798