xen_shm_machdep.c revision 1.16.2.1 1 1.16.2.1 thorpej /* $NetBSD: xen_shm_machdep.c,v 1.16.2.1 2021/04/03 22:28:41 thorpej 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.16.2.1 thorpej __KERNEL_RCSID(0, "$NetBSD: xen_shm_machdep.c,v 1.16.2.1 2021/04/03 22:28:41 thorpej 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.16.2.1 thorpej /*
51 1.16.2.1 thorpej * Map the memory referenced via grefp to supplied VA space.
52 1.16.2.1 thorpej * If there is a failure for particular gref, no memory is mapped
53 1.16.2.1 thorpej * and error is returned.
54 1.16.2.1 thorpej */
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.16.2.1 thorpej if (__predict_false(ret < 0)) {
78 1.16.2.1 thorpej #ifdef DIAGNOSTIC
79 1.16.2.1 thorpej printf("%s: HYPERVISOR_grant_table_op failed %d\n", __func__,
80 1.16.2.1 thorpej ret);
81 1.16.2.1 thorpej #endif
82 1.15 jdolecek return EINVAL;
83 1.12 maxv }
84 1.12 maxv
85 1.16.2.1 thorpej /*
86 1.16.2.1 thorpej * If ret is positive, it means there was an error in processing,
87 1.16.2.1 thorpej * and only first ret entries were actually handled. If it's zero,
88 1.16.2.1 thorpej * it only means all entries were processed, but there could still
89 1.16.2.1 thorpej * be failure.
90 1.16.2.1 thorpej */
91 1.16.2.1 thorpej if (__predict_false(ret > 0 && ret < nentries)) {
92 1.16.2.1 thorpej nentries = ret;
93 1.16.2.1 thorpej }
94 1.16.2.1 thorpej
95 1.2 bouyer for (i = 0; i < nentries; i++) {
96 1.16.2.1 thorpej if (__predict_false(op[i].status)) {
97 1.15 jdolecek #ifdef DIAGNOSTIC
98 1.16.2.1 thorpej printf("%s: op[%d] bad status %d gref %u\n", __func__,
99 1.16.2.1 thorpej i, op[i].status, grefp[i]);
100 1.15 jdolecek #endif
101 1.16.2.1 thorpej ret = 1;
102 1.16.2.1 thorpej continue;
103 1.16.2.1 thorpej }
104 1.2 bouyer handlep[i] = op[i].handle;
105 1.2 bouyer }
106 1.12 maxv
107 1.16.2.1 thorpej if (__predict_false(ret > 0)) {
108 1.16.2.1 thorpej int uncnt = 0;
109 1.16.2.1 thorpej gnttab_unmap_grant_ref_t unop[XENSHM_MAX_PAGES_PER_REQUEST];
110 1.16.2.1 thorpej
111 1.16.2.1 thorpej /*
112 1.16.2.1 thorpej * When returning error, make sure the successfully mapped
113 1.16.2.1 thorpej * entries are unmapped before returning the error.
114 1.16.2.1 thorpej * xen_shm_unmap() can't be used, it assumes
115 1.16.2.1 thorpej * linear consecutive space.
116 1.16.2.1 thorpej */
117 1.16.2.1 thorpej for (i = uncnt = 0; i < nentries; i++) {
118 1.16.2.1 thorpej if (op[i].status == 0) {
119 1.16.2.1 thorpej unop[uncnt].host_addr = va + i * PAGE_SIZE;
120 1.16.2.1 thorpej unop[uncnt].dev_bus_addr = 0;
121 1.16.2.1 thorpej unop[uncnt].handle = handlep[i];
122 1.16.2.1 thorpej uncnt++;
123 1.16.2.1 thorpej }
124 1.16.2.1 thorpej }
125 1.16.2.1 thorpej if (uncnt > 0) {
126 1.16.2.1 thorpej ret = HYPERVISOR_grant_table_op(
127 1.16.2.1 thorpej GNTTABOP_unmap_grant_ref, unop, uncnt);
128 1.16.2.1 thorpej if (ret != 0) {
129 1.16.2.1 thorpej panic("%s: unmap on error recovery failed"
130 1.16.2.1 thorpej " %d", __func__, ret);
131 1.16.2.1 thorpej }
132 1.16.2.1 thorpej }
133 1.16.2.1 thorpej #ifdef DIAGNOSTIC
134 1.16.2.1 thorpej printf("%s: HYPERVISOR_grant_table_op bad entry\n",
135 1.16.2.1 thorpej __func__);
136 1.16.2.1 thorpej #endif
137 1.16.2.1 thorpej return EINVAL;
138 1.16.2.1 thorpej }
139 1.16.2.1 thorpej
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