xref: /netbsd-src/sys/rump/librump/rumpkern/rumpcopy.c (revision 8747f41571b66df4281139e8fd29aabeb82a7ee9)
1*8747f415Sriastradh /*	$NetBSD: rumpcopy.c,v 1.25 2020/07/01 00:42:13 riastradh Exp $	*/
2080522e1Spooka 
3080522e1Spooka /*
4080522e1Spooka  * Copyright (c) 2009 Antti Kantee.  All Rights Reserved.
5080522e1Spooka  *
6080522e1Spooka  * Redistribution and use in source and binary forms, with or without
7080522e1Spooka  * modification, are permitted provided that the following conditions
8080522e1Spooka  * are met:
9080522e1Spooka  * 1. Redistributions of source code must retain the above copyright
10080522e1Spooka  *    notice, this list of conditions and the following disclaimer.
11080522e1Spooka  * 2. Redistributions in binary form must reproduce the above copyright
12080522e1Spooka  *    notice, this list of conditions and the following disclaimer in the
13080522e1Spooka  *    documentation and/or other materials provided with the distribution.
14080522e1Spooka  *
15080522e1Spooka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16080522e1Spooka  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17080522e1Spooka  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18080522e1Spooka  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19080522e1Spooka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20080522e1Spooka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21080522e1Spooka  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22080522e1Spooka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23080522e1Spooka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24080522e1Spooka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25080522e1Spooka  * SUCH DAMAGE.
26080522e1Spooka  */
27080522e1Spooka 
28080522e1Spooka #include <sys/cdefs.h>
29*8747f415Sriastradh __KERNEL_RCSID(0, "$NetBSD: rumpcopy.c,v 1.25 2020/07/01 00:42:13 riastradh Exp $");
3091bfaeb6Sthorpej 
3191bfaeb6Sthorpej #define	__UFETCHSTORE_PRIVATE
3291bfaeb6Sthorpej #define	__UCAS_PRIVATE
33080522e1Spooka 
34080522e1Spooka #include <sys/param.h>
35080522e1Spooka #include <sys/lwp.h>
36080522e1Spooka #include <sys/systm.h>
379be03442Spooka #include <sys/uio.h>
38080522e1Spooka 
396bb51422Spooka #include <rump-sys/kern.h>
40080522e1Spooka 
416bb51422Spooka #include <rump/rumpuser.h>
42080522e1Spooka 
43080522e1Spooka int
copyin(const void * uaddr,void * kaddr,size_t len)44080522e1Spooka copyin(const void *uaddr, void *kaddr, size_t len)
45080522e1Spooka {
469be03442Spooka 	int error = 0;
47082af2faSpooka 
4817a313ddSkamil 	if (len == 0)
4917a313ddSkamil 		return 0;
5017a313ddSkamil 
515397c7b6Spooka 	if (__predict_false(uaddr == NULL && len)) {
5270d05149Spooka 		return EFAULT;
535397c7b6Spooka 	}
54b1842c22Spooka 
55a4d5652aSpooka 	if (RUMP_LOCALPROC_P(curproc)) {
56080522e1Spooka 		memcpy(kaddr, uaddr, len);
57574a31f2Spooka 	} else if (len) {
586195daadSpooka 		error = rump_sysproxy_copyin(RUMP_SPVM2CTL(curproc->p_vmspace),
599be03442Spooka 		    uaddr, kaddr, len);
6070d05149Spooka 	}
619be03442Spooka 
629be03442Spooka 	return error;
63080522e1Spooka }
64080522e1Spooka 
65080522e1Spooka int
copyout(const void * kaddr,void * uaddr,size_t len)66080522e1Spooka copyout(const void *kaddr, void *uaddr, size_t len)
67080522e1Spooka {
689be03442Spooka 	int error = 0;
69082af2faSpooka 
7017a313ddSkamil 	if (len == 0)
7117a313ddSkamil 		return 0;
7217a313ddSkamil 
735397c7b6Spooka 	if (__predict_false(uaddr == NULL && len)) {
7470d05149Spooka 		return EFAULT;
755397c7b6Spooka 	}
76b1842c22Spooka 
77a4d5652aSpooka 	if (RUMP_LOCALPROC_P(curproc)) {
78080522e1Spooka 		memcpy(uaddr, kaddr, len);
79574a31f2Spooka 	} else if (len) {
806195daadSpooka 		error = rump_sysproxy_copyout(RUMP_SPVM2CTL(curproc->p_vmspace),
819be03442Spooka 		    kaddr, uaddr, len);
8270d05149Spooka 	}
839be03442Spooka 	return error;
84080522e1Spooka }
85080522e1Spooka 
86080522e1Spooka int
copyinstr(const void * uaddr,void * kaddr,size_t len,size_t * done)87080522e1Spooka copyinstr(const void *uaddr, void *kaddr, size_t len, size_t *done)
88080522e1Spooka {
898fcead89Spooka 	uint8_t *to;
908fcead89Spooka 	int rv;
91080522e1Spooka 
92b9b99119Spooka 	if (len == 0)
93b9b99119Spooka 		return 0;
94b9b99119Spooka 
95c74676d0Snjoly 	if (__predict_false(uaddr == NULL)) {
96c74676d0Snjoly 		return EFAULT;
97c74676d0Snjoly 	}
98c74676d0Snjoly 
99a4d5652aSpooka 	if (RUMP_LOCALPROC_P(curproc))
1008fcead89Spooka 		return copystr(uaddr, kaddr, len, done);
1018fcead89Spooka 
1026195daadSpooka 	if ((rv = rump_sysproxy_copyinstr(RUMP_SPVM2CTL(curproc->p_vmspace),
1036b71288cSpooka 	    uaddr, kaddr, &len)) != 0)
1048fcead89Spooka 		return rv;
1058fcead89Spooka 
106b9b99119Spooka 	/* figure out if we got a terminated string or not */
107b9b99119Spooka 	to = (uint8_t *)kaddr + (len-1);
10835e989d6Spooka 	while (to >= (uint8_t *)kaddr) {
1098fcead89Spooka 		if (*to == 0)
1108fcead89Spooka 			goto found;
1118fcead89Spooka 		to--;
1128fcead89Spooka 	}
1138fcead89Spooka 	return ENAMETOOLONG;
1148fcead89Spooka 
1158fcead89Spooka  found:
116080522e1Spooka 	if (done)
117080522e1Spooka 		*done = strlen(kaddr)+1; /* includes termination */
1188fcead89Spooka 
119080522e1Spooka 	return 0;
120080522e1Spooka }
121080522e1Spooka 
122080522e1Spooka int
copyoutstr(const void * kaddr,void * uaddr,size_t len,size_t * done)123080522e1Spooka copyoutstr(const void *kaddr, void *uaddr, size_t len, size_t *done)
124080522e1Spooka {
1258fcead89Spooka 	size_t slen;
1269be03442Spooka 	int error;
127080522e1Spooka 
12817a313ddSkamil 	if (len == 0)
12917a313ddSkamil 		return 0;
13017a313ddSkamil 
131c74676d0Snjoly 	if (__predict_false(uaddr == NULL && len)) {
132c74676d0Snjoly 		return EFAULT;
133c74676d0Snjoly 	}
134c74676d0Snjoly 
135a4d5652aSpooka 	if (RUMP_LOCALPROC_P(curproc))
1368fcead89Spooka 		return copystr(kaddr, uaddr, len, done);
1378fcead89Spooka 
1388fcead89Spooka 	slen = strlen(kaddr)+1;
1398fcead89Spooka 	if (slen > len)
1408fcead89Spooka 		return ENAMETOOLONG;
1418fcead89Spooka 
1426195daadSpooka 	error = rump_sysproxy_copyoutstr(RUMP_SPVM2CTL(curproc->p_vmspace),
1436b71288cSpooka 	    kaddr, uaddr, &slen);
144080522e1Spooka 	if (done)
1458fcead89Spooka 		*done = slen;
1468fcead89Spooka 
1479be03442Spooka 	return error;
148080522e1Spooka }
149080522e1Spooka 
150080522e1Spooka int
kcopy(const void * src,void * dst,size_t len)151080522e1Spooka kcopy(const void *src, void *dst, size_t len)
152080522e1Spooka {
153080522e1Spooka 
15417a313ddSkamil 	if (len == 0)
15517a313ddSkamil 		return 0;
15617a313ddSkamil 
157080522e1Spooka 	memcpy(dst, src, len);
158080522e1Spooka 	return 0;
159080522e1Spooka }
1609be03442Spooka 
1619be03442Spooka /*
1629be03442Spooka  * Low-level I/O routine.  This is used only when "all else fails",
1639be03442Spooka  * i.e. the current thread does not have an appropriate vm context.
1649be03442Spooka  */
1659be03442Spooka int
uvm_io(struct vm_map * vm,struct uio * uio,int flag)16619ea7434Schristos uvm_io(struct vm_map *vm, struct uio *uio, int flag)
1679be03442Spooka {
16803969dbaSpooka 	int error = 0;
1699be03442Spooka 
1709be03442Spooka 	/* loop over iovecs one-by-one and copyout */
1719be03442Spooka 	for (; uio->uio_resid && uio->uio_iovcnt;
1729be03442Spooka 	    uio->uio_iovcnt--, uio->uio_iov++) {
1739be03442Spooka 		struct iovec *iov = uio->uio_iov;
1749be03442Spooka 		size_t curlen = MIN(uio->uio_resid, iov->iov_len);
1759be03442Spooka 
1769be03442Spooka 		if (__predict_false(curlen == 0))
1779be03442Spooka 			continue;
1789be03442Spooka 
1799be03442Spooka 		if (uio->uio_rw == UIO_READ) {
1806195daadSpooka 			error = rump_sysproxy_copyin(RUMP_SPVM2CTL(vm),
1819be03442Spooka 			    (void *)(vaddr_t)uio->uio_offset, iov->iov_base,
1829be03442Spooka 			    curlen);
1839be03442Spooka 		} else {
1846195daadSpooka 			error = rump_sysproxy_copyout(RUMP_SPVM2CTL(vm),
1859be03442Spooka 			    iov->iov_base, (void *)(vaddr_t)uio->uio_offset,
1869be03442Spooka 			    curlen);
1879be03442Spooka 		}
1889be03442Spooka 		if (error)
1899be03442Spooka 			break;
1909be03442Spooka 
1919be03442Spooka 		iov->iov_base = (uint8_t *)iov->iov_base + curlen;
1929be03442Spooka 		iov->iov_len -= curlen;
1939be03442Spooka 
1949be03442Spooka 		uio->uio_resid -= curlen;
1959be03442Spooka 		uio->uio_offset += curlen;
1969be03442Spooka 	}
1979be03442Spooka 
1989be03442Spooka 	return error;
1999be03442Spooka }
20061583090Shaad 
20161583090Shaad int
_ucas_32(volatile uint32_t * uaddr,uint32_t old,uint32_t new,uint32_t * ret)20291bfaeb6Sthorpej _ucas_32(volatile uint32_t *uaddr, uint32_t old, uint32_t new, uint32_t *ret)
20361583090Shaad {
20491bfaeb6Sthorpej 	uint32_t *uva = ((void *)(uintptr_t)uaddr);
20561583090Shaad 	int error;
20661583090Shaad 
20791bfaeb6Sthorpej 	/* XXXXJRT do we need a MP CPU gate? */
20861583090Shaad 
20991bfaeb6Sthorpej 	kpreempt_disable();
21091bfaeb6Sthorpej 	error = _ufetch_32(uva, ret);
21191bfaeb6Sthorpej 	if (error == 0 && *ret == old) {
21291bfaeb6Sthorpej 		error = _ustore_32(uva, new);
21361583090Shaad 	}
21491bfaeb6Sthorpej 	kpreempt_enable();
21591bfaeb6Sthorpej 
21691bfaeb6Sthorpej 	return error;
21791bfaeb6Sthorpej }
21891bfaeb6Sthorpej 
21991bfaeb6Sthorpej #ifdef _LP64
22091bfaeb6Sthorpej int
_ucas_64(volatile uint64_t * uaddr,uint64_t old,uint64_t new,uint64_t * ret)22191bfaeb6Sthorpej _ucas_64(volatile uint64_t *uaddr, uint64_t old, uint64_t new, uint64_t *ret)
22291bfaeb6Sthorpej {
22391bfaeb6Sthorpej 	uint64_t *uva = ((void *)(uintptr_t)uaddr);
22491bfaeb6Sthorpej 	int error;
22591bfaeb6Sthorpej 
22691bfaeb6Sthorpej 	/* XXXXJRT do we need a MP CPU gate? */
22791bfaeb6Sthorpej 
22891bfaeb6Sthorpej 	kpreempt_disable();
22991bfaeb6Sthorpej 	error = _ufetch_64(uva, ret);
23091bfaeb6Sthorpej 	if (error == 0 && *ret == old) {
23191bfaeb6Sthorpej 		error = _ustore_64(uva, new);
23291bfaeb6Sthorpej 	}
23391bfaeb6Sthorpej 	kpreempt_enable();
23491bfaeb6Sthorpej 
23591bfaeb6Sthorpej 	return error;
23691bfaeb6Sthorpej }
23791bfaeb6Sthorpej #endif /* _LP64 */
23891bfaeb6Sthorpej 
23991bfaeb6Sthorpej #define	UFETCH(sz)							\
24091bfaeb6Sthorpej int									\
24191bfaeb6Sthorpej _ufetch_ ## sz(const uint ## sz ##_t *uaddr, uint ## sz ## _t *valp)	\
24291bfaeb6Sthorpej {									\
24391bfaeb6Sthorpej 	int error = 0;							\
24491bfaeb6Sthorpej 									\
24591bfaeb6Sthorpej 	if (RUMP_LOCALPROC_P(curproc)) {				\
24691bfaeb6Sthorpej 		*valp = *uaddr;						\
24791bfaeb6Sthorpej 	} else {							\
24891bfaeb6Sthorpej 		error = rump_sysproxy_copyin(				\
24991bfaeb6Sthorpej 		    RUMP_SPVM2CTL(curproc->p_vmspace),			\
25091bfaeb6Sthorpej 		    uaddr, valp, sizeof(*valp));			\
25191bfaeb6Sthorpej 	}								\
25291bfaeb6Sthorpej 	return error;							\
25391bfaeb6Sthorpej }
25491bfaeb6Sthorpej 
25591bfaeb6Sthorpej UFETCH(8)
25691bfaeb6Sthorpej UFETCH(16)
25791bfaeb6Sthorpej UFETCH(32)
25891bfaeb6Sthorpej #ifdef _LP64
25991bfaeb6Sthorpej UFETCH(64)
26091bfaeb6Sthorpej #endif
26191bfaeb6Sthorpej 
26291bfaeb6Sthorpej #undef UFETCH
26391bfaeb6Sthorpej 
26491bfaeb6Sthorpej #define	USTORE(sz)							\
26591bfaeb6Sthorpej int									\
26691bfaeb6Sthorpej _ustore_ ## sz(uint ## sz ## _t *uaddr, uint ## sz ## _t val)		\
26791bfaeb6Sthorpej {									\
26891bfaeb6Sthorpej 	int error = 0;							\
26991bfaeb6Sthorpej 									\
27091bfaeb6Sthorpej 	if (RUMP_LOCALPROC_P(curproc)) {				\
27191bfaeb6Sthorpej 		*uaddr = val;						\
27291bfaeb6Sthorpej 	} else {							\
27391bfaeb6Sthorpej 		error = rump_sysproxy_copyout(				\
27491bfaeb6Sthorpej 		    RUMP_SPVM2CTL(curproc->p_vmspace),			\
27591bfaeb6Sthorpej 		    &val, uaddr, sizeof(val));				\
27691bfaeb6Sthorpej 	}								\
27791bfaeb6Sthorpej 	return error;							\
27891bfaeb6Sthorpej }
27991bfaeb6Sthorpej 
28091bfaeb6Sthorpej USTORE(8)
28191bfaeb6Sthorpej USTORE(16)
28291bfaeb6Sthorpej USTORE(32)
28391bfaeb6Sthorpej #ifdef _LP64
28491bfaeb6Sthorpej USTORE(64)
28591bfaeb6Sthorpej #endif
28691bfaeb6Sthorpej 
28791bfaeb6Sthorpej #undef USTORE
288