xref: /openbmc/qemu/hw/xen/xen-operations.c (revision 2df1eb27)
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