128993443SEd Schouten /*- 228993443SEd Schouten * Copyright (c) 1982, 1986, 1991, 1993 328993443SEd Schouten * The Regents of the University of California. All rights reserved. 428993443SEd Schouten * (c) UNIX System Laboratories, Inc. 528993443SEd Schouten * All or some portions of this file are derived from material licensed 628993443SEd Schouten * to the University of California by American Telephone and Telegraph 728993443SEd Schouten * Co. or Unix System Laboratories, Inc. and are reproduced herein with 828993443SEd Schouten * the permission of UNIX System Laboratories, Inc. 928993443SEd Schouten * 1028993443SEd Schouten * Redistribution and use in source and binary forms, with or without 1128993443SEd Schouten * modification, are permitted provided that the following conditions 1228993443SEd Schouten * are met: 1328993443SEd Schouten * 1. Redistributions of source code must retain the above copyright 1428993443SEd Schouten * notice, this list of conditions and the following disclaimer. 1528993443SEd Schouten * 2. Redistributions in binary form must reproduce the above copyright 1628993443SEd Schouten * notice, this list of conditions and the following disclaimer in the 1728993443SEd Schouten * documentation and/or other materials provided with the distribution. 1828993443SEd Schouten * 4. Neither the name of the University nor the names of its contributors 1928993443SEd Schouten * may be used to endorse or promote products derived from this software 2028993443SEd Schouten * without specific prior written permission. 2128993443SEd Schouten * 2228993443SEd Schouten * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2328993443SEd Schouten * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2428993443SEd Schouten * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2528993443SEd Schouten * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2628993443SEd Schouten * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2728993443SEd Schouten * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2828993443SEd Schouten * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2928993443SEd Schouten * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3028993443SEd Schouten * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3128993443SEd Schouten * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3228993443SEd Schouten * SUCH DAMAGE. 3328993443SEd Schouten * 3428993443SEd Schouten * @(#)kern_subr.c 8.3 (Berkeley) 1/21/94 3528993443SEd Schouten */ 3628993443SEd Schouten 3728993443SEd Schouten #include <sys/cdefs.h> 3828993443SEd Schouten __FBSDID("$FreeBSD$"); 3928993443SEd Schouten 4028993443SEd Schouten #include "opt_zero.h" 4128993443SEd Schouten 4228993443SEd Schouten #include <sys/param.h> 4328993443SEd Schouten #include <sys/systm.h> 4428993443SEd Schouten #include <sys/kernel.h> 4528993443SEd Schouten #include <sys/limits.h> 4628993443SEd Schouten #include <sys/lock.h> 470f502d1cSKonstantin Belousov #include <sys/mman.h> 4828993443SEd Schouten #include <sys/proc.h> 490f502d1cSKonstantin Belousov #include <sys/resourcevar.h> 5089f6b863SAttilio Rao #include <sys/rwlock.h> 5128993443SEd Schouten #include <sys/sched.h> 5228993443SEd Schouten #include <sys/sysctl.h> 5328993443SEd Schouten #include <sys/vnode.h> 5428993443SEd Schouten 5528993443SEd Schouten #include <vm/vm.h> 561c771f92SKonstantin Belousov #include <vm/vm_param.h> 570f502d1cSKonstantin Belousov #include <vm/vm_extern.h> 5828993443SEd Schouten #include <vm/vm_page.h> 59*e946b949SAttilio Rao #include <vm/vm_pageout.h> 6028993443SEd Schouten #include <vm/vm_map.h> 61e37e60c3SAndre Oppermann #ifdef SOCKET_SEND_COW 6228993443SEd Schouten #include <vm/vm_object.h> 6328993443SEd Schouten #endif 6428993443SEd Schouten 6528993443SEd Schouten SYSCTL_INT(_kern, KERN_IOV_MAX, iov_max, CTLFLAG_RD, NULL, UIO_MAXIOV, 6628993443SEd Schouten "Maximum number of elements in an I/O vector; sysconf(_SC_IOV_MAX)"); 6728993443SEd Schouten 682801687dSKonstantin Belousov static int uiomove_faultflag(void *cp, int n, struct uio *uio, int nofault); 692801687dSKonstantin Belousov 70e37e60c3SAndre Oppermann #ifdef SOCKET_SEND_COW 7128993443SEd Schouten /* Declared in uipc_socket.c */ 7228993443SEd Schouten extern int so_zero_copy_receive; 7328993443SEd Schouten 7428993443SEd Schouten /* 7528993443SEd Schouten * Identify the physical page mapped at the given kernel virtual 7628993443SEd Schouten * address. Insert this physical page into the given address space at 7728993443SEd Schouten * the given virtual address, replacing the physical page, if any, 7828993443SEd Schouten * that already exists there. 7928993443SEd Schouten */ 8028993443SEd Schouten static int 8128993443SEd Schouten vm_pgmoveco(vm_map_t mapa, vm_offset_t kaddr, vm_offset_t uaddr) 8228993443SEd Schouten { 8328993443SEd Schouten vm_map_t map = mapa; 8428993443SEd Schouten vm_page_t kern_pg, user_pg; 8528993443SEd Schouten vm_object_t uobject; 8628993443SEd Schouten vm_map_entry_t entry; 8728993443SEd Schouten vm_pindex_t upindex; 8828993443SEd Schouten vm_prot_t prot; 8928993443SEd Schouten boolean_t wired; 9028993443SEd Schouten 9128993443SEd Schouten KASSERT((uaddr & PAGE_MASK) == 0, 9228993443SEd Schouten ("vm_pgmoveco: uaddr is not page aligned")); 9328993443SEd Schouten 9428993443SEd Schouten /* 9528993443SEd Schouten * Herein the physical page is validated and dirtied. It is 9628993443SEd Schouten * unwired in sf_buf_mext(). 9728993443SEd Schouten */ 9828993443SEd Schouten kern_pg = PHYS_TO_VM_PAGE(vtophys(kaddr)); 9928993443SEd Schouten kern_pg->valid = VM_PAGE_BITS_ALL; 10028993443SEd Schouten KASSERT(kern_pg->queue == PQ_NONE && kern_pg->wire_count == 1, 10128993443SEd Schouten ("vm_pgmoveco: kern_pg is not correctly wired")); 10228993443SEd Schouten 10328993443SEd Schouten if ((vm_map_lookup(&map, uaddr, 10428993443SEd Schouten VM_PROT_WRITE, &entry, &uobject, 10528993443SEd Schouten &upindex, &prot, &wired)) != KERN_SUCCESS) { 10628993443SEd Schouten return(EFAULT); 10728993443SEd Schouten } 10889f6b863SAttilio Rao VM_OBJECT_WLOCK(uobject); 10928993443SEd Schouten retry: 11028993443SEd Schouten if ((user_pg = vm_page_lookup(uobject, upindex)) != NULL) { 111c7aebda8SAttilio Rao if (vm_page_sleep_if_busy(user_pg, "vm_pgmoveco")) 11228993443SEd Schouten goto retry; 1135ac59343SAlan Cox vm_page_lock(user_pg); 11428993443SEd Schouten pmap_remove_all(user_pg); 11528993443SEd Schouten vm_page_free(user_pg); 1165ac59343SAlan Cox vm_page_unlock(user_pg); 11728993443SEd Schouten } else { 11828993443SEd Schouten /* 11928993443SEd Schouten * Even if a physical page does not exist in the 12028993443SEd Schouten * object chain's first object, a physical page from a 12128993443SEd Schouten * backing object may be mapped read only. 12228993443SEd Schouten */ 12328993443SEd Schouten if (uobject->backing_object != NULL) 12428993443SEd Schouten pmap_remove(map->pmap, uaddr, uaddr + PAGE_SIZE); 12528993443SEd Schouten } 126*e946b949SAttilio Rao if (vm_page_insert(kern_pg, uobject, upindex)) { 127*e946b949SAttilio Rao VM_OBJECT_WUNLOCK(uobject); 128*e946b949SAttilio Rao VM_WAIT; 129*e946b949SAttilio Rao VM_OBJECT_WLOCK(uobject); 130*e946b949SAttilio Rao goto retry; 131*e946b949SAttilio Rao } 13228993443SEd Schouten vm_page_dirty(kern_pg); 13389f6b863SAttilio Rao VM_OBJECT_WUNLOCK(uobject); 13428993443SEd Schouten vm_map_lookup_done(map, entry); 13528993443SEd Schouten return(KERN_SUCCESS); 13628993443SEd Schouten } 137e37e60c3SAndre Oppermann #endif /* SOCKET_SEND_COW */ 13828993443SEd Schouten 13928993443SEd Schouten int 1402801687dSKonstantin Belousov copyin_nofault(const void *udaddr, void *kaddr, size_t len) 1412801687dSKonstantin Belousov { 1422801687dSKonstantin Belousov int error, save; 1432801687dSKonstantin Belousov 1442801687dSKonstantin Belousov save = vm_fault_disable_pagefaults(); 1452801687dSKonstantin Belousov error = copyin(udaddr, kaddr, len); 1462801687dSKonstantin Belousov vm_fault_enable_pagefaults(save); 1472801687dSKonstantin Belousov return (error); 1482801687dSKonstantin Belousov } 1492801687dSKonstantin Belousov 1502801687dSKonstantin Belousov int 1512801687dSKonstantin Belousov copyout_nofault(const void *kaddr, void *udaddr, size_t len) 1522801687dSKonstantin Belousov { 1532801687dSKonstantin Belousov int error, save; 1542801687dSKonstantin Belousov 1552801687dSKonstantin Belousov save = vm_fault_disable_pagefaults(); 1562801687dSKonstantin Belousov error = copyout(kaddr, udaddr, len); 1572801687dSKonstantin Belousov vm_fault_enable_pagefaults(save); 1582801687dSKonstantin Belousov return (error); 1592801687dSKonstantin Belousov } 1602801687dSKonstantin Belousov 161dd0b4fb6SKonstantin Belousov #define PHYS_PAGE_COUNT(len) (howmany(len, PAGE_SIZE) + 1) 162dd0b4fb6SKonstantin Belousov 163dd0b4fb6SKonstantin Belousov int 164dd0b4fb6SKonstantin Belousov physcopyin(void *src, vm_paddr_t dst, size_t len) 165dd0b4fb6SKonstantin Belousov { 166dd0b4fb6SKonstantin Belousov vm_page_t m[PHYS_PAGE_COUNT(len)]; 167dd0b4fb6SKonstantin Belousov struct iovec iov[1]; 168dd0b4fb6SKonstantin Belousov struct uio uio; 169dd0b4fb6SKonstantin Belousov int i; 170dd0b4fb6SKonstantin Belousov 171dd0b4fb6SKonstantin Belousov iov[0].iov_base = src; 172dd0b4fb6SKonstantin Belousov iov[0].iov_len = len; 173dd0b4fb6SKonstantin Belousov uio.uio_iov = iov; 174dd0b4fb6SKonstantin Belousov uio.uio_iovcnt = 1; 175dd0b4fb6SKonstantin Belousov uio.uio_offset = 0; 176dd0b4fb6SKonstantin Belousov uio.uio_resid = len; 177dd0b4fb6SKonstantin Belousov uio.uio_segflg = UIO_SYSSPACE; 178dd0b4fb6SKonstantin Belousov uio.uio_rw = UIO_WRITE; 179dd0b4fb6SKonstantin Belousov for (i = 0; i < PHYS_PAGE_COUNT(len); i++, dst += PAGE_SIZE) 180dd0b4fb6SKonstantin Belousov m[i] = PHYS_TO_VM_PAGE(dst); 181dd0b4fb6SKonstantin Belousov return (uiomove_fromphys(m, dst & PAGE_MASK, len, &uio)); 182dd0b4fb6SKonstantin Belousov } 183dd0b4fb6SKonstantin Belousov 184dd0b4fb6SKonstantin Belousov int 185dd0b4fb6SKonstantin Belousov physcopyout(vm_paddr_t src, void *dst, size_t len) 186dd0b4fb6SKonstantin Belousov { 187dd0b4fb6SKonstantin Belousov vm_page_t m[PHYS_PAGE_COUNT(len)]; 188dd0b4fb6SKonstantin Belousov struct iovec iov[1]; 189dd0b4fb6SKonstantin Belousov struct uio uio; 190dd0b4fb6SKonstantin Belousov int i; 191dd0b4fb6SKonstantin Belousov 192dd0b4fb6SKonstantin Belousov iov[0].iov_base = dst; 193dd0b4fb6SKonstantin Belousov iov[0].iov_len = len; 194dd0b4fb6SKonstantin Belousov uio.uio_iov = iov; 195dd0b4fb6SKonstantin Belousov uio.uio_iovcnt = 1; 196dd0b4fb6SKonstantin Belousov uio.uio_offset = 0; 197dd0b4fb6SKonstantin Belousov uio.uio_resid = len; 198dd0b4fb6SKonstantin Belousov uio.uio_segflg = UIO_SYSSPACE; 199dd0b4fb6SKonstantin Belousov uio.uio_rw = UIO_READ; 200dd0b4fb6SKonstantin Belousov for (i = 0; i < PHYS_PAGE_COUNT(len); i++, src += PAGE_SIZE) 201dd0b4fb6SKonstantin Belousov m[i] = PHYS_TO_VM_PAGE(src); 202dd0b4fb6SKonstantin Belousov return (uiomove_fromphys(m, src & PAGE_MASK, len, &uio)); 203dd0b4fb6SKonstantin Belousov } 204dd0b4fb6SKonstantin Belousov 205dd0b4fb6SKonstantin Belousov #undef PHYS_PAGE_COUNT 206dd0b4fb6SKonstantin Belousov 2072801687dSKonstantin Belousov int 20828993443SEd Schouten uiomove(void *cp, int n, struct uio *uio) 20928993443SEd Schouten { 2102801687dSKonstantin Belousov 2112801687dSKonstantin Belousov return (uiomove_faultflag(cp, n, uio, 0)); 2122801687dSKonstantin Belousov } 2132801687dSKonstantin Belousov 2142801687dSKonstantin Belousov int 2152801687dSKonstantin Belousov uiomove_nofault(void *cp, int n, struct uio *uio) 2162801687dSKonstantin Belousov { 2172801687dSKonstantin Belousov 2182801687dSKonstantin Belousov return (uiomove_faultflag(cp, n, uio, 1)); 2192801687dSKonstantin Belousov } 2202801687dSKonstantin Belousov 2212801687dSKonstantin Belousov static int 2222801687dSKonstantin Belousov uiomove_faultflag(void *cp, int n, struct uio *uio, int nofault) 2232801687dSKonstantin Belousov { 2242801687dSKonstantin Belousov struct thread *td; 22528993443SEd Schouten struct iovec *iov; 226526d0bd5SKonstantin Belousov size_t cnt; 2272801687dSKonstantin Belousov int error, newflags, save; 2282801687dSKonstantin Belousov 2292801687dSKonstantin Belousov td = curthread; 2302801687dSKonstantin Belousov error = 0; 23128993443SEd Schouten 23228993443SEd Schouten KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE, 23328993443SEd Schouten ("uiomove: mode")); 2342801687dSKonstantin Belousov KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_td == td, 23528993443SEd Schouten ("uiomove proc")); 2362801687dSKonstantin Belousov if (!nofault) 23728993443SEd Schouten WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, 23828993443SEd Schouten "Calling uiomove()"); 23928993443SEd Schouten 2402801687dSKonstantin Belousov /* XXX does it make a sense to set TDP_DEADLKTREAT for UIO_SYSSPACE ? */ 2412801687dSKonstantin Belousov newflags = TDP_DEADLKTREAT; 2425730afc9SAlan Cox if (uio->uio_segflg == UIO_USERSPACE && nofault) { 2435730afc9SAlan Cox /* 2445730afc9SAlan Cox * Fail if a non-spurious page fault occurs. 2455730afc9SAlan Cox */ 2465730afc9SAlan Cox newflags |= TDP_NOFAULTING | TDP_RESETSPUR; 2475730afc9SAlan Cox } 2482801687dSKonstantin Belousov save = curthread_pflags_set(newflags); 24928993443SEd Schouten 25028993443SEd Schouten while (n > 0 && uio->uio_resid) { 25128993443SEd Schouten iov = uio->uio_iov; 25228993443SEd Schouten cnt = iov->iov_len; 25328993443SEd Schouten if (cnt == 0) { 25428993443SEd Schouten uio->uio_iov++; 25528993443SEd Schouten uio->uio_iovcnt--; 25628993443SEd Schouten continue; 25728993443SEd Schouten } 25828993443SEd Schouten if (cnt > n) 25928993443SEd Schouten cnt = n; 26028993443SEd Schouten 26128993443SEd Schouten switch (uio->uio_segflg) { 26228993443SEd Schouten 26328993443SEd Schouten case UIO_USERSPACE: 26408b163faSMatthew D Fleming maybe_yield(); 26528993443SEd Schouten if (uio->uio_rw == UIO_READ) 26628993443SEd Schouten error = copyout(cp, iov->iov_base, cnt); 26728993443SEd Schouten else 26828993443SEd Schouten error = copyin(iov->iov_base, cp, cnt); 26928993443SEd Schouten if (error) 27028993443SEd Schouten goto out; 27128993443SEd Schouten break; 27228993443SEd Schouten 27328993443SEd Schouten case UIO_SYSSPACE: 27428993443SEd Schouten if (uio->uio_rw == UIO_READ) 27528993443SEd Schouten bcopy(cp, iov->iov_base, cnt); 27628993443SEd Schouten else 27728993443SEd Schouten bcopy(iov->iov_base, cp, cnt); 27828993443SEd Schouten break; 27928993443SEd Schouten case UIO_NOCOPY: 28028993443SEd Schouten break; 28128993443SEd Schouten } 28228993443SEd Schouten iov->iov_base = (char *)iov->iov_base + cnt; 28328993443SEd Schouten iov->iov_len -= cnt; 28428993443SEd Schouten uio->uio_resid -= cnt; 28528993443SEd Schouten uio->uio_offset += cnt; 28628993443SEd Schouten cp = (char *)cp + cnt; 28728993443SEd Schouten n -= cnt; 28828993443SEd Schouten } 28928993443SEd Schouten out: 2902801687dSKonstantin Belousov curthread_pflags_restore(save); 29128993443SEd Schouten return (error); 29228993443SEd Schouten } 29328993443SEd Schouten 29428993443SEd Schouten /* 29528993443SEd Schouten * Wrapper for uiomove() that validates the arguments against a known-good 29628993443SEd Schouten * kernel buffer. Currently, uiomove accepts a signed (n) argument, which 29728993443SEd Schouten * is almost definitely a bad thing, so we catch that here as well. We 29828993443SEd Schouten * return a runtime failure, but it might be desirable to generate a runtime 29928993443SEd Schouten * assertion failure instead. 30028993443SEd Schouten */ 30128993443SEd Schouten int 30228993443SEd Schouten uiomove_frombuf(void *buf, int buflen, struct uio *uio) 30328993443SEd Schouten { 304526d0bd5SKonstantin Belousov size_t offset, n; 30528993443SEd Schouten 30628993443SEd Schouten if (uio->uio_offset < 0 || uio->uio_resid < 0 || 30728993443SEd Schouten (offset = uio->uio_offset) != uio->uio_offset) 30828993443SEd Schouten return (EINVAL); 30928993443SEd Schouten if (buflen <= 0 || offset >= buflen) 31028993443SEd Schouten return (0); 311526d0bd5SKonstantin Belousov if ((n = buflen - offset) > IOSIZE_MAX) 31228993443SEd Schouten return (EINVAL); 31328993443SEd Schouten return (uiomove((char *)buf + offset, n, uio)); 31428993443SEd Schouten } 31528993443SEd Schouten 316e37e60c3SAndre Oppermann #ifdef SOCKET_RECV_PFLIP 31728993443SEd Schouten /* 31828993443SEd Schouten * Experimental support for zero-copy I/O 31928993443SEd Schouten */ 32028993443SEd Schouten static int 32128993443SEd Schouten userspaceco(void *cp, u_int cnt, struct uio *uio, int disposable) 32228993443SEd Schouten { 32328993443SEd Schouten struct iovec *iov; 32428993443SEd Schouten int error; 32528993443SEd Schouten 32628993443SEd Schouten iov = uio->uio_iov; 32728993443SEd Schouten if (uio->uio_rw == UIO_READ) { 32828993443SEd Schouten if ((so_zero_copy_receive != 0) 32928993443SEd Schouten && ((cnt & PAGE_MASK) == 0) 33028993443SEd Schouten && ((((intptr_t) iov->iov_base) & PAGE_MASK) == 0) 33128993443SEd Schouten && ((uio->uio_offset & PAGE_MASK) == 0) 33228993443SEd Schouten && ((((intptr_t) cp) & PAGE_MASK) == 0) 33328993443SEd Schouten && (disposable != 0)) { 33428993443SEd Schouten /* SOCKET: use page-trading */ 33528993443SEd Schouten /* 33628993443SEd Schouten * We only want to call vm_pgmoveco() on 33728993443SEd Schouten * disposeable pages, since it gives the 33828993443SEd Schouten * kernel page to the userland process. 33928993443SEd Schouten */ 34028993443SEd Schouten error = vm_pgmoveco(&curproc->p_vmspace->vm_map, 34128993443SEd Schouten (vm_offset_t)cp, (vm_offset_t)iov->iov_base); 34228993443SEd Schouten 34328993443SEd Schouten /* 34428993443SEd Schouten * If we get an error back, attempt 34528993443SEd Schouten * to use copyout() instead. The 34628993443SEd Schouten * disposable page should be freed 34728993443SEd Schouten * automatically if we weren't able to move 34828993443SEd Schouten * it into userland. 34928993443SEd Schouten */ 35028993443SEd Schouten if (error != 0) 35128993443SEd Schouten error = copyout(cp, iov->iov_base, cnt); 35228993443SEd Schouten } else { 35328993443SEd Schouten error = copyout(cp, iov->iov_base, cnt); 35428993443SEd Schouten } 35528993443SEd Schouten } else { 35628993443SEd Schouten error = copyin(iov->iov_base, cp, cnt); 35728993443SEd Schouten } 35828993443SEd Schouten return (error); 35928993443SEd Schouten } 36028993443SEd Schouten 36128993443SEd Schouten int 36228993443SEd Schouten uiomoveco(void *cp, int n, struct uio *uio, int disposable) 36328993443SEd Schouten { 36428993443SEd Schouten struct iovec *iov; 36528993443SEd Schouten u_int cnt; 36628993443SEd Schouten int error; 36728993443SEd Schouten 36828993443SEd Schouten KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE, 36928993443SEd Schouten ("uiomoveco: mode")); 37028993443SEd Schouten KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_td == curthread, 37128993443SEd Schouten ("uiomoveco proc")); 37228993443SEd Schouten 37328993443SEd Schouten while (n > 0 && uio->uio_resid) { 37428993443SEd Schouten iov = uio->uio_iov; 37528993443SEd Schouten cnt = iov->iov_len; 37628993443SEd Schouten if (cnt == 0) { 37728993443SEd Schouten uio->uio_iov++; 37828993443SEd Schouten uio->uio_iovcnt--; 37928993443SEd Schouten continue; 38028993443SEd Schouten } 38128993443SEd Schouten if (cnt > n) 38228993443SEd Schouten cnt = n; 38328993443SEd Schouten 38428993443SEd Schouten switch (uio->uio_segflg) { 38528993443SEd Schouten 38628993443SEd Schouten case UIO_USERSPACE: 38708b163faSMatthew D Fleming maybe_yield(); 38828993443SEd Schouten error = userspaceco(cp, cnt, uio, disposable); 38928993443SEd Schouten if (error) 39028993443SEd Schouten return (error); 39128993443SEd Schouten break; 39228993443SEd Schouten 39328993443SEd Schouten case UIO_SYSSPACE: 39428993443SEd Schouten if (uio->uio_rw == UIO_READ) 39528993443SEd Schouten bcopy(cp, iov->iov_base, cnt); 39628993443SEd Schouten else 39728993443SEd Schouten bcopy(iov->iov_base, cp, cnt); 39828993443SEd Schouten break; 39928993443SEd Schouten case UIO_NOCOPY: 40028993443SEd Schouten break; 40128993443SEd Schouten } 40228993443SEd Schouten iov->iov_base = (char *)iov->iov_base + cnt; 40328993443SEd Schouten iov->iov_len -= cnt; 40428993443SEd Schouten uio->uio_resid -= cnt; 40528993443SEd Schouten uio->uio_offset += cnt; 40628993443SEd Schouten cp = (char *)cp + cnt; 40728993443SEd Schouten n -= cnt; 40828993443SEd Schouten } 40928993443SEd Schouten return (0); 41028993443SEd Schouten } 411e37e60c3SAndre Oppermann #endif /* SOCKET_RECV_PFLIP */ 41228993443SEd Schouten 41328993443SEd Schouten /* 41428993443SEd Schouten * Give next character to user as result of read. 41528993443SEd Schouten */ 41628993443SEd Schouten int 41728993443SEd Schouten ureadc(int c, struct uio *uio) 41828993443SEd Schouten { 41928993443SEd Schouten struct iovec *iov; 42028993443SEd Schouten char *iov_base; 42128993443SEd Schouten 42228993443SEd Schouten WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, 42328993443SEd Schouten "Calling ureadc()"); 42428993443SEd Schouten 42528993443SEd Schouten again: 42628993443SEd Schouten if (uio->uio_iovcnt == 0 || uio->uio_resid == 0) 42728993443SEd Schouten panic("ureadc"); 42828993443SEd Schouten iov = uio->uio_iov; 42928993443SEd Schouten if (iov->iov_len == 0) { 43028993443SEd Schouten uio->uio_iovcnt--; 43128993443SEd Schouten uio->uio_iov++; 43228993443SEd Schouten goto again; 43328993443SEd Schouten } 43428993443SEd Schouten switch (uio->uio_segflg) { 43528993443SEd Schouten 43628993443SEd Schouten case UIO_USERSPACE: 43728993443SEd Schouten if (subyte(iov->iov_base, c) < 0) 43828993443SEd Schouten return (EFAULT); 43928993443SEd Schouten break; 44028993443SEd Schouten 44128993443SEd Schouten case UIO_SYSSPACE: 44228993443SEd Schouten iov_base = iov->iov_base; 44328993443SEd Schouten *iov_base = c; 44428993443SEd Schouten break; 44528993443SEd Schouten 44628993443SEd Schouten case UIO_NOCOPY: 44728993443SEd Schouten break; 44828993443SEd Schouten } 44928993443SEd Schouten iov->iov_base = (char *)iov->iov_base + 1; 45028993443SEd Schouten iov->iov_len--; 45128993443SEd Schouten uio->uio_resid--; 45228993443SEd Schouten uio->uio_offset++; 45328993443SEd Schouten return (0); 45428993443SEd Schouten } 45528993443SEd Schouten 45628993443SEd Schouten int 45728993443SEd Schouten copyinfrom(const void * __restrict src, void * __restrict dst, size_t len, 45828993443SEd Schouten int seg) 45928993443SEd Schouten { 46028993443SEd Schouten int error = 0; 46128993443SEd Schouten 46228993443SEd Schouten switch (seg) { 46328993443SEd Schouten case UIO_USERSPACE: 46428993443SEd Schouten error = copyin(src, dst, len); 46528993443SEd Schouten break; 46628993443SEd Schouten case UIO_SYSSPACE: 46728993443SEd Schouten bcopy(src, dst, len); 46828993443SEd Schouten break; 46928993443SEd Schouten default: 47028993443SEd Schouten panic("copyinfrom: bad seg %d\n", seg); 47128993443SEd Schouten } 47228993443SEd Schouten return (error); 47328993443SEd Schouten } 47428993443SEd Schouten 47528993443SEd Schouten int 47628993443SEd Schouten copyinstrfrom(const void * __restrict src, void * __restrict dst, size_t len, 47728993443SEd Schouten size_t * __restrict copied, int seg) 47828993443SEd Schouten { 47928993443SEd Schouten int error = 0; 48028993443SEd Schouten 48128993443SEd Schouten switch (seg) { 48228993443SEd Schouten case UIO_USERSPACE: 48328993443SEd Schouten error = copyinstr(src, dst, len, copied); 48428993443SEd Schouten break; 48528993443SEd Schouten case UIO_SYSSPACE: 48628993443SEd Schouten error = copystr(src, dst, len, copied); 48728993443SEd Schouten break; 48828993443SEd Schouten default: 48928993443SEd Schouten panic("copyinstrfrom: bad seg %d\n", seg); 49028993443SEd Schouten } 49128993443SEd Schouten return (error); 49228993443SEd Schouten } 49328993443SEd Schouten 49428993443SEd Schouten int 495cfb09e00SAlfred Perlstein copyiniov(const struct iovec *iovp, u_int iovcnt, struct iovec **iov, int error) 49628993443SEd Schouten { 49728993443SEd Schouten u_int iovlen; 49828993443SEd Schouten 49928993443SEd Schouten *iov = NULL; 50028993443SEd Schouten if (iovcnt > UIO_MAXIOV) 50128993443SEd Schouten return (error); 50228993443SEd Schouten iovlen = iovcnt * sizeof (struct iovec); 50328993443SEd Schouten *iov = malloc(iovlen, M_IOV, M_WAITOK); 50428993443SEd Schouten error = copyin(iovp, *iov, iovlen); 50528993443SEd Schouten if (error) { 50628993443SEd Schouten free(*iov, M_IOV); 50728993443SEd Schouten *iov = NULL; 50828993443SEd Schouten } 50928993443SEd Schouten return (error); 51028993443SEd Schouten } 51128993443SEd Schouten 51228993443SEd Schouten int 513cfb09e00SAlfred Perlstein copyinuio(const struct iovec *iovp, u_int iovcnt, struct uio **uiop) 51428993443SEd Schouten { 51528993443SEd Schouten struct iovec *iov; 51628993443SEd Schouten struct uio *uio; 51728993443SEd Schouten u_int iovlen; 51828993443SEd Schouten int error, i; 51928993443SEd Schouten 52028993443SEd Schouten *uiop = NULL; 52128993443SEd Schouten if (iovcnt > UIO_MAXIOV) 52228993443SEd Schouten return (EINVAL); 52328993443SEd Schouten iovlen = iovcnt * sizeof (struct iovec); 52428993443SEd Schouten uio = malloc(iovlen + sizeof *uio, M_IOV, M_WAITOK); 52528993443SEd Schouten iov = (struct iovec *)(uio + 1); 52628993443SEd Schouten error = copyin(iovp, iov, iovlen); 52728993443SEd Schouten if (error) { 52828993443SEd Schouten free(uio, M_IOV); 52928993443SEd Schouten return (error); 53028993443SEd Schouten } 53128993443SEd Schouten uio->uio_iov = iov; 53228993443SEd Schouten uio->uio_iovcnt = iovcnt; 53328993443SEd Schouten uio->uio_segflg = UIO_USERSPACE; 53428993443SEd Schouten uio->uio_offset = -1; 53528993443SEd Schouten uio->uio_resid = 0; 53628993443SEd Schouten for (i = 0; i < iovcnt; i++) { 537526d0bd5SKonstantin Belousov if (iov->iov_len > IOSIZE_MAX - uio->uio_resid) { 53828993443SEd Schouten free(uio, M_IOV); 53928993443SEd Schouten return (EINVAL); 54028993443SEd Schouten } 54128993443SEd Schouten uio->uio_resid += iov->iov_len; 54228993443SEd Schouten iov++; 54328993443SEd Schouten } 54428993443SEd Schouten *uiop = uio; 54528993443SEd Schouten return (0); 54628993443SEd Schouten } 54728993443SEd Schouten 54828993443SEd Schouten struct uio * 54928993443SEd Schouten cloneuio(struct uio *uiop) 55028993443SEd Schouten { 55128993443SEd Schouten struct uio *uio; 55228993443SEd Schouten int iovlen; 55328993443SEd Schouten 55428993443SEd Schouten iovlen = uiop->uio_iovcnt * sizeof (struct iovec); 55528993443SEd Schouten uio = malloc(iovlen + sizeof *uio, M_IOV, M_WAITOK); 55628993443SEd Schouten *uio = *uiop; 55728993443SEd Schouten uio->uio_iov = (struct iovec *)(uio + 1); 55828993443SEd Schouten bcopy(uiop->uio_iov, uio->uio_iov, iovlen); 55928993443SEd Schouten return (uio); 56028993443SEd Schouten } 5610f502d1cSKonstantin Belousov 5620f502d1cSKonstantin Belousov /* 5630f502d1cSKonstantin Belousov * Map some anonymous memory in user space of size sz, rounded up to the page 5640f502d1cSKonstantin Belousov * boundary. 5650f502d1cSKonstantin Belousov */ 5660f502d1cSKonstantin Belousov int 5670f502d1cSKonstantin Belousov copyout_map(struct thread *td, vm_offset_t *addr, size_t sz) 5680f502d1cSKonstantin Belousov { 569cce6e354SKonstantin Belousov struct vmspace *vms; 5700f502d1cSKonstantin Belousov int error; 5710f502d1cSKonstantin Belousov vm_size_t size; 5720f502d1cSKonstantin Belousov 573cce6e354SKonstantin Belousov vms = td->td_proc->p_vmspace; 574cce6e354SKonstantin Belousov 5750f502d1cSKonstantin Belousov /* 5760f502d1cSKonstantin Belousov * Map somewhere after heap in process memory. 5770f502d1cSKonstantin Belousov */ 5780f502d1cSKonstantin Belousov PROC_LOCK(td->td_proc); 5790f502d1cSKonstantin Belousov *addr = round_page((vm_offset_t)vms->vm_daddr + 5800f502d1cSKonstantin Belousov lim_max(td->td_proc, RLIMIT_DATA)); 5810f502d1cSKonstantin Belousov PROC_UNLOCK(td->td_proc); 5820f502d1cSKonstantin Belousov 5830f502d1cSKonstantin Belousov /* round size up to page boundry */ 5840f502d1cSKonstantin Belousov size = (vm_size_t)round_page(sz); 5850f502d1cSKonstantin Belousov 5860f502d1cSKonstantin Belousov error = vm_mmap(&vms->vm_map, addr, size, PROT_READ | PROT_WRITE, 5870f502d1cSKonstantin Belousov VM_PROT_ALL, MAP_PRIVATE | MAP_ANON, OBJT_DEFAULT, NULL, 0); 5880f502d1cSKonstantin Belousov 5890f502d1cSKonstantin Belousov return (error); 5900f502d1cSKonstantin Belousov } 5910f502d1cSKonstantin Belousov 5920f502d1cSKonstantin Belousov /* 5930f502d1cSKonstantin Belousov * Unmap memory in user space. 5940f502d1cSKonstantin Belousov */ 5950f502d1cSKonstantin Belousov int 5960f502d1cSKonstantin Belousov copyout_unmap(struct thread *td, vm_offset_t addr, size_t sz) 5970f502d1cSKonstantin Belousov { 5980f502d1cSKonstantin Belousov vm_map_t map; 5990f502d1cSKonstantin Belousov vm_size_t size; 6000f502d1cSKonstantin Belousov 601937060a8SKonstantin Belousov if (sz == 0) 602937060a8SKonstantin Belousov return (0); 603937060a8SKonstantin Belousov 6040f502d1cSKonstantin Belousov map = &td->td_proc->p_vmspace->vm_map; 6050f502d1cSKonstantin Belousov size = (vm_size_t)round_page(sz); 6060f502d1cSKonstantin Belousov 607cea8f30aSKonstantin Belousov if (vm_map_remove(map, addr, addr + size) != KERN_SUCCESS) 6080f502d1cSKonstantin Belousov return (EINVAL); 6090f502d1cSKonstantin Belousov 6100f502d1cSKonstantin Belousov return (0); 6110f502d1cSKonstantin Belousov } 612