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