9231995cbf211c2b763395cd491007cee3489bf5
[dragonfly.git] / sys / platform / vkernel / platform / copyio.c
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  * $DragonFly: src/sys/platform/vkernel/platform/copyio.c,v 1.9 2008/05/09 07:24:47 dillon Exp $
35  */
36
37 #include <sys/types.h>
38 #include <sys/systm.h>
39 #include <sys/sfbuf.h>
40 #include <vm/vm_page.h>
41 #include <vm/vm_extern.h>
42 #include <assert.h>
43
44 #include <sys/stat.h>
45 #include <sys/mman.h>
46
47 #include <sys/mplock2.h>
48
49 /*
50  * A bcopy that works dring low level boot, before FP is working
51  */
52 void
53 ovbcopy(const void *src, void *dst, size_t len)
54 {
55         bcopy(src, dst, len);
56 }
57
58 void
59 bcopyi(const void *src, void *dst, size_t len)
60 {
61         bcopy(src, dst, len);
62 }
63
64 int
65 copystr(const void *kfaddr, void *kdaddr, size_t len, size_t *lencopied)
66 {
67         size_t i;
68
69         for (i = 0; i < len; ++i) {
70                 if ((((char *)kdaddr)[i] = ((const char *)kfaddr)[i]) == 0) {
71                         if (lencopied)
72                                 *lencopied = i + 1;
73                         return(0);
74                 }
75         }
76         return (ENAMETOOLONG);
77 }
78
79 /*
80  * Copies a NUL-terminated string from user space to kernel space.
81  * The number of bytes copied, including the terminator, is returned in
82  * (*res).
83  *
84  * Returns 0 on success, EFAULT or ENAMETOOLONG on failure.
85  */
86 int
87 copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *res)
88 {
89         int error;
90         size_t n;
91         const char *uptr = udaddr;
92         char *kptr = kaddr;
93
94         if (res)
95                 *res = 0;
96         while (len) {
97                 n = PAGE_SIZE - ((vm_offset_t)uptr & PAGE_MASK);
98                 if (n > 32)
99                         n = 32;
100                 if (n > len)
101                         n = len;
102                 if ((error = copyin(uptr, kptr, n)) != 0)
103                         return(error);
104                 while (n) {
105                         if (res)
106                                 ++*res;
107                         if (*kptr == 0)
108                                 return(0);
109                         ++kptr;
110                         ++uptr;
111                         --n;
112                         --len;
113                 }
114
115         }
116         return(ENAMETOOLONG);
117 }
118
119 /*
120  * Copy a binary buffer from user space to kernel space.
121  *
122  * NOTE: on a real system copyin/copyout are MP safe, but the current
123  * implementation on a vkernel is not so we get the mp lock.
124  *
125  * Returns 0 on success, EFAULT on failure.
126  */
127 int
128 copyin(const void *udaddr, void *kaddr, size_t len)
129 {
130         struct vmspace *vm = curproc->p_vmspace;
131         struct sf_buf *sf;
132         vm_page_t m;
133         int error;
134         size_t n;
135
136         error = 0;
137         get_mplock();
138         while (len) {
139                 m = vm_fault_page(&vm->vm_map, trunc_page((vm_offset_t)udaddr),
140                                   VM_PROT_READ,
141                                   VM_FAULT_NORMAL, &error);
142                 if (error)
143                         break;
144                 n = PAGE_SIZE - ((vm_offset_t)udaddr & PAGE_MASK);
145                 if (n > len)
146                         n = len;
147                 sf = sf_buf_alloc(m, SFB_CPUPRIVATE);
148                 bcopy((char *)sf_buf_kva(sf)+((vm_offset_t)udaddr & PAGE_MASK),
149                       kaddr, n);
150                 len -= n;
151                 udaddr = (const char *)udaddr + n;
152                 kaddr = (char *)kaddr + n;
153                 vm_page_unhold(m);
154                 sf_buf_free(sf);
155         }
156         rel_mplock();
157         return (error);
158 }
159
160 /*
161  * Copy a binary buffer from kernel space to user space.
162  *
163  * Returns 0 on success, EFAULT on failure.
164  */
165 int
166 copyout(const void *kaddr, void *udaddr, size_t len)
167 {
168         struct vmspace *vm = curproc->p_vmspace;
169         struct sf_buf *sf;
170         vm_page_t m;
171         int error;
172         size_t n;
173
174         error = 0;
175         get_mplock();
176         while (len) {
177                 m = vm_fault_page(&vm->vm_map, trunc_page((vm_offset_t)udaddr),
178                                   VM_PROT_READ|VM_PROT_WRITE, 
179                                   VM_FAULT_NORMAL, &error);
180                 if (error)
181                         break;
182                 n = PAGE_SIZE - ((vm_offset_t)udaddr & PAGE_MASK);
183                 if (n > len)
184                         n = len;
185                 sf = sf_buf_alloc(m, SFB_CPUPRIVATE);
186                 bcopy(kaddr, (char *)sf_buf_kva(sf) +
187                              ((vm_offset_t)udaddr & PAGE_MASK), n);
188                 len -= n;
189                 udaddr = (char *)udaddr + n;
190                 kaddr = (const char *)kaddr + n;
191                 vm_page_dirty(m);
192                 vm_page_unhold(m);
193                 sf_buf_free(sf);
194         }
195         rel_mplock();
196         return (error);
197 }
198  
199 /*
200  * Fetch the byte at the specified user address.  Returns -1 on failure.
201  */
202 int
203 fubyte(const void *base)
204 {
205         unsigned char c;
206         int error;
207
208         if ((error = copyin(base, &c, 1)) == 0)
209                 return((int)c);
210         return(-1);
211 }
212
213 /*
214  * Store a byte at the specified user address.  Returns -1 on failure.
215  */
216 int
217 subyte (void *base, int byte)
218 {
219         unsigned char c = byte;
220         int error;
221
222         if ((error = copyout(&c, base, 1)) == 0)
223                 return(0);
224         return(-1);
225 }
226
227 /*
228  * Fetch a word (integer, 32 bits) from user space
229  */
230 long
231 fuword(const void *base)
232 {
233         long v;
234         int error;
235
236         if ((error = copyin(base, &v, sizeof(v))) == 0)
237                 return((long)v);
238         return(-1);
239 }
240
241 /*
242  * Store a word (integer, 32 bits) to user space
243  */
244 int
245 suword(void *base, long word)
246 {
247         int error;
248
249         if ((error = copyout(&word, base, sizeof(word))) == 0)
250                 return(0);
251         return(-1);
252 }
253
254 /*
255  * Fetch an short word (16 bits) from user space
256  */
257 int
258 fusword(void *base)
259 {
260         unsigned short sword;
261         int error;
262
263         if ((error = copyin(base, &sword, sizeof(sword))) == 0)
264                 return((int)sword);
265         return(-1);
266 }
267
268 /*
269  * Store a short word (16 bits) to user space
270  */
271 int
272 susword (void *base, int word)
273 {
274         unsigned short sword = word;
275         int error;
276
277         if ((error = copyout(&sword, base, sizeof(sword))) == 0)
278                 return(0);
279         return(-1);
280 }
281