xen_shm_machdep.c revision 1.18 1 1.18 bouyer /* $NetBSD: xen_shm_machdep.c,v 1.18 2022/09/01 12:29:00 bouyer 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.18 bouyer __KERNEL_RCSID(0, "$NetBSD: xen_shm_machdep.c,v 1.18 2022/09/01 12:29:00 bouyer Exp $");
29 1.18 bouyer
30 1.18 bouyer #include "opt_xen.h"
31 1.3 bouyer
32 1.2 bouyer #include <sys/types.h>
33 1.2 bouyer #include <sys/param.h>
34 1.2 bouyer #include <sys/systm.h>
35 1.2 bouyer #include <sys/queue.h>
36 1.2 bouyer #include <sys/vmem.h>
37 1.2 bouyer #include <sys/kernel.h>
38 1.2 bouyer #include <uvm/uvm.h>
39 1.2 bouyer
40 1.2 bouyer #include <machine/pmap.h>
41 1.2 bouyer #include <xen/hypervisor.h>
42 1.2 bouyer #include <xen/xen.h>
43 1.2 bouyer #include <xen/evtchn.h>
44 1.18 bouyer #include <xen/xenmem.h>
45 1.2 bouyer #include <xen/xen_shm.h>
46 1.2 bouyer
47 1.2 bouyer /*
48 1.12 maxv * Helper routines for the backend drivers. This implements the necessary
49 1.12 maxv * functions to map a bunch of pages from foreign domains into our kernel VM
50 1.2 bouyer * space, do I/O to it, and unmap it.
51 1.2 bouyer */
52 1.2 bouyer
53 1.17 jdolecek /*
54 1.17 jdolecek * Map the memory referenced via grefp to supplied VA space.
55 1.17 jdolecek * If there is a failure for particular gref, no memory is mapped
56 1.17 jdolecek * and error is returned.
57 1.17 jdolecek */
58 1.2 bouyer int
59 1.15 jdolecek xen_shm_map(int nentries, int domid, grant_ref_t *grefp, vaddr_t va,
60 1.2 bouyer grant_handle_t *handlep, int flags)
61 1.2 bouyer {
62 1.12 maxv gnttab_map_grant_ref_t op[XENSHM_MAX_PAGES_PER_REQUEST];
63 1.15 jdolecek int ret, i;
64 1.18 bouyer #ifndef XENPV
65 1.18 bouyer paddr_t base_paddr;
66 1.18 bouyer #endif
67 1.18 bouyer
68 1.2 bouyer
69 1.2 bouyer #ifdef DIAGNOSTIC
70 1.2 bouyer if (nentries > XENSHM_MAX_PAGES_PER_REQUEST) {
71 1.12 maxv panic("xen_shm_map: %d entries", nentries);
72 1.2 bouyer }
73 1.2 bouyer #endif
74 1.18 bouyer #ifndef XENPV
75 1.18 bouyer base_paddr = xenmem_alloc_pa(nentries * PAGE_SIZE, PAGE_SIZE, false);
76 1.18 bouyer if (base_paddr == 0)
77 1.18 bouyer return ENOMEM;
78 1.18 bouyer #endif
79 1.12 maxv
80 1.2 bouyer for (i = 0; i < nentries; i++) {
81 1.18 bouyer #ifndef XENPV
82 1.18 bouyer op[i].host_addr = base_paddr + i * PAGE_SIZE;
83 1.18 bouyer #else
84 1.15 jdolecek op[i].host_addr = va + i * PAGE_SIZE;
85 1.18 bouyer #endif
86 1.2 bouyer op[i].dom = domid;
87 1.2 bouyer op[i].ref = grefp[i];
88 1.2 bouyer op[i].flags = GNTMAP_host_map |
89 1.2 bouyer ((flags & XSHM_RO) ? GNTMAP_readonly : 0);
90 1.2 bouyer }
91 1.12 maxv
92 1.12 maxv ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, op, nentries);
93 1.17 jdolecek if (__predict_false(ret < 0)) {
94 1.17 jdolecek #ifdef DIAGNOSTIC
95 1.17 jdolecek printf("%s: HYPERVISOR_grant_table_op failed %d\n", __func__,
96 1.17 jdolecek ret);
97 1.17 jdolecek #endif
98 1.18 bouyer ret = EINVAL;
99 1.18 bouyer goto err1;
100 1.12 maxv }
101 1.12 maxv
102 1.17 jdolecek /*
103 1.17 jdolecek * If ret is positive, it means there was an error in processing,
104 1.17 jdolecek * and only first ret entries were actually handled. If it's zero,
105 1.17 jdolecek * it only means all entries were processed, but there could still
106 1.17 jdolecek * be failure.
107 1.17 jdolecek */
108 1.17 jdolecek if (__predict_false(ret > 0 && ret < nentries)) {
109 1.17 jdolecek nentries = ret;
110 1.17 jdolecek }
111 1.17 jdolecek
112 1.2 bouyer for (i = 0; i < nentries; i++) {
113 1.17 jdolecek if (__predict_false(op[i].status)) {
114 1.15 jdolecek #ifdef DIAGNOSTIC
115 1.17 jdolecek printf("%s: op[%d] bad status %d gref %u\n", __func__,
116 1.17 jdolecek i, op[i].status, grefp[i]);
117 1.15 jdolecek #endif
118 1.17 jdolecek ret = 1;
119 1.17 jdolecek continue;
120 1.17 jdolecek }
121 1.2 bouyer handlep[i] = op[i].handle;
122 1.2 bouyer }
123 1.12 maxv
124 1.17 jdolecek if (__predict_false(ret > 0)) {
125 1.17 jdolecek int uncnt = 0;
126 1.17 jdolecek gnttab_unmap_grant_ref_t unop[XENSHM_MAX_PAGES_PER_REQUEST];
127 1.17 jdolecek
128 1.17 jdolecek /*
129 1.17 jdolecek * When returning error, make sure the successfully mapped
130 1.17 jdolecek * entries are unmapped before returning the error.
131 1.17 jdolecek * xen_shm_unmap() can't be used, it assumes
132 1.17 jdolecek * linear consecutive space.
133 1.17 jdolecek */
134 1.17 jdolecek for (i = uncnt = 0; i < nentries; i++) {
135 1.17 jdolecek if (op[i].status == 0) {
136 1.18 bouyer #ifndef XENPV
137 1.18 bouyer unop[uncnt].host_addr =
138 1.18 bouyer base_paddr + i * PAGE_SIZE;
139 1.18 bouyer #else
140 1.17 jdolecek unop[uncnt].host_addr = va + i * PAGE_SIZE;
141 1.18 bouyer #endif
142 1.17 jdolecek unop[uncnt].dev_bus_addr = 0;
143 1.17 jdolecek unop[uncnt].handle = handlep[i];
144 1.17 jdolecek uncnt++;
145 1.17 jdolecek }
146 1.17 jdolecek }
147 1.17 jdolecek if (uncnt > 0) {
148 1.17 jdolecek ret = HYPERVISOR_grant_table_op(
149 1.17 jdolecek GNTTABOP_unmap_grant_ref, unop, uncnt);
150 1.17 jdolecek if (ret != 0) {
151 1.17 jdolecek panic("%s: unmap on error recovery failed"
152 1.17 jdolecek " %d", __func__, ret);
153 1.17 jdolecek }
154 1.17 jdolecek }
155 1.17 jdolecek #ifdef DIAGNOSTIC
156 1.17 jdolecek printf("%s: HYPERVISOR_grant_table_op bad entry\n",
157 1.17 jdolecek __func__);
158 1.17 jdolecek #endif
159 1.18 bouyer ret = EINVAL;
160 1.18 bouyer goto err1;
161 1.18 bouyer }
162 1.18 bouyer #ifndef XENPV
163 1.18 bouyer for (i = 0; i < nentries; i++) {
164 1.18 bouyer pmap_kenter_pa(va + i * PAGE_SIZE,
165 1.18 bouyer base_paddr + i * PAGE_SIZE,
166 1.18 bouyer VM_PROT_READ | VM_PROT_WRITE, 0);
167 1.17 jdolecek }
168 1.18 bouyer #endif
169 1.17 jdolecek
170 1.2 bouyer return 0;
171 1.18 bouyer err1:
172 1.18 bouyer #ifndef XENPV
173 1.18 bouyer xenmem_free_pa(base_paddr, nentries * PAGE_SIZE);
174 1.18 bouyer #endif
175 1.18 bouyer return ret;
176 1.2 bouyer }
177 1.2 bouyer
178 1.2 bouyer void
179 1.2 bouyer xen_shm_unmap(vaddr_t va, int nentries, grant_handle_t *handlep)
180 1.2 bouyer {
181 1.2 bouyer gnttab_unmap_grant_ref_t op[XENSHM_MAX_PAGES_PER_REQUEST];
182 1.15 jdolecek int ret, i;
183 1.18 bouyer #ifndef XENPV
184 1.18 bouyer paddr_t base_paddr;
185 1.18 bouyer if (pmap_extract(pmap_kernel(), va, &base_paddr) != true)
186 1.18 bouyer panic("xen_shm_unmap: unmapped va");
187 1.18 bouyer #endif
188 1.2 bouyer
189 1.2 bouyer #ifdef DIAGNOSTIC
190 1.2 bouyer if (nentries > XENSHM_MAX_PAGES_PER_REQUEST) {
191 1.12 maxv panic("xen_shm_unmap: %d entries", nentries);
192 1.2 bouyer }
193 1.2 bouyer #endif
194 1.2 bouyer
195 1.2 bouyer for (i = 0; i < nentries; i++) {
196 1.18 bouyer #ifndef XENPV
197 1.18 bouyer pmap_kremove(va + i * PAGE_SIZE, PAGE_SIZE);
198 1.18 bouyer op[i].host_addr = base_paddr + i * PAGE_SIZE;
199 1.18 bouyer #else
200 1.2 bouyer op[i].host_addr = va + i * PAGE_SIZE;
201 1.18 bouyer #endif
202 1.2 bouyer op[i].dev_bus_addr = 0;
203 1.2 bouyer op[i].handle = handlep[i];
204 1.2 bouyer }
205 1.12 maxv
206 1.2 bouyer ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref,
207 1.2 bouyer op, nentries);
208 1.12 maxv if (__predict_false(ret)) {
209 1.2 bouyer panic("xen_shm_unmap: unmap failed");
210 1.12 maxv }
211 1.18 bouyer #ifndef XENPV
212 1.18 bouyer xenmem_free_pa(base_paddr, PAGE_SIZE * nentries);
213 1.18 bouyer #endif
214 1.2 bouyer }
215