xref: /netbsd-src/sys/rump/librump/rumpkern/rumpcopy.c (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
1 /*	$NetBSD: rumpcopy.c,v 1.17 2011/01/18 22:21:23 haad Exp $	*/
2 
3 /*
4  * Copyright (c) 2009 Antti Kantee.  All Rights Reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: rumpcopy.c,v 1.17 2011/01/18 22:21:23 haad Exp $");
30 
31 #include <sys/param.h>
32 #include <sys/lwp.h>
33 #include <sys/systm.h>
34 #include <sys/uio.h>
35 
36 #include <rump/rumpuser.h>
37 
38 #include "rump_private.h"
39 
40 int
41 copyin(const void *uaddr, void *kaddr, size_t len)
42 {
43 	int error = 0;
44 
45 	if (__predict_false(uaddr == NULL && len)) {
46 		return EFAULT;
47 	}
48 
49 	if (RUMP_LOCALPROC_P(curproc)) {
50 		memcpy(kaddr, uaddr, len);
51 	} else if (len) {
52 		error = rumpuser_sp_copyin(curproc->p_vmspace->vm_map.pmap,
53 		    uaddr, kaddr, len);
54 	}
55 
56 	return error;
57 }
58 
59 int
60 copyout(const void *kaddr, void *uaddr, size_t len)
61 {
62 	int error = 0;
63 
64 	if (__predict_false(uaddr == NULL && len)) {
65 		return EFAULT;
66 	}
67 
68 	if (RUMP_LOCALPROC_P(curproc)) {
69 		memcpy(uaddr, kaddr, len);
70 	} else if (len) {
71 		error = rumpuser_sp_copyout(curproc->p_vmspace->vm_map.pmap,
72 		    kaddr, uaddr, len);
73 	}
74 	return error;
75 }
76 
77 int
78 subyte(void *uaddr, int byte)
79 {
80 	int error = 0;
81 
82 	if (RUMP_LOCALPROC_P(curproc))
83 		*(char *)uaddr = byte;
84 	else
85 		error = rumpuser_sp_copyout(curproc->p_vmspace->vm_map.pmap,
86 		    &byte, uaddr, 1);
87 
88 	return error;
89 }
90 
91 int
92 copystr(const void *kfaddr, void *kdaddr, size_t len, size_t *done)
93 {
94 	uint8_t *to = kdaddr;
95 	const uint8_t *from = kfaddr;
96 	size_t actlen = 0;
97 
98 	while (len-- > 0 && (*to++ = *from++) != 0)
99 		actlen++;
100 
101 	if (len+1 == 0 && *(to-1) != 0)
102 		return ENAMETOOLONG;
103 
104 	if (done)
105 		*done = actlen+1; /* + '\0' */
106 	return 0;
107 }
108 
109 int
110 copyinstr(const void *uaddr, void *kaddr, size_t len, size_t *done)
111 {
112 	uint8_t *to;
113 	int rv;
114 
115 	if (len == 0)
116 		return 0;
117 
118 	if (RUMP_LOCALPROC_P(curproc))
119 		return copystr(uaddr, kaddr, len, done);
120 
121 	if ((rv = rumpuser_sp_copyinstr(curproc->p_vmspace->vm_map.pmap,
122 	    uaddr, kaddr, &len)) != 0)
123 		return rv;
124 
125 	/* figure out if we got a terminated string or not */
126 	to = (uint8_t *)kaddr + (len-1);
127 	while (to >= (uint8_t *)kaddr) {
128 		if (*to == 0)
129 			goto found;
130 		to--;
131 	}
132 	return ENAMETOOLONG;
133 
134  found:
135 	if (done)
136 		*done = strlen(kaddr)+1; /* includes termination */
137 
138 	return 0;
139 }
140 
141 int
142 copyoutstr(const void *kaddr, void *uaddr, size_t len, size_t *done)
143 {
144 	size_t slen;
145 	int error;
146 
147 	if (RUMP_LOCALPROC_P(curproc))
148 		return copystr(kaddr, uaddr, len, done);
149 
150 	slen = strlen(kaddr)+1;
151 	if (slen > len)
152 		return ENAMETOOLONG;
153 
154 	error = rumpuser_sp_copyoutstr(curproc->p_vmspace->vm_map.pmap,
155 	    kaddr, uaddr, &slen);
156 	if (done)
157 		*done = slen;
158 
159 	return error;
160 }
161 
162 int
163 kcopy(const void *src, void *dst, size_t len)
164 {
165 
166 	memcpy(dst, src, len);
167 	return 0;
168 }
169 
170 /*
171  * Low-level I/O routine.  This is used only when "all else fails",
172  * i.e. the current thread does not have an appropriate vm context.
173  */
174 int
175 uvm_io(struct vm_map *vm, struct uio *uio)
176 {
177 	int error = 0;
178 
179 	/* loop over iovecs one-by-one and copyout */
180 	for (; uio->uio_resid && uio->uio_iovcnt;
181 	    uio->uio_iovcnt--, uio->uio_iov++) {
182 		struct iovec *iov = uio->uio_iov;
183 		size_t curlen = MIN(uio->uio_resid, iov->iov_len);
184 
185 		if (__predict_false(curlen == 0))
186 			continue;
187 
188 		if (uio->uio_rw == UIO_READ) {
189 			error = rumpuser_sp_copyin(vm->pmap,
190 			    (void *)(vaddr_t)uio->uio_offset, iov->iov_base,
191 			    curlen);
192 		} else {
193 			error = rumpuser_sp_copyout(vm->pmap,
194 			    iov->iov_base, (void *)(vaddr_t)uio->uio_offset,
195 			    curlen);
196 		}
197 		if (error)
198 			break;
199 
200 		iov->iov_base = (uint8_t *)iov->iov_base + curlen;
201 		iov->iov_len -= curlen;
202 
203 		uio->uio_resid -= curlen;
204 		uio->uio_offset += curlen;
205 	}
206 
207 	return error;
208 }
209 
210 /*
211  * Copy one byte from userspace to kernel.
212  */
213 int
214 fubyte(const void *base)
215 {
216 	unsigned char val;
217 	int error;
218 
219 	error = copyin(base, &val, sizeof(char));
220 	if (error != 0)
221 		return -1;
222 
223 	return (int)val;
224 }
225