xref: /freebsd/sys/kern/subr_uio.c (revision 51369649b03ece2aed3eb61b0c8214b9aa5b2fa2)
128993443SEd Schouten /*-
2*51369649SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
3*51369649SPedro F. Giffuni  *
428993443SEd Schouten  * Copyright (c) 1982, 1986, 1991, 1993
528993443SEd Schouten  *	The Regents of the University of California.  All rights reserved.
628993443SEd Schouten  * (c) UNIX System Laboratories, Inc.
728993443SEd Schouten  * All or some portions of this file are derived from material licensed
828993443SEd Schouten  * to the University of California by American Telephone and Telegraph
928993443SEd Schouten  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
1028993443SEd Schouten  * the permission of UNIX System Laboratories, Inc.
1128993443SEd Schouten  *
124f3dc900SKonstantin Belousov  * Copyright (c) 2014 The FreeBSD Foundation
134f3dc900SKonstantin Belousov  *
144f3dc900SKonstantin Belousov  * Portions of this software were developed by Konstantin Belousov
154f3dc900SKonstantin Belousov  * under sponsorship from the FreeBSD Foundation.
164f3dc900SKonstantin Belousov  *
1728993443SEd Schouten  * Redistribution and use in source and binary forms, with or without
1828993443SEd Schouten  * modification, are permitted provided that the following conditions
1928993443SEd Schouten  * are met:
2028993443SEd Schouten  * 1. Redistributions of source code must retain the above copyright
2128993443SEd Schouten  *    notice, this list of conditions and the following disclaimer.
2228993443SEd Schouten  * 2. Redistributions in binary form must reproduce the above copyright
2328993443SEd Schouten  *    notice, this list of conditions and the following disclaimer in the
2428993443SEd Schouten  *    documentation and/or other materials provided with the distribution.
2569a28758SEd Maste  * 3. Neither the name of the University nor the names of its contributors
2628993443SEd Schouten  *    may be used to endorse or promote products derived from this software
2728993443SEd Schouten  *    without specific prior written permission.
2828993443SEd Schouten  *
2928993443SEd Schouten  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
3028993443SEd Schouten  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3128993443SEd Schouten  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3228993443SEd Schouten  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3328993443SEd Schouten  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3428993443SEd Schouten  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3528993443SEd Schouten  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3628993443SEd Schouten  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3728993443SEd Schouten  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3828993443SEd Schouten  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3928993443SEd Schouten  * SUCH DAMAGE.
4028993443SEd Schouten  *
4128993443SEd Schouten  *	@(#)kern_subr.c	8.3 (Berkeley) 1/21/94
4228993443SEd Schouten  */
4328993443SEd Schouten 
4428993443SEd Schouten #include <sys/cdefs.h>
4528993443SEd Schouten __FBSDID("$FreeBSD$");
4628993443SEd Schouten 
4728993443SEd Schouten #include <sys/param.h>
4828993443SEd Schouten #include <sys/systm.h>
4928993443SEd Schouten #include <sys/kernel.h>
5028993443SEd Schouten #include <sys/limits.h>
5128993443SEd Schouten #include <sys/lock.h>
520f502d1cSKonstantin Belousov #include <sys/mman.h>
5328993443SEd Schouten #include <sys/proc.h>
540f502d1cSKonstantin Belousov #include <sys/resourcevar.h>
5589f6b863SAttilio Rao #include <sys/rwlock.h>
5628993443SEd Schouten #include <sys/sched.h>
5728993443SEd Schouten #include <sys/sysctl.h>
5828993443SEd Schouten #include <sys/vnode.h>
5928993443SEd Schouten 
6028993443SEd Schouten #include <vm/vm.h>
611c771f92SKonstantin Belousov #include <vm/vm_param.h>
620f502d1cSKonstantin Belousov #include <vm/vm_extern.h>
6328993443SEd Schouten #include <vm/vm_page.h>
64e946b949SAttilio Rao #include <vm/vm_pageout.h>
6528993443SEd Schouten #include <vm/vm_map.h>
6628993443SEd Schouten 
67a9934668SKenneth D. Merry #include <machine/bus.h>
68a9934668SKenneth D. Merry 
69f0188618SHans Petter Selasky SYSCTL_INT(_kern, KERN_IOV_MAX, iov_max, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, UIO_MAXIOV,
7028993443SEd Schouten 	"Maximum number of elements in an I/O vector; sysconf(_SC_IOV_MAX)");
7128993443SEd Schouten 
722801687dSKonstantin Belousov static int uiomove_faultflag(void *cp, int n, struct uio *uio, int nofault);
732801687dSKonstantin Belousov 
7428993443SEd Schouten int
752801687dSKonstantin Belousov copyin_nofault(const void *udaddr, void *kaddr, size_t len)
762801687dSKonstantin Belousov {
772801687dSKonstantin Belousov 	int error, save;
782801687dSKonstantin Belousov 
792801687dSKonstantin Belousov 	save = vm_fault_disable_pagefaults();
802801687dSKonstantin Belousov 	error = copyin(udaddr, kaddr, len);
812801687dSKonstantin Belousov 	vm_fault_enable_pagefaults(save);
822801687dSKonstantin Belousov 	return (error);
832801687dSKonstantin Belousov }
842801687dSKonstantin Belousov 
852801687dSKonstantin Belousov int
862801687dSKonstantin Belousov copyout_nofault(const void *kaddr, void *udaddr, size_t len)
872801687dSKonstantin Belousov {
882801687dSKonstantin Belousov 	int error, save;
892801687dSKonstantin Belousov 
902801687dSKonstantin Belousov 	save = vm_fault_disable_pagefaults();
912801687dSKonstantin Belousov 	error = copyout(kaddr, udaddr, len);
922801687dSKonstantin Belousov 	vm_fault_enable_pagefaults(save);
932801687dSKonstantin Belousov 	return (error);
942801687dSKonstantin Belousov }
952801687dSKonstantin Belousov 
96dd0b4fb6SKonstantin Belousov #define	PHYS_PAGE_COUNT(len)	(howmany(len, PAGE_SIZE) + 1)
97dd0b4fb6SKonstantin Belousov 
98dd0b4fb6SKonstantin Belousov int
99dd0b4fb6SKonstantin Belousov physcopyin(void *src, vm_paddr_t dst, size_t len)
100dd0b4fb6SKonstantin Belousov {
101dd0b4fb6SKonstantin Belousov 	vm_page_t m[PHYS_PAGE_COUNT(len)];
102dd0b4fb6SKonstantin Belousov 	struct iovec iov[1];
103dd0b4fb6SKonstantin Belousov 	struct uio uio;
104dd0b4fb6SKonstantin Belousov 	int i;
105dd0b4fb6SKonstantin Belousov 
106dd0b4fb6SKonstantin Belousov 	iov[0].iov_base = src;
107dd0b4fb6SKonstantin Belousov 	iov[0].iov_len = len;
108dd0b4fb6SKonstantin Belousov 	uio.uio_iov = iov;
109dd0b4fb6SKonstantin Belousov 	uio.uio_iovcnt = 1;
110dd0b4fb6SKonstantin Belousov 	uio.uio_offset = 0;
111dd0b4fb6SKonstantin Belousov 	uio.uio_resid = len;
112dd0b4fb6SKonstantin Belousov 	uio.uio_segflg = UIO_SYSSPACE;
113dd0b4fb6SKonstantin Belousov 	uio.uio_rw = UIO_WRITE;
114dd0b4fb6SKonstantin Belousov 	for (i = 0; i < PHYS_PAGE_COUNT(len); i++, dst += PAGE_SIZE)
115dd0b4fb6SKonstantin Belousov 		m[i] = PHYS_TO_VM_PAGE(dst);
116dd0b4fb6SKonstantin Belousov 	return (uiomove_fromphys(m, dst & PAGE_MASK, len, &uio));
117dd0b4fb6SKonstantin Belousov }
118dd0b4fb6SKonstantin Belousov 
119dd0b4fb6SKonstantin Belousov int
120dd0b4fb6SKonstantin Belousov physcopyout(vm_paddr_t src, void *dst, size_t len)
121dd0b4fb6SKonstantin Belousov {
122dd0b4fb6SKonstantin Belousov 	vm_page_t m[PHYS_PAGE_COUNT(len)];
123dd0b4fb6SKonstantin Belousov 	struct iovec iov[1];
124dd0b4fb6SKonstantin Belousov 	struct uio uio;
125dd0b4fb6SKonstantin Belousov 	int i;
126dd0b4fb6SKonstantin Belousov 
127dd0b4fb6SKonstantin Belousov 	iov[0].iov_base = dst;
128dd0b4fb6SKonstantin Belousov 	iov[0].iov_len = len;
129dd0b4fb6SKonstantin Belousov 	uio.uio_iov = iov;
130dd0b4fb6SKonstantin Belousov 	uio.uio_iovcnt = 1;
131dd0b4fb6SKonstantin Belousov 	uio.uio_offset = 0;
132dd0b4fb6SKonstantin Belousov 	uio.uio_resid = len;
133dd0b4fb6SKonstantin Belousov 	uio.uio_segflg = UIO_SYSSPACE;
134dd0b4fb6SKonstantin Belousov 	uio.uio_rw = UIO_READ;
135dd0b4fb6SKonstantin Belousov 	for (i = 0; i < PHYS_PAGE_COUNT(len); i++, src += PAGE_SIZE)
136dd0b4fb6SKonstantin Belousov 		m[i] = PHYS_TO_VM_PAGE(src);
137dd0b4fb6SKonstantin Belousov 	return (uiomove_fromphys(m, src & PAGE_MASK, len, &uio));
138dd0b4fb6SKonstantin Belousov }
139dd0b4fb6SKonstantin Belousov 
140dd0b4fb6SKonstantin Belousov #undef PHYS_PAGE_COUNT
141dd0b4fb6SKonstantin Belousov 
1422801687dSKonstantin Belousov int
143a9934668SKenneth D. Merry physcopyin_vlist(bus_dma_segment_t *src, off_t offset, vm_paddr_t dst,
144a9934668SKenneth D. Merry     size_t len)
145a9934668SKenneth D. Merry {
146a9934668SKenneth D. Merry 	size_t seg_len;
147a9934668SKenneth D. Merry 	int error;
148a9934668SKenneth D. Merry 
149a9934668SKenneth D. Merry 	error = 0;
150a9934668SKenneth D. Merry 	while (offset >= src->ds_len) {
151a9934668SKenneth D. Merry 		offset -= src->ds_len;
152a9934668SKenneth D. Merry 		src++;
153a9934668SKenneth D. Merry 	}
154a9934668SKenneth D. Merry 
155a9934668SKenneth D. Merry 	while (len > 0 && error == 0) {
156a9934668SKenneth D. Merry 		seg_len = MIN(src->ds_len - offset, len);
157a9934668SKenneth D. Merry 		error = physcopyin((void *)(uintptr_t)(src->ds_addr + offset),
158a9934668SKenneth D. Merry 		    dst, seg_len);
159a9934668SKenneth D. Merry 		offset = 0;
160a9934668SKenneth D. Merry 		src++;
161a9934668SKenneth D. Merry 		len -= seg_len;
162a9934668SKenneth D. Merry 		dst += seg_len;
163a9934668SKenneth D. Merry 	}
164a9934668SKenneth D. Merry 
165a9934668SKenneth D. Merry 	return (error);
166a9934668SKenneth D. Merry }
167a9934668SKenneth D. Merry 
168a9934668SKenneth D. Merry int
169a9934668SKenneth D. Merry physcopyout_vlist(vm_paddr_t src, bus_dma_segment_t *dst, off_t offset,
170a9934668SKenneth D. Merry     size_t len)
171a9934668SKenneth D. Merry {
172a9934668SKenneth D. Merry 	size_t seg_len;
173a9934668SKenneth D. Merry 	int error;
174a9934668SKenneth D. Merry 
175a9934668SKenneth D. Merry 	error = 0;
176a9934668SKenneth D. Merry 	while (offset >= dst->ds_len) {
177a9934668SKenneth D. Merry 		offset -= dst->ds_len;
178a9934668SKenneth D. Merry 		dst++;
179a9934668SKenneth D. Merry 	}
180a9934668SKenneth D. Merry 
181a9934668SKenneth D. Merry 	while (len > 0 && error == 0) {
182a9934668SKenneth D. Merry 		seg_len = MIN(dst->ds_len - offset, len);
183a9934668SKenneth D. Merry 		error = physcopyout(src, (void *)(uintptr_t)(dst->ds_addr +
184a9934668SKenneth D. Merry 		    offset), seg_len);
185a9934668SKenneth D. Merry 		offset = 0;
186a9934668SKenneth D. Merry 		dst++;
187a9934668SKenneth D. Merry 		len -= seg_len;
188a9934668SKenneth D. Merry 		src += seg_len;
189a9934668SKenneth D. Merry 	}
190a9934668SKenneth D. Merry 
191a9934668SKenneth D. Merry 	return (error);
192a9934668SKenneth D. Merry }
193a9934668SKenneth D. Merry 
194a9934668SKenneth D. Merry int
19528993443SEd Schouten uiomove(void *cp, int n, struct uio *uio)
19628993443SEd Schouten {
1972801687dSKonstantin Belousov 
1982801687dSKonstantin Belousov 	return (uiomove_faultflag(cp, n, uio, 0));
1992801687dSKonstantin Belousov }
2002801687dSKonstantin Belousov 
2012801687dSKonstantin Belousov int
2022801687dSKonstantin Belousov uiomove_nofault(void *cp, int n, struct uio *uio)
2032801687dSKonstantin Belousov {
2042801687dSKonstantin Belousov 
2052801687dSKonstantin Belousov 	return (uiomove_faultflag(cp, n, uio, 1));
2062801687dSKonstantin Belousov }
2072801687dSKonstantin Belousov 
2082801687dSKonstantin Belousov static int
2092801687dSKonstantin Belousov uiomove_faultflag(void *cp, int n, struct uio *uio, int nofault)
2102801687dSKonstantin Belousov {
21128993443SEd Schouten 	struct iovec *iov;
212526d0bd5SKonstantin Belousov 	size_t cnt;
2132801687dSKonstantin Belousov 	int error, newflags, save;
2142801687dSKonstantin Belousov 
2152801687dSKonstantin Belousov 	error = 0;
21628993443SEd Schouten 
21728993443SEd Schouten 	KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE,
21828993443SEd Schouten 	    ("uiomove: mode"));
219a5169546SAndrew Gallatin 	KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_td == curthread,
22028993443SEd Schouten 	    ("uiomove proc"));
22128993443SEd Schouten 
222a5169546SAndrew Gallatin 	if (uio->uio_segflg == UIO_USERSPACE) {
2232801687dSKonstantin Belousov 		newflags = TDP_DEADLKTREAT;
224a5169546SAndrew Gallatin 		if (nofault) {
2255730afc9SAlan Cox 			/*
2265730afc9SAlan Cox 			 * Fail if a non-spurious page fault occurs.
2275730afc9SAlan Cox 			 */
2285730afc9SAlan Cox 			newflags |= TDP_NOFAULTING | TDP_RESETSPUR;
229a5169546SAndrew Gallatin 		} else {
230a5169546SAndrew Gallatin 			WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
231a5169546SAndrew Gallatin 			    "Calling uiomove()");
2325730afc9SAlan Cox 		}
2332801687dSKonstantin Belousov 		save = curthread_pflags_set(newflags);
234a5169546SAndrew Gallatin 	} else {
235a5169546SAndrew Gallatin 		KASSERT(nofault == 0, ("uiomove: nofault"));
236a5169546SAndrew Gallatin 	}
23728993443SEd Schouten 
23828993443SEd Schouten 	while (n > 0 && uio->uio_resid) {
23928993443SEd Schouten 		iov = uio->uio_iov;
24028993443SEd Schouten 		cnt = iov->iov_len;
24128993443SEd Schouten 		if (cnt == 0) {
24228993443SEd Schouten 			uio->uio_iov++;
24328993443SEd Schouten 			uio->uio_iovcnt--;
24428993443SEd Schouten 			continue;
24528993443SEd Schouten 		}
24628993443SEd Schouten 		if (cnt > n)
24728993443SEd Schouten 			cnt = n;
24828993443SEd Schouten 
24928993443SEd Schouten 		switch (uio->uio_segflg) {
25028993443SEd Schouten 
25128993443SEd Schouten 		case UIO_USERSPACE:
25208b163faSMatthew D Fleming 			maybe_yield();
25328993443SEd Schouten 			if (uio->uio_rw == UIO_READ)
25428993443SEd Schouten 				error = copyout(cp, iov->iov_base, cnt);
25528993443SEd Schouten 			else
25628993443SEd Schouten 				error = copyin(iov->iov_base, cp, cnt);
25728993443SEd Schouten 			if (error)
25828993443SEd Schouten 				goto out;
25928993443SEd Schouten 			break;
26028993443SEd Schouten 
26128993443SEd Schouten 		case UIO_SYSSPACE:
26228993443SEd Schouten 			if (uio->uio_rw == UIO_READ)
26328993443SEd Schouten 				bcopy(cp, iov->iov_base, cnt);
26428993443SEd Schouten 			else
26528993443SEd Schouten 				bcopy(iov->iov_base, cp, cnt);
26628993443SEd Schouten 			break;
26728993443SEd Schouten 		case UIO_NOCOPY:
26828993443SEd Schouten 			break;
26928993443SEd Schouten 		}
27028993443SEd Schouten 		iov->iov_base = (char *)iov->iov_base + cnt;
27128993443SEd Schouten 		iov->iov_len -= cnt;
27228993443SEd Schouten 		uio->uio_resid -= cnt;
27328993443SEd Schouten 		uio->uio_offset += cnt;
27428993443SEd Schouten 		cp = (char *)cp + cnt;
27528993443SEd Schouten 		n -= cnt;
27628993443SEd Schouten 	}
27728993443SEd Schouten out:
278a5169546SAndrew Gallatin 	if (uio->uio_segflg == UIO_USERSPACE)
2792801687dSKonstantin Belousov 		curthread_pflags_restore(save);
28028993443SEd Schouten 	return (error);
28128993443SEd Schouten }
28228993443SEd Schouten 
28328993443SEd Schouten /*
28428993443SEd Schouten  * Wrapper for uiomove() that validates the arguments against a known-good
28528993443SEd Schouten  * kernel buffer.  Currently, uiomove accepts a signed (n) argument, which
28628993443SEd Schouten  * is almost definitely a bad thing, so we catch that here as well.  We
28728993443SEd Schouten  * return a runtime failure, but it might be desirable to generate a runtime
28828993443SEd Schouten  * assertion failure instead.
28928993443SEd Schouten  */
29028993443SEd Schouten int
29128993443SEd Schouten uiomove_frombuf(void *buf, int buflen, struct uio *uio)
29228993443SEd Schouten {
293526d0bd5SKonstantin Belousov 	size_t offset, n;
29428993443SEd Schouten 
29528993443SEd Schouten 	if (uio->uio_offset < 0 || uio->uio_resid < 0 ||
29628993443SEd Schouten 	    (offset = uio->uio_offset) != uio->uio_offset)
29728993443SEd Schouten 		return (EINVAL);
29828993443SEd Schouten 	if (buflen <= 0 || offset >= buflen)
29928993443SEd Schouten 		return (0);
300526d0bd5SKonstantin Belousov 	if ((n = buflen - offset) > IOSIZE_MAX)
30128993443SEd Schouten 		return (EINVAL);
30228993443SEd Schouten 	return (uiomove((char *)buf + offset, n, uio));
30328993443SEd Schouten }
30428993443SEd Schouten 
30528993443SEd Schouten /*
30628993443SEd Schouten  * Give next character to user as result of read.
30728993443SEd Schouten  */
30828993443SEd Schouten int
30928993443SEd Schouten ureadc(int c, struct uio *uio)
31028993443SEd Schouten {
31128993443SEd Schouten 	struct iovec *iov;
31228993443SEd Schouten 	char *iov_base;
31328993443SEd Schouten 
31428993443SEd Schouten 	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
31528993443SEd Schouten 	    "Calling ureadc()");
31628993443SEd Schouten 
31728993443SEd Schouten again:
31828993443SEd Schouten 	if (uio->uio_iovcnt == 0 || uio->uio_resid == 0)
31928993443SEd Schouten 		panic("ureadc");
32028993443SEd Schouten 	iov = uio->uio_iov;
32128993443SEd Schouten 	if (iov->iov_len == 0) {
32228993443SEd Schouten 		uio->uio_iovcnt--;
32328993443SEd Schouten 		uio->uio_iov++;
32428993443SEd Schouten 		goto again;
32528993443SEd Schouten 	}
32628993443SEd Schouten 	switch (uio->uio_segflg) {
32728993443SEd Schouten 
32828993443SEd Schouten 	case UIO_USERSPACE:
32928993443SEd Schouten 		if (subyte(iov->iov_base, c) < 0)
33028993443SEd Schouten 			return (EFAULT);
33128993443SEd Schouten 		break;
33228993443SEd Schouten 
33328993443SEd Schouten 	case UIO_SYSSPACE:
33428993443SEd Schouten 		iov_base = iov->iov_base;
33528993443SEd Schouten 		*iov_base = c;
33628993443SEd Schouten 		break;
33728993443SEd Schouten 
33828993443SEd Schouten 	case UIO_NOCOPY:
33928993443SEd Schouten 		break;
34028993443SEd Schouten 	}
34128993443SEd Schouten 	iov->iov_base = (char *)iov->iov_base + 1;
34228993443SEd Schouten 	iov->iov_len--;
34328993443SEd Schouten 	uio->uio_resid--;
34428993443SEd Schouten 	uio->uio_offset++;
34528993443SEd Schouten 	return (0);
34628993443SEd Schouten }
34728993443SEd Schouten 
34828993443SEd Schouten int
34928993443SEd Schouten copyinfrom(const void * __restrict src, void * __restrict dst, size_t len,
35028993443SEd Schouten     int seg)
35128993443SEd Schouten {
35228993443SEd Schouten 	int error = 0;
35328993443SEd Schouten 
35428993443SEd Schouten 	switch (seg) {
35528993443SEd Schouten 	case UIO_USERSPACE:
35628993443SEd Schouten 		error = copyin(src, dst, len);
35728993443SEd Schouten 		break;
35828993443SEd Schouten 	case UIO_SYSSPACE:
35928993443SEd Schouten 		bcopy(src, dst, len);
36028993443SEd Schouten 		break;
36128993443SEd Schouten 	default:
36228993443SEd Schouten 		panic("copyinfrom: bad seg %d\n", seg);
36328993443SEd Schouten 	}
36428993443SEd Schouten 	return (error);
36528993443SEd Schouten }
36628993443SEd Schouten 
36728993443SEd Schouten int
36828993443SEd Schouten copyinstrfrom(const void * __restrict src, void * __restrict dst, size_t len,
36928993443SEd Schouten     size_t * __restrict copied, int seg)
37028993443SEd Schouten {
37128993443SEd Schouten 	int error = 0;
37228993443SEd Schouten 
37328993443SEd Schouten 	switch (seg) {
37428993443SEd Schouten 	case UIO_USERSPACE:
37528993443SEd Schouten 		error = copyinstr(src, dst, len, copied);
37628993443SEd Schouten 		break;
37728993443SEd Schouten 	case UIO_SYSSPACE:
37828993443SEd Schouten 		error = copystr(src, dst, len, copied);
37928993443SEd Schouten 		break;
38028993443SEd Schouten 	default:
38128993443SEd Schouten 		panic("copyinstrfrom: bad seg %d\n", seg);
38228993443SEd Schouten 	}
38328993443SEd Schouten 	return (error);
38428993443SEd Schouten }
38528993443SEd Schouten 
38628993443SEd Schouten int
387cfb09e00SAlfred Perlstein copyiniov(const struct iovec *iovp, u_int iovcnt, struct iovec **iov, int error)
38828993443SEd Schouten {
38928993443SEd Schouten 	u_int iovlen;
39028993443SEd Schouten 
39128993443SEd Schouten 	*iov = NULL;
39228993443SEd Schouten 	if (iovcnt > UIO_MAXIOV)
39328993443SEd Schouten 		return (error);
39428993443SEd Schouten 	iovlen = iovcnt * sizeof (struct iovec);
39528993443SEd Schouten 	*iov = malloc(iovlen, M_IOV, M_WAITOK);
39628993443SEd Schouten 	error = copyin(iovp, *iov, iovlen);
39728993443SEd Schouten 	if (error) {
39828993443SEd Schouten 		free(*iov, M_IOV);
39928993443SEd Schouten 		*iov = NULL;
40028993443SEd Schouten 	}
40128993443SEd Schouten 	return (error);
40228993443SEd Schouten }
40328993443SEd Schouten 
40428993443SEd Schouten int
405cfb09e00SAlfred Perlstein copyinuio(const struct iovec *iovp, u_int iovcnt, struct uio **uiop)
40628993443SEd Schouten {
40728993443SEd Schouten 	struct iovec *iov;
40828993443SEd Schouten 	struct uio *uio;
40928993443SEd Schouten 	u_int iovlen;
41028993443SEd Schouten 	int error, i;
41128993443SEd Schouten 
41228993443SEd Schouten 	*uiop = NULL;
41328993443SEd Schouten 	if (iovcnt > UIO_MAXIOV)
41428993443SEd Schouten 		return (EINVAL);
41528993443SEd Schouten 	iovlen = iovcnt * sizeof (struct iovec);
41628993443SEd Schouten 	uio = malloc(iovlen + sizeof *uio, M_IOV, M_WAITOK);
41728993443SEd Schouten 	iov = (struct iovec *)(uio + 1);
41828993443SEd Schouten 	error = copyin(iovp, iov, iovlen);
41928993443SEd Schouten 	if (error) {
42028993443SEd Schouten 		free(uio, M_IOV);
42128993443SEd Schouten 		return (error);
42228993443SEd Schouten 	}
42328993443SEd Schouten 	uio->uio_iov = iov;
42428993443SEd Schouten 	uio->uio_iovcnt = iovcnt;
42528993443SEd Schouten 	uio->uio_segflg = UIO_USERSPACE;
42628993443SEd Schouten 	uio->uio_offset = -1;
42728993443SEd Schouten 	uio->uio_resid = 0;
42828993443SEd Schouten 	for (i = 0; i < iovcnt; i++) {
429526d0bd5SKonstantin Belousov 		if (iov->iov_len > IOSIZE_MAX - uio->uio_resid) {
43028993443SEd Schouten 			free(uio, M_IOV);
43128993443SEd Schouten 			return (EINVAL);
43228993443SEd Schouten 		}
43328993443SEd Schouten 		uio->uio_resid += iov->iov_len;
43428993443SEd Schouten 		iov++;
43528993443SEd Schouten 	}
43628993443SEd Schouten 	*uiop = uio;
43728993443SEd Schouten 	return (0);
43828993443SEd Schouten }
43928993443SEd Schouten 
44028993443SEd Schouten struct uio *
44128993443SEd Schouten cloneuio(struct uio *uiop)
44228993443SEd Schouten {
44328993443SEd Schouten 	struct uio *uio;
44428993443SEd Schouten 	int iovlen;
44528993443SEd Schouten 
44628993443SEd Schouten 	iovlen = uiop->uio_iovcnt * sizeof (struct iovec);
44728993443SEd Schouten 	uio = malloc(iovlen + sizeof *uio, M_IOV, M_WAITOK);
44828993443SEd Schouten 	*uio = *uiop;
44928993443SEd Schouten 	uio->uio_iov = (struct iovec *)(uio + 1);
45028993443SEd Schouten 	bcopy(uiop->uio_iov, uio->uio_iov, iovlen);
45128993443SEd Schouten 	return (uio);
45228993443SEd Schouten }
4530f502d1cSKonstantin Belousov 
4540f502d1cSKonstantin Belousov /*
4550f502d1cSKonstantin Belousov  * Map some anonymous memory in user space of size sz, rounded up to the page
4560f502d1cSKonstantin Belousov  * boundary.
4570f502d1cSKonstantin Belousov  */
4580f502d1cSKonstantin Belousov int
4590f502d1cSKonstantin Belousov copyout_map(struct thread *td, vm_offset_t *addr, size_t sz)
4600f502d1cSKonstantin Belousov {
461cce6e354SKonstantin Belousov 	struct vmspace *vms;
4620f502d1cSKonstantin Belousov 	int error;
4630f502d1cSKonstantin Belousov 	vm_size_t size;
4640f502d1cSKonstantin Belousov 
465cce6e354SKonstantin Belousov 	vms = td->td_proc->p_vmspace;
466cce6e354SKonstantin Belousov 
4670f502d1cSKonstantin Belousov 	/*
4680f502d1cSKonstantin Belousov 	 * Map somewhere after heap in process memory.
4690f502d1cSKonstantin Belousov 	 */
4700f502d1cSKonstantin Belousov 	*addr = round_page((vm_offset_t)vms->vm_daddr +
471f6f6d240SMateusz Guzik 	    lim_max(td, RLIMIT_DATA));
4720f502d1cSKonstantin Belousov 
473e3043798SPedro F. Giffuni 	/* round size up to page boundary */
4740f502d1cSKonstantin Belousov 	size = (vm_size_t)round_page(sz);
475f2277b64SKonstantin Belousov 	if (size == 0)
476f2277b64SKonstantin Belousov 		return (EINVAL);
477f2277b64SKonstantin Belousov 	error = vm_mmap_object(&vms->vm_map, addr, size, VM_PROT_READ |
478f2277b64SKonstantin Belousov 	    VM_PROT_WRITE, VM_PROT_ALL, MAP_PRIVATE | MAP_ANON, NULL, 0,
479f2277b64SKonstantin Belousov 	    FALSE, td);
4800f502d1cSKonstantin Belousov 	return (error);
4810f502d1cSKonstantin Belousov }
4820f502d1cSKonstantin Belousov 
4830f502d1cSKonstantin Belousov /*
4840f502d1cSKonstantin Belousov  * Unmap memory in user space.
4850f502d1cSKonstantin Belousov  */
4860f502d1cSKonstantin Belousov int
4870f502d1cSKonstantin Belousov copyout_unmap(struct thread *td, vm_offset_t addr, size_t sz)
4880f502d1cSKonstantin Belousov {
4890f502d1cSKonstantin Belousov 	vm_map_t map;
4900f502d1cSKonstantin Belousov 	vm_size_t size;
4910f502d1cSKonstantin Belousov 
492937060a8SKonstantin Belousov 	if (sz == 0)
493937060a8SKonstantin Belousov 		return (0);
494937060a8SKonstantin Belousov 
4950f502d1cSKonstantin Belousov 	map = &td->td_proc->p_vmspace->vm_map;
4960f502d1cSKonstantin Belousov 	size = (vm_size_t)round_page(sz);
4970f502d1cSKonstantin Belousov 
498cea8f30aSKonstantin Belousov 	if (vm_map_remove(map, addr, addr + size) != KERN_SUCCESS)
4990f502d1cSKonstantin Belousov 		return (EINVAL);
5000f502d1cSKonstantin Belousov 
5010f502d1cSKonstantin Belousov 	return (0);
5020f502d1cSKonstantin Belousov }
5034f3dc900SKonstantin Belousov 
5044f3dc900SKonstantin Belousov #ifdef NO_FUEWORD
5054f3dc900SKonstantin Belousov /*
5064f3dc900SKonstantin Belousov  * XXXKIB The temporal implementation of fue*() functions which do not
5074f3dc900SKonstantin Belousov  * handle usermode -1 properly, mixing it with the fault code.  Keep
5083e937c3aSKonstantin Belousov  * this until MD code is written.  Currently sparc64 and mips do not
5093e937c3aSKonstantin Belousov  * have proper implementation.
5104f3dc900SKonstantin Belousov  */
5114f3dc900SKonstantin Belousov 
5124f3dc900SKonstantin Belousov int
5132361c6d1SKonstantin Belousov fueword(volatile const void *base, long *val)
5144f3dc900SKonstantin Belousov {
5154f3dc900SKonstantin Belousov 	long res;
5164f3dc900SKonstantin Belousov 
5174f3dc900SKonstantin Belousov 	res = fuword(base);
5184f3dc900SKonstantin Belousov 	if (res == -1)
5194f3dc900SKonstantin Belousov 		return (-1);
5204f3dc900SKonstantin Belousov 	*val = res;
5214f3dc900SKonstantin Belousov 	return (0);
5224f3dc900SKonstantin Belousov }
5234f3dc900SKonstantin Belousov 
5244f3dc900SKonstantin Belousov int
5252361c6d1SKonstantin Belousov fueword32(volatile const void *base, int32_t *val)
5264f3dc900SKonstantin Belousov {
5274f3dc900SKonstantin Belousov 	int32_t res;
5284f3dc900SKonstantin Belousov 
5294f3dc900SKonstantin Belousov 	res = fuword32(base);
5304f3dc900SKonstantin Belousov 	if (res == -1)
5314f3dc900SKonstantin Belousov 		return (-1);
5324f3dc900SKonstantin Belousov 	*val = res;
5334f3dc900SKonstantin Belousov 	return (0);
5344f3dc900SKonstantin Belousov }
5354f3dc900SKonstantin Belousov 
5364f3dc900SKonstantin Belousov #ifdef _LP64
5374f3dc900SKonstantin Belousov int
5382361c6d1SKonstantin Belousov fueword64(volatile const void *base, int64_t *val)
5394f3dc900SKonstantin Belousov {
54055ee7a4cSKonstantin Belousov 	int64_t res;
5414f3dc900SKonstantin Belousov 
5424f3dc900SKonstantin Belousov 	res = fuword64(base);
5434f3dc900SKonstantin Belousov 	if (res == -1)
5444f3dc900SKonstantin Belousov 		return (-1);
5454f3dc900SKonstantin Belousov 	*val = res;
5464f3dc900SKonstantin Belousov 	return (0);
5474f3dc900SKonstantin Belousov }
5484f3dc900SKonstantin Belousov #endif
5494f3dc900SKonstantin Belousov 
5504f3dc900SKonstantin Belousov int
5514f3dc900SKonstantin Belousov casueword32(volatile uint32_t *base, uint32_t oldval, uint32_t *oldvalp,
5524f3dc900SKonstantin Belousov     uint32_t newval)
5534f3dc900SKonstantin Belousov {
5544f3dc900SKonstantin Belousov 	int32_t ov;
5554f3dc900SKonstantin Belousov 
5564f3dc900SKonstantin Belousov 	ov = casuword32(base, oldval, newval);
5574f3dc900SKonstantin Belousov 	if (ov == -1)
5584f3dc900SKonstantin Belousov 		return (-1);
5594f3dc900SKonstantin Belousov 	*oldvalp = ov;
5604f3dc900SKonstantin Belousov 	return (0);
5614f3dc900SKonstantin Belousov }
5624f3dc900SKonstantin Belousov 
5634f3dc900SKonstantin Belousov int
5644f3dc900SKonstantin Belousov casueword(volatile u_long *p, u_long oldval, u_long *oldvalp, u_long newval)
5654f3dc900SKonstantin Belousov {
5664f3dc900SKonstantin Belousov 	u_long ov;
5674f3dc900SKonstantin Belousov 
5684f3dc900SKonstantin Belousov 	ov = casuword(p, oldval, newval);
5694f3dc900SKonstantin Belousov 	if (ov == -1)
5704f3dc900SKonstantin Belousov 		return (-1);
5714f3dc900SKonstantin Belousov 	*oldvalp = ov;
5724f3dc900SKonstantin Belousov 	return (0);
5734f3dc900SKonstantin Belousov }
5744f3dc900SKonstantin Belousov #else /* NO_FUEWORD */
5754f3dc900SKonstantin Belousov int32_t
5762361c6d1SKonstantin Belousov fuword32(volatile const void *addr)
5774f3dc900SKonstantin Belousov {
5784f3dc900SKonstantin Belousov 	int rv;
5794f3dc900SKonstantin Belousov 	int32_t val;
5804f3dc900SKonstantin Belousov 
5814f3dc900SKonstantin Belousov 	rv = fueword32(addr, &val);
5824f3dc900SKonstantin Belousov 	return (rv == -1 ? -1 : val);
5834f3dc900SKonstantin Belousov }
5844f3dc900SKonstantin Belousov 
5854f3dc900SKonstantin Belousov #ifdef _LP64
5864f3dc900SKonstantin Belousov int64_t
5872361c6d1SKonstantin Belousov fuword64(volatile const void *addr)
5884f3dc900SKonstantin Belousov {
5894f3dc900SKonstantin Belousov 	int rv;
5904f3dc900SKonstantin Belousov 	int64_t val;
5914f3dc900SKonstantin Belousov 
5924f3dc900SKonstantin Belousov 	rv = fueword64(addr, &val);
5934f3dc900SKonstantin Belousov 	return (rv == -1 ? -1 : val);
5944f3dc900SKonstantin Belousov }
5954f3dc900SKonstantin Belousov #endif /* _LP64 */
5964f3dc900SKonstantin Belousov 
5974f3dc900SKonstantin Belousov long
5982361c6d1SKonstantin Belousov fuword(volatile const void *addr)
5994f3dc900SKonstantin Belousov {
6004f3dc900SKonstantin Belousov 	long val;
6014f3dc900SKonstantin Belousov 	int rv;
6024f3dc900SKonstantin Belousov 
6034f3dc900SKonstantin Belousov 	rv = fueword(addr, &val);
6044f3dc900SKonstantin Belousov 	return (rv == -1 ? -1 : val);
6054f3dc900SKonstantin Belousov }
6064f3dc900SKonstantin Belousov 
6074f3dc900SKonstantin Belousov uint32_t
6084f3dc900SKonstantin Belousov casuword32(volatile uint32_t *addr, uint32_t old, uint32_t new)
6094f3dc900SKonstantin Belousov {
6104f3dc900SKonstantin Belousov 	int rv;
6114f3dc900SKonstantin Belousov 	uint32_t val;
6124f3dc900SKonstantin Belousov 
6134f3dc900SKonstantin Belousov 	rv = casueword32(addr, old, &val, new);
6144f3dc900SKonstantin Belousov 	return (rv == -1 ? -1 : val);
6154f3dc900SKonstantin Belousov }
6164f3dc900SKonstantin Belousov 
6174f3dc900SKonstantin Belousov u_long
6184f3dc900SKonstantin Belousov casuword(volatile u_long *addr, u_long old, u_long new)
6194f3dc900SKonstantin Belousov {
6204f3dc900SKonstantin Belousov 	int rv;
6214f3dc900SKonstantin Belousov 	u_long val;
6224f3dc900SKonstantin Belousov 
6234f3dc900SKonstantin Belousov 	rv = casueword(addr, old, &val, new);
6244f3dc900SKonstantin Belousov 	return (rv == -1 ? -1 : val);
6254f3dc900SKonstantin Belousov }
6264f3dc900SKonstantin Belousov 
6274f3dc900SKonstantin Belousov #endif /* NO_FUEWORD */
628