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 if (error) 153 error = EFAULT; 154 return (error); 155 } 156 157 /* 158 * Copy a binary buffer from kernel space to user space. 159 * 160 * Returns 0 on success, EFAULT on failure. 161 */ 162 int 163 copyout(const void *kaddr, void *udaddr, size_t len) 164 { 165 struct vmspace *vm = curproc->p_vmspace; 166 struct lwbuf *lwb; 167 struct lwbuf lwb_cache; 168 vm_page_t m; 169 int error; 170 size_t n; 171 172 error = 0; 173 while (len) { 174 m = vm_fault_page(&vm->vm_map, trunc_page((vm_offset_t)udaddr), 175 VM_PROT_READ|VM_PROT_WRITE, 176 VM_FAULT_NORMAL, &error); 177 if (error) 178 break; 179 n = PAGE_SIZE - ((vm_offset_t)udaddr & PAGE_MASK); 180 if (n > len) 181 n = len; 182 lwb = lwbuf_alloc(m, &lwb_cache); 183 bcopy(kaddr, (char *)lwbuf_kva(lwb) + 184 ((vm_offset_t)udaddr & PAGE_MASK), n); 185 len -= n; 186 udaddr = (char *)udaddr + n; 187 kaddr = (const char *)kaddr + n; 188 vm_page_dirty(m); 189 lwbuf_free(lwb); 190 vm_page_unhold(m); 191 } 192 if (error) 193 error = EFAULT; 194 return (error); 195 } 196 197 /* 198 * Fetch the byte at the specified user address. Returns -1 on failure. 199 */ 200 int 201 fubyte(const void *base) 202 { 203 unsigned char c; 204 205 if (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 218 if (copyout(&c, base, 1) == 0) 219 return(0); 220 return(-1); 221 } 222 223 /* 224 * Fetch a word (integer, 32 bits) from user space 225 */ 226 long 227 fuword(const void *base) 228 { 229 long v; 230 231 if (copyin(base, &v, sizeof(v)) == 0) 232 return(v); 233 return(-1); 234 } 235 236 /* 237 * Store a word (integer, 32 bits) to user space 238 */ 239 int 240 suword(void *base, long word) 241 { 242 if (copyout(&word, base, sizeof(word)) == 0) 243 return(0); 244 return(-1); 245 } 246 247 int 248 suword32(void *base, int word) 249 { 250 if (copyout(&word, base, sizeof(word)) == 0) 251 return(0); 252 return(-1); 253 } 254 255 /* 256 * Fetch an short word (16 bits) from user space 257 */ 258 int 259 fusword(void *base) 260 { 261 unsigned short sword; 262 263 if (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 276 if (copyout(&sword, base, sizeof(sword)) == 0) 277 return(0); 278 return(-1); 279 } 280