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
libxengnttab_fallback_grant_copy(xengnttab_handle * xgt,bool to_domain,uint32_t domid,XenGrantCopySegment segs[],unsigned int nr_segs,Error ** errp)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
libxengnttab_backend_grant_copy(xengnttab_handle * xgt,bool to_domain,uint32_t domid,XenGrantCopySegment * segs,uint32_t nr_segs,Error ** errp)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
libxenevtchn_backend_open(void)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
libxengnttab_backend_open(void)170 static xengnttab_handle *libxengnttab_backend_open(void)
171 {
172 return xengnttab_open(NULL, 0);
173 }
174
libxengnttab_backend_unmap(xengnttab_handle * xgt,void * start_address,uint32_t * refs,uint32_t count)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
libxenforeignmem_backend_map(uint32_t dom,void * addr,int prot,size_t pages,xen_pfn_t * pfns,int * errs)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
libxenforeignmem_backend_unmap(void * addr,size_t pages)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
watch_event(void * opaque)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
libxenstore_open(void)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
libxenstore_close(struct qemu_xs_handle * h)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
libxenstore_get_domain_path(struct qemu_xs_handle * h,unsigned int domid)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
libxenstore_directory(struct qemu_xs_handle * h,xs_transaction_t t,const char * path,unsigned int * num)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
libxenstore_read(struct qemu_xs_handle * h,xs_transaction_t t,const char * path,unsigned int * len)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
libxenstore_write(struct qemu_xs_handle * h,xs_transaction_t t,const char * path,const void * data,unsigned int len)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
libxenstore_create(struct qemu_xs_handle * h,xs_transaction_t t,unsigned int owner,unsigned int domid,unsigned int perms,const char * path)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
libxenstore_destroy(struct qemu_xs_handle * h,xs_transaction_t t,const char * path)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
watch_notify(Notifier * n,void * data)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
new_watch(const char * path,xs_watch_fn fn,void * opaque)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
free_watch(struct qemu_xs_watch * w)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
libxenstore_watch(struct qemu_xs_handle * h,const char * path,xs_watch_fn fn,void * opaque)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
libxenstore_unwatch(struct qemu_xs_handle * h,struct qemu_xs_watch * w)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
libxenstore_transaction_start(struct qemu_xs_handle * h)381 static xs_transaction_t libxenstore_transaction_start(struct qemu_xs_handle *h)
382 {
383 return xs_transaction_start(h->xsh);
384 }
385
libxenstore_transaction_end(struct qemu_xs_handle * h,xs_transaction_t t,bool abort)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
setup_xen_backend_ops(void)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