xen-operations.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. /*
  2. * QEMU Xen backend support: Operations for true Xen
  3. *
  4. * Copyright © 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  5. *
  6. * Authors: David Woodhouse <dwmw2@infradead.org>
  7. *
  8. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  9. * See the COPYING file in the top-level directory.
  10. */
  11. #include "qemu/osdep.h"
  12. #include "qemu/uuid.h"
  13. #include "qapi/error.h"
  14. #include "hw/xen/xen_native.h"
  15. #include "hw/xen/xen_backend_ops.h"
  16. /*
  17. * If we have new enough libxenctrl then we do not want/need these compat
  18. * interfaces, despite what the user supplied cflags might say. They
  19. * must be undefined before including xenctrl.h
  20. */
  21. #undef XC_WANT_COMPAT_EVTCHN_API
  22. #undef XC_WANT_COMPAT_GNTTAB_API
  23. #undef XC_WANT_COMPAT_MAP_FOREIGN_API
  24. #include <xenctrl.h>
  25. /*
  26. * We don't support Xen prior to 4.7.1.
  27. */
  28. #include <xenevtchn.h>
  29. #include <xengnttab.h>
  30. #include <xenforeignmemory.h>
  31. /* Xen before 4.8 */
  32. static int libxengnttab_fallback_grant_copy(xengnttab_handle *xgt,
  33. bool to_domain, uint32_t domid,
  34. XenGrantCopySegment segs[],
  35. unsigned int nr_segs, Error **errp)
  36. {
  37. uint32_t *refs = g_new(uint32_t, nr_segs);
  38. int prot = to_domain ? PROT_WRITE : PROT_READ;
  39. void *map;
  40. unsigned int i;
  41. int rc = 0;
  42. for (i = 0; i < nr_segs; i++) {
  43. XenGrantCopySegment *seg = &segs[i];
  44. refs[i] = to_domain ? seg->dest.foreign.ref :
  45. seg->source.foreign.ref;
  46. }
  47. map = xengnttab_map_domain_grant_refs(xgt, nr_segs, domid, refs, prot);
  48. if (!map) {
  49. if (errp) {
  50. error_setg_errno(errp, errno,
  51. "xengnttab_map_domain_grant_refs failed");
  52. }
  53. rc = -errno;
  54. goto done;
  55. }
  56. for (i = 0; i < nr_segs; i++) {
  57. XenGrantCopySegment *seg = &segs[i];
  58. void *page = map + (i * XEN_PAGE_SIZE);
  59. if (to_domain) {
  60. memcpy(page + seg->dest.foreign.offset, seg->source.virt,
  61. seg->len);
  62. } else {
  63. memcpy(seg->dest.virt, page + seg->source.foreign.offset,
  64. seg->len);
  65. }
  66. }
  67. if (xengnttab_unmap(xgt, map, nr_segs)) {
  68. if (errp) {
  69. error_setg_errno(errp, errno, "xengnttab_unmap failed");
  70. }
  71. rc = -errno;
  72. }
  73. done:
  74. g_free(refs);
  75. return rc;
  76. }
  77. #if CONFIG_XEN_CTRL_INTERFACE_VERSION >= 40800
  78. static int libxengnttab_backend_grant_copy(xengnttab_handle *xgt,
  79. bool to_domain, uint32_t domid,
  80. XenGrantCopySegment *segs,
  81. uint32_t nr_segs, Error **errp)
  82. {
  83. xengnttab_grant_copy_segment_t *xengnttab_segs;
  84. unsigned int i;
  85. int rc;
  86. xengnttab_segs = g_new0(xengnttab_grant_copy_segment_t, nr_segs);
  87. for (i = 0; i < nr_segs; i++) {
  88. XenGrantCopySegment *seg = &segs[i];
  89. xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i];
  90. if (to_domain) {
  91. xengnttab_seg->flags = GNTCOPY_dest_gref;
  92. xengnttab_seg->dest.foreign.domid = domid;
  93. xengnttab_seg->dest.foreign.ref = seg->dest.foreign.ref;
  94. xengnttab_seg->dest.foreign.offset = seg->dest.foreign.offset;
  95. xengnttab_seg->source.virt = seg->source.virt;
  96. } else {
  97. xengnttab_seg->flags = GNTCOPY_source_gref;
  98. xengnttab_seg->source.foreign.domid = domid;
  99. xengnttab_seg->source.foreign.ref = seg->source.foreign.ref;
  100. xengnttab_seg->source.foreign.offset =
  101. seg->source.foreign.offset;
  102. xengnttab_seg->dest.virt = seg->dest.virt;
  103. }
  104. xengnttab_seg->len = seg->len;
  105. }
  106. if (xengnttab_grant_copy(xgt, nr_segs, xengnttab_segs)) {
  107. if (errp) {
  108. error_setg_errno(errp, errno, "xengnttab_grant_copy failed");
  109. }
  110. rc = -errno;
  111. goto done;
  112. }
  113. rc = 0;
  114. for (i = 0; i < nr_segs; i++) {
  115. xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i];
  116. if (xengnttab_seg->status != GNTST_okay) {
  117. if (errp) {
  118. error_setg(errp, "xengnttab_grant_copy seg[%u] failed", i);
  119. }
  120. rc = -EIO;
  121. break;
  122. }
  123. }
  124. done:
  125. g_free(xengnttab_segs);
  126. return rc;
  127. }
  128. #endif
  129. static xenevtchn_handle *libxenevtchn_backend_open(void)
  130. {
  131. return xenevtchn_open(NULL, 0);
  132. }
  133. struct evtchn_backend_ops libxenevtchn_backend_ops = {
  134. .open = libxenevtchn_backend_open,
  135. .close = xenevtchn_close,
  136. .bind_interdomain = xenevtchn_bind_interdomain,
  137. .unbind = xenevtchn_unbind,
  138. .get_fd = xenevtchn_fd,
  139. .notify = xenevtchn_notify,
  140. .unmask = xenevtchn_unmask,
  141. .pending = xenevtchn_pending,
  142. };
  143. static xengnttab_handle *libxengnttab_backend_open(void)
  144. {
  145. return xengnttab_open(NULL, 0);
  146. }
  147. static int libxengnttab_backend_unmap(xengnttab_handle *xgt,
  148. void *start_address, uint32_t *refs,
  149. uint32_t count)
  150. {
  151. return xengnttab_unmap(xgt, start_address, count);
  152. }
  153. static struct gnttab_backend_ops libxengnttab_backend_ops = {
  154. .features = XEN_GNTTAB_OP_FEATURE_MAP_MULTIPLE,
  155. .open = libxengnttab_backend_open,
  156. .close = xengnttab_close,
  157. .grant_copy = libxengnttab_fallback_grant_copy,
  158. .set_max_grants = xengnttab_set_max_grants,
  159. .map_refs = xengnttab_map_domain_grant_refs,
  160. .unmap = libxengnttab_backend_unmap,
  161. };
  162. static void *libxenforeignmem_backend_map(uint32_t dom, void *addr, int prot,
  163. size_t pages, xen_pfn_t *pfns,
  164. int *errs)
  165. {
  166. return xenforeignmemory_map2(xen_fmem, dom, addr, prot, 0, pages, pfns,
  167. errs);
  168. }
  169. static int libxenforeignmem_backend_unmap(void *addr, size_t pages)
  170. {
  171. return xenforeignmemory_unmap(xen_fmem, addr, pages);
  172. }
  173. struct foreignmem_backend_ops libxenforeignmem_backend_ops = {
  174. .map = libxenforeignmem_backend_map,
  175. .unmap = libxenforeignmem_backend_unmap,
  176. };
  177. struct qemu_xs_handle {
  178. struct xs_handle *xsh;
  179. NotifierList notifiers;
  180. };
  181. static void watch_event(void *opaque)
  182. {
  183. struct qemu_xs_handle *h = opaque;
  184. for (;;) {
  185. char **v = xs_check_watch(h->xsh);
  186. if (!v) {
  187. break;
  188. }
  189. notifier_list_notify(&h->notifiers, v);
  190. free(v);
  191. }
  192. }
  193. static struct qemu_xs_handle *libxenstore_open(void)
  194. {
  195. struct xs_handle *xsh = xs_open(0);
  196. struct qemu_xs_handle *h;
  197. if (!xsh) {
  198. return NULL;
  199. }
  200. h = g_new0(struct qemu_xs_handle, 1);
  201. h->xsh = xsh;
  202. notifier_list_init(&h->notifiers);
  203. qemu_set_fd_handler(xs_fileno(h->xsh), watch_event, NULL, h);
  204. return h;
  205. }
  206. static void libxenstore_close(struct qemu_xs_handle *h)
  207. {
  208. g_assert(notifier_list_empty(&h->notifiers));
  209. qemu_set_fd_handler(xs_fileno(h->xsh), NULL, NULL, NULL);
  210. xs_close(h->xsh);
  211. g_free(h);
  212. }
  213. static char *libxenstore_get_domain_path(struct qemu_xs_handle *h,
  214. unsigned int domid)
  215. {
  216. return xs_get_domain_path(h->xsh, domid);
  217. }
  218. static char **libxenstore_directory(struct qemu_xs_handle *h,
  219. xs_transaction_t t, const char *path,
  220. unsigned int *num)
  221. {
  222. return xs_directory(h->xsh, t, path, num);
  223. }
  224. static void *libxenstore_read(struct qemu_xs_handle *h, xs_transaction_t t,
  225. const char *path, unsigned int *len)
  226. {
  227. return xs_read(h->xsh, t, path, len);
  228. }
  229. static bool libxenstore_write(struct qemu_xs_handle *h, xs_transaction_t t,
  230. const char *path, const void *data,
  231. unsigned int len)
  232. {
  233. return xs_write(h->xsh, t, path, data, len);
  234. }
  235. static bool libxenstore_create(struct qemu_xs_handle *h, xs_transaction_t t,
  236. unsigned int owner, unsigned int domid,
  237. unsigned int perms, const char *path)
  238. {
  239. struct xs_permissions perms_list[] = {
  240. {
  241. .id = owner,
  242. .perms = XS_PERM_NONE,
  243. },
  244. {
  245. .id = domid,
  246. .perms = perms,
  247. },
  248. };
  249. if (!xs_mkdir(h->xsh, t, path)) {
  250. return false;
  251. }
  252. return xs_set_permissions(h->xsh, t, path, perms_list,
  253. ARRAY_SIZE(perms_list));
  254. }
  255. static bool libxenstore_destroy(struct qemu_xs_handle *h, xs_transaction_t t,
  256. const char *path)
  257. {
  258. return xs_rm(h->xsh, t, path);
  259. }
  260. struct qemu_xs_watch {
  261. char *path;
  262. char *token;
  263. xs_watch_fn fn;
  264. void *opaque;
  265. Notifier notifier;
  266. };
  267. static void watch_notify(Notifier *n, void *data)
  268. {
  269. struct qemu_xs_watch *w = container_of(n, struct qemu_xs_watch, notifier);
  270. const char **v = data;
  271. if (!strcmp(w->token, v[XS_WATCH_TOKEN])) {
  272. w->fn(w->opaque, v[XS_WATCH_PATH]);
  273. }
  274. }
  275. static struct qemu_xs_watch *new_watch(const char *path, xs_watch_fn fn,
  276. void *opaque)
  277. {
  278. struct qemu_xs_watch *w = g_new0(struct qemu_xs_watch, 1);
  279. QemuUUID uuid;
  280. qemu_uuid_generate(&uuid);
  281. w->token = qemu_uuid_unparse_strdup(&uuid);
  282. w->path = g_strdup(path);
  283. w->fn = fn;
  284. w->opaque = opaque;
  285. w->notifier.notify = watch_notify;
  286. return w;
  287. }
  288. static void free_watch(struct qemu_xs_watch *w)
  289. {
  290. g_free(w->token);
  291. g_free(w->path);
  292. g_free(w);
  293. }
  294. static struct qemu_xs_watch *libxenstore_watch(struct qemu_xs_handle *h,
  295. const char *path, xs_watch_fn fn,
  296. void *opaque)
  297. {
  298. struct qemu_xs_watch *w = new_watch(path, fn, opaque);
  299. notifier_list_add(&h->notifiers, &w->notifier);
  300. if (!xs_watch(h->xsh, path, w->token)) {
  301. notifier_remove(&w->notifier);
  302. free_watch(w);
  303. return NULL;
  304. }
  305. return w;
  306. }
  307. static void libxenstore_unwatch(struct qemu_xs_handle *h,
  308. struct qemu_xs_watch *w)
  309. {
  310. xs_unwatch(h->xsh, w->path, w->token);
  311. notifier_remove(&w->notifier);
  312. free_watch(w);
  313. }
  314. static xs_transaction_t libxenstore_transaction_start(struct qemu_xs_handle *h)
  315. {
  316. return xs_transaction_start(h->xsh);
  317. }
  318. static bool libxenstore_transaction_end(struct qemu_xs_handle *h,
  319. xs_transaction_t t, bool abort)
  320. {
  321. return xs_transaction_end(h->xsh, t, abort);
  322. }
  323. struct xenstore_backend_ops libxenstore_backend_ops = {
  324. .open = libxenstore_open,
  325. .close = libxenstore_close,
  326. .get_domain_path = libxenstore_get_domain_path,
  327. .directory = libxenstore_directory,
  328. .read = libxenstore_read,
  329. .write = libxenstore_write,
  330. .create = libxenstore_create,
  331. .destroy = libxenstore_destroy,
  332. .watch = libxenstore_watch,
  333. .unwatch = libxenstore_unwatch,
  334. .transaction_start = libxenstore_transaction_start,
  335. .transaction_end = libxenstore_transaction_end,
  336. };
  337. void setup_xen_backend_ops(void)
  338. {
  339. #if CONFIG_XEN_CTRL_INTERFACE_VERSION >= 40800
  340. xengnttab_handle *xgt = xengnttab_open(NULL, 0);
  341. if (xgt) {
  342. if (xengnttab_grant_copy(xgt, 0, NULL) == 0) {
  343. libxengnttab_backend_ops.grant_copy = libxengnttab_backend_grant_copy;
  344. }
  345. xengnttab_close(xgt);
  346. }
  347. #endif
  348. xen_evtchn_ops = &libxenevtchn_backend_ops;
  349. xen_gnttab_ops = &libxengnttab_backend_ops;
  350. xen_foreignmem_ops = &libxenforeignmem_backend_ops;
  351. xen_xenstore_ops = &libxenstore_backend_ops;
  352. }