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