xen_shm_machdep.c revision 1.17 1 1.17 jdolecek /* $NetBSD: xen_shm_machdep.c,v 1.17 2021/02/21 20:11:59 jdolecek Exp $ */
2 1.2 bouyer
3 1.2 bouyer /*
4 1.2 bouyer * Copyright (c) 2006 Manuel Bouyer.
5 1.2 bouyer *
6 1.2 bouyer * Redistribution and use in source and binary forms, with or without
7 1.2 bouyer * modification, are permitted provided that the following conditions
8 1.2 bouyer * are met:
9 1.2 bouyer * 1. Redistributions of source code must retain the above copyright
10 1.2 bouyer * notice, this list of conditions and the following disclaimer.
11 1.2 bouyer * 2. Redistributions in binary form must reproduce the above copyright
12 1.2 bouyer * notice, this list of conditions and the following disclaimer in the
13 1.2 bouyer * documentation and/or other materials provided with the distribution.
14 1.2 bouyer *
15 1.2 bouyer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 1.2 bouyer * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 1.2 bouyer * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 1.2 bouyer * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 1.2 bouyer * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 1.2 bouyer * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 1.2 bouyer * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 1.2 bouyer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 1.2 bouyer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 1.2 bouyer * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 1.2 bouyer */
26 1.2 bouyer
27 1.3 bouyer #include <sys/cdefs.h>
28 1.17 jdolecek __KERNEL_RCSID(0, "$NetBSD: xen_shm_machdep.c,v 1.17 2021/02/21 20:11:59 jdolecek Exp $");
29 1.3 bouyer
30 1.2 bouyer #include <sys/types.h>
31 1.2 bouyer #include <sys/param.h>
32 1.2 bouyer #include <sys/systm.h>
33 1.2 bouyer #include <sys/queue.h>
34 1.2 bouyer #include <sys/vmem.h>
35 1.2 bouyer #include <sys/kernel.h>
36 1.2 bouyer #include <uvm/uvm.h>
37 1.2 bouyer
38 1.2 bouyer #include <machine/pmap.h>
39 1.2 bouyer #include <xen/hypervisor.h>
40 1.2 bouyer #include <xen/xen.h>
41 1.2 bouyer #include <xen/evtchn.h>
42 1.2 bouyer #include <xen/xen_shm.h>
43 1.2 bouyer
44 1.2 bouyer /*
45 1.12 maxv * Helper routines for the backend drivers. This implements the necessary
46 1.12 maxv * functions to map a bunch of pages from foreign domains into our kernel VM
47 1.2 bouyer * space, do I/O to it, and unmap it.
48 1.2 bouyer */
49 1.2 bouyer
50 1.17 jdolecek /*
51 1.17 jdolecek * Map the memory referenced via grefp to supplied VA space.
52 1.17 jdolecek * If there is a failure for particular gref, no memory is mapped
53 1.17 jdolecek * and error is returned.
54 1.17 jdolecek */
55 1.2 bouyer int
56 1.15 jdolecek xen_shm_map(int nentries, int domid, grant_ref_t *grefp, vaddr_t va,
57 1.2 bouyer grant_handle_t *handlep, int flags)
58 1.2 bouyer {
59 1.12 maxv gnttab_map_grant_ref_t op[XENSHM_MAX_PAGES_PER_REQUEST];
60 1.15 jdolecek int ret, i;
61 1.2 bouyer
62 1.2 bouyer #ifdef DIAGNOSTIC
63 1.2 bouyer if (nentries > XENSHM_MAX_PAGES_PER_REQUEST) {
64 1.12 maxv panic("xen_shm_map: %d entries", nentries);
65 1.2 bouyer }
66 1.2 bouyer #endif
67 1.12 maxv
68 1.2 bouyer for (i = 0; i < nentries; i++) {
69 1.15 jdolecek op[i].host_addr = va + i * PAGE_SIZE;
70 1.2 bouyer op[i].dom = domid;
71 1.2 bouyer op[i].ref = grefp[i];
72 1.2 bouyer op[i].flags = GNTMAP_host_map |
73 1.2 bouyer ((flags & XSHM_RO) ? GNTMAP_readonly : 0);
74 1.2 bouyer }
75 1.12 maxv
76 1.12 maxv ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, op, nentries);
77 1.17 jdolecek if (__predict_false(ret < 0)) {
78 1.17 jdolecek #ifdef DIAGNOSTIC
79 1.17 jdolecek printf("%s: HYPERVISOR_grant_table_op failed %d\n", __func__,
80 1.17 jdolecek ret);
81 1.17 jdolecek #endif
82 1.15 jdolecek return EINVAL;
83 1.12 maxv }
84 1.12 maxv
85 1.17 jdolecek /*
86 1.17 jdolecek * If ret is positive, it means there was an error in processing,
87 1.17 jdolecek * and only first ret entries were actually handled. If it's zero,
88 1.17 jdolecek * it only means all entries were processed, but there could still
89 1.17 jdolecek * be failure.
90 1.17 jdolecek */
91 1.17 jdolecek if (__predict_false(ret > 0 && ret < nentries)) {
92 1.17 jdolecek nentries = ret;
93 1.17 jdolecek }
94 1.17 jdolecek
95 1.2 bouyer for (i = 0; i < nentries; i++) {
96 1.17 jdolecek if (__predict_false(op[i].status)) {
97 1.15 jdolecek #ifdef DIAGNOSTIC
98 1.17 jdolecek printf("%s: op[%d] bad status %d gref %u\n", __func__,
99 1.17 jdolecek i, op[i].status, grefp[i]);
100 1.15 jdolecek #endif
101 1.17 jdolecek ret = 1;
102 1.17 jdolecek continue;
103 1.17 jdolecek }
104 1.2 bouyer handlep[i] = op[i].handle;
105 1.2 bouyer }
106 1.12 maxv
107 1.17 jdolecek if (__predict_false(ret > 0)) {
108 1.17 jdolecek int uncnt = 0;
109 1.17 jdolecek gnttab_unmap_grant_ref_t unop[XENSHM_MAX_PAGES_PER_REQUEST];
110 1.17 jdolecek
111 1.17 jdolecek /*
112 1.17 jdolecek * When returning error, make sure the successfully mapped
113 1.17 jdolecek * entries are unmapped before returning the error.
114 1.17 jdolecek * xen_shm_unmap() can't be used, it assumes
115 1.17 jdolecek * linear consecutive space.
116 1.17 jdolecek */
117 1.17 jdolecek for (i = uncnt = 0; i < nentries; i++) {
118 1.17 jdolecek if (op[i].status == 0) {
119 1.17 jdolecek unop[uncnt].host_addr = va + i * PAGE_SIZE;
120 1.17 jdolecek unop[uncnt].dev_bus_addr = 0;
121 1.17 jdolecek unop[uncnt].handle = handlep[i];
122 1.17 jdolecek uncnt++;
123 1.17 jdolecek }
124 1.17 jdolecek }
125 1.17 jdolecek if (uncnt > 0) {
126 1.17 jdolecek ret = HYPERVISOR_grant_table_op(
127 1.17 jdolecek GNTTABOP_unmap_grant_ref, unop, uncnt);
128 1.17 jdolecek if (ret != 0) {
129 1.17 jdolecek panic("%s: unmap on error recovery failed"
130 1.17 jdolecek " %d", __func__, ret);
131 1.17 jdolecek }
132 1.17 jdolecek }
133 1.17 jdolecek #ifdef DIAGNOSTIC
134 1.17 jdolecek printf("%s: HYPERVISOR_grant_table_op bad entry\n",
135 1.17 jdolecek __func__);
136 1.17 jdolecek #endif
137 1.17 jdolecek return EINVAL;
138 1.17 jdolecek }
139 1.17 jdolecek
140 1.2 bouyer return 0;
141 1.2 bouyer }
142 1.2 bouyer
143 1.2 bouyer void
144 1.2 bouyer xen_shm_unmap(vaddr_t va, int nentries, grant_handle_t *handlep)
145 1.2 bouyer {
146 1.2 bouyer gnttab_unmap_grant_ref_t op[XENSHM_MAX_PAGES_PER_REQUEST];
147 1.15 jdolecek int ret, i;
148 1.2 bouyer
149 1.2 bouyer #ifdef DIAGNOSTIC
150 1.2 bouyer if (nentries > XENSHM_MAX_PAGES_PER_REQUEST) {
151 1.12 maxv panic("xen_shm_unmap: %d entries", nentries);
152 1.2 bouyer }
153 1.2 bouyer #endif
154 1.2 bouyer
155 1.2 bouyer for (i = 0; i < nentries; i++) {
156 1.2 bouyer op[i].host_addr = va + i * PAGE_SIZE;
157 1.2 bouyer op[i].dev_bus_addr = 0;
158 1.2 bouyer op[i].handle = handlep[i];
159 1.2 bouyer }
160 1.12 maxv
161 1.2 bouyer ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref,
162 1.2 bouyer op, nentries);
163 1.12 maxv if (__predict_false(ret)) {
164 1.2 bouyer panic("xen_shm_unmap: unmap failed");
165 1.12 maxv }
166 1.2 bouyer }
167