1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 29*7c478bd9Sstevel@tonic-gate 30*7c478bd9Sstevel@tonic-gate /* 31*7c478bd9Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988 32*7c478bd9Sstevel@tonic-gate * The Regents of the University of California 33*7c478bd9Sstevel@tonic-gate * All Rights Reserved 34*7c478bd9Sstevel@tonic-gate * 35*7c478bd9Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from 36*7c478bd9Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its 37*7c478bd9Sstevel@tonic-gate * contributors. 38*7c478bd9Sstevel@tonic-gate */ 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/uio.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate /* 50*7c478bd9Sstevel@tonic-gate * Move "n" bytes at byte address "p"; "rw" indicates the direction 51*7c478bd9Sstevel@tonic-gate * of the move, and the I/O parameters are provided in "uio", which is 52*7c478bd9Sstevel@tonic-gate * update to reflect the data which was moved. Returns 0 on success or 53*7c478bd9Sstevel@tonic-gate * a non-zero errno on failure. 54*7c478bd9Sstevel@tonic-gate */ 55*7c478bd9Sstevel@tonic-gate int 56*7c478bd9Sstevel@tonic-gate uiomove(void *p, size_t n, enum uio_rw rw, struct uio *uio) 57*7c478bd9Sstevel@tonic-gate { 58*7c478bd9Sstevel@tonic-gate struct iovec *iov; 59*7c478bd9Sstevel@tonic-gate ulong_t cnt; 60*7c478bd9Sstevel@tonic-gate int error; 61*7c478bd9Sstevel@tonic-gate 62*7c478bd9Sstevel@tonic-gate while (n && uio->uio_resid) { 63*7c478bd9Sstevel@tonic-gate iov = uio->uio_iov; 64*7c478bd9Sstevel@tonic-gate cnt = MIN(iov->iov_len, n); 65*7c478bd9Sstevel@tonic-gate if (cnt == 0l) { 66*7c478bd9Sstevel@tonic-gate uio->uio_iov++; 67*7c478bd9Sstevel@tonic-gate uio->uio_iovcnt--; 68*7c478bd9Sstevel@tonic-gate continue; 69*7c478bd9Sstevel@tonic-gate } 70*7c478bd9Sstevel@tonic-gate switch (uio->uio_segflg) { 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate case UIO_USERSPACE: 73*7c478bd9Sstevel@tonic-gate case UIO_USERISPACE: 74*7c478bd9Sstevel@tonic-gate if (rw == UIO_READ) { 75*7c478bd9Sstevel@tonic-gate error = xcopyout_nta(p, iov->iov_base, cnt, 76*7c478bd9Sstevel@tonic-gate (uio->uio_extflg & UIO_COPY_CACHED)); 77*7c478bd9Sstevel@tonic-gate } else { 78*7c478bd9Sstevel@tonic-gate error = xcopyin_nta(iov->iov_base, p, cnt, 79*7c478bd9Sstevel@tonic-gate (uio->uio_extflg & UIO_COPY_CACHED)); 80*7c478bd9Sstevel@tonic-gate } 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate if (error) 83*7c478bd9Sstevel@tonic-gate return (error); 84*7c478bd9Sstevel@tonic-gate break; 85*7c478bd9Sstevel@tonic-gate 86*7c478bd9Sstevel@tonic-gate case UIO_SYSSPACE: 87*7c478bd9Sstevel@tonic-gate if (rw == UIO_READ) 88*7c478bd9Sstevel@tonic-gate error = kcopy_nta(p, iov->iov_base, cnt, 89*7c478bd9Sstevel@tonic-gate (uio->uio_extflg & UIO_COPY_CACHED)); 90*7c478bd9Sstevel@tonic-gate else 91*7c478bd9Sstevel@tonic-gate error = kcopy_nta(iov->iov_base, p, cnt, 92*7c478bd9Sstevel@tonic-gate (uio->uio_extflg & UIO_COPY_CACHED)); 93*7c478bd9Sstevel@tonic-gate if (error) 94*7c478bd9Sstevel@tonic-gate return (error); 95*7c478bd9Sstevel@tonic-gate break; 96*7c478bd9Sstevel@tonic-gate } 97*7c478bd9Sstevel@tonic-gate iov->iov_base += cnt; 98*7c478bd9Sstevel@tonic-gate iov->iov_len -= cnt; 99*7c478bd9Sstevel@tonic-gate uio->uio_resid -= cnt; 100*7c478bd9Sstevel@tonic-gate uio->uio_loffset += cnt; 101*7c478bd9Sstevel@tonic-gate p = (caddr_t)p + cnt; 102*7c478bd9Sstevel@tonic-gate n -= cnt; 103*7c478bd9Sstevel@tonic-gate } 104*7c478bd9Sstevel@tonic-gate return (0); 105*7c478bd9Sstevel@tonic-gate } 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate /* 108*7c478bd9Sstevel@tonic-gate * transfer a character value into the address space 109*7c478bd9Sstevel@tonic-gate * delineated by a uio and update fields within the 110*7c478bd9Sstevel@tonic-gate * uio for next character. Return 0 for success, EFAULT 111*7c478bd9Sstevel@tonic-gate * for error. 112*7c478bd9Sstevel@tonic-gate */ 113*7c478bd9Sstevel@tonic-gate int 114*7c478bd9Sstevel@tonic-gate ureadc(int val, struct uio *uiop) 115*7c478bd9Sstevel@tonic-gate { 116*7c478bd9Sstevel@tonic-gate struct iovec *iovp; 117*7c478bd9Sstevel@tonic-gate unsigned char c; 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate /* 120*7c478bd9Sstevel@tonic-gate * first determine if uio is valid. uiop should be 121*7c478bd9Sstevel@tonic-gate * non-NULL and the resid count > 0. 122*7c478bd9Sstevel@tonic-gate */ 123*7c478bd9Sstevel@tonic-gate if (!(uiop && uiop->uio_resid > 0)) 124*7c478bd9Sstevel@tonic-gate return (EFAULT); 125*7c478bd9Sstevel@tonic-gate 126*7c478bd9Sstevel@tonic-gate /* 127*7c478bd9Sstevel@tonic-gate * scan through iovecs until one is found that is non-empty. 128*7c478bd9Sstevel@tonic-gate * Return EFAULT if none found. 129*7c478bd9Sstevel@tonic-gate */ 130*7c478bd9Sstevel@tonic-gate while (uiop->uio_iovcnt > 0) { 131*7c478bd9Sstevel@tonic-gate iovp = uiop->uio_iov; 132*7c478bd9Sstevel@tonic-gate if (iovp->iov_len <= 0) { 133*7c478bd9Sstevel@tonic-gate uiop->uio_iovcnt--; 134*7c478bd9Sstevel@tonic-gate uiop->uio_iov++; 135*7c478bd9Sstevel@tonic-gate } else 136*7c478bd9Sstevel@tonic-gate break; 137*7c478bd9Sstevel@tonic-gate } 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate if (uiop->uio_iovcnt <= 0) 140*7c478bd9Sstevel@tonic-gate return (EFAULT); 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate /* 143*7c478bd9Sstevel@tonic-gate * Transfer character to uio space. 144*7c478bd9Sstevel@tonic-gate */ 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate c = (unsigned char) (val & 0xFF); 147*7c478bd9Sstevel@tonic-gate 148*7c478bd9Sstevel@tonic-gate switch (uiop->uio_segflg) { 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate case UIO_USERISPACE: 151*7c478bd9Sstevel@tonic-gate case UIO_USERSPACE: 152*7c478bd9Sstevel@tonic-gate if (copyout(&c, iovp->iov_base, sizeof (unsigned char))) 153*7c478bd9Sstevel@tonic-gate return (EFAULT); 154*7c478bd9Sstevel@tonic-gate break; 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate case UIO_SYSSPACE: /* can do direct copy since kernel-kernel */ 157*7c478bd9Sstevel@tonic-gate *iovp->iov_base = c; 158*7c478bd9Sstevel@tonic-gate break; 159*7c478bd9Sstevel@tonic-gate 160*7c478bd9Sstevel@tonic-gate default: 161*7c478bd9Sstevel@tonic-gate return (EFAULT); /* invalid segflg value */ 162*7c478bd9Sstevel@tonic-gate } 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate /* 165*7c478bd9Sstevel@tonic-gate * bump up/down iovec and uio members to reflect transfer. 166*7c478bd9Sstevel@tonic-gate */ 167*7c478bd9Sstevel@tonic-gate iovp->iov_base++; 168*7c478bd9Sstevel@tonic-gate iovp->iov_len--; 169*7c478bd9Sstevel@tonic-gate uiop->uio_resid--; 170*7c478bd9Sstevel@tonic-gate uiop->uio_loffset++; 171*7c478bd9Sstevel@tonic-gate return (0); /* success */ 172*7c478bd9Sstevel@tonic-gate } 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate /* 175*7c478bd9Sstevel@tonic-gate * return a character value from the address space 176*7c478bd9Sstevel@tonic-gate * delineated by a uio and update fields within the 177*7c478bd9Sstevel@tonic-gate * uio for next character. Return the character for success, 178*7c478bd9Sstevel@tonic-gate * -1 for error. 179*7c478bd9Sstevel@tonic-gate */ 180*7c478bd9Sstevel@tonic-gate int 181*7c478bd9Sstevel@tonic-gate uwritec(struct uio *uiop) 182*7c478bd9Sstevel@tonic-gate { 183*7c478bd9Sstevel@tonic-gate struct iovec *iovp; 184*7c478bd9Sstevel@tonic-gate unsigned char c; 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate /* 187*7c478bd9Sstevel@tonic-gate * verify we were passed a valid uio structure. 188*7c478bd9Sstevel@tonic-gate * (1) non-NULL uiop, (2) positive resid count 189*7c478bd9Sstevel@tonic-gate * (3) there is an iovec with positive length 190*7c478bd9Sstevel@tonic-gate */ 191*7c478bd9Sstevel@tonic-gate 192*7c478bd9Sstevel@tonic-gate if (!(uiop && uiop->uio_resid > 0)) 193*7c478bd9Sstevel@tonic-gate return (-1); 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate while (uiop->uio_iovcnt > 0) { 196*7c478bd9Sstevel@tonic-gate iovp = uiop->uio_iov; 197*7c478bd9Sstevel@tonic-gate if (iovp->iov_len <= 0) { 198*7c478bd9Sstevel@tonic-gate uiop->uio_iovcnt--; 199*7c478bd9Sstevel@tonic-gate uiop->uio_iov++; 200*7c478bd9Sstevel@tonic-gate } else 201*7c478bd9Sstevel@tonic-gate break; 202*7c478bd9Sstevel@tonic-gate } 203*7c478bd9Sstevel@tonic-gate 204*7c478bd9Sstevel@tonic-gate if (uiop->uio_iovcnt <= 0) 205*7c478bd9Sstevel@tonic-gate return (-1); 206*7c478bd9Sstevel@tonic-gate 207*7c478bd9Sstevel@tonic-gate /* 208*7c478bd9Sstevel@tonic-gate * Get the character from the uio address space. 209*7c478bd9Sstevel@tonic-gate */ 210*7c478bd9Sstevel@tonic-gate switch (uiop->uio_segflg) { 211*7c478bd9Sstevel@tonic-gate 212*7c478bd9Sstevel@tonic-gate case UIO_USERISPACE: 213*7c478bd9Sstevel@tonic-gate case UIO_USERSPACE: 214*7c478bd9Sstevel@tonic-gate if (copyin(iovp->iov_base, &c, sizeof (unsigned char))) 215*7c478bd9Sstevel@tonic-gate return (-1); 216*7c478bd9Sstevel@tonic-gate break; 217*7c478bd9Sstevel@tonic-gate 218*7c478bd9Sstevel@tonic-gate case UIO_SYSSPACE: 219*7c478bd9Sstevel@tonic-gate c = *iovp->iov_base; 220*7c478bd9Sstevel@tonic-gate break; 221*7c478bd9Sstevel@tonic-gate 222*7c478bd9Sstevel@tonic-gate default: 223*7c478bd9Sstevel@tonic-gate return (-1); /* invalid segflg */ 224*7c478bd9Sstevel@tonic-gate } 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate /* 227*7c478bd9Sstevel@tonic-gate * Adjust fields of iovec and uio appropriately. 228*7c478bd9Sstevel@tonic-gate */ 229*7c478bd9Sstevel@tonic-gate iovp->iov_base++; 230*7c478bd9Sstevel@tonic-gate iovp->iov_len--; 231*7c478bd9Sstevel@tonic-gate uiop->uio_resid--; 232*7c478bd9Sstevel@tonic-gate uiop->uio_loffset++; 233*7c478bd9Sstevel@tonic-gate return ((int)c & 0xFF); /* success */ 234*7c478bd9Sstevel@tonic-gate } 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate /* 237*7c478bd9Sstevel@tonic-gate * Drop the next n chars out of *uiop. 238*7c478bd9Sstevel@tonic-gate */ 239*7c478bd9Sstevel@tonic-gate void 240*7c478bd9Sstevel@tonic-gate uioskip(uio_t *uiop, size_t n) 241*7c478bd9Sstevel@tonic-gate { 242*7c478bd9Sstevel@tonic-gate if (n > uiop->uio_resid) 243*7c478bd9Sstevel@tonic-gate return; 244*7c478bd9Sstevel@tonic-gate while (n != 0) { 245*7c478bd9Sstevel@tonic-gate register iovec_t *iovp = uiop->uio_iov; 246*7c478bd9Sstevel@tonic-gate register size_t niovb = MIN(iovp->iov_len, n); 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate if (niovb == 0) { 249*7c478bd9Sstevel@tonic-gate uiop->uio_iov++; 250*7c478bd9Sstevel@tonic-gate uiop->uio_iovcnt--; 251*7c478bd9Sstevel@tonic-gate continue; 252*7c478bd9Sstevel@tonic-gate } 253*7c478bd9Sstevel@tonic-gate iovp->iov_base += niovb; 254*7c478bd9Sstevel@tonic-gate uiop->uio_loffset += niovb; 255*7c478bd9Sstevel@tonic-gate iovp->iov_len -= niovb; 256*7c478bd9Sstevel@tonic-gate uiop->uio_resid -= niovb; 257*7c478bd9Sstevel@tonic-gate n -= niovb; 258*7c478bd9Sstevel@tonic-gate } 259*7c478bd9Sstevel@tonic-gate } 260*7c478bd9Sstevel@tonic-gate 261*7c478bd9Sstevel@tonic-gate /* 262*7c478bd9Sstevel@tonic-gate * Dup the suio into the duio and diovec of size diov_cnt. If diov 263*7c478bd9Sstevel@tonic-gate * is too small to dup suio then an error will be returned, else 0. 264*7c478bd9Sstevel@tonic-gate */ 265*7c478bd9Sstevel@tonic-gate int 266*7c478bd9Sstevel@tonic-gate uiodup(uio_t *suio, uio_t *duio, iovec_t *diov, int diov_cnt) 267*7c478bd9Sstevel@tonic-gate { 268*7c478bd9Sstevel@tonic-gate int ix; 269*7c478bd9Sstevel@tonic-gate iovec_t *siov = suio->uio_iov; 270*7c478bd9Sstevel@tonic-gate 271*7c478bd9Sstevel@tonic-gate *duio = *suio; 272*7c478bd9Sstevel@tonic-gate for (ix = 0; ix < suio->uio_iovcnt; ix++) { 273*7c478bd9Sstevel@tonic-gate diov[ix] = siov[ix]; 274*7c478bd9Sstevel@tonic-gate if (ix >= diov_cnt) 275*7c478bd9Sstevel@tonic-gate return (1); 276*7c478bd9Sstevel@tonic-gate } 277*7c478bd9Sstevel@tonic-gate duio->uio_iov = diov; 278*7c478bd9Sstevel@tonic-gate return (0); 279*7c478bd9Sstevel@tonic-gate } 280