/*1* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 20092* The President and Fellows of Harvard College.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12* 3. Neither the name of the University nor the names of its contributors13* may be used to endorse or promote products derived from this software14* without specific prior written permission.15*16* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND17* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE18* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE19* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE20* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL21* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS22* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)23* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT24* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY25* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF26* SUCH DAMAGE.27*/2829#include <types.h>30#include <lib.h>31#include <uio.h>32#include <thread.h>33#include <current.h>34#include <copyinout.h>3536/*37* See uio.h for a description.38*/3940int41uiomove(void *ptr, size_t n, struct uio *uio)42{43struct iovec *iov;44size_t size;45int result;4647if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE) {48panic("uiomove: Invalid uio_rw %d\n", (int) uio->uio_rw);49}50if (uio->uio_segflg==UIO_SYSSPACE) {51KASSERT(uio->uio_space == NULL);52}53else {54KASSERT(uio->uio_space == curthread->t_addrspace);55}5657while (n > 0 && uio->uio_resid > 0) {58/* get the first iovec */59iov = uio->uio_iov;60size = iov->iov_len;6162if (size > n) {63size = n;64}6566if (size == 0) {67/* move to the next iovec and try again */68uio->uio_iov++;69uio->uio_iovcnt--;70if (uio->uio_iovcnt == 0) {71/*72* This should only happen if you set73* uio_resid incorrectly (to more than74* the total length of buffers the uio75* points to).76*/77panic("uiomove: ran out of buffers\n");78}79continue;80}8182switch (uio->uio_segflg) {83case UIO_SYSSPACE:84result = 0;85if (uio->uio_rw == UIO_READ) {86memmove(iov->iov_kbase, ptr, size);87}88else {89memmove(ptr, iov->iov_kbase, size);90}91iov->iov_kbase = ((char *)iov->iov_kbase+size);92break;93case UIO_USERSPACE:94case UIO_USERISPACE:95if (uio->uio_rw == UIO_READ) {96result = copyout(ptr, iov->iov_ubase,size);97}98else {99result = copyin(iov->iov_ubase, ptr, size);100}101if (result) {102return result;103}104iov->iov_ubase += size;105break;106default:107panic("uiomove: Invalid uio_segflg %d\n",108(int)uio->uio_segflg);109}110111iov->iov_len -= size;112uio->uio_resid -= size;113uio->uio_offset += size;114ptr = ((char *)ptr + size);115n -= size;116}117118return 0;119}120121int122uiomovezeros(size_t n, struct uio *uio)123{124/* static, so initialized as zero */125static char zeros[16];126size_t amt;127int result;128129/* This only makes sense when reading */130KASSERT(uio->uio_rw == UIO_READ);131132while (n > 0) {133amt = sizeof(zeros);134if (amt > n) {135amt = n;136}137result = uiomove(zeros, amt, uio);138if (result) {139return result;140}141n -= amt;142}143144return 0;145}146147/*148* Convenience function to initialize an iovec and uio for kernel I/O.149*/150151void152uio_kinit(struct iovec *iov, struct uio *u,153void *kbuf, size_t len, off_t pos, enum uio_rw rw)154{155iov->iov_kbase = kbuf;156iov->iov_len = len;157u->uio_iov = iov;158u->uio_iovcnt = 1;159u->uio_offset = pos;160u->uio_resid = len;161u->uio_segflg = UIO_SYSSPACE;162u->uio_rw = rw;163u->uio_space = NULL;164}165166167