xen-legacy-backend.c 19 KB

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