kernel - Introduce lightweight buffers
[dragonfly.git] / sys / platform / vkernel / platform / copyio.c
CommitLineData
8a9d8995
MD
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 *
17cde63e 34 * $DragonFly: src/sys/platform/vkernel/platform/copyio.c,v 1.9 2008/05/09 07:24:47 dillon Exp $
8a9d8995
MD
35 */
36
37#include <sys/types.h>
38#include <sys/systm.h>
5c5185ae 39#include <cpu/lwbuf.h>
8a9d8995 40#include <vm/vm_page.h>
6092278a 41#include <vm/vm_extern.h>
8a9d8995
MD
42#include <assert.h>
43
6092278a
MD
44#include <sys/stat.h>
45#include <sys/mman.h>
46
684a93c4
MD
47#include <sys/mplock2.h>
48
8a9d8995 49/*
e4a473f1
MD
50 * A bcopy that works dring low level boot, before FP is working
51 */
52void
53ovbcopy(const void *src, void *dst, size_t len)
54{
55 bcopy(src, dst, len);
56}
57
6f7b98e0
MD
58void
59bcopyi(const void *src, void *dst, size_t len)
60{
61 bcopy(src, dst, len);
62}
63
64int
65copystr(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) {
0171c06b
MD
71 if (lencopied)
72 *lencopied = i + 1;
6f7b98e0
MD
73 return(0);
74 }
75 }
76 return (ENAMETOOLONG);
77}
78
e4a473f1 79/*
8a9d8995
MD
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 */
86int
87copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *res)
88{
6092278a
MD
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);
8a9d8995
MD
117}
118
119/*
120 * Copy a binary buffer from user space to kernel space.
121 *
7e522155
MD
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 *
8a9d8995
MD
125 * Returns 0 on success, EFAULT on failure.
126 */
127int
6092278a 128copyin(const void *udaddr, void *kaddr, size_t len)
8a9d8995 129{
6092278a 130 struct vmspace *vm = curproc->p_vmspace;
5c5185ae 131 struct lwbuf *lwb;
6092278a
MD
132 vm_page_t m;
133 int error;
134 size_t n;
135
136 error = 0;
7e522155 137 get_mplock();
6092278a
MD
138 while (len) {
139 m = vm_fault_page(&vm->vm_map, trunc_page((vm_offset_t)udaddr),
0035dca9
MD
140 VM_PROT_READ,
141 VM_FAULT_NORMAL, &error);
6092278a
MD
142 if (error)
143 break;
144 n = PAGE_SIZE - ((vm_offset_t)udaddr & PAGE_MASK);
145 if (n > len)
146 n = len;
5c5185ae
SG
147 lwb = lwbuf_alloc(m);
148 bcopy((char *)lwbuf_kva(lwb)+((vm_offset_t)udaddr & PAGE_MASK),
6092278a
MD
149 kaddr, n);
150 len -= n;
151 udaddr = (const char *)udaddr + n;
152 kaddr = (char *)kaddr + n;
6092278a 153 vm_page_unhold(m);
5c5185ae 154 lwbuf_free(lwb);
6092278a 155 }
7e522155 156 rel_mplock();
6092278a 157 return (error);
8a9d8995
MD
158}
159
160/*
161 * Copy a binary buffer from kernel space to user space.
162 *
163 * Returns 0 on success, EFAULT on failure.
164 */
165int
6092278a 166copyout(const void *kaddr, void *udaddr, size_t len)
8a9d8995 167{
6092278a 168 struct vmspace *vm = curproc->p_vmspace;
5c5185ae 169 struct lwbuf *lwb;
6092278a
MD
170 vm_page_t m;
171 int error;
172 size_t n;
173
174 error = 0;
7e522155 175 get_mplock();
6092278a
MD
176 while (len) {
177 m = vm_fault_page(&vm->vm_map, trunc_page((vm_offset_t)udaddr),
0035dca9
MD
178 VM_PROT_READ|VM_PROT_WRITE,
179 VM_FAULT_NORMAL, &error);
6092278a
MD
180 if (error)
181 break;
182 n = PAGE_SIZE - ((vm_offset_t)udaddr & PAGE_MASK);
183 if (n > len)
184 n = len;
5c5185ae
SG
185 lwb = lwbuf_alloc(m);
186 bcopy(kaddr, (char *)lwbuf_kva(lwb) +
6092278a
MD
187 ((vm_offset_t)udaddr & PAGE_MASK), n);
188 len -= n;
189 udaddr = (char *)udaddr + n;
190 kaddr = (const char *)kaddr + n;
17cde63e 191 vm_page_dirty(m);
6092278a 192 vm_page_unhold(m);
5c5185ae 193 lwbuf_free(lwb);
6092278a 194 }
7e522155 195 rel_mplock();
6092278a 196 return (error);
8a9d8995
MD
197}
198
199/*
200 * Fetch the byte at the specified user address. Returns -1 on failure.
201 */
202int
203fubyte(const void *base)
204{
6092278a
MD
205 unsigned char c;
206 int error;
207
208 if ((error = copyin(base, &c, 1)) == 0)
209 return((int)c);
210 return(-1);
8a9d8995
MD
211}
212
213/*
214 * Store a byte at the specified user address. Returns -1 on failure.
215 */
216int
217subyte (void *base, int byte)
218{
6092278a
MD
219 unsigned char c = byte;
220 int error;
221
222 if ((error = copyout(&c, base, 1)) == 0)
223 return(0);
224 return(-1);
8a9d8995
MD
225}
226
227/*
228 * Fetch a word (integer, 32 bits) from user space
229 */
230long
6092278a 231fuword(const void *base)
8a9d8995 232{
6092278a
MD
233 long v;
234 int error;
235
236 if ((error = copyin(base, &v, sizeof(v))) == 0)
237 return((long)v);
238 return(-1);
8a9d8995
MD
239}
240
241/*
242 * Store a word (integer, 32 bits) to user space
243 */
244int
6092278a 245suword(void *base, long word)
8a9d8995 246{
6092278a
MD
247 int error;
248
249 if ((error = copyout(&word, base, sizeof(word))) == 0)
250 return(0);
251 return(-1);
8a9d8995
MD
252}
253
254/*
255 * Fetch an short word (16 bits) from user space
256 */
257int
6092278a 258fusword(void *base)
8a9d8995 259{
6092278a
MD
260 unsigned short sword;
261 int error;
262
263 if ((error = copyin(base, &sword, sizeof(sword))) == 0)
264 return((int)sword);
265 return(-1);
8a9d8995
MD
266}
267
268/*
269 * Store a short word (16 bits) to user space
270 */
271int
272susword (void *base, int word)
273{
6092278a
MD
274 unsigned short sword = word;
275 int error;
276
277 if ((error = copyout(&sword, base, sizeof(sword))) == 0)
278 return(0);
279 return(-1);
8a9d8995
MD
280}
281