xref: /freebsd/sys/kern/subr_uio.c (revision e3043798aa79660648a80166c1b48461668c4887)
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  *
104f3dc900SKonstantin Belousov  * Copyright (c) 2014 The FreeBSD Foundation
114f3dc900SKonstantin Belousov  *
124f3dc900SKonstantin Belousov  * Portions of this software were developed by Konstantin Belousov
134f3dc900SKonstantin Belousov  * under sponsorship from the FreeBSD Foundation.
144f3dc900SKonstantin Belousov  *
1528993443SEd Schouten  * Redistribution and use in source and binary forms, with or without
1628993443SEd Schouten  * modification, are permitted provided that the following conditions
1728993443SEd Schouten  * are met:
1828993443SEd Schouten  * 1. Redistributions of source code must retain the above copyright
1928993443SEd Schouten  *    notice, this list of conditions and the following disclaimer.
2028993443SEd Schouten  * 2. Redistributions in binary form must reproduce the above copyright
2128993443SEd Schouten  *    notice, this list of conditions and the following disclaimer in the
2228993443SEd Schouten  *    documentation and/or other materials provided with the distribution.
2328993443SEd Schouten  * 4. Neither the name of the University nor the names of its contributors
2428993443SEd Schouten  *    may be used to endorse or promote products derived from this software
2528993443SEd Schouten  *    without specific prior written permission.
2628993443SEd Schouten  *
2728993443SEd Schouten  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2828993443SEd Schouten  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2928993443SEd Schouten  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3028993443SEd Schouten  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3128993443SEd Schouten  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3228993443SEd Schouten  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3328993443SEd Schouten  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3428993443SEd Schouten  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3528993443SEd Schouten  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3628993443SEd Schouten  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3728993443SEd Schouten  * SUCH DAMAGE.
3828993443SEd Schouten  *
3928993443SEd Schouten  *	@(#)kern_subr.c	8.3 (Berkeley) 1/21/94
4028993443SEd Schouten  */
4128993443SEd Schouten 
4228993443SEd Schouten #include <sys/cdefs.h>
4328993443SEd Schouten __FBSDID("$FreeBSD$");
4428993443SEd Schouten 
4528993443SEd Schouten #include <sys/param.h>
4628993443SEd Schouten #include <sys/systm.h>
4728993443SEd Schouten #include <sys/kernel.h>
4828993443SEd Schouten #include <sys/limits.h>
4928993443SEd Schouten #include <sys/lock.h>
500f502d1cSKonstantin Belousov #include <sys/mman.h>
5128993443SEd Schouten #include <sys/proc.h>
520f502d1cSKonstantin Belousov #include <sys/resourcevar.h>
5389f6b863SAttilio Rao #include <sys/rwlock.h>
5428993443SEd Schouten #include <sys/sched.h>
5528993443SEd Schouten #include <sys/sysctl.h>
5628993443SEd Schouten #include <sys/vnode.h>
5728993443SEd Schouten 
5828993443SEd Schouten #include <vm/vm.h>
591c771f92SKonstantin Belousov #include <vm/vm_param.h>
600f502d1cSKonstantin Belousov #include <vm/vm_extern.h>
6128993443SEd Schouten #include <vm/vm_page.h>
62e946b949SAttilio Rao #include <vm/vm_pageout.h>
6328993443SEd Schouten #include <vm/vm_map.h>
6428993443SEd Schouten 
65a9934668SKenneth D. Merry #include <machine/bus.h>
66a9934668SKenneth D. Merry 
67f0188618SHans Petter Selasky SYSCTL_INT(_kern, KERN_IOV_MAX, iov_max, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, UIO_MAXIOV,
6828993443SEd Schouten 	"Maximum number of elements in an I/O vector; sysconf(_SC_IOV_MAX)");
6928993443SEd Schouten 
702801687dSKonstantin Belousov static int uiomove_faultflag(void *cp, int n, struct uio *uio, int nofault);
712801687dSKonstantin Belousov 
7228993443SEd Schouten int
732801687dSKonstantin Belousov copyin_nofault(const void *udaddr, void *kaddr, size_t len)
742801687dSKonstantin Belousov {
752801687dSKonstantin Belousov 	int error, save;
762801687dSKonstantin Belousov 
772801687dSKonstantin Belousov 	save = vm_fault_disable_pagefaults();
782801687dSKonstantin Belousov 	error = copyin(udaddr, kaddr, len);
792801687dSKonstantin Belousov 	vm_fault_enable_pagefaults(save);
802801687dSKonstantin Belousov 	return (error);
812801687dSKonstantin Belousov }
822801687dSKonstantin Belousov 
832801687dSKonstantin Belousov int
842801687dSKonstantin Belousov copyout_nofault(const void *kaddr, void *udaddr, size_t len)
852801687dSKonstantin Belousov {
862801687dSKonstantin Belousov 	int error, save;
872801687dSKonstantin Belousov 
882801687dSKonstantin Belousov 	save = vm_fault_disable_pagefaults();
892801687dSKonstantin Belousov 	error = copyout(kaddr, udaddr, len);
902801687dSKonstantin Belousov 	vm_fault_enable_pagefaults(save);
912801687dSKonstantin Belousov 	return (error);
922801687dSKonstantin Belousov }
932801687dSKonstantin Belousov 
94dd0b4fb6SKonstantin Belousov #define	PHYS_PAGE_COUNT(len)	(howmany(len, PAGE_SIZE) + 1)
95dd0b4fb6SKonstantin Belousov 
96dd0b4fb6SKonstantin Belousov int
97dd0b4fb6SKonstantin Belousov physcopyin(void *src, vm_paddr_t dst, size_t len)
98dd0b4fb6SKonstantin Belousov {
99dd0b4fb6SKonstantin Belousov 	vm_page_t m[PHYS_PAGE_COUNT(len)];
100dd0b4fb6SKonstantin Belousov 	struct iovec iov[1];
101dd0b4fb6SKonstantin Belousov 	struct uio uio;
102dd0b4fb6SKonstantin Belousov 	int i;
103dd0b4fb6SKonstantin Belousov 
104dd0b4fb6SKonstantin Belousov 	iov[0].iov_base = src;
105dd0b4fb6SKonstantin Belousov 	iov[0].iov_len = len;
106dd0b4fb6SKonstantin Belousov 	uio.uio_iov = iov;
107dd0b4fb6SKonstantin Belousov 	uio.uio_iovcnt = 1;
108dd0b4fb6SKonstantin Belousov 	uio.uio_offset = 0;
109dd0b4fb6SKonstantin Belousov 	uio.uio_resid = len;
110dd0b4fb6SKonstantin Belousov 	uio.uio_segflg = UIO_SYSSPACE;
111dd0b4fb6SKonstantin Belousov 	uio.uio_rw = UIO_WRITE;
112dd0b4fb6SKonstantin Belousov 	for (i = 0; i < PHYS_PAGE_COUNT(len); i++, dst += PAGE_SIZE)
113dd0b4fb6SKonstantin Belousov 		m[i] = PHYS_TO_VM_PAGE(dst);
114dd0b4fb6SKonstantin Belousov 	return (uiomove_fromphys(m, dst & PAGE_MASK, len, &uio));
115dd0b4fb6SKonstantin Belousov }
116dd0b4fb6SKonstantin Belousov 
117dd0b4fb6SKonstantin Belousov int
118dd0b4fb6SKonstantin Belousov physcopyout(vm_paddr_t src, void *dst, size_t len)
119dd0b4fb6SKonstantin Belousov {
120dd0b4fb6SKonstantin Belousov 	vm_page_t m[PHYS_PAGE_COUNT(len)];
121dd0b4fb6SKonstantin Belousov 	struct iovec iov[1];
122dd0b4fb6SKonstantin Belousov 	struct uio uio;
123dd0b4fb6SKonstantin Belousov 	int i;
124dd0b4fb6SKonstantin Belousov 
125dd0b4fb6SKonstantin Belousov 	iov[0].iov_base = dst;
126dd0b4fb6SKonstantin Belousov 	iov[0].iov_len = len;
127dd0b4fb6SKonstantin Belousov 	uio.uio_iov = iov;
128dd0b4fb6SKonstantin Belousov 	uio.uio_iovcnt = 1;
129dd0b4fb6SKonstantin Belousov 	uio.uio_offset = 0;
130dd0b4fb6SKonstantin Belousov 	uio.uio_resid = len;
131dd0b4fb6SKonstantin Belousov 	uio.uio_segflg = UIO_SYSSPACE;
132dd0b4fb6SKonstantin Belousov 	uio.uio_rw = UIO_READ;
133dd0b4fb6SKonstantin Belousov 	for (i = 0; i < PHYS_PAGE_COUNT(len); i++, src += PAGE_SIZE)
134dd0b4fb6SKonstantin Belousov 		m[i] = PHYS_TO_VM_PAGE(src);
135dd0b4fb6SKonstantin Belousov 	return (uiomove_fromphys(m, src & PAGE_MASK, len, &uio));
136dd0b4fb6SKonstantin Belousov }
137dd0b4fb6SKonstantin Belousov 
138dd0b4fb6SKonstantin Belousov #undef PHYS_PAGE_COUNT
139dd0b4fb6SKonstantin Belousov 
1402801687dSKonstantin Belousov int
141a9934668SKenneth D. Merry physcopyin_vlist(bus_dma_segment_t *src, off_t offset, vm_paddr_t dst,
142a9934668SKenneth D. Merry     size_t len)
143a9934668SKenneth D. Merry {
144a9934668SKenneth D. Merry 	size_t seg_len;
145a9934668SKenneth D. Merry 	int error;
146a9934668SKenneth D. Merry 
147a9934668SKenneth D. Merry 	error = 0;
148a9934668SKenneth D. Merry 	while (offset >= src->ds_len) {
149a9934668SKenneth D. Merry 		offset -= src->ds_len;
150a9934668SKenneth D. Merry 		src++;
151a9934668SKenneth D. Merry 	}
152a9934668SKenneth D. Merry 
153a9934668SKenneth D. Merry 	while (len > 0 && error == 0) {
154a9934668SKenneth D. Merry 		seg_len = MIN(src->ds_len - offset, len);
155a9934668SKenneth D. Merry 		error = physcopyin((void *)(uintptr_t)(src->ds_addr + offset),
156a9934668SKenneth D. Merry 		    dst, seg_len);
157a9934668SKenneth D. Merry 		offset = 0;
158a9934668SKenneth D. Merry 		src++;
159a9934668SKenneth D. Merry 		len -= seg_len;
160a9934668SKenneth D. Merry 		dst += seg_len;
161a9934668SKenneth D. Merry 	}
162a9934668SKenneth D. Merry 
163a9934668SKenneth D. Merry 	return (error);
164a9934668SKenneth D. Merry }
165a9934668SKenneth D. Merry 
166a9934668SKenneth D. Merry int
167a9934668SKenneth D. Merry physcopyout_vlist(vm_paddr_t src, bus_dma_segment_t *dst, off_t offset,
168a9934668SKenneth D. Merry     size_t len)
169a9934668SKenneth D. Merry {
170a9934668SKenneth D. Merry 	size_t seg_len;
171a9934668SKenneth D. Merry 	int error;
172a9934668SKenneth D. Merry 
173a9934668SKenneth D. Merry 	error = 0;
174a9934668SKenneth D. Merry 	while (offset >= dst->ds_len) {
175a9934668SKenneth D. Merry 		offset -= dst->ds_len;
176a9934668SKenneth D. Merry 		dst++;
177a9934668SKenneth D. Merry 	}
178a9934668SKenneth D. Merry 
179a9934668SKenneth D. Merry 	while (len > 0 && error == 0) {
180a9934668SKenneth D. Merry 		seg_len = MIN(dst->ds_len - offset, len);
181a9934668SKenneth D. Merry 		error = physcopyout(src, (void *)(uintptr_t)(dst->ds_addr +
182a9934668SKenneth D. Merry 		    offset), seg_len);
183a9934668SKenneth D. Merry 		offset = 0;
184a9934668SKenneth D. Merry 		dst++;
185a9934668SKenneth D. Merry 		len -= seg_len;
186a9934668SKenneth D. Merry 		src += seg_len;
187a9934668SKenneth D. Merry 	}
188a9934668SKenneth D. Merry 
189a9934668SKenneth D. Merry 	return (error);
190a9934668SKenneth D. Merry }
191a9934668SKenneth D. Merry 
192a9934668SKenneth D. Merry int
19328993443SEd Schouten uiomove(void *cp, int n, struct uio *uio)
19428993443SEd Schouten {
1952801687dSKonstantin Belousov 
1962801687dSKonstantin Belousov 	return (uiomove_faultflag(cp, n, uio, 0));
1972801687dSKonstantin Belousov }
1982801687dSKonstantin Belousov 
1992801687dSKonstantin Belousov int
2002801687dSKonstantin Belousov uiomove_nofault(void *cp, int n, struct uio *uio)
2012801687dSKonstantin Belousov {
2022801687dSKonstantin Belousov 
2032801687dSKonstantin Belousov 	return (uiomove_faultflag(cp, n, uio, 1));
2042801687dSKonstantin Belousov }
2052801687dSKonstantin Belousov 
2062801687dSKonstantin Belousov static int
2072801687dSKonstantin Belousov uiomove_faultflag(void *cp, int n, struct uio *uio, int nofault)
2082801687dSKonstantin Belousov {
2092801687dSKonstantin Belousov 	struct thread *td;
21028993443SEd Schouten 	struct iovec *iov;
211526d0bd5SKonstantin Belousov 	size_t cnt;
2122801687dSKonstantin Belousov 	int error, newflags, save;
2132801687dSKonstantin Belousov 
2142801687dSKonstantin Belousov 	td = curthread;
2152801687dSKonstantin Belousov 	error = 0;
21628993443SEd Schouten 
21728993443SEd Schouten 	KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE,
21828993443SEd Schouten 	    ("uiomove: mode"));
2192801687dSKonstantin Belousov 	KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_td == td,
22028993443SEd Schouten 	    ("uiomove proc"));
2212801687dSKonstantin Belousov 	if (!nofault)
22228993443SEd Schouten 		WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
22328993443SEd Schouten 		    "Calling uiomove()");
22428993443SEd Schouten 
2252801687dSKonstantin Belousov 	/* XXX does it make a sense to set TDP_DEADLKTREAT for UIO_SYSSPACE ? */
2262801687dSKonstantin Belousov 	newflags = TDP_DEADLKTREAT;
2275730afc9SAlan Cox 	if (uio->uio_segflg == UIO_USERSPACE && nofault) {
2285730afc9SAlan Cox 		/*
2295730afc9SAlan Cox 		 * Fail if a non-spurious page fault occurs.
2305730afc9SAlan Cox 		 */
2315730afc9SAlan Cox 		newflags |= TDP_NOFAULTING | TDP_RESETSPUR;
2325730afc9SAlan Cox 	}
2332801687dSKonstantin Belousov 	save = curthread_pflags_set(newflags);
23428993443SEd Schouten 
23528993443SEd Schouten 	while (n > 0 && uio->uio_resid) {
23628993443SEd Schouten 		iov = uio->uio_iov;
23728993443SEd Schouten 		cnt = iov->iov_len;
23828993443SEd Schouten 		if (cnt == 0) {
23928993443SEd Schouten 			uio->uio_iov++;
24028993443SEd Schouten 			uio->uio_iovcnt--;
24128993443SEd Schouten 			continue;
24228993443SEd Schouten 		}
24328993443SEd Schouten 		if (cnt > n)
24428993443SEd Schouten 			cnt = n;
24528993443SEd Schouten 
24628993443SEd Schouten 		switch (uio->uio_segflg) {
24728993443SEd Schouten 
24828993443SEd Schouten 		case UIO_USERSPACE:
24908b163faSMatthew D Fleming 			maybe_yield();
25028993443SEd Schouten 			if (uio->uio_rw == UIO_READ)
25128993443SEd Schouten 				error = copyout(cp, iov->iov_base, cnt);
25228993443SEd Schouten 			else
25328993443SEd Schouten 				error = copyin(iov->iov_base, cp, cnt);
25428993443SEd Schouten 			if (error)
25528993443SEd Schouten 				goto out;
25628993443SEd Schouten 			break;
25728993443SEd Schouten 
25828993443SEd Schouten 		case UIO_SYSSPACE:
25928993443SEd Schouten 			if (uio->uio_rw == UIO_READ)
26028993443SEd Schouten 				bcopy(cp, iov->iov_base, cnt);
26128993443SEd Schouten 			else
26228993443SEd Schouten 				bcopy(iov->iov_base, cp, cnt);
26328993443SEd Schouten 			break;
26428993443SEd Schouten 		case UIO_NOCOPY:
26528993443SEd Schouten 			break;
26628993443SEd Schouten 		}
26728993443SEd Schouten 		iov->iov_base = (char *)iov->iov_base + cnt;
26828993443SEd Schouten 		iov->iov_len -= cnt;
26928993443SEd Schouten 		uio->uio_resid -= cnt;
27028993443SEd Schouten 		uio->uio_offset += cnt;
27128993443SEd Schouten 		cp = (char *)cp + cnt;
27228993443SEd Schouten 		n -= cnt;
27328993443SEd Schouten 	}
27428993443SEd Schouten out:
2752801687dSKonstantin Belousov 	curthread_pflags_restore(save);
27628993443SEd Schouten 	return (error);
27728993443SEd Schouten }
27828993443SEd Schouten 
27928993443SEd Schouten /*
28028993443SEd Schouten  * Wrapper for uiomove() that validates the arguments against a known-good
28128993443SEd Schouten  * kernel buffer.  Currently, uiomove accepts a signed (n) argument, which
28228993443SEd Schouten  * is almost definitely a bad thing, so we catch that here as well.  We
28328993443SEd Schouten  * return a runtime failure, but it might be desirable to generate a runtime
28428993443SEd Schouten  * assertion failure instead.
28528993443SEd Schouten  */
28628993443SEd Schouten int
28728993443SEd Schouten uiomove_frombuf(void *buf, int buflen, struct uio *uio)
28828993443SEd Schouten {
289526d0bd5SKonstantin Belousov 	size_t offset, n;
29028993443SEd Schouten 
29128993443SEd Schouten 	if (uio->uio_offset < 0 || uio->uio_resid < 0 ||
29228993443SEd Schouten 	    (offset = uio->uio_offset) != uio->uio_offset)
29328993443SEd Schouten 		return (EINVAL);
29428993443SEd Schouten 	if (buflen <= 0 || offset >= buflen)
29528993443SEd Schouten 		return (0);
296526d0bd5SKonstantin Belousov 	if ((n = buflen - offset) > IOSIZE_MAX)
29728993443SEd Schouten 		return (EINVAL);
29828993443SEd Schouten 	return (uiomove((char *)buf + offset, n, uio));
29928993443SEd Schouten }
30028993443SEd Schouten 
30128993443SEd Schouten /*
30228993443SEd Schouten  * Give next character to user as result of read.
30328993443SEd Schouten  */
30428993443SEd Schouten int
30528993443SEd Schouten ureadc(int c, struct uio *uio)
30628993443SEd Schouten {
30728993443SEd Schouten 	struct iovec *iov;
30828993443SEd Schouten 	char *iov_base;
30928993443SEd Schouten 
31028993443SEd Schouten 	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
31128993443SEd Schouten 	    "Calling ureadc()");
31228993443SEd Schouten 
31328993443SEd Schouten again:
31428993443SEd Schouten 	if (uio->uio_iovcnt == 0 || uio->uio_resid == 0)
31528993443SEd Schouten 		panic("ureadc");
31628993443SEd Schouten 	iov = uio->uio_iov;
31728993443SEd Schouten 	if (iov->iov_len == 0) {
31828993443SEd Schouten 		uio->uio_iovcnt--;
31928993443SEd Schouten 		uio->uio_iov++;
32028993443SEd Schouten 		goto again;
32128993443SEd Schouten 	}
32228993443SEd Schouten 	switch (uio->uio_segflg) {
32328993443SEd Schouten 
32428993443SEd Schouten 	case UIO_USERSPACE:
32528993443SEd Schouten 		if (subyte(iov->iov_base, c) < 0)
32628993443SEd Schouten 			return (EFAULT);
32728993443SEd Schouten 		break;
32828993443SEd Schouten 
32928993443SEd Schouten 	case UIO_SYSSPACE:
33028993443SEd Schouten 		iov_base = iov->iov_base;
33128993443SEd Schouten 		*iov_base = c;
33228993443SEd Schouten 		break;
33328993443SEd Schouten 
33428993443SEd Schouten 	case UIO_NOCOPY:
33528993443SEd Schouten 		break;
33628993443SEd Schouten 	}
33728993443SEd Schouten 	iov->iov_base = (char *)iov->iov_base + 1;
33828993443SEd Schouten 	iov->iov_len--;
33928993443SEd Schouten 	uio->uio_resid--;
34028993443SEd Schouten 	uio->uio_offset++;
34128993443SEd Schouten 	return (0);
34228993443SEd Schouten }
34328993443SEd Schouten 
34428993443SEd Schouten int
34528993443SEd Schouten copyinfrom(const void * __restrict src, void * __restrict dst, size_t len,
34628993443SEd Schouten     int seg)
34728993443SEd Schouten {
34828993443SEd Schouten 	int error = 0;
34928993443SEd Schouten 
35028993443SEd Schouten 	switch (seg) {
35128993443SEd Schouten 	case UIO_USERSPACE:
35228993443SEd Schouten 		error = copyin(src, dst, len);
35328993443SEd Schouten 		break;
35428993443SEd Schouten 	case UIO_SYSSPACE:
35528993443SEd Schouten 		bcopy(src, dst, len);
35628993443SEd Schouten 		break;
35728993443SEd Schouten 	default:
35828993443SEd Schouten 		panic("copyinfrom: bad seg %d\n", seg);
35928993443SEd Schouten 	}
36028993443SEd Schouten 	return (error);
36128993443SEd Schouten }
36228993443SEd Schouten 
36328993443SEd Schouten int
36428993443SEd Schouten copyinstrfrom(const void * __restrict src, void * __restrict dst, size_t len,
36528993443SEd Schouten     size_t * __restrict copied, int seg)
36628993443SEd Schouten {
36728993443SEd Schouten 	int error = 0;
36828993443SEd Schouten 
36928993443SEd Schouten 	switch (seg) {
37028993443SEd Schouten 	case UIO_USERSPACE:
37128993443SEd Schouten 		error = copyinstr(src, dst, len, copied);
37228993443SEd Schouten 		break;
37328993443SEd Schouten 	case UIO_SYSSPACE:
37428993443SEd Schouten 		error = copystr(src, dst, len, copied);
37528993443SEd Schouten 		break;
37628993443SEd Schouten 	default:
37728993443SEd Schouten 		panic("copyinstrfrom: bad seg %d\n", seg);
37828993443SEd Schouten 	}
37928993443SEd Schouten 	return (error);
38028993443SEd Schouten }
38128993443SEd Schouten 
38228993443SEd Schouten int
383cfb09e00SAlfred Perlstein copyiniov(const struct iovec *iovp, u_int iovcnt, struct iovec **iov, int error)
38428993443SEd Schouten {
38528993443SEd Schouten 	u_int iovlen;
38628993443SEd Schouten 
38728993443SEd Schouten 	*iov = NULL;
38828993443SEd Schouten 	if (iovcnt > UIO_MAXIOV)
38928993443SEd Schouten 		return (error);
39028993443SEd Schouten 	iovlen = iovcnt * sizeof (struct iovec);
39128993443SEd Schouten 	*iov = malloc(iovlen, M_IOV, M_WAITOK);
39228993443SEd Schouten 	error = copyin(iovp, *iov, iovlen);
39328993443SEd Schouten 	if (error) {
39428993443SEd Schouten 		free(*iov, M_IOV);
39528993443SEd Schouten 		*iov = NULL;
39628993443SEd Schouten 	}
39728993443SEd Schouten 	return (error);
39828993443SEd Schouten }
39928993443SEd Schouten 
40028993443SEd Schouten int
401cfb09e00SAlfred Perlstein copyinuio(const struct iovec *iovp, u_int iovcnt, struct uio **uiop)
40228993443SEd Schouten {
40328993443SEd Schouten 	struct iovec *iov;
40428993443SEd Schouten 	struct uio *uio;
40528993443SEd Schouten 	u_int iovlen;
40628993443SEd Schouten 	int error, i;
40728993443SEd Schouten 
40828993443SEd Schouten 	*uiop = NULL;
40928993443SEd Schouten 	if (iovcnt > UIO_MAXIOV)
41028993443SEd Schouten 		return (EINVAL);
41128993443SEd Schouten 	iovlen = iovcnt * sizeof (struct iovec);
41228993443SEd Schouten 	uio = malloc(iovlen + sizeof *uio, M_IOV, M_WAITOK);
41328993443SEd Schouten 	iov = (struct iovec *)(uio + 1);
41428993443SEd Schouten 	error = copyin(iovp, iov, iovlen);
41528993443SEd Schouten 	if (error) {
41628993443SEd Schouten 		free(uio, M_IOV);
41728993443SEd Schouten 		return (error);
41828993443SEd Schouten 	}
41928993443SEd Schouten 	uio->uio_iov = iov;
42028993443SEd Schouten 	uio->uio_iovcnt = iovcnt;
42128993443SEd Schouten 	uio->uio_segflg = UIO_USERSPACE;
42228993443SEd Schouten 	uio->uio_offset = -1;
42328993443SEd Schouten 	uio->uio_resid = 0;
42428993443SEd Schouten 	for (i = 0; i < iovcnt; i++) {
425526d0bd5SKonstantin Belousov 		if (iov->iov_len > IOSIZE_MAX - uio->uio_resid) {
42628993443SEd Schouten 			free(uio, M_IOV);
42728993443SEd Schouten 			return (EINVAL);
42828993443SEd Schouten 		}
42928993443SEd Schouten 		uio->uio_resid += iov->iov_len;
43028993443SEd Schouten 		iov++;
43128993443SEd Schouten 	}
43228993443SEd Schouten 	*uiop = uio;
43328993443SEd Schouten 	return (0);
43428993443SEd Schouten }
43528993443SEd Schouten 
43628993443SEd Schouten struct uio *
43728993443SEd Schouten cloneuio(struct uio *uiop)
43828993443SEd Schouten {
43928993443SEd Schouten 	struct uio *uio;
44028993443SEd Schouten 	int iovlen;
44128993443SEd Schouten 
44228993443SEd Schouten 	iovlen = uiop->uio_iovcnt * sizeof (struct iovec);
44328993443SEd Schouten 	uio = malloc(iovlen + sizeof *uio, M_IOV, M_WAITOK);
44428993443SEd Schouten 	*uio = *uiop;
44528993443SEd Schouten 	uio->uio_iov = (struct iovec *)(uio + 1);
44628993443SEd Schouten 	bcopy(uiop->uio_iov, uio->uio_iov, iovlen);
44728993443SEd Schouten 	return (uio);
44828993443SEd Schouten }
4490f502d1cSKonstantin Belousov 
4500f502d1cSKonstantin Belousov /*
4510f502d1cSKonstantin Belousov  * Map some anonymous memory in user space of size sz, rounded up to the page
4520f502d1cSKonstantin Belousov  * boundary.
4530f502d1cSKonstantin Belousov  */
4540f502d1cSKonstantin Belousov int
4550f502d1cSKonstantin Belousov copyout_map(struct thread *td, vm_offset_t *addr, size_t sz)
4560f502d1cSKonstantin Belousov {
457cce6e354SKonstantin Belousov 	struct vmspace *vms;
4580f502d1cSKonstantin Belousov 	int error;
4590f502d1cSKonstantin Belousov 	vm_size_t size;
4600f502d1cSKonstantin Belousov 
461cce6e354SKonstantin Belousov 	vms = td->td_proc->p_vmspace;
462cce6e354SKonstantin Belousov 
4630f502d1cSKonstantin Belousov 	/*
4640f502d1cSKonstantin Belousov 	 * Map somewhere after heap in process memory.
4650f502d1cSKonstantin Belousov 	 */
4660f502d1cSKonstantin Belousov 	*addr = round_page((vm_offset_t)vms->vm_daddr +
467f6f6d240SMateusz Guzik 	    lim_max(td, RLIMIT_DATA));
4680f502d1cSKonstantin Belousov 
469*e3043798SPedro F. Giffuni 	/* round size up to page boundary */
4700f502d1cSKonstantin Belousov 	size = (vm_size_t)round_page(sz);
4710f502d1cSKonstantin Belousov 
4727077c426SJohn Baldwin 	error = vm_mmap(&vms->vm_map, addr, size, VM_PROT_READ | VM_PROT_WRITE,
4730f502d1cSKonstantin Belousov 	    VM_PROT_ALL, MAP_PRIVATE | MAP_ANON, OBJT_DEFAULT, NULL, 0);
4740f502d1cSKonstantin Belousov 
4750f502d1cSKonstantin Belousov 	return (error);
4760f502d1cSKonstantin Belousov }
4770f502d1cSKonstantin Belousov 
4780f502d1cSKonstantin Belousov /*
4790f502d1cSKonstantin Belousov  * Unmap memory in user space.
4800f502d1cSKonstantin Belousov  */
4810f502d1cSKonstantin Belousov int
4820f502d1cSKonstantin Belousov copyout_unmap(struct thread *td, vm_offset_t addr, size_t sz)
4830f502d1cSKonstantin Belousov {
4840f502d1cSKonstantin Belousov 	vm_map_t map;
4850f502d1cSKonstantin Belousov 	vm_size_t size;
4860f502d1cSKonstantin Belousov 
487937060a8SKonstantin Belousov 	if (sz == 0)
488937060a8SKonstantin Belousov 		return (0);
489937060a8SKonstantin Belousov 
4900f502d1cSKonstantin Belousov 	map = &td->td_proc->p_vmspace->vm_map;
4910f502d1cSKonstantin Belousov 	size = (vm_size_t)round_page(sz);
4920f502d1cSKonstantin Belousov 
493cea8f30aSKonstantin Belousov 	if (vm_map_remove(map, addr, addr + size) != KERN_SUCCESS)
4940f502d1cSKonstantin Belousov 		return (EINVAL);
4950f502d1cSKonstantin Belousov 
4960f502d1cSKonstantin Belousov 	return (0);
4970f502d1cSKonstantin Belousov }
4984f3dc900SKonstantin Belousov 
4994f3dc900SKonstantin Belousov #ifdef NO_FUEWORD
5004f3dc900SKonstantin Belousov /*
5014f3dc900SKonstantin Belousov  * XXXKIB The temporal implementation of fue*() functions which do not
5024f3dc900SKonstantin Belousov  * handle usermode -1 properly, mixing it with the fault code.  Keep
5033e937c3aSKonstantin Belousov  * this until MD code is written.  Currently sparc64 and mips do not
5043e937c3aSKonstantin Belousov  * have proper implementation.
5054f3dc900SKonstantin Belousov  */
5064f3dc900SKonstantin Belousov 
5074f3dc900SKonstantin Belousov int
5082361c6d1SKonstantin Belousov fueword(volatile const void *base, long *val)
5094f3dc900SKonstantin Belousov {
5104f3dc900SKonstantin Belousov 	long res;
5114f3dc900SKonstantin Belousov 
5124f3dc900SKonstantin Belousov 	res = fuword(base);
5134f3dc900SKonstantin Belousov 	if (res == -1)
5144f3dc900SKonstantin Belousov 		return (-1);
5154f3dc900SKonstantin Belousov 	*val = res;
5164f3dc900SKonstantin Belousov 	return (0);
5174f3dc900SKonstantin Belousov }
5184f3dc900SKonstantin Belousov 
5194f3dc900SKonstantin Belousov int
5202361c6d1SKonstantin Belousov fueword32(volatile const void *base, int32_t *val)
5214f3dc900SKonstantin Belousov {
5224f3dc900SKonstantin Belousov 	int32_t res;
5234f3dc900SKonstantin Belousov 
5244f3dc900SKonstantin Belousov 	res = fuword32(base);
5254f3dc900SKonstantin Belousov 	if (res == -1)
5264f3dc900SKonstantin Belousov 		return (-1);
5274f3dc900SKonstantin Belousov 	*val = res;
5284f3dc900SKonstantin Belousov 	return (0);
5294f3dc900SKonstantin Belousov }
5304f3dc900SKonstantin Belousov 
5314f3dc900SKonstantin Belousov #ifdef _LP64
5324f3dc900SKonstantin Belousov int
5332361c6d1SKonstantin Belousov fueword64(volatile const void *base, int64_t *val)
5344f3dc900SKonstantin Belousov {
5354f3dc900SKonstantin Belousov 	int32_t res;
5364f3dc900SKonstantin Belousov 
5374f3dc900SKonstantin Belousov 	res = fuword64(base);
5384f3dc900SKonstantin Belousov 	if (res == -1)
5394f3dc900SKonstantin Belousov 		return (-1);
5404f3dc900SKonstantin Belousov 	*val = res;
5414f3dc900SKonstantin Belousov 	return (0);
5424f3dc900SKonstantin Belousov }
5434f3dc900SKonstantin Belousov #endif
5444f3dc900SKonstantin Belousov 
5454f3dc900SKonstantin Belousov int
5464f3dc900SKonstantin Belousov casueword32(volatile uint32_t *base, uint32_t oldval, uint32_t *oldvalp,
5474f3dc900SKonstantin Belousov     uint32_t newval)
5484f3dc900SKonstantin Belousov {
5494f3dc900SKonstantin Belousov 	int32_t ov;
5504f3dc900SKonstantin Belousov 
5514f3dc900SKonstantin Belousov 	ov = casuword32(base, oldval, newval);
5524f3dc900SKonstantin Belousov 	if (ov == -1)
5534f3dc900SKonstantin Belousov 		return (-1);
5544f3dc900SKonstantin Belousov 	*oldvalp = ov;
5554f3dc900SKonstantin Belousov 	return (0);
5564f3dc900SKonstantin Belousov }
5574f3dc900SKonstantin Belousov 
5584f3dc900SKonstantin Belousov int
5594f3dc900SKonstantin Belousov casueword(volatile u_long *p, u_long oldval, u_long *oldvalp, u_long newval)
5604f3dc900SKonstantin Belousov {
5614f3dc900SKonstantin Belousov 	u_long ov;
5624f3dc900SKonstantin Belousov 
5634f3dc900SKonstantin Belousov 	ov = casuword(p, oldval, newval);
5644f3dc900SKonstantin Belousov 	if (ov == -1)
5654f3dc900SKonstantin Belousov 		return (-1);
5664f3dc900SKonstantin Belousov 	*oldvalp = ov;
5674f3dc900SKonstantin Belousov 	return (0);
5684f3dc900SKonstantin Belousov }
5694f3dc900SKonstantin Belousov #else /* NO_FUEWORD */
5704f3dc900SKonstantin Belousov int32_t
5712361c6d1SKonstantin Belousov fuword32(volatile const void *addr)
5724f3dc900SKonstantin Belousov {
5734f3dc900SKonstantin Belousov 	int rv;
5744f3dc900SKonstantin Belousov 	int32_t val;
5754f3dc900SKonstantin Belousov 
5764f3dc900SKonstantin Belousov 	rv = fueword32(addr, &val);
5774f3dc900SKonstantin Belousov 	return (rv == -1 ? -1 : val);
5784f3dc900SKonstantin Belousov }
5794f3dc900SKonstantin Belousov 
5804f3dc900SKonstantin Belousov #ifdef _LP64
5814f3dc900SKonstantin Belousov int64_t
5822361c6d1SKonstantin Belousov fuword64(volatile const void *addr)
5834f3dc900SKonstantin Belousov {
5844f3dc900SKonstantin Belousov 	int rv;
5854f3dc900SKonstantin Belousov 	int64_t val;
5864f3dc900SKonstantin Belousov 
5874f3dc900SKonstantin Belousov 	rv = fueword64(addr, &val);
5884f3dc900SKonstantin Belousov 	return (rv == -1 ? -1 : val);
5894f3dc900SKonstantin Belousov }
5904f3dc900SKonstantin Belousov #endif /* _LP64 */
5914f3dc900SKonstantin Belousov 
5924f3dc900SKonstantin Belousov long
5932361c6d1SKonstantin Belousov fuword(volatile const void *addr)
5944f3dc900SKonstantin Belousov {
5954f3dc900SKonstantin Belousov 	long val;
5964f3dc900SKonstantin Belousov 	int rv;
5974f3dc900SKonstantin Belousov 
5984f3dc900SKonstantin Belousov 	rv = fueword(addr, &val);
5994f3dc900SKonstantin Belousov 	return (rv == -1 ? -1 : val);
6004f3dc900SKonstantin Belousov }
6014f3dc900SKonstantin Belousov 
6024f3dc900SKonstantin Belousov uint32_t
6034f3dc900SKonstantin Belousov casuword32(volatile uint32_t *addr, uint32_t old, uint32_t new)
6044f3dc900SKonstantin Belousov {
6054f3dc900SKonstantin Belousov 	int rv;
6064f3dc900SKonstantin Belousov 	uint32_t val;
6074f3dc900SKonstantin Belousov 
6084f3dc900SKonstantin Belousov 	rv = casueword32(addr, old, &val, new);
6094f3dc900SKonstantin Belousov 	return (rv == -1 ? -1 : val);
6104f3dc900SKonstantin Belousov }
6114f3dc900SKonstantin Belousov 
6124f3dc900SKonstantin Belousov u_long
6134f3dc900SKonstantin Belousov casuword(volatile u_long *addr, u_long old, u_long new)
6144f3dc900SKonstantin Belousov {
6154f3dc900SKonstantin Belousov 	int rv;
6164f3dc900SKonstantin Belousov 	u_long val;
6174f3dc900SKonstantin Belousov 
6184f3dc900SKonstantin Belousov 	rv = casueword(addr, old, &val, new);
6194f3dc900SKonstantin Belousov 	return (rv == -1 ? -1 : val);
6204f3dc900SKonstantin Belousov }
6214f3dc900SKonstantin Belousov 
6224f3dc900SKonstantin Belousov #endif /* NO_FUEWORD */
623