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