xen_pvdev.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. /*
  2. * Xen para-virtualization device
  3. *
  4. * (c) 2008 Gerd Hoffmann <kraxel@redhat.com>
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, see <http://www.gnu.org/licenses/>
  18. */
  19. #include "qemu/osdep.h"
  20. #include "qemu/log.h"
  21. #include "qemu/main-loop.h"
  22. #include "hw/qdev-core.h"
  23. #include "hw/xen/xen-legacy-backend.h"
  24. #include "hw/xen/xen_pvdev.h"
  25. /* private */
  26. static int debug;
  27. struct xs_dirs {
  28. char *xs_dir;
  29. QTAILQ_ENTRY(xs_dirs) list;
  30. };
  31. static QTAILQ_HEAD(, xs_dirs) xs_cleanup =
  32. QTAILQ_HEAD_INITIALIZER(xs_cleanup);
  33. static QTAILQ_HEAD(, XenLegacyDevice) xendevs =
  34. QTAILQ_HEAD_INITIALIZER(xendevs);
  35. /* ------------------------------------------------------------- */
  36. static void xenstore_cleanup_dir(char *dir)
  37. {
  38. struct xs_dirs *d;
  39. d = g_malloc(sizeof(*d));
  40. d->xs_dir = dir;
  41. QTAILQ_INSERT_TAIL(&xs_cleanup, d, list);
  42. }
  43. void xen_config_cleanup(void)
  44. {
  45. struct xs_dirs *d;
  46. QTAILQ_FOREACH(d, &xs_cleanup, list) {
  47. xs_rm(xenstore, 0, d->xs_dir);
  48. }
  49. }
  50. int xenstore_mkdir(char *path, int p)
  51. {
  52. struct xs_permissions perms[2] = {
  53. {
  54. .id = 0, /* set owner: dom0 */
  55. }, {
  56. .id = xen_domid,
  57. .perms = p,
  58. }
  59. };
  60. if (!xs_mkdir(xenstore, 0, path)) {
  61. xen_pv_printf(NULL, 0, "xs_mkdir %s: failed\n", path);
  62. return -1;
  63. }
  64. xenstore_cleanup_dir(g_strdup(path));
  65. if (!xs_set_permissions(xenstore, 0, path, perms, 2)) {
  66. xen_pv_printf(NULL, 0, "xs_set_permissions %s: failed\n", path);
  67. return -1;
  68. }
  69. return 0;
  70. }
  71. int xenstore_write_str(const char *base, const char *node, const char *val)
  72. {
  73. char abspath[XEN_BUFSIZE];
  74. snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
  75. if (!xs_write(xenstore, 0, abspath, val, strlen(val))) {
  76. return -1;
  77. }
  78. return 0;
  79. }
  80. char *xenstore_read_str(const char *base, const char *node)
  81. {
  82. char abspath[XEN_BUFSIZE];
  83. unsigned int len;
  84. char *str, *ret = NULL;
  85. snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
  86. str = xs_read(xenstore, 0, abspath, &len);
  87. if (str != NULL) {
  88. /* move to qemu-allocated memory to make sure
  89. * callers can savely g_free() stuff. */
  90. ret = g_strdup(str);
  91. free(str);
  92. }
  93. return ret;
  94. }
  95. int xenstore_write_int(const char *base, const char *node, int ival)
  96. {
  97. char val[12];
  98. snprintf(val, sizeof(val), "%d", ival);
  99. return xenstore_write_str(base, node, val);
  100. }
  101. int xenstore_write_int64(const char *base, const char *node, int64_t ival)
  102. {
  103. char val[21];
  104. snprintf(val, sizeof(val), "%"PRId64, ival);
  105. return xenstore_write_str(base, node, val);
  106. }
  107. int xenstore_read_int(const char *base, const char *node, int *ival)
  108. {
  109. char *val;
  110. int rc = -1;
  111. val = xenstore_read_str(base, node);
  112. if (val && 1 == sscanf(val, "%d", ival)) {
  113. rc = 0;
  114. }
  115. g_free(val);
  116. return rc;
  117. }
  118. int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval)
  119. {
  120. char *val;
  121. int rc = -1;
  122. val = xenstore_read_str(base, node);
  123. if (val && 1 == sscanf(val, "%"SCNu64, uval)) {
  124. rc = 0;
  125. }
  126. g_free(val);
  127. return rc;
  128. }
  129. void xenstore_update(void *unused)
  130. {
  131. char **vec = NULL;
  132. intptr_t type, ops, ptr;
  133. unsigned int dom, count;
  134. vec = xs_read_watch(xenstore, &count);
  135. if (vec == NULL) {
  136. goto cleanup;
  137. }
  138. if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
  139. &type, &dom, &ops) == 3) {
  140. xenstore_update_be(vec[XS_WATCH_PATH], (void *)type, dom, (void*)ops);
  141. }
  142. if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1) {
  143. xenstore_update_fe(vec[XS_WATCH_PATH], (void *)ptr);
  144. }
  145. cleanup:
  146. free(vec);
  147. }
  148. const char *xenbus_strstate(enum xenbus_state state)
  149. {
  150. static const char *const name[] = {
  151. [XenbusStateUnknown] = "Unknown",
  152. [XenbusStateInitialising] = "Initialising",
  153. [XenbusStateInitWait] = "InitWait",
  154. [XenbusStateInitialised] = "Initialised",
  155. [XenbusStateConnected] = "Connected",
  156. [XenbusStateClosing] = "Closing",
  157. [XenbusStateClosed] = "Closed",
  158. };
  159. return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
  160. }
  161. /*
  162. * msg_level:
  163. * 0 == errors (stderr + logfile).
  164. * 1 == informative debug messages (logfile only).
  165. * 2 == noisy debug messages (logfile only).
  166. * 3 == will flood your log (logfile only).
  167. */
  168. G_GNUC_PRINTF(3, 0)
  169. static void xen_pv_output_msg(struct XenLegacyDevice *xendev,
  170. FILE *f, const char *fmt, va_list args)
  171. {
  172. if (xendev) {
  173. fprintf(f, "xen be: %s: ", xendev->name);
  174. } else {
  175. fprintf(f, "xen be core: ");
  176. }
  177. vfprintf(f, fmt, args);
  178. }
  179. void xen_pv_printf(struct XenLegacyDevice *xendev, int msg_level,
  180. const char *fmt, ...)
  181. {
  182. FILE *logfile;
  183. va_list args;
  184. if (msg_level > (xendev ? xendev->debug : debug)) {
  185. return;
  186. }
  187. logfile = qemu_log_trylock();
  188. if (logfile) {
  189. va_start(args, fmt);
  190. xen_pv_output_msg(xendev, logfile, fmt, args);
  191. va_end(args);
  192. qemu_log_unlock(logfile);
  193. }
  194. if (msg_level == 0) {
  195. va_start(args, fmt);
  196. xen_pv_output_msg(xendev, stderr, fmt, args);
  197. va_end(args);
  198. }
  199. }
  200. void xen_pv_evtchn_event(void *opaque)
  201. {
  202. struct XenLegacyDevice *xendev = opaque;
  203. evtchn_port_t port;
  204. port = xenevtchn_pending(xendev->evtchndev);
  205. if (port != xendev->local_port) {
  206. xen_pv_printf(xendev, 0,
  207. "xenevtchn_pending returned %d (expected %d)\n",
  208. port, xendev->local_port);
  209. return;
  210. }
  211. xenevtchn_unmask(xendev->evtchndev, port);
  212. if (xendev->ops->event) {
  213. xendev->ops->event(xendev);
  214. }
  215. }
  216. void xen_pv_unbind_evtchn(struct XenLegacyDevice *xendev)
  217. {
  218. if (xendev->local_port == -1) {
  219. return;
  220. }
  221. qemu_set_fd_handler(xenevtchn_fd(xendev->evtchndev), NULL, NULL, NULL);
  222. xenevtchn_unbind(xendev->evtchndev, xendev->local_port);
  223. xen_pv_printf(xendev, 2, "unbind evtchn port %d\n", xendev->local_port);
  224. xendev->local_port = -1;
  225. }
  226. int xen_pv_send_notify(struct XenLegacyDevice *xendev)
  227. {
  228. return xenevtchn_notify(xendev->evtchndev, xendev->local_port);
  229. }
  230. /* ------------------------------------------------------------- */
  231. struct XenLegacyDevice *xen_pv_find_xendev(const char *type, int dom, int dev)
  232. {
  233. struct XenLegacyDevice *xendev;
  234. QTAILQ_FOREACH(xendev, &xendevs, next) {
  235. if (xendev->dom != dom) {
  236. continue;
  237. }
  238. if (xendev->dev != dev) {
  239. continue;
  240. }
  241. if (strcmp(xendev->type, type) != 0) {
  242. continue;
  243. }
  244. return xendev;
  245. }
  246. return NULL;
  247. }
  248. /*
  249. * release xen backend device.
  250. */
  251. void xen_pv_del_xendev(struct XenLegacyDevice *xendev)
  252. {
  253. if (xendev->ops->free) {
  254. xendev->ops->free(xendev);
  255. }
  256. if (xendev->fe) {
  257. char token[XEN_BUFSIZE];
  258. snprintf(token, sizeof(token), "fe:%p", xendev);
  259. xs_unwatch(xenstore, xendev->fe, token);
  260. g_free(xendev->fe);
  261. }
  262. if (xendev->evtchndev != NULL) {
  263. xenevtchn_close(xendev->evtchndev);
  264. }
  265. if (xendev->gnttabdev != NULL) {
  266. xengnttab_close(xendev->gnttabdev);
  267. }
  268. QTAILQ_REMOVE(&xendevs, xendev, next);
  269. qdev_unplug(&xendev->qdev, NULL);
  270. }
  271. void xen_pv_insert_xendev(struct XenLegacyDevice *xendev)
  272. {
  273. QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
  274. }