1*5dac1986Sbouyer /* $NetBSD: xen_shm_machdep.c,v 1.18 2022/09/01 12:29:00 bouyer Exp $ */
24e541343Sbouyer
34e541343Sbouyer /*
44e541343Sbouyer * Copyright (c) 2006 Manuel Bouyer.
54e541343Sbouyer *
64e541343Sbouyer * Redistribution and use in source and binary forms, with or without
74e541343Sbouyer * modification, are permitted provided that the following conditions
84e541343Sbouyer * are met:
94e541343Sbouyer * 1. Redistributions of source code must retain the above copyright
104e541343Sbouyer * notice, this list of conditions and the following disclaimer.
114e541343Sbouyer * 2. Redistributions in binary form must reproduce the above copyright
124e541343Sbouyer * notice, this list of conditions and the following disclaimer in the
134e541343Sbouyer * documentation and/or other materials provided with the distribution.
144e541343Sbouyer *
154e541343Sbouyer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
164e541343Sbouyer * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
174e541343Sbouyer * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
184e541343Sbouyer * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
194e541343Sbouyer * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
204e541343Sbouyer * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
214e541343Sbouyer * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
224e541343Sbouyer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
234e541343Sbouyer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
244e541343Sbouyer * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
254e541343Sbouyer */
264e541343Sbouyer
27a9cd1764Sbouyer #include <sys/cdefs.h>
28*5dac1986Sbouyer __KERNEL_RCSID(0, "$NetBSD: xen_shm_machdep.c,v 1.18 2022/09/01 12:29:00 bouyer Exp $");
29*5dac1986Sbouyer
30*5dac1986Sbouyer #include "opt_xen.h"
31a9cd1764Sbouyer
324e541343Sbouyer #include <sys/types.h>
334e541343Sbouyer #include <sys/param.h>
344e541343Sbouyer #include <sys/systm.h>
354e541343Sbouyer #include <sys/queue.h>
364e541343Sbouyer #include <sys/vmem.h>
374e541343Sbouyer #include <sys/kernel.h>
384e541343Sbouyer #include <uvm/uvm.h>
394e541343Sbouyer
404e541343Sbouyer #include <machine/pmap.h>
414e541343Sbouyer #include <xen/hypervisor.h>
424e541343Sbouyer #include <xen/xen.h>
434e541343Sbouyer #include <xen/evtchn.h>
44*5dac1986Sbouyer #include <xen/xenmem.h>
454e541343Sbouyer #include <xen/xen_shm.h>
464e541343Sbouyer
474e541343Sbouyer /*
482542c094Smaxv * Helper routines for the backend drivers. This implements the necessary
492542c094Smaxv * functions to map a bunch of pages from foreign domains into our kernel VM
504e541343Sbouyer * space, do I/O to it, and unmap it.
514e541343Sbouyer */
524e541343Sbouyer
53d477b21bSjdolecek /*
54d477b21bSjdolecek * Map the memory referenced via grefp to supplied VA space.
55d477b21bSjdolecek * If there is a failure for particular gref, no memory is mapped
56d477b21bSjdolecek * and error is returned.
57d477b21bSjdolecek */
584e541343Sbouyer int
xen_shm_map(int nentries,int domid,grant_ref_t * grefp,vaddr_t va,grant_handle_t * handlep,int flags)598d1b8859Sjdolecek xen_shm_map(int nentries, int domid, grant_ref_t *grefp, vaddr_t va,
604e541343Sbouyer grant_handle_t *handlep, int flags)
614e541343Sbouyer {
624e541343Sbouyer gnttab_map_grant_ref_t op[XENSHM_MAX_PAGES_PER_REQUEST];
638d1b8859Sjdolecek int ret, i;
64*5dac1986Sbouyer #ifndef XENPV
65*5dac1986Sbouyer paddr_t base_paddr;
66*5dac1986Sbouyer #endif
67*5dac1986Sbouyer
684e541343Sbouyer
694e541343Sbouyer #ifdef DIAGNOSTIC
704e541343Sbouyer if (nentries > XENSHM_MAX_PAGES_PER_REQUEST) {
712542c094Smaxv panic("xen_shm_map: %d entries", nentries);
724e541343Sbouyer }
734e541343Sbouyer #endif
74*5dac1986Sbouyer #ifndef XENPV
75*5dac1986Sbouyer base_paddr = xenmem_alloc_pa(nentries * PAGE_SIZE, PAGE_SIZE, false);
76*5dac1986Sbouyer if (base_paddr == 0)
77*5dac1986Sbouyer return ENOMEM;
78*5dac1986Sbouyer #endif
792542c094Smaxv
804e541343Sbouyer for (i = 0; i < nentries; i++) {
81*5dac1986Sbouyer #ifndef XENPV
82*5dac1986Sbouyer op[i].host_addr = base_paddr + i * PAGE_SIZE;
83*5dac1986Sbouyer #else
848d1b8859Sjdolecek op[i].host_addr = va + i * PAGE_SIZE;
85*5dac1986Sbouyer #endif
864e541343Sbouyer op[i].dom = domid;
874e541343Sbouyer op[i].ref = grefp[i];
884e541343Sbouyer op[i].flags = GNTMAP_host_map |
894e541343Sbouyer ((flags & XSHM_RO) ? GNTMAP_readonly : 0);
904e541343Sbouyer }
912542c094Smaxv
922542c094Smaxv ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, op, nentries);
93d477b21bSjdolecek if (__predict_false(ret < 0)) {
94d477b21bSjdolecek #ifdef DIAGNOSTIC
95d477b21bSjdolecek printf("%s: HYPERVISOR_grant_table_op failed %d\n", __func__,
96d477b21bSjdolecek ret);
97d477b21bSjdolecek #endif
98*5dac1986Sbouyer ret = EINVAL;
99*5dac1986Sbouyer goto err1;
1002542c094Smaxv }
1012542c094Smaxv
102d477b21bSjdolecek /*
103d477b21bSjdolecek * If ret is positive, it means there was an error in processing,
104d477b21bSjdolecek * and only first ret entries were actually handled. If it's zero,
105d477b21bSjdolecek * it only means all entries were processed, but there could still
106d477b21bSjdolecek * be failure.
107d477b21bSjdolecek */
108d477b21bSjdolecek if (__predict_false(ret > 0 && ret < nentries)) {
109d477b21bSjdolecek nentries = ret;
110d477b21bSjdolecek }
111d477b21bSjdolecek
1124e541343Sbouyer for (i = 0; i < nentries; i++) {
113d477b21bSjdolecek if (__predict_false(op[i].status)) {
1148d1b8859Sjdolecek #ifdef DIAGNOSTIC
115d477b21bSjdolecek printf("%s: op[%d] bad status %d gref %u\n", __func__,
116d477b21bSjdolecek i, op[i].status, grefp[i]);
1178d1b8859Sjdolecek #endif
118d477b21bSjdolecek ret = 1;
119d477b21bSjdolecek continue;
120d477b21bSjdolecek }
1214e541343Sbouyer handlep[i] = op[i].handle;
1224e541343Sbouyer }
1232542c094Smaxv
124d477b21bSjdolecek if (__predict_false(ret > 0)) {
125d477b21bSjdolecek int uncnt = 0;
126d477b21bSjdolecek gnttab_unmap_grant_ref_t unop[XENSHM_MAX_PAGES_PER_REQUEST];
127d477b21bSjdolecek
128d477b21bSjdolecek /*
129d477b21bSjdolecek * When returning error, make sure the successfully mapped
130d477b21bSjdolecek * entries are unmapped before returning the error.
131d477b21bSjdolecek * xen_shm_unmap() can't be used, it assumes
132d477b21bSjdolecek * linear consecutive space.
133d477b21bSjdolecek */
134d477b21bSjdolecek for (i = uncnt = 0; i < nentries; i++) {
135d477b21bSjdolecek if (op[i].status == 0) {
136*5dac1986Sbouyer #ifndef XENPV
137*5dac1986Sbouyer unop[uncnt].host_addr =
138*5dac1986Sbouyer base_paddr + i * PAGE_SIZE;
139*5dac1986Sbouyer #else
140d477b21bSjdolecek unop[uncnt].host_addr = va + i * PAGE_SIZE;
141*5dac1986Sbouyer #endif
142d477b21bSjdolecek unop[uncnt].dev_bus_addr = 0;
143d477b21bSjdolecek unop[uncnt].handle = handlep[i];
144d477b21bSjdolecek uncnt++;
145d477b21bSjdolecek }
146d477b21bSjdolecek }
147d477b21bSjdolecek if (uncnt > 0) {
148d477b21bSjdolecek ret = HYPERVISOR_grant_table_op(
149d477b21bSjdolecek GNTTABOP_unmap_grant_ref, unop, uncnt);
150d477b21bSjdolecek if (ret != 0) {
151d477b21bSjdolecek panic("%s: unmap on error recovery failed"
152d477b21bSjdolecek " %d", __func__, ret);
153d477b21bSjdolecek }
154d477b21bSjdolecek }
155d477b21bSjdolecek #ifdef DIAGNOSTIC
156d477b21bSjdolecek printf("%s: HYPERVISOR_grant_table_op bad entry\n",
157d477b21bSjdolecek __func__);
158d477b21bSjdolecek #endif
159*5dac1986Sbouyer ret = EINVAL;
160*5dac1986Sbouyer goto err1;
161d477b21bSjdolecek }
162*5dac1986Sbouyer #ifndef XENPV
163*5dac1986Sbouyer for (i = 0; i < nentries; i++) {
164*5dac1986Sbouyer pmap_kenter_pa(va + i * PAGE_SIZE,
165*5dac1986Sbouyer base_paddr + i * PAGE_SIZE,
166*5dac1986Sbouyer VM_PROT_READ | VM_PROT_WRITE, 0);
167*5dac1986Sbouyer }
168*5dac1986Sbouyer #endif
169d477b21bSjdolecek
1704e541343Sbouyer return 0;
171*5dac1986Sbouyer err1:
172*5dac1986Sbouyer #ifndef XENPV
173*5dac1986Sbouyer xenmem_free_pa(base_paddr, nentries * PAGE_SIZE);
174*5dac1986Sbouyer #endif
175*5dac1986Sbouyer return ret;
1764e541343Sbouyer }
1774e541343Sbouyer
1784e541343Sbouyer void
xen_shm_unmap(vaddr_t va,int nentries,grant_handle_t * handlep)1794e541343Sbouyer xen_shm_unmap(vaddr_t va, int nentries, grant_handle_t *handlep)
1804e541343Sbouyer {
1814e541343Sbouyer gnttab_unmap_grant_ref_t op[XENSHM_MAX_PAGES_PER_REQUEST];
1828d1b8859Sjdolecek int ret, i;
183*5dac1986Sbouyer #ifndef XENPV
184*5dac1986Sbouyer paddr_t base_paddr;
185*5dac1986Sbouyer if (pmap_extract(pmap_kernel(), va, &base_paddr) != true)
186*5dac1986Sbouyer panic("xen_shm_unmap: unmapped va");
187*5dac1986Sbouyer #endif
1884e541343Sbouyer
1894e541343Sbouyer #ifdef DIAGNOSTIC
1904e541343Sbouyer if (nentries > XENSHM_MAX_PAGES_PER_REQUEST) {
1912542c094Smaxv panic("xen_shm_unmap: %d entries", nentries);
1924e541343Sbouyer }
1934e541343Sbouyer #endif
1944e541343Sbouyer
1954e541343Sbouyer for (i = 0; i < nentries; i++) {
196*5dac1986Sbouyer #ifndef XENPV
197*5dac1986Sbouyer pmap_kremove(va + i * PAGE_SIZE, PAGE_SIZE);
198*5dac1986Sbouyer op[i].host_addr = base_paddr + i * PAGE_SIZE;
199*5dac1986Sbouyer #else
2004e541343Sbouyer op[i].host_addr = va + i * PAGE_SIZE;
201*5dac1986Sbouyer #endif
2024e541343Sbouyer op[i].dev_bus_addr = 0;
2034e541343Sbouyer op[i].handle = handlep[i];
2044e541343Sbouyer }
2052542c094Smaxv
2064e541343Sbouyer ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref,
2074e541343Sbouyer op, nentries);
2082542c094Smaxv if (__predict_false(ret)) {
2094e541343Sbouyer panic("xen_shm_unmap: unmap failed");
2102542c094Smaxv }
211*5dac1986Sbouyer #ifndef XENPV
212*5dac1986Sbouyer xenmem_free_pa(base_paddr, PAGE_SIZE * nentries);
213*5dac1986Sbouyer #endif
2144e541343Sbouyer }
215