1 /*
2  * Copyright (c) 2006 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include <sys/types.h>
36 #include <sys/systm.h>
37 #include <cpu/lwbuf.h>
38 #include <vm/vm_page.h>
39 #include <vm/vm_extern.h>
40 #include <assert.h>
41 
42 #include <sys/stat.h>
43 #include <sys/mman.h>
44 
45 /*
46  * A bcopy that works dring low level boot, before FP is working
47  */
48 void
49 ovbcopy(const void *src, void *dst, size_t len)
50 {
51 	bcopy(src, dst, len);
52 }
53 
54 void
55 bcopyi(const void *src, void *dst, size_t len)
56 {
57 	bcopy(src, dst, len);
58 }
59 
60 int
61 copystr(const void *kfaddr, void *kdaddr, size_t len, size_t *lencopied)
62 {
63 	size_t i;
64 
65 	for (i = 0; i < len; ++i) {
66 		if ((((char *)kdaddr)[i] = ((const char *)kfaddr)[i]) == 0) {
67 			if (lencopied)
68 				*lencopied = i + 1;
69 			return(0);
70 		}
71 	}
72 	return (ENAMETOOLONG);
73 }
74 
75 /*
76  * Copies a NUL-terminated string from user space to kernel space.
77  * The number of bytes copied, including the terminator, is returned in
78  * (*res).
79  *
80  * Returns 0 on success, EFAULT or ENAMETOOLONG on failure.
81  */
82 int
83 copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *res)
84 {
85 	int error;
86 	size_t n;
87 	const char *uptr = udaddr;
88 	char *kptr = kaddr;
89 
90 	if (res)
91 		*res = 0;
92 	while (len) {
93 		n = PAGE_SIZE - ((vm_offset_t)uptr & PAGE_MASK);
94 		if (n > 32)
95 			n = 32;
96 		if (n > len)
97 			n = len;
98 		if ((error = copyin(uptr, kptr, n)) != 0)
99 			return(error);
100 		while (n) {
101 			if (res)
102 				++*res;
103 			if (*kptr == 0)
104 				return(0);
105 			++kptr;
106 			++uptr;
107 			--n;
108 			--len;
109 		}
110 
111 	}
112 	return(ENAMETOOLONG);
113 }
114 
115 /*
116  * Copy a binary buffer from user space to kernel space.
117  *
118  * NOTE: on a real system copyin/copyout are MP safe, but the current
119  * implementation on a vkernel is not so we get the mp lock.
120  *
121  * Returns 0 on success, EFAULT on failure.
122  */
123 int
124 copyin(const void *udaddr, void *kaddr, size_t len)
125 {
126 	struct vmspace *vm = curproc->p_vmspace;
127 	struct lwbuf *lwb;
128 	struct lwbuf lwb_cache;
129 	vm_page_t m;
130 	int error;
131 	size_t n;
132 
133 	error = 0;
134 	while (len) {
135 		m = vm_fault_page(&vm->vm_map, trunc_page((vm_offset_t)udaddr),
136 				  VM_PROT_READ,
137 				  VM_FAULT_NORMAL, &error);
138 		if (error)
139 			break;
140 		n = PAGE_SIZE - ((vm_offset_t)udaddr & PAGE_MASK);
141 		if (n > len)
142 			n = len;
143 		lwb = lwbuf_alloc(m, &lwb_cache);
144 		bcopy((char *)lwbuf_kva(lwb)+((vm_offset_t)udaddr & PAGE_MASK),
145 		      kaddr, n);
146 		len -= n;
147 		udaddr = (const char *)udaddr + n;
148 		kaddr = (char *)kaddr + n;
149 		lwbuf_free(lwb);
150 		vm_page_unhold(m);
151 	}
152 	return (error);
153 }
154 
155 /*
156  * Copy a binary buffer from kernel space to user space.
157  *
158  * Returns 0 on success, EFAULT on failure.
159  */
160 int
161 copyout(const void *kaddr, void *udaddr, size_t len)
162 {
163 	struct vmspace *vm = curproc->p_vmspace;
164 	struct lwbuf *lwb;
165 	struct lwbuf lwb_cache;
166 	vm_page_t m;
167 	int error;
168 	size_t n;
169 
170 	error = 0;
171 	while (len) {
172 		m = vm_fault_page(&vm->vm_map, trunc_page((vm_offset_t)udaddr),
173 				  VM_PROT_READ|VM_PROT_WRITE,
174 				  VM_FAULT_NORMAL, &error);
175 		if (error)
176 			break;
177 		n = PAGE_SIZE - ((vm_offset_t)udaddr & PAGE_MASK);
178 		if (n > len)
179 			n = len;
180 		lwb = lwbuf_alloc(m, &lwb_cache);
181 		bcopy(kaddr, (char *)lwbuf_kva(lwb) +
182 			     ((vm_offset_t)udaddr & PAGE_MASK), n);
183 		len -= n;
184 		udaddr = (char *)udaddr + n;
185 		kaddr = (const char *)kaddr + n;
186 		vm_page_dirty(m);
187 		lwbuf_free(lwb);
188 		vm_page_unhold(m);
189 	}
190 	return (error);
191 }
192 
193 /*
194  * Fetch the byte at the specified user address.  Returns -1 on failure.
195  */
196 int
197 fubyte(const void *base)
198 {
199 	unsigned char c;
200 
201 	if (copyin(base, &c, 1) == 0)
202 		return((int)c);
203 	return(-1);
204 }
205 
206 /*
207  * Store a byte at the specified user address.  Returns -1 on failure.
208  */
209 int
210 subyte (void *base, int byte)
211 {
212 	unsigned char c = byte;
213 
214 	if (copyout(&c, base, 1) == 0)
215 		return(0);
216 	return(-1);
217 }
218 
219 /*
220  * Fetch a word (integer, 32 bits) from user space
221  */
222 long
223 fuword(const void *base)
224 {
225 	long v;
226 
227 	if (copyin(base, &v, sizeof(v)) == 0)
228 		return((long)v);
229 	return(-1);
230 }
231 
232 /*
233  * Store a word (integer, 32 bits) to user space
234  */
235 int
236 suword(void *base, long word)
237 {
238 	if (copyout(&word, base, sizeof(word)) == 0)
239 		return(0);
240 	return(-1);
241 }
242 
243 int
244 suword32(void *base, int word)
245 {
246 	if (copyout(&word, base, sizeof(word)) == 0)
247 		return(0);
248 	return(-1);
249 }
250 
251 /*
252  * Fetch an short word (16 bits) from user space
253  */
254 int
255 fusword(void *base)
256 {
257 	unsigned short sword;
258 
259 	if (copyin(base, &sword, sizeof(sword)) == 0)
260 		return((int)sword);
261 	return(-1);
262 }
263 
264 /*
265  * Store a short word (16 bits) to user space
266  */
267 int
268 susword (void *base, int word)
269 {
270 	unsigned short sword = word;
271 
272 	if (copyout(&sword, base, sizeof(sword)) == 0)
273 		return(0);
274 	return(-1);
275 }
276