xref: /openbmc/qemu/hw/xen/xen-legacy-backend.c (revision 787ea49e)
1 /*
2  *  xen backend driver infrastructure
3  *  (c) 2008 Gerd Hoffmann <kraxel@redhat.com>
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; under version 2 of the License.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License along
15  *  with this program; if not, see <http://www.gnu.org/licenses/>.
16  *
17  *  Contributions after 2012-01-13 are licensed under the terms of the
18  *  GNU GPL, version 2 or (at your option) any later version.
19  */
20 
21 /*
22  * TODO: add some xenbus / xenstore concepts overview here.
23  */
24 
25 #include "qemu/osdep.h"
26 
27 #include "hw/sysbus.h"
28 #include "hw/boards.h"
29 #include "hw/qdev-properties.h"
30 #include "qemu/main-loop.h"
31 #include "qapi/error.h"
32 #include "hw/xen/xen-legacy-backend.h"
33 #include "hw/xen/xen_pvdev.h"
34 #include "monitor/qdev.h"
35 
36 DeviceState *xen_sysdev;
37 BusState *xen_sysbus;
38 
39 /* ------------------------------------------------------------- */
40 
41 /* public */
42 struct qemu_xs_handle *xenstore;
43 const char *xen_protocol;
44 
45 /* private */
46 static int debug;
47 
48 int xenstore_write_be_str(struct XenLegacyDevice *xendev, const char *node,
49                           const char *val)
50 {
51     return xenstore_write_str(xendev->be, node, val);
52 }
53 
54 int xenstore_write_be_int(struct XenLegacyDevice *xendev, const char *node,
55                           int ival)
56 {
57     return xenstore_write_int(xendev->be, node, ival);
58 }
59 
60 int xenstore_write_be_int64(struct XenLegacyDevice *xendev, const char *node,
61                             int64_t ival)
62 {
63     return xenstore_write_int64(xendev->be, node, ival);
64 }
65 
66 char *xenstore_read_be_str(struct XenLegacyDevice *xendev, const char *node)
67 {
68     return xenstore_read_str(xendev->be, node);
69 }
70 
71 int xenstore_read_be_int(struct XenLegacyDevice *xendev, const char *node,
72                          int *ival)
73 {
74     return xenstore_read_int(xendev->be, node, ival);
75 }
76 
77 char *xenstore_read_fe_str(struct XenLegacyDevice *xendev, const char *node)
78 {
79     return xenstore_read_str(xendev->fe, node);
80 }
81 
82 int xenstore_read_fe_int(struct XenLegacyDevice *xendev, const char *node,
83                          int *ival)
84 {
85     return xenstore_read_int(xendev->fe, node, ival);
86 }
87 
88 int xenstore_read_fe_uint64(struct XenLegacyDevice *xendev, const char *node,
89                             uint64_t *uval)
90 {
91     return xenstore_read_uint64(xendev->fe, node, uval);
92 }
93 
94 /* ------------------------------------------------------------- */
95 
96 int xen_be_set_state(struct XenLegacyDevice *xendev, enum xenbus_state state)
97 {
98     int rc;
99 
100     rc = xenstore_write_be_int(xendev, "state", state);
101     if (rc < 0) {
102         return rc;
103     }
104     xen_pv_printf(xendev, 1, "backend state: %s -> %s\n",
105                   xenbus_strstate(xendev->be_state), xenbus_strstate(state));
106     xendev->be_state = state;
107     return 0;
108 }
109 
110 void xen_be_set_max_grant_refs(struct XenLegacyDevice *xendev,
111                                unsigned int nr_refs)
112 {
113     assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV);
114 
115     if (qemu_xen_gnttab_set_max_grants(xendev->gnttabdev, nr_refs)) {
116         xen_pv_printf(xendev, 0, "xengnttab_set_max_grants failed: %s\n",
117                       strerror(errno));
118     }
119 }
120 
121 void *xen_be_map_grant_refs(struct XenLegacyDevice *xendev, uint32_t *refs,
122                             unsigned int nr_refs, int prot)
123 {
124     void *ptr;
125 
126     assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV);
127 
128     ptr = qemu_xen_gnttab_map_refs(xendev->gnttabdev, nr_refs, xen_domid, refs,
129                                    prot);
130     if (!ptr) {
131         xen_pv_printf(xendev, 0,
132                       "xengnttab_map_domain_grant_refs failed: %s\n",
133                       strerror(errno));
134     }
135 
136     return ptr;
137 }
138 
139 void xen_be_unmap_grant_refs(struct XenLegacyDevice *xendev, void *ptr,
140                              uint32_t *refs, unsigned int nr_refs)
141 {
142     assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV);
143 
144     if (qemu_xen_gnttab_unmap(xendev->gnttabdev, ptr, refs, nr_refs)) {
145         xen_pv_printf(xendev, 0, "xengnttab_unmap failed: %s\n",
146                       strerror(errno));
147     }
148 }
149 
150 int xen_be_copy_grant_refs(struct XenLegacyDevice *xendev,
151                            bool to_domain,
152                            XenGrantCopySegment segs[],
153                            unsigned int nr_segs)
154 {
155     int rc;
156 
157     assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV);
158 
159     rc = qemu_xen_gnttab_grant_copy(xendev->gnttabdev, to_domain, xen_domid,
160                                     segs, nr_segs, NULL);
161     if (rc) {
162         xen_pv_printf(xendev, 0, "xengnttab_grant_copy failed: %s\n",
163                       strerror(-rc));
164     }
165     return rc;
166 }
167 
168 /*
169  * get xen backend device, allocate a new one if it doesn't exist.
170  */
171 static struct XenLegacyDevice *xen_be_get_xendev(const char *type, int dom,
172                                                  int dev,
173                                                  struct XenDevOps *ops)
174 {
175     struct XenLegacyDevice *xendev;
176 
177     xendev = xen_pv_find_xendev(type, dom, dev);
178     if (xendev) {
179         return xendev;
180     }
181 
182     /* init new xendev */
183     xendev = g_malloc0(ops->size);
184     object_initialize(&xendev->qdev, ops->size, TYPE_XENBACKEND);
185     OBJECT(xendev)->free = g_free;
186     qdev_set_id(DEVICE(xendev), g_strdup_printf("xen-%s-%d", type, dev),
187                 &error_fatal);
188     qdev_realize(DEVICE(xendev), xen_sysbus, &error_fatal);
189     object_unref(OBJECT(xendev));
190 
191     xendev->type  = type;
192     xendev->dom   = dom;
193     xendev->dev   = dev;
194     xendev->ops   = ops;
195 
196     snprintf(xendev->be, sizeof(xendev->be), "backend/%s/%d/%d",
197              xendev->type, xendev->dom, xendev->dev);
198     snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
199              xendev->type, xendev->dev);
200 
201     xendev->debug      = debug;
202     xendev->local_port = -1;
203 
204     xendev->evtchndev = qemu_xen_evtchn_open();
205     if (xendev->evtchndev == NULL) {
206         xen_pv_printf(NULL, 0, "can't open evtchn device\n");
207         qdev_unplug(DEVICE(xendev), NULL);
208         return NULL;
209     }
210     qemu_set_cloexec(qemu_xen_evtchn_fd(xendev->evtchndev));
211 
212     xen_pv_insert_xendev(xendev);
213 
214     if (xendev->ops->alloc) {
215         xendev->ops->alloc(xendev);
216     }
217 
218     return xendev;
219 }
220 
221 
222 /*
223  * Sync internal data structures on xenstore updates.
224  * Node specifies the changed field.  node = NULL means
225  * update all fields (used for initialization).
226  */
227 static void xen_be_backend_changed(struct XenLegacyDevice *xendev,
228                                    const char *node)
229 {
230     if (node == NULL  ||  strcmp(node, "online") == 0) {
231         if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1) {
232             xendev->online = 0;
233         }
234     }
235 
236     if (node) {
237         xen_pv_printf(xendev, 2, "backend update: %s\n", node);
238         if (xendev->ops->backend_changed) {
239             xendev->ops->backend_changed(xendev, node);
240         }
241     }
242 }
243 
244 static void xen_be_frontend_changed(struct XenLegacyDevice *xendev,
245                                     const char *node)
246 {
247     int fe_state;
248 
249     if (node == NULL  ||  strcmp(node, "state") == 0) {
250         if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
251             fe_state = XenbusStateUnknown;
252         }
253         if (xendev->fe_state != fe_state) {
254             xen_pv_printf(xendev, 1, "frontend state: %s -> %s\n",
255                           xenbus_strstate(xendev->fe_state),
256                           xenbus_strstate(fe_state));
257         }
258         xendev->fe_state = fe_state;
259     }
260     if (node == NULL  ||  strcmp(node, "protocol") == 0) {
261         g_free(xendev->protocol);
262         xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
263         if (xendev->protocol) {
264             xen_pv_printf(xendev, 1, "frontend protocol: %s\n",
265                           xendev->protocol);
266         }
267     }
268 
269     if (node) {
270         xen_pv_printf(xendev, 2, "frontend update: %s\n", node);
271         if (xendev->ops->frontend_changed) {
272             xendev->ops->frontend_changed(xendev, node);
273         }
274     }
275 }
276 
277 static void xenstore_update_fe(void *opaque, const char *watch)
278 {
279     struct XenLegacyDevice *xendev = opaque;
280     const char *node;
281     unsigned int len;
282 
283     len = strlen(xendev->fe);
284     if (strncmp(xendev->fe, watch, len) != 0) {
285         return;
286     }
287     if (watch[len] != '/') {
288         return;
289     }
290     node = watch + len + 1;
291 
292     xen_be_frontend_changed(xendev, node);
293     xen_be_check_state(xendev);
294 }
295 
296 /* ------------------------------------------------------------- */
297 /* Check for possible state transitions and perform them.        */
298 
299 /*
300  * Initial xendev setup.  Read frontend path, register watch for it.
301  * Should succeed once xend finished setting up the backend device.
302  *
303  * Also sets initial state (-> Initializing) when done.  Which
304  * only affects the xendev->be_state variable as xenbus should
305  * already be put into that state by xend.
306  */
307 static int xen_be_try_setup(struct XenLegacyDevice *xendev)
308 {
309     int be_state;
310 
311     if (xenstore_read_be_int(xendev, "state", &be_state) == -1) {
312         xen_pv_printf(xendev, 0, "reading backend state failed\n");
313         return -1;
314     }
315 
316     if (be_state != XenbusStateInitialising) {
317         xen_pv_printf(xendev, 0, "initial backend state is wrong (%s)\n",
318                       xenbus_strstate(be_state));
319         return -1;
320     }
321 
322     xendev->fe = xenstore_read_be_str(xendev, "frontend");
323     if (xendev->fe == NULL) {
324         xen_pv_printf(xendev, 0, "reading frontend path failed\n");
325         return -1;
326     }
327 
328     /* setup frontend watch */
329     xendev->watch = qemu_xen_xs_watch(xenstore, xendev->fe, xenstore_update_fe,
330                                       xendev);
331     if (!xendev->watch) {
332         xen_pv_printf(xendev, 0, "watching frontend path (%s) failed\n",
333                       xendev->fe);
334         return -1;
335     }
336     xen_be_set_state(xendev, XenbusStateInitialising);
337 
338     xen_be_backend_changed(xendev, NULL);
339     xen_be_frontend_changed(xendev, NULL);
340     return 0;
341 }
342 
343 /*
344  * Try initialize xendev.  Prepare everything the backend can do
345  * without synchronizing with the frontend.  Fakes hotplug-status.  No
346  * hotplug involved here because this is about userspace drivers, thus
347  * there are kernel backend devices which could invoke hotplug.
348  *
349  * Goes to InitWait on success.
350  */
351 static int xen_be_try_init(struct XenLegacyDevice *xendev)
352 {
353     int rc = 0;
354 
355     if (!xendev->online) {
356         xen_pv_printf(xendev, 1, "not online\n");
357         return -1;
358     }
359 
360     if (xendev->ops->init) {
361         rc = xendev->ops->init(xendev);
362     }
363     if (rc != 0) {
364         xen_pv_printf(xendev, 1, "init() failed\n");
365         return rc;
366     }
367 
368     xenstore_write_be_str(xendev, "hotplug-status", "connected");
369     xen_be_set_state(xendev, XenbusStateInitWait);
370     return 0;
371 }
372 
373 /*
374  * Try to initialise xendev.  Depends on the frontend being ready
375  * for it (shared ring and evtchn info in xenstore, state being
376  * Initialised or Connected).
377  *
378  * Goes to Connected on success.
379  */
380 static int xen_be_try_initialise(struct XenLegacyDevice *xendev)
381 {
382     int rc = 0;
383 
384     if (xendev->fe_state != XenbusStateInitialised  &&
385         xendev->fe_state != XenbusStateConnected) {
386         if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
387             xen_pv_printf(xendev, 2, "frontend not ready, ignoring\n");
388         } else {
389             xen_pv_printf(xendev, 2, "frontend not ready (yet)\n");
390             return -1;
391         }
392     }
393 
394     if (xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
395         xendev->gnttabdev = qemu_xen_gnttab_open();
396         if (xendev->gnttabdev == NULL) {
397             xen_pv_printf(NULL, 0, "can't open gnttab device\n");
398             return -1;
399         }
400     } else {
401         xendev->gnttabdev = NULL;
402     }
403 
404     if (xendev->ops->initialise) {
405         rc = xendev->ops->initialise(xendev);
406     }
407     if (rc != 0) {
408         xen_pv_printf(xendev, 0, "initialise() failed\n");
409         return rc;
410     }
411 
412     xen_be_set_state(xendev, XenbusStateConnected);
413     return 0;
414 }
415 
416 /*
417  * Try to let xendev know that it is connected.  Depends on the
418  * frontend being Connected.  Note that this may be called more
419  * than once since the backend state is not modified.
420  */
421 static void xen_be_try_connected(struct XenLegacyDevice *xendev)
422 {
423     if (!xendev->ops->connected) {
424         return;
425     }
426 
427     if (xendev->fe_state != XenbusStateConnected) {
428         if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
429             xen_pv_printf(xendev, 2, "frontend not ready, ignoring\n");
430         } else {
431             xen_pv_printf(xendev, 2, "frontend not ready (yet)\n");
432             return;
433         }
434     }
435 
436     xendev->ops->connected(xendev);
437 }
438 
439 /*
440  * Teardown connection.
441  *
442  * Goes to Closed when done.
443  */
444 static void xen_be_disconnect(struct XenLegacyDevice *xendev,
445                               enum xenbus_state state)
446 {
447     if (xendev->be_state != XenbusStateClosing &&
448         xendev->be_state != XenbusStateClosed  &&
449         xendev->ops->disconnect) {
450         xendev->ops->disconnect(xendev);
451     }
452     if (xendev->gnttabdev) {
453         qemu_xen_gnttab_close(xendev->gnttabdev);
454         xendev->gnttabdev = NULL;
455     }
456     if (xendev->be_state != state) {
457         xen_be_set_state(xendev, state);
458     }
459 }
460 
461 /*
462  * Try to reset xendev, for reconnection by another frontend instance.
463  */
464 static int xen_be_try_reset(struct XenLegacyDevice *xendev)
465 {
466     if (xendev->fe_state != XenbusStateInitialising) {
467         return -1;
468     }
469 
470     xen_pv_printf(xendev, 1, "device reset (for re-connect)\n");
471     xen_be_set_state(xendev, XenbusStateInitialising);
472     return 0;
473 }
474 
475 /*
476  * state change dispatcher function
477  */
478 void xen_be_check_state(struct XenLegacyDevice *xendev)
479 {
480     int rc = 0;
481 
482     /* frontend may request shutdown from almost anywhere */
483     if (xendev->fe_state == XenbusStateClosing ||
484         xendev->fe_state == XenbusStateClosed) {
485         xen_be_disconnect(xendev, xendev->fe_state);
486         return;
487     }
488 
489     /* check for possible backend state transitions */
490     for (;;) {
491         switch (xendev->be_state) {
492         case XenbusStateUnknown:
493             rc = xen_be_try_setup(xendev);
494             break;
495         case XenbusStateInitialising:
496             rc = xen_be_try_init(xendev);
497             break;
498         case XenbusStateInitWait:
499             rc = xen_be_try_initialise(xendev);
500             break;
501         case XenbusStateConnected:
502             /* xendev->be_state doesn't change */
503             xen_be_try_connected(xendev);
504             rc = -1;
505             break;
506         case XenbusStateClosed:
507             rc = xen_be_try_reset(xendev);
508             break;
509         default:
510             rc = -1;
511         }
512         if (rc != 0) {
513             break;
514         }
515     }
516 }
517 
518 /* ------------------------------------------------------------- */
519 
520 struct xenstore_be {
521     const char *type;
522     int dom;
523     struct XenDevOps *ops;
524 };
525 
526 static void xenstore_update_be(void *opaque, const char *watch)
527 {
528     struct xenstore_be *be = opaque;
529     struct XenLegacyDevice *xendev;
530     char path[XEN_BUFSIZE], *bepath;
531     unsigned int len, dev;
532 
533     len = snprintf(path, sizeof(path), "backend/%s/%d", be->type, be->dom);
534     if (strncmp(path, watch, len) != 0) {
535         return;
536     }
537     if (sscanf(watch + len, "/%u/%255s", &dev, path) != 2) {
538         strcpy(path, "");
539         if (sscanf(watch + len, "/%u", &dev) != 1) {
540             dev = -1;
541         }
542     }
543     if (dev == -1) {
544         return;
545     }
546 
547     xendev = xen_be_get_xendev(be->type, be->dom, dev, be->ops);
548     if (xendev != NULL) {
549         bepath = qemu_xen_xs_read(xenstore, 0, xendev->be, &len);
550         if (bepath == NULL) {
551             xen_pv_del_xendev(xendev);
552         } else {
553             free(bepath);
554             xen_be_backend_changed(xendev, path);
555             xen_be_check_state(xendev);
556         }
557     }
558 }
559 
560 static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops)
561 {
562     struct XenLegacyDevice *xendev;
563     char path[XEN_BUFSIZE];
564     struct xenstore_be *be = g_new0(struct xenstore_be, 1);
565     char **dev = NULL;
566     unsigned int cdev, j;
567 
568     /* setup watch */
569     be->type = type;
570     be->dom = dom;
571     be->ops = ops;
572     snprintf(path, sizeof(path), "backend/%s/%d", type, dom);
573     if (!qemu_xen_xs_watch(xenstore, path, xenstore_update_be, be)) {
574         xen_pv_printf(NULL, 0, "xen be: watching backend path (%s) failed\n",
575                       path);
576         return -1;
577     }
578 
579     /* look for backends */
580     dev = qemu_xen_xs_directory(xenstore, 0, path, &cdev);
581     if (!dev) {
582         return 0;
583     }
584     for (j = 0; j < cdev; j++) {
585         xendev = xen_be_get_xendev(type, dom, atoi(dev[j]), ops);
586         if (xendev == NULL) {
587             continue;
588         }
589         xen_be_check_state(xendev);
590     }
591     free(dev);
592     return 0;
593 }
594 
595 /* -------------------------------------------------------------------- */
596 
597 static void xen_set_dynamic_sysbus(void)
598 {
599     Object *machine = qdev_get_machine();
600     ObjectClass *oc = object_get_class(machine);
601     MachineClass *mc = MACHINE_CLASS(oc);
602 
603     machine_class_allow_dynamic_sysbus_dev(mc, TYPE_XENSYSDEV);
604 }
605 
606 void xen_be_init(void)
607 {
608     xenstore = qemu_xen_xs_open();
609     if (!xenstore) {
610         xen_pv_printf(NULL, 0, "can't connect to xenstored\n");
611         exit(1);
612     }
613 
614     if (xen_evtchn_ops == NULL || xen_gnttab_ops == NULL) {
615         xen_pv_printf(NULL, 0, "Xen operations not set up\n");
616         exit(1);
617     }
618 
619     xen_sysdev = qdev_new(TYPE_XENSYSDEV);
620     sysbus_realize_and_unref(SYS_BUS_DEVICE(xen_sysdev), &error_fatal);
621     xen_sysbus = qbus_new(TYPE_XENSYSBUS, xen_sysdev, "xen-sysbus");
622     qbus_set_bus_hotplug_handler(xen_sysbus);
623 
624     xen_set_dynamic_sysbus();
625 }
626 
627 int xen_be_register(const char *type, struct XenDevOps *ops)
628 {
629     char path[50];
630 
631     snprintf(path, sizeof(path), "device-model/%u/backends/%s", xen_domid,
632              type);
633     xenstore_mkdir(path, XS_PERM_NONE);
634 
635     return xenstore_scan(type, xen_domid, ops);
636 }
637 
638 int xen_be_bind_evtchn(struct XenLegacyDevice *xendev)
639 {
640     if (xendev->local_port != -1) {
641         return 0;
642     }
643     xendev->local_port = qemu_xen_evtchn_bind_interdomain
644         (xendev->evtchndev, xendev->dom, xendev->remote_port);
645     if (xendev->local_port == -1) {
646         xen_pv_printf(xendev, 0, "xenevtchn_bind_interdomain failed\n");
647         return -1;
648     }
649     xen_pv_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
650     qemu_set_fd_handler(qemu_xen_evtchn_fd(xendev->evtchndev),
651                         xen_pv_evtchn_event, NULL, xendev);
652     return 0;
653 }
654 
655 
656 static Property xendev_properties[] = {
657     DEFINE_PROP_END_OF_LIST(),
658 };
659 
660 static void xendev_class_init(ObjectClass *klass, void *data)
661 {
662     DeviceClass *dc = DEVICE_CLASS(klass);
663 
664     device_class_set_props(dc, xendev_properties);
665     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
666     /* xen-backend devices can be plugged/unplugged dynamically */
667     dc->user_creatable = true;
668     dc->bus_type = TYPE_XENSYSBUS;
669 }
670 
671 static const TypeInfo xendev_type_info = {
672     .name          = TYPE_XENBACKEND,
673     .parent        = TYPE_DEVICE,
674     .class_init    = xendev_class_init,
675     .instance_size = sizeof(struct XenLegacyDevice),
676 };
677 
678 static void xen_sysbus_class_init(ObjectClass *klass, void *data)
679 {
680     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
681 
682     hc->unplug = qdev_simple_device_unplug_cb;
683 }
684 
685 static const TypeInfo xensysbus_info = {
686     .name       = TYPE_XENSYSBUS,
687     .parent     = TYPE_BUS,
688     .class_init = xen_sysbus_class_init,
689     .interfaces = (InterfaceInfo[]) {
690         { TYPE_HOTPLUG_HANDLER },
691         { }
692     }
693 };
694 
695 static Property xen_sysdev_properties[] = {
696     {/* end of property list */},
697 };
698 
699 static void xen_sysdev_class_init(ObjectClass *klass, void *data)
700 {
701     DeviceClass *dc = DEVICE_CLASS(klass);
702 
703     device_class_set_props(dc, xen_sysdev_properties);
704 }
705 
706 static const TypeInfo xensysdev_info = {
707     .name          = TYPE_XENSYSDEV,
708     .parent        = TYPE_SYS_BUS_DEVICE,
709     .instance_size = sizeof(SysBusDevice),
710     .class_init    = xen_sysdev_class_init,
711 };
712 
713 static void xenbe_register_types(void)
714 {
715     type_register_static(&xensysbus_info);
716     type_register_static(&xensysdev_info);
717     type_register_static(&xendev_type_info);
718 }
719 
720 type_init(xenbe_register_types)
721