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