1 /* $NetBSD: subr_copy.c,v 1.1 2009/11/04 16:54:00 pooka Exp $ */ 2 3 /*- 4 * Copyright (c) 1997, 1998, 1999, 2002, 2007, 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 1982, 1986, 1991, 1993 35 * The Regents of the University of California. All rights reserved. 36 * (c) UNIX System Laboratories, Inc. 37 * All or some portions of this file are derived from material licensed 38 * to the University of California by American Telephone and Telegraph 39 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 40 * the permission of UNIX System Laboratories, Inc. 41 * 42 * Copyright (c) 1992, 1993 43 * The Regents of the University of California. All rights reserved. 44 * 45 * This software was developed by the Computer Systems Engineering group 46 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 47 * contributed to Berkeley. 48 * 49 * All advertising materials mentioning features or use of this software 50 * must display the following acknowledgement: 51 * This product includes software developed by the University of 52 * California, Lawrence Berkeley Laboratory. 53 * 54 * Redistribution and use in source and binary forms, with or without 55 * modification, are permitted provided that the following conditions 56 * are met: 57 * 1. Redistributions of source code must retain the above copyright 58 * notice, this list of conditions and the following disclaimer. 59 * 2. Redistributions in binary form must reproduce the above copyright 60 * notice, this list of conditions and the following disclaimer in the 61 * documentation and/or other materials provided with the distribution. 62 * 3. Neither the name of the University nor the names of its contributors 63 * may be used to endorse or promote products derived from this software 64 * without specific prior written permission. 65 * 66 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 67 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 68 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 69 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 70 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 71 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 72 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 73 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 74 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 75 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 76 * SUCH DAMAGE. 77 * 78 * @(#)kern_subr.c 8.4 (Berkeley) 2/14/95 79 */ 80 81 #include <sys/cdefs.h> 82 __KERNEL_RCSID(0, "$NetBSD: subr_copy.c,v 1.1 2009/11/04 16:54:00 pooka Exp $"); 83 84 #include <sys/param.h> 85 #include <sys/fcntl.h> 86 #include <sys/proc.h> 87 #include <sys/systm.h> 88 89 #include <uvm/uvm_extern.h> 90 91 void 92 uio_setup_sysspace(struct uio *uio) 93 { 94 95 uio->uio_vmspace = vmspace_kernel(); 96 } 97 98 int 99 uiomove(void *buf, size_t n, struct uio *uio) 100 { 101 struct vmspace *vm = uio->uio_vmspace; 102 struct iovec *iov; 103 size_t cnt; 104 int error = 0; 105 char *cp = buf; 106 107 ASSERT_SLEEPABLE(); 108 109 #ifdef DIAGNOSTIC 110 if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE) 111 panic("uiomove: mode"); 112 #endif 113 while (n > 0 && uio->uio_resid) { 114 iov = uio->uio_iov; 115 cnt = iov->iov_len; 116 if (cnt == 0) { 117 KASSERT(uio->uio_iovcnt > 0); 118 uio->uio_iov++; 119 uio->uio_iovcnt--; 120 continue; 121 } 122 if (cnt > n) 123 cnt = n; 124 if (!VMSPACE_IS_KERNEL_P(vm)) { 125 if (curcpu()->ci_schedstate.spc_flags & 126 SPCF_SHOULDYIELD) 127 preempt(); 128 } 129 130 if (uio->uio_rw == UIO_READ) { 131 error = copyout_vmspace(vm, cp, iov->iov_base, 132 cnt); 133 } else { 134 error = copyin_vmspace(vm, iov->iov_base, cp, 135 cnt); 136 } 137 if (error) { 138 break; 139 } 140 iov->iov_base = (char *)iov->iov_base + cnt; 141 iov->iov_len -= cnt; 142 uio->uio_resid -= cnt; 143 uio->uio_offset += cnt; 144 cp += cnt; 145 KDASSERT(cnt <= n); 146 n -= cnt; 147 } 148 149 return (error); 150 } 151 152 /* 153 * Wrapper for uiomove() that validates the arguments against a known-good 154 * kernel buffer. 155 */ 156 int 157 uiomove_frombuf(void *buf, size_t buflen, struct uio *uio) 158 { 159 size_t offset; 160 161 if (uio->uio_offset < 0 || /* uio->uio_resid < 0 || */ 162 (offset = uio->uio_offset) != uio->uio_offset) 163 return (EINVAL); 164 if (offset >= buflen) 165 return (0); 166 return (uiomove((char *)buf + offset, buflen - offset, uio)); 167 } 168 169 /* 170 * Give next character to user as result of read. 171 */ 172 int 173 ureadc(int c, struct uio *uio) 174 { 175 struct iovec *iov; 176 177 if (uio->uio_resid <= 0) 178 panic("ureadc: non-positive resid"); 179 again: 180 if (uio->uio_iovcnt <= 0) 181 panic("ureadc: non-positive iovcnt"); 182 iov = uio->uio_iov; 183 if (iov->iov_len <= 0) { 184 uio->uio_iovcnt--; 185 uio->uio_iov++; 186 goto again; 187 } 188 if (!VMSPACE_IS_KERNEL_P(uio->uio_vmspace)) { 189 if (subyte(iov->iov_base, c) < 0) 190 return (EFAULT); 191 } else { 192 *(char *)iov->iov_base = c; 193 } 194 iov->iov_base = (char *)iov->iov_base + 1; 195 iov->iov_len--; 196 uio->uio_resid--; 197 uio->uio_offset++; 198 return (0); 199 } 200 201 /* 202 * Like copyin(), but operates on an arbitrary vmspace. 203 */ 204 int 205 copyin_vmspace(struct vmspace *vm, const void *uaddr, void *kaddr, size_t len) 206 { 207 struct iovec iov; 208 struct uio uio; 209 int error; 210 211 if (len == 0) 212 return (0); 213 214 if (VMSPACE_IS_KERNEL_P(vm)) { 215 return kcopy(uaddr, kaddr, len); 216 } 217 if (__predict_true(vm == curproc->p_vmspace)) { 218 return copyin(uaddr, kaddr, len); 219 } 220 221 iov.iov_base = kaddr; 222 iov.iov_len = len; 223 uio.uio_iov = &iov; 224 uio.uio_iovcnt = 1; 225 uio.uio_offset = (off_t)(uintptr_t)uaddr; 226 uio.uio_resid = len; 227 uio.uio_rw = UIO_READ; 228 UIO_SETUP_SYSSPACE(&uio); 229 error = uvm_io(&vm->vm_map, &uio); 230 231 return (error); 232 } 233 234 /* 235 * Like copyout(), but operates on an arbitrary vmspace. 236 */ 237 int 238 copyout_vmspace(struct vmspace *vm, const void *kaddr, void *uaddr, size_t len) 239 { 240 struct iovec iov; 241 struct uio uio; 242 int error; 243 244 if (len == 0) 245 return (0); 246 247 if (VMSPACE_IS_KERNEL_P(vm)) { 248 return kcopy(kaddr, uaddr, len); 249 } 250 if (__predict_true(vm == curproc->p_vmspace)) { 251 return copyout(kaddr, uaddr, len); 252 } 253 254 iov.iov_base = __UNCONST(kaddr); /* XXXUNCONST cast away const */ 255 iov.iov_len = len; 256 uio.uio_iov = &iov; 257 uio.uio_iovcnt = 1; 258 uio.uio_offset = (off_t)(uintptr_t)uaddr; 259 uio.uio_resid = len; 260 uio.uio_rw = UIO_WRITE; 261 UIO_SETUP_SYSSPACE(&uio); 262 error = uvm_io(&vm->vm_map, &uio); 263 264 return (error); 265 } 266 267 /* 268 * Like copyin(), but operates on an arbitrary process. 269 */ 270 int 271 copyin_proc(struct proc *p, const void *uaddr, void *kaddr, size_t len) 272 { 273 struct vmspace *vm; 274 int error; 275 276 error = proc_vmspace_getref(p, &vm); 277 if (error) { 278 return error; 279 } 280 error = copyin_vmspace(vm, uaddr, kaddr, len); 281 uvmspace_free(vm); 282 283 return error; 284 } 285 286 /* 287 * Like copyout(), but operates on an arbitrary process. 288 */ 289 int 290 copyout_proc(struct proc *p, const void *kaddr, void *uaddr, size_t len) 291 { 292 struct vmspace *vm; 293 int error; 294 295 error = proc_vmspace_getref(p, &vm); 296 if (error) { 297 return error; 298 } 299 error = copyout_vmspace(vm, kaddr, uaddr, len); 300 uvmspace_free(vm); 301 302 return error; 303 } 304 305 /* 306 * Like copyin(), except it operates on kernel addresses when the FKIOCTL 307 * flag is passed in `ioctlflags' from the ioctl call. 308 */ 309 int 310 ioctl_copyin(int ioctlflags, const void *src, void *dst, size_t len) 311 { 312 if (ioctlflags & FKIOCTL) 313 return kcopy(src, dst, len); 314 return copyin(src, dst, len); 315 } 316 317 /* 318 * Like copyout(), except it operates on kernel addresses when the FKIOCTL 319 * flag is passed in `ioctlflags' from the ioctl call. 320 */ 321 int 322 ioctl_copyout(int ioctlflags, const void *src, void *dst, size_t len) 323 { 324 if (ioctlflags & FKIOCTL) 325 return kcopy(src, dst, len); 326 return copyout(src, dst, len); 327 } 328