2 * QEMU Xen backend support: Operations for true Xen
4 * Copyright © 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
6 * Authors: David Woodhouse <dwmw2@infradead.org>
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.
12 #include "qemu/osdep.h"
13 #include "qemu/uuid.h"
14 #include "qapi/error.h"
16 #include "hw/xen/xen_native.h"
17 #include "hw/xen/xen_backend_ops.h"
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
24 #undef XC_WANT_COMPAT_EVTCHN_API
25 #undef XC_WANT_COMPAT_GNTTAB_API
26 #undef XC_WANT_COMPAT_MAP_FOREIGN_API
31 * We don't support Xen prior to 4.7.1.
34 #include <xenevtchn.h>
35 #include <xengnttab.h>
36 #include <xenforeignmemory.h>
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
)
45 uint32_t *refs
= g_new(uint32_t, nr_segs
);
46 int prot
= to_domain
? PROT_WRITE
: PROT_READ
;
51 for (i
= 0; i
< nr_segs
; i
++) {
52 XenGrantCopySegment
*seg
= &segs
[i
];
54 refs
[i
] = to_domain
? seg
->dest
.foreign
.ref
:
55 seg
->source
.foreign
.ref
;
57 map
= xengnttab_map_domain_grant_refs(xgt
, nr_segs
, domid
, refs
, prot
);
60 error_setg_errno(errp
, errno
,
61 "xengnttab_map_domain_grant_refs failed");
67 for (i
= 0; i
< nr_segs
; i
++) {
68 XenGrantCopySegment
*seg
= &segs
[i
];
69 void *page
= map
+ (i
* XEN_PAGE_SIZE
);
72 memcpy(page
+ seg
->dest
.foreign
.offset
, seg
->source
.virt
,
75 memcpy(seg
->dest
.virt
, page
+ seg
->source
.foreign
.offset
,
80 if (xengnttab_unmap(xgt
, map
, nr_segs
)) {
82 error_setg_errno(errp
, errno
, "xengnttab_unmap failed");
92 #if CONFIG_XEN_CTRL_INTERFACE_VERSION >= 40800
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
)
99 xengnttab_grant_copy_segment_t
*xengnttab_segs
;
103 xengnttab_segs
= g_new0(xengnttab_grant_copy_segment_t
, nr_segs
);
105 for (i
= 0; i
< nr_segs
; i
++) {
106 XenGrantCopySegment
*seg
= &segs
[i
];
107 xengnttab_grant_copy_segment_t
*xengnttab_seg
= &xengnttab_segs
[i
];
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
;
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
;
124 xengnttab_seg
->len
= seg
->len
;
127 if (xengnttab_grant_copy(xgt
, nr_segs
, xengnttab_segs
)) {
129 error_setg_errno(errp
, errno
, "xengnttab_grant_copy failed");
136 for (i
= 0; i
< nr_segs
; i
++) {
137 xengnttab_grant_copy_segment_t
*xengnttab_seg
= &xengnttab_segs
[i
];
139 if (xengnttab_seg
->status
!= GNTST_okay
) {
141 error_setg(errp
, "xengnttab_grant_copy seg[%u] failed", i
);
149 g_free(xengnttab_segs
);
154 static xenevtchn_handle
*libxenevtchn_backend_open(void)
156 return xenevtchn_open(NULL
, 0);
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
,
170 static xengnttab_handle
*libxengnttab_backend_open(void)
172 return xengnttab_open(NULL
, 0);
175 static int libxengnttab_backend_unmap(xengnttab_handle
*xgt
,
176 void *start_address
, uint32_t *refs
,
179 return xengnttab_unmap(xgt
, start_address
, count
);
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
,
193 static void *libxenforeignmem_backend_map(uint32_t dom
, void *addr
, int prot
,
194 size_t pages
, xen_pfn_t
*pfns
,
197 return xenforeignmemory_map2(xen_fmem
, dom
, addr
, prot
, 0, pages
, pfns
,
201 static int libxenforeignmem_backend_unmap(void *addr
, size_t pages
)
203 return xenforeignmemory_unmap(xen_fmem
, addr
, pages
);
206 struct foreignmem_backend_ops libxenforeignmem_backend_ops
= {
207 .map
= libxenforeignmem_backend_map
,
208 .unmap
= libxenforeignmem_backend_unmap
,
211 struct qemu_xs_handle
{
212 struct xs_handle
*xsh
;
213 NotifierList notifiers
;
216 static void watch_event(void *opaque
)
218 struct qemu_xs_handle
*h
= opaque
;
221 char **v
= xs_check_watch(h
->xsh
);
227 notifier_list_notify(&h
->notifiers
, v
);
232 static struct qemu_xs_handle
*libxenstore_open(void)
234 struct xs_handle
*xsh
= xs_open(0);
235 struct qemu_xs_handle
*h
;
241 h
= g_new0(struct qemu_xs_handle
, 1);
244 notifier_list_init(&h
->notifiers
);
245 qemu_set_fd_handler(xs_fileno(h
->xsh
), watch_event
, NULL
, h
);
250 static void libxenstore_close(struct qemu_xs_handle
*h
)
252 g_assert(notifier_list_empty(&h
->notifiers
));
253 qemu_set_fd_handler(xs_fileno(h
->xsh
), NULL
, NULL
, NULL
);
258 static char *libxenstore_get_domain_path(struct qemu_xs_handle
*h
,
261 return xs_get_domain_path(h
->xsh
, domid
);
264 static char **libxenstore_directory(struct qemu_xs_handle
*h
,
265 xs_transaction_t t
, const char *path
,
268 return xs_directory(h
->xsh
, t
, path
, num
);
271 static void *libxenstore_read(struct qemu_xs_handle
*h
, xs_transaction_t t
,
272 const char *path
, unsigned int *len
)
274 return xs_read(h
->xsh
, t
, path
, len
);
277 static bool libxenstore_write(struct qemu_xs_handle
*h
, xs_transaction_t t
,
278 const char *path
, const void *data
,
281 return xs_write(h
->xsh
, t
, path
, data
, len
);
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
)
288 struct xs_permissions perms_list
[] = {
291 .perms
= XS_PERM_NONE
,
299 if (!xs_mkdir(h
->xsh
, t
, path
)) {
303 return xs_set_permissions(h
->xsh
, t
, path
, perms_list
,
304 ARRAY_SIZE(perms_list
));
307 static bool libxenstore_destroy(struct qemu_xs_handle
*h
, xs_transaction_t t
,
310 return xs_rm(h
->xsh
, t
, path
);
313 struct qemu_xs_watch
{
321 static void watch_notify(Notifier
*n
, void *data
)
323 struct qemu_xs_watch
*w
= container_of(n
, struct qemu_xs_watch
, notifier
);
324 const char **v
= data
;
326 if (!strcmp(w
->token
, v
[XS_WATCH_TOKEN
])) {
327 w
->fn(w
->opaque
, v
[XS_WATCH_PATH
]);
331 static struct qemu_xs_watch
*new_watch(const char *path
, xs_watch_fn fn
,
334 struct qemu_xs_watch
*w
= g_new0(struct qemu_xs_watch
, 1);
337 qemu_uuid_generate(&uuid
);
339 w
->token
= qemu_uuid_unparse_strdup(&uuid
);
340 w
->path
= g_strdup(path
);
343 w
->notifier
.notify
= watch_notify
;
348 static void free_watch(struct qemu_xs_watch
*w
)
356 static struct qemu_xs_watch
*libxenstore_watch(struct qemu_xs_handle
*h
,
357 const char *path
, xs_watch_fn fn
,
360 struct qemu_xs_watch
*w
= new_watch(path
, fn
, opaque
);
362 notifier_list_add(&h
->notifiers
, &w
->notifier
);
364 if (!xs_watch(h
->xsh
, path
, w
->token
)) {
365 notifier_remove(&w
->notifier
);
373 static void libxenstore_unwatch(struct qemu_xs_handle
*h
,
374 struct qemu_xs_watch
*w
)
376 xs_unwatch(h
->xsh
, w
->path
, w
->token
);
377 notifier_remove(&w
->notifier
);
381 static xs_transaction_t
libxenstore_transaction_start(struct qemu_xs_handle
*h
)
383 return xs_transaction_start(h
->xsh
);
386 static bool libxenstore_transaction_end(struct qemu_xs_handle
*h
,
387 xs_transaction_t t
, bool abort
)
389 return xs_transaction_end(h
->xsh
, t
, abort
);
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
,
407 void setup_xen_backend_ops(void)
409 #if CONFIG_XEN_CTRL_INTERFACE_VERSION >= 40800
410 xengnttab_handle
*xgt
= xengnttab_open(NULL
, 0);
413 if (xengnttab_grant_copy(xgt
, 0, NULL
) == 0) {
414 libxengnttab_backend_ops
.grant_copy
= libxengnttab_backend_grant_copy
;
416 xengnttab_close(xgt
);
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
;