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 12 #include "qemu/osdep.h" 13 #include "qemu/uuid.h" 14 #include "qapi/error.h" 15 16 #include "hw/xen/xen_native.h" 17 #include "hw/xen/xen_backend_ops.h" 18 19 /* 20 * If we have new enough libxenctrl then we do not want/need these compat 21 * interfaces, despite what the user supplied cflags might say. They 22 * must be undefined before including xenctrl.h 23 */ 24 #undef XC_WANT_COMPAT_EVTCHN_API 25 #undef XC_WANT_COMPAT_GNTTAB_API 26 #undef XC_WANT_COMPAT_MAP_FOREIGN_API 27 28 #include <xenctrl.h> 29 30 /* 31 * We don't support Xen prior to 4.2.0. 32 */ 33 34 /* Xen 4.2 through 4.6 */ 35 #if CONFIG_XEN_CTRL_INTERFACE_VERSION < 40701 36 37 typedef xc_evtchn xenevtchn_handle; 38 typedef evtchn_port_or_error_t xenevtchn_port_or_error_t; 39 40 #define xenevtchn_open(l, f) xc_evtchn_open(l, f); 41 #define xenevtchn_close(h) xc_evtchn_close(h) 42 #define xenevtchn_fd(h) xc_evtchn_fd(h) 43 #define xenevtchn_pending(h) xc_evtchn_pending(h) 44 #define xenevtchn_notify(h, p) xc_evtchn_notify(h, p) 45 #define xenevtchn_bind_interdomain(h, d, p) xc_evtchn_bind_interdomain(h, d, p) 46 #define xenevtchn_unmask(h, p) xc_evtchn_unmask(h, p) 47 #define xenevtchn_unbind(h, p) xc_evtchn_unbind(h, p) 48 49 typedef xc_gnttab xengnttab_handle; 50 51 #define xengnttab_open(l, f) xc_gnttab_open(l, f) 52 #define xengnttab_close(h) xc_gnttab_close(h) 53 #define xengnttab_set_max_grants(h, n) xc_gnttab_set_max_grants(h, n) 54 #define xengnttab_map_grant_ref(h, d, r, p) xc_gnttab_map_grant_ref(h, d, r, p) 55 #define xengnttab_unmap(h, a, n) xc_gnttab_munmap(h, a, n) 56 #define xengnttab_map_grant_refs(h, c, d, r, p) \ 57 xc_gnttab_map_grant_refs(h, c, d, r, p) 58 #define xengnttab_map_domain_grant_refs(h, c, d, r, p) \ 59 xc_gnttab_map_domain_grant_refs(h, c, d, r, p) 60 61 typedef xc_interface xenforeignmemory_handle; 62 63 #else /* CONFIG_XEN_CTRL_INTERFACE_VERSION >= 40701 */ 64 65 #include <xenevtchn.h> 66 #include <xengnttab.h> 67 #include <xenforeignmemory.h> 68 69 #endif 70 71 /* Xen before 4.8 */ 72 73 static int libxengnttab_fallback_grant_copy(xengnttab_handle *xgt, 74 bool to_domain, uint32_t domid, 75 XenGrantCopySegment segs[], 76 unsigned int nr_segs, Error **errp) 77 { 78 uint32_t *refs = g_new(uint32_t, nr_segs); 79 int prot = to_domain ? PROT_WRITE : PROT_READ; 80 void *map; 81 unsigned int i; 82 int rc = 0; 83 84 for (i = 0; i < nr_segs; i++) { 85 XenGrantCopySegment *seg = &segs[i]; 86 87 refs[i] = to_domain ? seg->dest.foreign.ref : 88 seg->source.foreign.ref; 89 } 90 map = xengnttab_map_domain_grant_refs(xgt, nr_segs, domid, refs, prot); 91 if (!map) { 92 if (errp) { 93 error_setg_errno(errp, errno, 94 "xengnttab_map_domain_grant_refs failed"); 95 } 96 rc = -errno; 97 goto done; 98 } 99 100 for (i = 0; i < nr_segs; i++) { 101 XenGrantCopySegment *seg = &segs[i]; 102 void *page = map + (i * XEN_PAGE_SIZE); 103 104 if (to_domain) { 105 memcpy(page + seg->dest.foreign.offset, seg->source.virt, 106 seg->len); 107 } else { 108 memcpy(seg->dest.virt, page + seg->source.foreign.offset, 109 seg->len); 110 } 111 } 112 113 if (xengnttab_unmap(xgt, map, nr_segs)) { 114 if (errp) { 115 error_setg_errno(errp, errno, "xengnttab_unmap failed"); 116 } 117 rc = -errno; 118 } 119 120 done: 121 g_free(refs); 122 return rc; 123 } 124 125 #if CONFIG_XEN_CTRL_INTERFACE_VERSION >= 40800 126 127 static int libxengnttab_backend_grant_copy(xengnttab_handle *xgt, 128 bool to_domain, uint32_t domid, 129 XenGrantCopySegment *segs, 130 uint32_t nr_segs, Error **errp) 131 { 132 xengnttab_grant_copy_segment_t *xengnttab_segs; 133 unsigned int i; 134 int rc; 135 136 xengnttab_segs = g_new0(xengnttab_grant_copy_segment_t, nr_segs); 137 138 for (i = 0; i < nr_segs; i++) { 139 XenGrantCopySegment *seg = &segs[i]; 140 xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i]; 141 142 if (to_domain) { 143 xengnttab_seg->flags = GNTCOPY_dest_gref; 144 xengnttab_seg->dest.foreign.domid = domid; 145 xengnttab_seg->dest.foreign.ref = seg->dest.foreign.ref; 146 xengnttab_seg->dest.foreign.offset = seg->dest.foreign.offset; 147 xengnttab_seg->source.virt = seg->source.virt; 148 } else { 149 xengnttab_seg->flags = GNTCOPY_source_gref; 150 xengnttab_seg->source.foreign.domid = domid; 151 xengnttab_seg->source.foreign.ref = seg->source.foreign.ref; 152 xengnttab_seg->source.foreign.offset = 153 seg->source.foreign.offset; 154 xengnttab_seg->dest.virt = seg->dest.virt; 155 } 156 157 xengnttab_seg->len = seg->len; 158 } 159 160 if (xengnttab_grant_copy(xgt, nr_segs, xengnttab_segs)) { 161 if (errp) { 162 error_setg_errno(errp, errno, "xengnttab_grant_copy failed"); 163 } 164 rc = -errno; 165 goto done; 166 } 167 168 rc = 0; 169 for (i = 0; i < nr_segs; i++) { 170 xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i]; 171 172 if (xengnttab_seg->status != GNTST_okay) { 173 if (errp) { 174 error_setg(errp, "xengnttab_grant_copy seg[%u] failed", i); 175 } 176 rc = -EIO; 177 break; 178 } 179 } 180 181 done: 182 g_free(xengnttab_segs); 183 return rc; 184 } 185 #endif 186 187 static xenevtchn_handle *libxenevtchn_backend_open(void) 188 { 189 return xenevtchn_open(NULL, 0); 190 } 191 192 struct evtchn_backend_ops libxenevtchn_backend_ops = { 193 .open = libxenevtchn_backend_open, 194 .close = xenevtchn_close, 195 .bind_interdomain = xenevtchn_bind_interdomain, 196 .unbind = xenevtchn_unbind, 197 .get_fd = xenevtchn_fd, 198 .notify = xenevtchn_notify, 199 .unmask = xenevtchn_unmask, 200 .pending = xenevtchn_pending, 201 }; 202 203 static xengnttab_handle *libxengnttab_backend_open(void) 204 { 205 return xengnttab_open(NULL, 0); 206 } 207 208 static int libxengnttab_backend_unmap(xengnttab_handle *xgt, 209 void *start_address, uint32_t *refs, 210 uint32_t count) 211 { 212 return xengnttab_unmap(xgt, start_address, count); 213 } 214 215 216 static struct gnttab_backend_ops libxengnttab_backend_ops = { 217 .features = XEN_GNTTAB_OP_FEATURE_MAP_MULTIPLE, 218 .open = libxengnttab_backend_open, 219 .close = xengnttab_close, 220 .grant_copy = libxengnttab_fallback_grant_copy, 221 .set_max_grants = xengnttab_set_max_grants, 222 .map_refs = xengnttab_map_domain_grant_refs, 223 .unmap = libxengnttab_backend_unmap, 224 }; 225 226 #if CONFIG_XEN_CTRL_INTERFACE_VERSION < 40701 227 228 static void *libxenforeignmem_backend_map(uint32_t dom, void *addr, int prot, 229 size_t pages, xfn_pfn_t *pfns, 230 int *errs) 231 { 232 if (errs) { 233 return xc_map_foreign_bulk(xen_xc, dom, prot, pfns, errs, pages); 234 } else { 235 return xc_map_foreign_pages(xen_xc, dom, prot, pfns, pages); 236 } 237 } 238 239 static int libxenforeignmem_backend_unmap(void *addr, size_t pages) 240 { 241 return munmap(addr, pages * XC_PAGE_SIZE); 242 } 243 244 #else /* CONFIG_XEN_CTRL_INTERFACE_VERSION >= 40701 */ 245 246 static void *libxenforeignmem_backend_map(uint32_t dom, void *addr, int prot, 247 size_t pages, xen_pfn_t *pfns, 248 int *errs) 249 { 250 return xenforeignmemory_map2(xen_fmem, dom, addr, prot, 0, pages, pfns, 251 errs); 252 } 253 254 static int libxenforeignmem_backend_unmap(void *addr, size_t pages) 255 { 256 return xenforeignmemory_unmap(xen_fmem, addr, pages); 257 } 258 259 #endif 260 261 struct foreignmem_backend_ops libxenforeignmem_backend_ops = { 262 .map = libxenforeignmem_backend_map, 263 .unmap = libxenforeignmem_backend_unmap, 264 }; 265 266 struct qemu_xs_handle { 267 struct xs_handle *xsh; 268 NotifierList notifiers; 269 }; 270 271 static void watch_event(void *opaque) 272 { 273 struct qemu_xs_handle *h = opaque; 274 275 for (;;) { 276 char **v = xs_check_watch(h->xsh); 277 278 if (!v) { 279 break; 280 } 281 282 notifier_list_notify(&h->notifiers, v); 283 free(v); 284 } 285 } 286 287 static struct qemu_xs_handle *libxenstore_open(void) 288 { 289 struct xs_handle *xsh = xs_open(0); 290 struct qemu_xs_handle *h = g_new0(struct qemu_xs_handle, 1); 291 292 if (!xsh) { 293 return NULL; 294 } 295 296 h = g_new0(struct qemu_xs_handle, 1); 297 h->xsh = xsh; 298 299 notifier_list_init(&h->notifiers); 300 qemu_set_fd_handler(xs_fileno(h->xsh), watch_event, NULL, h); 301 302 return h; 303 } 304 305 static void libxenstore_close(struct qemu_xs_handle *h) 306 { 307 g_assert(notifier_list_empty(&h->notifiers)); 308 qemu_set_fd_handler(xs_fileno(h->xsh), NULL, NULL, NULL); 309 xs_close(h->xsh); 310 g_free(h); 311 } 312 313 static char *libxenstore_get_domain_path(struct qemu_xs_handle *h, 314 unsigned int domid) 315 { 316 return xs_get_domain_path(h->xsh, domid); 317 } 318 319 static char **libxenstore_directory(struct qemu_xs_handle *h, 320 xs_transaction_t t, const char *path, 321 unsigned int *num) 322 { 323 return xs_directory(h->xsh, t, path, num); 324 } 325 326 static void *libxenstore_read(struct qemu_xs_handle *h, xs_transaction_t t, 327 const char *path, unsigned int *len) 328 { 329 return xs_read(h->xsh, t, path, len); 330 } 331 332 static bool libxenstore_write(struct qemu_xs_handle *h, xs_transaction_t t, 333 const char *path, const void *data, 334 unsigned int len) 335 { 336 return xs_write(h->xsh, t, path, data, len); 337 } 338 339 static bool libxenstore_create(struct qemu_xs_handle *h, xs_transaction_t t, 340 unsigned int owner, unsigned int domid, 341 unsigned int perms, const char *path) 342 { 343 struct xs_permissions perms_list[] = { 344 { 345 .id = owner, 346 .perms = XS_PERM_NONE, 347 }, 348 { 349 .id = domid, 350 .perms = perms, 351 }, 352 }; 353 354 if (!xs_mkdir(h->xsh, t, path)) { 355 return false; 356 } 357 358 return xs_set_permissions(h->xsh, t, path, perms_list, 359 ARRAY_SIZE(perms_list)); 360 } 361 362 static bool libxenstore_destroy(struct qemu_xs_handle *h, xs_transaction_t t, 363 const char *path) 364 { 365 return xs_rm(h->xsh, t, path); 366 } 367 368 struct qemu_xs_watch { 369 char *path; 370 char *token; 371 xs_watch_fn fn; 372 void *opaque; 373 Notifier notifier; 374 }; 375 376 static void watch_notify(Notifier *n, void *data) 377 { 378 struct qemu_xs_watch *w = container_of(n, struct qemu_xs_watch, notifier); 379 const char **v = data; 380 381 if (!strcmp(w->token, v[XS_WATCH_TOKEN])) { 382 w->fn(w->opaque, v[XS_WATCH_PATH]); 383 } 384 } 385 386 static struct qemu_xs_watch *new_watch(const char *path, xs_watch_fn fn, 387 void *opaque) 388 { 389 struct qemu_xs_watch *w = g_new0(struct qemu_xs_watch, 1); 390 QemuUUID uuid; 391 392 qemu_uuid_generate(&uuid); 393 394 w->token = qemu_uuid_unparse_strdup(&uuid); 395 w->path = g_strdup(path); 396 w->fn = fn; 397 w->opaque = opaque; 398 w->notifier.notify = watch_notify; 399 400 return w; 401 } 402 403 static void free_watch(struct qemu_xs_watch *w) 404 { 405 g_free(w->token); 406 g_free(w->path); 407 408 g_free(w); 409 } 410 411 static struct qemu_xs_watch *libxenstore_watch(struct qemu_xs_handle *h, 412 const char *path, xs_watch_fn fn, 413 void *opaque) 414 { 415 struct qemu_xs_watch *w = new_watch(path, fn, opaque); 416 417 notifier_list_add(&h->notifiers, &w->notifier); 418 419 if (!xs_watch(h->xsh, path, w->token)) { 420 notifier_remove(&w->notifier); 421 free_watch(w); 422 return NULL; 423 } 424 425 return w; 426 } 427 428 static void libxenstore_unwatch(struct qemu_xs_handle *h, 429 struct qemu_xs_watch *w) 430 { 431 xs_unwatch(h->xsh, w->path, w->token); 432 notifier_remove(&w->notifier); 433 free_watch(w); 434 } 435 436 static xs_transaction_t libxenstore_transaction_start(struct qemu_xs_handle *h) 437 { 438 return xs_transaction_start(h->xsh); 439 } 440 441 static bool libxenstore_transaction_end(struct qemu_xs_handle *h, 442 xs_transaction_t t, bool abort) 443 { 444 return xs_transaction_end(h->xsh, t, abort); 445 } 446 447 struct xenstore_backend_ops libxenstore_backend_ops = { 448 .open = libxenstore_open, 449 .close = libxenstore_close, 450 .get_domain_path = libxenstore_get_domain_path, 451 .directory = libxenstore_directory, 452 .read = libxenstore_read, 453 .write = libxenstore_write, 454 .create = libxenstore_create, 455 .destroy = libxenstore_destroy, 456 .watch = libxenstore_watch, 457 .unwatch = libxenstore_unwatch, 458 .transaction_start = libxenstore_transaction_start, 459 .transaction_end = libxenstore_transaction_end, 460 }; 461 462 void setup_xen_backend_ops(void) 463 { 464 #if CONFIG_XEN_CTRL_INTERFACE_VERSION >= 40800 465 xengnttab_handle *xgt = xengnttab_open(NULL, 0); 466 467 if (xgt) { 468 if (xengnttab_grant_copy(xgt, 0, NULL) == 0) { 469 libxengnttab_backend_ops.grant_copy = libxengnttab_backend_grant_copy; 470 } 471 xengnttab_close(xgt); 472 } 473 #endif 474 xen_evtchn_ops = &libxenevtchn_backend_ops; 475 xen_gnttab_ops = &libxengnttab_backend_ops; 476 xen_foreignmem_ops = &libxenforeignmem_backend_ops; 477 xen_xenstore_ops = &libxenstore_backend_ops; 478 } 479