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 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/errno.h> 31 #include <sys/proc.h> 32 #include <sys/procfs.h> 33 #include <sys/sysmacros.h> 34 #include <sys/uio.h> 35 #include <sys/cmn_err.h> 36 37 #if defined(__sparc) 38 #include <sys/stack.h> 39 #endif 40 41 #define STACK_BUF_SIZE 64 /* power of 2 */ 42 43 int 44 prusrio(proc_t *p, enum uio_rw rw, struct uio *uiop, int old) 45 { 46 /* longlong-aligned short buffer */ 47 longlong_t buffer[STACK_BUF_SIZE / sizeof (longlong_t)]; 48 int error = 0; 49 void *bp; 50 int allocated; 51 ssize_t total = uiop->uio_resid; 52 uintptr_t addr; 53 size_t len; 54 55 /* for short reads/writes, use the on-stack buffer */ 56 if (uiop->uio_resid <= STACK_BUF_SIZE) { 57 bp = buffer; 58 allocated = 0; 59 } else { 60 bp = kmem_alloc(PAGESIZE, KM_SLEEP); 61 allocated = 1; 62 } 63 64 #if defined(__sparc) 65 if (p == curproc) 66 (void) flush_user_windows_to_stack(NULL); 67 #endif 68 69 switch (rw) { 70 case UIO_READ: 71 while (uiop->uio_resid != 0) { 72 addr = uiop->uio_offset; 73 len = MIN(uiop->uio_resid, 74 PAGESIZE - (addr & PAGEOFFSET)); 75 76 if ((error = uread(p, bp, len, addr)) != 0 || 77 (error = uiomove(bp, len, UIO_READ, uiop)) != 0) 78 break; 79 } 80 81 /* 82 * ENXIO indicates that a page didn't exist. If the I/O was 83 * truncated, return success; otherwise convert the error into 84 * EIO. When obeying new /proc semantics, we don't return an 85 * error for a read that begins at an invalid address. 86 */ 87 if (error == ENXIO) { 88 if (total != uiop->uio_resid || !old) 89 error = 0; 90 else 91 error = EIO; 92 } 93 break; 94 case UIO_WRITE: 95 while (uiop->uio_resid != 0) { 96 addr = uiop->uio_offset; 97 len = MIN(uiop->uio_resid, 98 PAGESIZE - (addr & PAGEOFFSET)); 99 100 if ((error = uiomove(bp, len, UIO_WRITE, uiop)) != 0) 101 break; 102 if ((error = uwrite(p, bp, len, addr)) != 0) { 103 uiop->uio_resid += len; 104 uiop->uio_loffset -= len; 105 break; 106 } 107 } 108 109 /* 110 * ENXIO indicates that a page didn't exist. If the I/O was 111 * truncated, return success; otherwise convert the error 112 * into EIO. 113 */ 114 if (error == ENXIO) { 115 if (total != uiop->uio_resid) 116 error = 0; 117 else 118 error = EIO; 119 } 120 break; 121 default: 122 panic("prusrio: rw=%d neither UIO_READ not UIO_WRITE", rw); 123 /*NOTREACHED*/ 124 } 125 126 if (allocated) 127 kmem_free(bp, PAGESIZE); 128 129 return (error); 130 } 131