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.7.1. 32 */ 33 34 #include <xenevtchn.h> 35 #include <xengnttab.h> 36 #include <xenforeignmemory.h> 37 38 /* Xen before 4.8 */ 39 40 static int libxengnttab_fallback_grant_copy(xengnttab_handle *xgt, 41 bool to_domain, uint32_t domid, 42 XenGrantCopySegment segs[], 43 unsigned int nr_segs, Error **errp) 44 { 45 uint32_t *refs = g_new(uint32_t, nr_segs); 46 int prot = to_domain ? PROT_WRITE : PROT_READ; 47 void *map; 48 unsigned int i; 49 int rc = 0; 50 51 for (i = 0; i < nr_segs; i++) { 52 XenGrantCopySegment *seg = &segs[i]; 53 54 refs[i] = to_domain ? seg->dest.foreign.ref : 55 seg->source.foreign.ref; 56 } 57 map = xengnttab_map_domain_grant_refs(xgt, nr_segs, domid, refs, prot); 58 if (!map) { 59 if (errp) { 60 error_setg_errno(errp, errno, 61 "xengnttab_map_domain_grant_refs failed"); 62 } 63 rc = -errno; 64 goto done; 65 } 66 67 for (i = 0; i < nr_segs; i++) { 68 XenGrantCopySegment *seg = &segs[i]; 69 void *page = map + (i * XEN_PAGE_SIZE); 70 71 if (to_domain) { 72 memcpy(page + seg->dest.foreign.offset, seg->source.virt, 73 seg->len); 74 } else { 75 memcpy(seg->dest.virt, page + seg->source.foreign.offset, 76 seg->len); 77 } 78 } 79 80 if (xengnttab_unmap(xgt, map, nr_segs)) { 81 if (errp) { 82 error_setg_errno(errp, errno, "xengnttab_unmap failed"); 83 } 84 rc = -errno; 85 } 86 87 done: 88 g_free(refs); 89 return rc; 90 } 91 92 #if CONFIG_XEN_CTRL_INTERFACE_VERSION >= 40800 93 94 static int libxengnttab_backend_grant_copy(xengnttab_handle *xgt, 95 bool to_domain, uint32_t domid, 96 XenGrantCopySegment *segs, 97 uint32_t nr_segs, Error **errp) 98 { 99 xengnttab_grant_copy_segment_t *xengnttab_segs; 100 unsigned int i; 101 int rc; 102 103 xengnttab_segs = g_new0(xengnttab_grant_copy_segment_t, nr_segs); 104 105 for (i = 0; i < nr_segs; i++) { 106 XenGrantCopySegment *seg = &segs[i]; 107 xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i]; 108 109 if (to_domain) { 110 xengnttab_seg->flags = GNTCOPY_dest_gref; 111 xengnttab_seg->dest.foreign.domid = domid; 112 xengnttab_seg->dest.foreign.ref = seg->dest.foreign.ref; 113 xengnttab_seg->dest.foreign.offset = seg->dest.foreign.offset; 114 xengnttab_seg->source.virt = seg->source.virt; 115 } else { 116 xengnttab_seg->flags = GNTCOPY_source_gref; 117 xengnttab_seg->source.foreign.domid = domid; 118 xengnttab_seg->source.foreign.ref = seg->source.foreign.ref; 119 xengnttab_seg->source.foreign.offset = 120 seg->source.foreign.offset; 121 xengnttab_seg->dest.virt = seg->dest.virt; 122 } 123 124 xengnttab_seg->len = seg->len; 125 } 126 127 if (xengnttab_grant_copy(xgt, nr_segs, xengnttab_segs)) { 128 if (errp) { 129 error_setg_errno(errp, errno, "xengnttab_grant_copy failed"); 130 } 131 rc = -errno; 132 goto done; 133 } 134 135 rc = 0; 136 for (i = 0; i < nr_segs; i++) { 137 xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i]; 138 139 if (xengnttab_seg->status != GNTST_okay) { 140 if (errp) { 141 error_setg(errp, "xengnttab_grant_copy seg[%u] failed", i); 142 } 143 rc = -EIO; 144 break; 145 } 146 } 147 148 done: 149 g_free(xengnttab_segs); 150 return rc; 151 } 152 #endif 153 154 static xenevtchn_handle *libxenevtchn_backend_open(void) 155 { 156 return xenevtchn_open(NULL, 0); 157 } 158 159 struct evtchn_backend_ops libxenevtchn_backend_ops = { 160 .open = libxenevtchn_backend_open, 161 .close = xenevtchn_close, 162 .bind_interdomain = xenevtchn_bind_interdomain, 163 .unbind = xenevtchn_unbind, 164 .get_fd = xenevtchn_fd, 165 .notify = xenevtchn_notify, 166 .unmask = xenevtchn_unmask, 167 .pending = xenevtchn_pending, 168 }; 169 170 static xengnttab_handle *libxengnttab_backend_open(void) 171 { 172 return xengnttab_open(NULL, 0); 173 } 174 175 static int libxengnttab_backend_unmap(xengnttab_handle *xgt, 176 void *start_address, uint32_t *refs, 177 uint32_t count) 178 { 179 return xengnttab_unmap(xgt, start_address, count); 180 } 181 182 183 static struct gnttab_backend_ops libxengnttab_backend_ops = { 184 .features = XEN_GNTTAB_OP_FEATURE_MAP_MULTIPLE, 185 .open = libxengnttab_backend_open, 186 .close = xengnttab_close, 187 .grant_copy = libxengnttab_fallback_grant_copy, 188 .set_max_grants = xengnttab_set_max_grants, 189 .map_refs = xengnttab_map_domain_grant_refs, 190 .unmap = libxengnttab_backend_unmap, 191 }; 192 193 static void *libxenforeignmem_backend_map(uint32_t dom, void *addr, int prot, 194 size_t pages, xen_pfn_t *pfns, 195 int *errs) 196 { 197 return xenforeignmemory_map2(xen_fmem, dom, addr, prot, 0, pages, pfns, 198 errs); 199 } 200 201 static int libxenforeignmem_backend_unmap(void *addr, size_t pages) 202 { 203 return xenforeignmemory_unmap(xen_fmem, addr, pages); 204 } 205 206 struct foreignmem_backend_ops libxenforeignmem_backend_ops = { 207 .map = libxenforeignmem_backend_map, 208 .unmap = libxenforeignmem_backend_unmap, 209 }; 210 211 struct qemu_xs_handle { 212 struct xs_handle *xsh; 213 NotifierList notifiers; 214 }; 215 216 static void watch_event(void *opaque) 217 { 218 struct qemu_xs_handle *h = opaque; 219 220 for (;;) { 221 char **v = xs_check_watch(h->xsh); 222 223 if (!v) { 224 break; 225 } 226 227 notifier_list_notify(&h->notifiers, v); 228 free(v); 229 } 230 } 231 232 static struct qemu_xs_handle *libxenstore_open(void) 233 { 234 struct xs_handle *xsh = xs_open(0); 235 struct qemu_xs_handle *h; 236 237 if (!xsh) { 238 return NULL; 239 } 240 241 h = g_new0(struct qemu_xs_handle, 1); 242 h->xsh = xsh; 243 244 notifier_list_init(&h->notifiers); 245 qemu_set_fd_handler(xs_fileno(h->xsh), watch_event, NULL, h); 246 247 return h; 248 } 249 250 static void libxenstore_close(struct qemu_xs_handle *h) 251 { 252 g_assert(notifier_list_empty(&h->notifiers)); 253 qemu_set_fd_handler(xs_fileno(h->xsh), NULL, NULL, NULL); 254 xs_close(h->xsh); 255 g_free(h); 256 } 257 258 static char *libxenstore_get_domain_path(struct qemu_xs_handle *h, 259 unsigned int domid) 260 { 261 return xs_get_domain_path(h->xsh, domid); 262 } 263 264 static char **libxenstore_directory(struct qemu_xs_handle *h, 265 xs_transaction_t t, const char *path, 266 unsigned int *num) 267 { 268 return xs_directory(h->xsh, t, path, num); 269 } 270 271 static void *libxenstore_read(struct qemu_xs_handle *h, xs_transaction_t t, 272 const char *path, unsigned int *len) 273 { 274 return xs_read(h->xsh, t, path, len); 275 } 276 277 static bool libxenstore_write(struct qemu_xs_handle *h, xs_transaction_t t, 278 const char *path, const void *data, 279 unsigned int len) 280 { 281 return xs_write(h->xsh, t, path, data, len); 282 } 283 284 static bool libxenstore_create(struct qemu_xs_handle *h, xs_transaction_t t, 285 unsigned int owner, unsigned int domid, 286 unsigned int perms, const char *path) 287 { 288 struct xs_permissions perms_list[] = { 289 { 290 .id = owner, 291 .perms = XS_PERM_NONE, 292 }, 293 { 294 .id = domid, 295 .perms = perms, 296 }, 297 }; 298 299 if (!xs_mkdir(h->xsh, t, path)) { 300 return false; 301 } 302 303 return xs_set_permissions(h->xsh, t, path, perms_list, 304 ARRAY_SIZE(perms_list)); 305 } 306 307 static bool libxenstore_destroy(struct qemu_xs_handle *h, xs_transaction_t t, 308 const char *path) 309 { 310 return xs_rm(h->xsh, t, path); 311 } 312 313 struct qemu_xs_watch { 314 char *path; 315 char *token; 316 xs_watch_fn fn; 317 void *opaque; 318 Notifier notifier; 319 }; 320 321 static void watch_notify(Notifier *n, void *data) 322 { 323 struct qemu_xs_watch *w = container_of(n, struct qemu_xs_watch, notifier); 324 const char **v = data; 325 326 if (!strcmp(w->token, v[XS_WATCH_TOKEN])) { 327 w->fn(w->opaque, v[XS_WATCH_PATH]); 328 } 329 } 330 331 static struct qemu_xs_watch *new_watch(const char *path, xs_watch_fn fn, 332 void *opaque) 333 { 334 struct qemu_xs_watch *w = g_new0(struct qemu_xs_watch, 1); 335 QemuUUID uuid; 336 337 qemu_uuid_generate(&uuid); 338 339 w->token = qemu_uuid_unparse_strdup(&uuid); 340 w->path = g_strdup(path); 341 w->fn = fn; 342 w->opaque = opaque; 343 w->notifier.notify = watch_notify; 344 345 return w; 346 } 347 348 static void free_watch(struct qemu_xs_watch *w) 349 { 350 g_free(w->token); 351 g_free(w->path); 352 353 g_free(w); 354 } 355 356 static struct qemu_xs_watch *libxenstore_watch(struct qemu_xs_handle *h, 357 const char *path, xs_watch_fn fn, 358 void *opaque) 359 { 360 struct qemu_xs_watch *w = new_watch(path, fn, opaque); 361 362 notifier_list_add(&h->notifiers, &w->notifier); 363 364 if (!xs_watch(h->xsh, path, w->token)) { 365 notifier_remove(&w->notifier); 366 free_watch(w); 367 return NULL; 368 } 369 370 return w; 371 } 372 373 static void libxenstore_unwatch(struct qemu_xs_handle *h, 374 struct qemu_xs_watch *w) 375 { 376 xs_unwatch(h->xsh, w->path, w->token); 377 notifier_remove(&w->notifier); 378 free_watch(w); 379 } 380 381 static xs_transaction_t libxenstore_transaction_start(struct qemu_xs_handle *h) 382 { 383 return xs_transaction_start(h->xsh); 384 } 385 386 static bool libxenstore_transaction_end(struct qemu_xs_handle *h, 387 xs_transaction_t t, bool abort) 388 { 389 return xs_transaction_end(h->xsh, t, abort); 390 } 391 392 struct xenstore_backend_ops libxenstore_backend_ops = { 393 .open = libxenstore_open, 394 .close = libxenstore_close, 395 .get_domain_path = libxenstore_get_domain_path, 396 .directory = libxenstore_directory, 397 .read = libxenstore_read, 398 .write = libxenstore_write, 399 .create = libxenstore_create, 400 .destroy = libxenstore_destroy, 401 .watch = libxenstore_watch, 402 .unwatch = libxenstore_unwatch, 403 .transaction_start = libxenstore_transaction_start, 404 .transaction_end = libxenstore_transaction_end, 405 }; 406 407 void setup_xen_backend_ops(void) 408 { 409 #if CONFIG_XEN_CTRL_INTERFACE_VERSION >= 40800 410 xengnttab_handle *xgt = xengnttab_open(NULL, 0); 411 412 if (xgt) { 413 if (xengnttab_grant_copy(xgt, 0, NULL) == 0) { 414 libxengnttab_backend_ops.grant_copy = libxengnttab_backend_grant_copy; 415 } 416 xengnttab_close(xgt); 417 } 418 #endif 419 xen_evtchn_ops = &libxenevtchn_backend_ops; 420 xen_gnttab_ops = &libxengnttab_backend_ops; 421 xen_foreignmem_ops = &libxenforeignmem_backend_ops; 422 xen_xenstore_ops = &libxenstore_backend_ops; 423 } 424