]>
git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_subr.c
2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
30 * Copyright (c) 1982, 1986, 1991, 1993
31 * The Regents of the University of California. All rights reserved.
32 * (c) UNIX System Laboratories, Inc.
33 * All or some portions of this file are derived from material licensed
34 * to the University of California by American Telephone and Telegraph
35 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
36 * the permission of UNIX System Laboratories, Inc.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 * must display the following acknowledgement:
48 * This product includes software developed by the University of
49 * California, Berkeley and its contributors.
50 * 4. Neither the name of the University nor the names of its contributors
51 * may be used to endorse or promote products derived from this software
52 * without specific prior written permission.
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66 * @(#)kern_subr.c 8.3 (Berkeley) 1/21/94
69 #include <sys/param.h>
70 #include <sys/systm.h>
71 #include <sys/proc_internal.h>
72 #include <sys/malloc.h>
73 #include <sys/queue.h>
75 #include <sys/uio_internal.h>
76 #include <kern/kalloc.h>
80 #include <sys/kdebug.h>
81 #define DBG_UIO_COPYOUT 16
82 #define DBG_UIO_COPYIN 17
85 #include <kern/simple_lock.h>
87 static uint32_t uio_t_count
= 0;
90 #define IS_VALID_UIO_SEGFLG(segflg) \
91 ( (segflg) == UIO_USERSPACE || \
92 (segflg) == UIO_SYSSPACE || \
93 (segflg) == UIO_USERSPACE32 || \
94 (segflg) == UIO_USERSPACE64 || \
95 (segflg) == UIO_SYSSPACE32 || \
96 (segflg) == UIO_USERISPACE || \
97 (segflg) == UIO_PHYS_USERSPACE || \
98 (segflg) == UIO_PHYS_SYSSPACE || \
99 (segflg) == UIO_USERISPACE32 || \
100 (segflg) == UIO_PHYS_USERSPACE32 || \
101 (segflg) == UIO_USERISPACE64 || \
102 (segflg) == UIO_PHYS_USERSPACE64 )
108 * Notes: The first argument should be a caddr_t, but const poisoning
109 * for typedef'ed types doesn't work in gcc.
112 uiomove(const char * cp
, int n
, uio_t uio
)
114 return uiomove64((const addr64_t
)(uintptr_t)cp
, n
, uio
);
126 uiomove64(const addr64_t c_cp
, int n
, struct uio
*uio
)
133 if (uio
->uio_rw
!= UIO_READ
&& uio
->uio_rw
!= UIO_WRITE
)
134 panic("uiomove: mode");
138 if (IS_VALID_UIO_SEGFLG(uio
->uio_segflg
) == 0) {
139 panic("%s :%d - invalid uio_segflg\n", __FILE__
, __LINE__
);
141 #endif /* LP64_DEBUG */
143 while (n
> 0 && uio_resid(uio
)) {
145 acnt
= uio_curriovlen(uio
);
149 if (n
> 0 && acnt
> (uint64_t)n
)
152 switch ((int) uio
->uio_segflg
) {
154 case UIO_USERSPACE64
:
155 case UIO_USERISPACE64
:
156 case UIO_USERSPACE32
:
157 case UIO_USERISPACE32
:
160 // LP64 - 3rd argument in debug code is 64 bit, expected to be 32 bit
161 if (uio
->uio_rw
== UIO_READ
)
163 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYOUT
)) | DBG_FUNC_START
,
164 (int)cp
, (uintptr_t)uio
->uio_iovs
.uiovp
->iov_base
, acnt
, 0,0);
166 error
= copyout( CAST_DOWN(caddr_t
, cp
), uio
->uio_iovs
.uiovp
->iov_base
, acnt
);
168 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYOUT
)) | DBG_FUNC_END
,
169 (int)cp
, (uintptr_t)uio
->uio_iovs
.uiovp
->iov_base
, acnt
, 0,0);
173 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYIN
)) | DBG_FUNC_START
,
174 (uintptr_t)uio
->uio_iovs
.uiovp
->iov_base
, (int)cp
, acnt
, 0,0);
176 error
= copyin(uio
->uio_iovs
.uiovp
->iov_base
, CAST_DOWN(caddr_t
, cp
), acnt
);
178 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYIN
)) | DBG_FUNC_END
,
179 (uintptr_t)uio
->uio_iovs
.uiovp
->iov_base
, (int)cp
, acnt
, 0,0);
187 if (uio
->uio_rw
== UIO_READ
)
188 error
= copywithin(CAST_DOWN(caddr_t
, cp
), CAST_DOWN(caddr_t
, uio
->uio_iovs
.kiovp
->iov_base
),
191 error
= copywithin(CAST_DOWN(caddr_t
, uio
->uio_iovs
.kiovp
->iov_base
), CAST_DOWN(caddr_t
, cp
),
195 case UIO_PHYS_USERSPACE64
:
196 case UIO_PHYS_USERSPACE32
:
197 case UIO_PHYS_USERSPACE
:
198 if (uio
->uio_rw
== UIO_READ
)
200 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYOUT
)) | DBG_FUNC_START
,
201 (int)cp
, (uintptr_t)uio
->uio_iovs
.uiovp
->iov_base
, acnt
, 1,0);
203 error
= copypv((addr64_t
)cp
, uio
->uio_iovs
.uiovp
->iov_base
, acnt
, cppvPsrc
| cppvNoRefSrc
);
204 if (error
) /* Copy physical to virtual */
207 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYOUT
)) | DBG_FUNC_END
,
208 (int)cp
, (uintptr_t)uio
->uio_iovs
.uiovp
->iov_base
, acnt
, 1,0);
212 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYIN
)) | DBG_FUNC_START
,
213 (uintptr_t)uio
->uio_iovs
.uiovp
->iov_base
, (int)cp
, acnt
, 1,0);
215 error
= copypv(uio
->uio_iovs
.uiovp
->iov_base
, (addr64_t
)cp
, acnt
, cppvPsnk
| cppvNoRefSrc
| cppvNoModSnk
);
216 if (error
) /* Copy virtual to physical */
219 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYIN
)) | DBG_FUNC_END
,
220 (uintptr_t)uio
->uio_iovs
.uiovp
->iov_base
, (int)cp
, acnt
, 1,0);
226 case UIO_PHYS_SYSSPACE
:
227 if (uio
->uio_rw
== UIO_READ
)
229 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYOUT
)) | DBG_FUNC_START
,
230 (int)cp
, (uintptr_t)uio
->uio_iovs
.kiovp
->iov_base
, acnt
, 2,0);
232 error
= copypv((addr64_t
)cp
, uio
->uio_iovs
.kiovp
->iov_base
, acnt
, cppvKmap
| cppvPsrc
| cppvNoRefSrc
);
233 if (error
) /* Copy physical to virtual */
236 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYOUT
)) | DBG_FUNC_END
,
237 (int)cp
, (uintptr_t)uio
->uio_iovs
.kiovp
->iov_base
, acnt
, 2,0);
241 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYIN
)) | DBG_FUNC_START
,
242 (uintptr_t)uio
->uio_iovs
.kiovp
->iov_base
, (int)cp
, acnt
, 2,0);
244 error
= copypv(uio
->uio_iovs
.kiovp
->iov_base
, (addr64_t
)cp
, acnt
, cppvKmap
| cppvPsnk
| cppvNoRefSrc
| cppvNoModSnk
);
245 if (error
) /* Copy virtual to physical */
248 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYIN
)) | DBG_FUNC_END
,
249 (uintptr_t)uio
->uio_iovs
.kiovp
->iov_base
, (int)cp
, acnt
, 2,0);
258 uio_update(uio
, acnt
);
266 * Give next character to user as result of read.
269 ureadc(int c
, struct uio
*uio
)
271 if (uio_resid(uio
) <= 0)
272 panic("ureadc: non-positive resid");
274 if (uio
->uio_iovcnt
== 0)
275 panic("ureadc: non-positive iovcnt");
276 if (uio_curriovlen(uio
) <= 0)
277 panic("ureadc: non-positive iovlen");
279 switch ((int) uio
->uio_segflg
) {
281 case UIO_USERSPACE32
:
283 case UIO_USERISPACE32
:
285 case UIO_USERSPACE64
:
286 case UIO_USERISPACE64
:
287 if (subyte((user_addr_t
)uio
->uio_iovs
.uiovp
->iov_base
, c
) < 0)
293 *(CAST_DOWN(caddr_t
, uio
->uio_iovs
.kiovp
->iov_base
)) = c
;
304 * General routine to allocate a hash table.
307 hashinit(int elements
, int type
, u_long
*hashmask
)
310 LIST_HEAD(generic
, generic
) *hashtbl
;
314 panic("hashinit: bad cnt");
315 for (hashsize
= 1; hashsize
<= elements
; hashsize
<<= 1)
318 MALLOC(hashtbl
, struct generic
*,
319 hashsize
* sizeof(*hashtbl
), type
, M_WAITOK
|M_ZERO
);
320 if (hashtbl
!= NULL
) {
321 for (i
= 0; i
< hashsize
; i
++)
322 LIST_INIT(&hashtbl
[i
]);
323 *hashmask
= hashsize
- 1;
329 * uio_resid - return the residual IO value for the given uio_t
331 user_ssize_t
uio_resid( uio_t a_uio
)
335 printf("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
337 /* if (IS_VALID_UIO_SEGFLG(a_uio->uio_segflg) == 0) { */
338 /* panic("%s :%d - invalid uio_segflg\n", __FILE__, __LINE__); */
342 /* return 0 if there are no active iovecs */
347 return( a_uio
->uio_resid_64
);
351 * uio_setresid - set the residual IO value for the given uio_t
353 void uio_setresid( uio_t a_uio
, user_ssize_t a_value
)
357 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
359 /* if (IS_VALID_UIO_SEGFLG(a_uio->uio_segflg) == 0) { */
360 /* panic("%s :%d - invalid uio_segflg\n", __FILE__, __LINE__); */
368 a_uio
->uio_resid_64
= a_value
;
373 * uio_curriovbase - return the base address of the current iovec associated
374 * with the given uio_t. May return 0.
376 user_addr_t
uio_curriovbase( uio_t a_uio
)
380 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
382 #endif /* LP64_DEBUG */
384 if (a_uio
== NULL
|| a_uio
->uio_iovcnt
< 1) {
388 if (UIO_IS_USER_SPACE(a_uio
)) {
389 return(a_uio
->uio_iovs
.uiovp
->iov_base
);
391 return((user_addr_t
)a_uio
->uio_iovs
.kiovp
->iov_base
);
396 * uio_curriovlen - return the length value of the current iovec associated
397 * with the given uio_t.
399 user_size_t
uio_curriovlen( uio_t a_uio
)
403 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
405 #endif /* LP64_DEBUG */
407 if (a_uio
== NULL
|| a_uio
->uio_iovcnt
< 1) {
411 if (UIO_IS_USER_SPACE(a_uio
)) {
412 return(a_uio
->uio_iovs
.uiovp
->iov_len
);
414 return((user_size_t
)a_uio
->uio_iovs
.kiovp
->iov_len
);
418 * uio_setcurriovlen - set the length value of the current iovec associated
419 * with the given uio_t.
421 __private_extern__
void uio_setcurriovlen( uio_t a_uio
, user_size_t a_value
)
425 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
427 #endif /* LP64_DEBUG */
433 if (UIO_IS_USER_SPACE(a_uio
)) {
434 a_uio
->uio_iovs
.uiovp
->iov_len
= a_value
;
438 if (a_value
> 0xFFFFFFFFull
) {
439 panic("%s :%d - invalid a_value\n", __FILE__
, __LINE__
);
441 #endif /* LP64_DEBUG */
442 a_uio
->uio_iovs
.kiovp
->iov_len
= (size_t)a_value
;
448 * uio_iovcnt - return count of active iovecs for the given uio_t
450 int uio_iovcnt( uio_t a_uio
)
454 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
456 #endif /* LP64_DEBUG */
462 return( a_uio
->uio_iovcnt
);
466 * uio_offset - return the current offset value for the given uio_t
468 off_t
uio_offset( uio_t a_uio
)
472 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
474 #endif /* LP64_DEBUG */
479 return( a_uio
->uio_offset
);
483 * uio_setoffset - set the current offset value for the given uio_t
485 void uio_setoffset( uio_t a_uio
, off_t a_offset
)
489 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
491 #endif /* LP64_DEBUG */
496 a_uio
->uio_offset
= a_offset
;
501 * uio_rw - return the read / write flag for the given uio_t
503 int uio_rw( uio_t a_uio
)
507 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
509 #endif /* LP64_DEBUG */
514 return( a_uio
->uio_rw
);
518 * uio_setrw - set the read / write flag for the given uio_t
520 void uio_setrw( uio_t a_uio
, int a_value
)
524 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
525 #endif /* LP64_DEBUG */
530 if (!(a_value
== UIO_READ
|| a_value
== UIO_WRITE
)) {
531 panic("%s :%d - invalid a_value\n", __FILE__
, __LINE__
);
533 #endif /* LP64_DEBUG */
535 if (a_value
== UIO_READ
|| a_value
== UIO_WRITE
) {
536 a_uio
->uio_rw
= a_value
;
542 * uio_isuserspace - return non zero value if the address space
543 * flag is for a user address space (could be 32 or 64 bit).
545 int uio_isuserspace( uio_t a_uio
)
549 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
550 #endif /* LP64_DEBUG */
554 if (UIO_SEG_IS_USER_SPACE(a_uio
->uio_segflg
)) {
562 * uio_create - create an uio_t.
563 * Space is allocated to hold up to a_iovcount number of iovecs. The uio_t
564 * is not fully initialized until all iovecs are added using uio_addiov calls.
565 * a_iovcount is the maximum number of iovecs you may add.
567 uio_t
uio_create( int a_iovcount
, /* number of iovecs */
568 off_t a_offset
, /* current offset */
569 int a_spacetype
, /* type of address space */
570 int a_iodirection
) /* read or write flag */
576 my_size
= UIO_SIZEOF(a_iovcount
);
577 my_buf_p
= kalloc(my_size
);
578 my_uio
= uio_createwithbuffer( a_iovcount
,
585 /* leave a note that we allocated this uio_t */
586 my_uio
->uio_flags
|= UIO_FLAGS_WE_ALLOCED
;
588 (void)hw_atomic_add(&uio_t_count
, 1);
597 * uio_createwithbuffer - create an uio_t.
598 * Create a uio_t using the given buffer. The uio_t
599 * is not fully initialized until all iovecs are added using uio_addiov calls.
600 * a_iovcount is the maximum number of iovecs you may add.
601 * This call may fail if the given buffer is not large enough.
603 __private_extern__ uio_t
604 uio_createwithbuffer( int a_iovcount
, /* number of iovecs */
605 off_t a_offset
, /* current offset */
606 int a_spacetype
, /* type of address space */
607 int a_iodirection
, /* read or write flag */
608 void *a_buf_p
, /* pointer to a uio_t buffer */
609 size_t a_buffer_size
) /* size of uio_t buffer */
611 uio_t my_uio
= (uio_t
) a_buf_p
;
614 my_size
= UIO_SIZEOF(a_iovcount
);
615 if (a_buffer_size
< my_size
) {
617 panic("%s :%d - a_buffer_size is too small\n", __FILE__
, __LINE__
);
621 my_size
= a_buffer_size
;
625 panic("%s :%d - could not allocate uio_t\n", __FILE__
, __LINE__
);
627 if (!IS_VALID_UIO_SEGFLG(a_spacetype
)) {
628 panic("%s :%d - invalid address space type\n", __FILE__
, __LINE__
);
630 if (!(a_iodirection
== UIO_READ
|| a_iodirection
== UIO_WRITE
)) {
631 panic("%s :%d - invalid IO direction flag\n", __FILE__
, __LINE__
);
633 if (a_iovcount
> UIO_MAXIOV
) {
634 panic("%s :%d - invalid a_iovcount\n", __FILE__
, __LINE__
);
638 bzero(my_uio
, my_size
);
639 my_uio
->uio_size
= my_size
;
642 * we use uio_segflg to indicate if the uio_t is the new format or
643 * old (pre LP64 support) legacy format
644 * This switch statement should canonicalize incoming space type
645 * to one of UIO_USERSPACE32/64, UIO_PHYS_USERSPACE32/64, or
646 * UIO_SYSSPACE/UIO_PHYS_SYSSPACE
648 switch (a_spacetype
) {
650 my_uio
->uio_segflg
= UIO_USERSPACE32
;
653 my_uio
->uio_segflg
= UIO_SYSSPACE
;
655 case UIO_PHYS_USERSPACE
:
656 my_uio
->uio_segflg
= UIO_PHYS_USERSPACE32
;
659 my_uio
->uio_segflg
= a_spacetype
;
663 if (a_iovcount
> 0) {
664 my_uio
->uio_iovs
.uiovp
= (struct user_iovec
*)
665 (((uint8_t *)my_uio
) + sizeof(struct uio
));
668 my_uio
->uio_iovs
.uiovp
= NULL
;
671 my_uio
->uio_max_iovs
= a_iovcount
;
672 my_uio
->uio_offset
= a_offset
;
673 my_uio
->uio_rw
= a_iodirection
;
674 my_uio
->uio_flags
= UIO_FLAGS_INITED
;
680 * uio_spacetype - return the address space type for the given uio_t
682 __private_extern__
int uio_spacetype( uio_t a_uio
)
686 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
687 #endif /* LP64_DEBUG */
691 return( a_uio
->uio_segflg
);
695 * uio_iovsaddr - get the address of the iovec array for the given uio_t.
696 * This returns the location of the iovecs within the uio.
697 * NOTE - for compatibility mode we just return the current value in uio_iovs
698 * which will increase as the IO is completed and is NOT embedded within the
699 * uio, it is a seperate array of one or more iovecs.
701 __private_extern__
struct user_iovec
* uio_iovsaddr( uio_t a_uio
)
703 struct user_iovec
* my_addr
;
709 if (UIO_SEG_IS_USER_SPACE(a_uio
->uio_segflg
)) {
710 /* we need this for compatibility mode. */
711 my_addr
= (struct user_iovec
*) a_uio
->uio_iovs
.uiovp
;
715 panic("uio_iovsaddr called for UIO_SYSSPACE request");
723 * uio_reset - reset an uio_t.
724 * Reset the given uio_t to initial values. The uio_t is not fully initialized
725 * until all iovecs are added using uio_addiov calls.
726 * The a_iovcount value passed in the uio_create is the maximum number of
727 * iovecs you may add.
729 void uio_reset( uio_t a_uio
,
730 off_t a_offset
, /* current offset */
731 int a_spacetype
, /* type of address space */
732 int a_iodirection
) /* read or write flag */
736 u_int32_t my_old_flags
;
740 panic("%s :%d - could not allocate uio_t\n", __FILE__
, __LINE__
);
742 if (!IS_VALID_UIO_SEGFLG(a_spacetype
)) {
743 panic("%s :%d - invalid address space type\n", __FILE__
, __LINE__
);
745 if (!(a_iodirection
== UIO_READ
|| a_iodirection
== UIO_WRITE
)) {
746 panic("%s :%d - invalid IO direction flag\n", __FILE__
, __LINE__
);
748 #endif /* LP64_DEBUG */
754 my_size
= a_uio
->uio_size
;
755 my_old_flags
= a_uio
->uio_flags
;
756 my_max_iovs
= a_uio
->uio_max_iovs
;
757 bzero(a_uio
, my_size
);
758 a_uio
->uio_size
= my_size
;
761 * we use uio_segflg to indicate if the uio_t is the new format or
762 * old (pre LP64 support) legacy format
763 * This switch statement should canonicalize incoming space type
764 * to one of UIO_USERSPACE32/64, UIO_PHYS_USERSPACE32/64, or
765 * UIO_SYSSPACE/UIO_PHYS_SYSSPACE
767 switch (a_spacetype
) {
769 a_uio
->uio_segflg
= UIO_USERSPACE32
;
772 a_uio
->uio_segflg
= UIO_SYSSPACE
;
774 case UIO_PHYS_USERSPACE
:
775 a_uio
->uio_segflg
= UIO_PHYS_USERSPACE32
;
778 a_uio
->uio_segflg
= a_spacetype
;
782 if (my_max_iovs
> 0) {
783 a_uio
->uio_iovs
.uiovp
= (struct user_iovec
*)
784 (((uint8_t *)a_uio
) + sizeof(struct uio
));
787 a_uio
->uio_iovs
.uiovp
= NULL
;
790 a_uio
->uio_max_iovs
= my_max_iovs
;
791 a_uio
->uio_offset
= a_offset
;
792 a_uio
->uio_rw
= a_iodirection
;
793 a_uio
->uio_flags
= my_old_flags
;
799 * uio_free - free a uio_t allocated via uio_init. this also frees all
802 void uio_free( uio_t a_uio
)
806 panic("%s :%d - passing NULL uio_t\n", __FILE__
, __LINE__
);
808 #endif /* LP64_DEBUG */
810 if (a_uio
!= NULL
&& (a_uio
->uio_flags
& UIO_FLAGS_WE_ALLOCED
) != 0) {
812 if (hw_atomic_sub(&uio_t_count
, 1) == UINT_MAX
)
813 panic("%s :%d - uio_t_count underflow\n", __FILE__
, __LINE__
);
815 kfree(a_uio
, a_uio
->uio_size
);
822 * uio_addiov - add an iovec to the given uio_t. You may call this up to
823 * the a_iovcount number that was passed to uio_create. This call will
824 * increment the residual IO count as iovecs are added to the uio_t.
825 * returns 0 if add was successful else non zero.
827 int uio_addiov( uio_t a_uio
, user_addr_t a_baseaddr
, user_size_t a_length
)
833 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
834 #endif /* LP64_DEBUG */
838 if (UIO_IS_USER_SPACE(a_uio
)) {
839 for ( i
= 0; i
< a_uio
->uio_max_iovs
; i
++ ) {
840 if (a_uio
->uio_iovs
.uiovp
[i
].iov_len
== 0 && a_uio
->uio_iovs
.uiovp
[i
].iov_base
== 0) {
841 a_uio
->uio_iovs
.uiovp
[i
].iov_len
= a_length
;
842 a_uio
->uio_iovs
.uiovp
[i
].iov_base
= a_baseaddr
;
844 a_uio
->uio_resid_64
+= a_length
;
850 for ( i
= 0; i
< a_uio
->uio_max_iovs
; i
++ ) {
851 if (a_uio
->uio_iovs
.kiovp
[i
].iov_len
== 0 && a_uio
->uio_iovs
.kiovp
[i
].iov_base
== 0) {
852 a_uio
->uio_iovs
.kiovp
[i
].iov_len
= (u_int64_t
)a_length
;
853 a_uio
->uio_iovs
.kiovp
[i
].iov_base
= (u_int64_t
)a_baseaddr
;
855 a_uio
->uio_resid_64
+= a_length
;
865 * uio_getiov - get iovec data associated with the given uio_t. Use
866 * a_index to iterate over each iovec (0 to (uio_iovcnt(uio_t) - 1)).
867 * a_baseaddr_p and a_length_p may be NULL.
868 * returns -1 when a_index is >= uio_t.uio_iovcnt or invalid uio_t.
869 * returns 0 when data is returned.
871 int uio_getiov( uio_t a_uio
,
873 user_addr_t
* a_baseaddr_p
,
874 user_size_t
* a_length_p
)
878 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
882 if ( a_index
< 0 || a_index
>= a_uio
->uio_iovcnt
) {
886 if (UIO_IS_USER_SPACE(a_uio
)) {
887 if (a_baseaddr_p
!= NULL
) {
888 *a_baseaddr_p
= a_uio
->uio_iovs
.uiovp
[a_index
].iov_base
;
890 if (a_length_p
!= NULL
) {
891 *a_length_p
= a_uio
->uio_iovs
.uiovp
[a_index
].iov_len
;
895 if (a_baseaddr_p
!= NULL
) {
896 *a_baseaddr_p
= a_uio
->uio_iovs
.kiovp
[a_index
].iov_base
;
898 if (a_length_p
!= NULL
) {
899 *a_length_p
= a_uio
->uio_iovs
.kiovp
[a_index
].iov_len
;
907 * uio_calculateresid - runs through all iovecs associated with this
908 * uio_t and calculates (and sets) the residual IO count.
910 __private_extern__
int uio_calculateresid( uio_t a_uio
)
917 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
918 #endif /* LP64_DEBUG */
922 a_uio
->uio_iovcnt
= a_uio
->uio_max_iovs
;
923 if (UIO_IS_USER_SPACE(a_uio
)) {
924 a_uio
->uio_resid_64
= 0;
925 for ( i
= 0; i
< a_uio
->uio_max_iovs
; i
++ ) {
926 if (a_uio
->uio_iovs
.uiovp
[i
].iov_len
!= 0 && a_uio
->uio_iovs
.uiovp
[i
].iov_base
!= 0) {
927 if (a_uio
->uio_iovs
.uiovp
[i
].iov_len
> LONG_MAX
)
929 resid
+= a_uio
->uio_iovs
.uiovp
[i
].iov_len
;
930 if (resid
> LONG_MAX
)
934 a_uio
->uio_resid_64
= resid
;
936 /* position to first non zero length iovec (4235922) */
937 while (a_uio
->uio_iovcnt
> 0 && a_uio
->uio_iovs
.uiovp
->iov_len
== 0) {
939 if (a_uio
->uio_iovcnt
> 0) {
940 a_uio
->uio_iovs
.uiovp
++;
945 a_uio
->uio_resid_64
= 0;
946 for ( i
= 0; i
< a_uio
->uio_max_iovs
; i
++ ) {
947 if (a_uio
->uio_iovs
.kiovp
[i
].iov_len
!= 0 && a_uio
->uio_iovs
.kiovp
[i
].iov_base
!= 0) {
948 if (a_uio
->uio_iovs
.kiovp
[i
].iov_len
> LONG_MAX
)
950 resid
+= a_uio
->uio_iovs
.kiovp
[i
].iov_len
;
951 if (resid
> LONG_MAX
)
955 a_uio
->uio_resid_64
= resid
;
957 /* position to first non zero length iovec (4235922) */
958 while (a_uio
->uio_iovcnt
> 0 && a_uio
->uio_iovs
.kiovp
->iov_len
== 0) {
960 if (a_uio
->uio_iovcnt
> 0) {
961 a_uio
->uio_iovs
.kiovp
++;
970 * uio_update - update the given uio_t for a_count of completed IO.
971 * This call decrements the current iovec length and residual IO value
972 * and increments the current iovec base address and offset value.
973 * If the current iovec length is 0 then advance to the next
975 * If the a_count passed in is 0, than only do the advancement
976 * over any 0 length iovec's.
978 void uio_update( uio_t a_uio
, user_size_t a_count
)
982 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
984 if (UIO_IS_32_BIT_SPACE(a_uio
) && a_count
> 0xFFFFFFFFull
) {
985 panic("%s :%d - invalid count value \n", __FILE__
, __LINE__
);
987 #endif /* LP64_DEBUG */
989 if (a_uio
== NULL
|| a_uio
->uio_iovcnt
< 1) {
993 if (UIO_IS_USER_SPACE(a_uio
)) {
995 * if a_count == 0, then we are asking to skip over
999 if (a_count
> a_uio
->uio_iovs
.uiovp
->iov_len
) {
1000 a_uio
->uio_iovs
.uiovp
->iov_base
+= a_uio
->uio_iovs
.uiovp
->iov_len
;
1001 a_uio
->uio_iovs
.uiovp
->iov_len
= 0;
1004 a_uio
->uio_iovs
.uiovp
->iov_base
+= a_count
;
1005 a_uio
->uio_iovs
.uiovp
->iov_len
-= a_count
;
1007 if (a_count
> (user_size_t
)a_uio
->uio_resid_64
) {
1008 a_uio
->uio_offset
+= a_uio
->uio_resid_64
;
1009 a_uio
->uio_resid_64
= 0;
1012 a_uio
->uio_offset
+= a_count
;
1013 a_uio
->uio_resid_64
-= a_count
;
1017 * advance to next iovec if current one is totally consumed
1019 while (a_uio
->uio_iovcnt
> 0 && a_uio
->uio_iovs
.uiovp
->iov_len
== 0) {
1020 a_uio
->uio_iovcnt
--;
1021 if (a_uio
->uio_iovcnt
> 0) {
1022 a_uio
->uio_iovs
.uiovp
++;
1028 * if a_count == 0, then we are asking to skip over
1032 if (a_count
> a_uio
->uio_iovs
.kiovp
->iov_len
) {
1033 a_uio
->uio_iovs
.kiovp
->iov_base
+= a_uio
->uio_iovs
.kiovp
->iov_len
;
1034 a_uio
->uio_iovs
.kiovp
->iov_len
= 0;
1037 a_uio
->uio_iovs
.kiovp
->iov_base
+= a_count
;
1038 a_uio
->uio_iovs
.kiovp
->iov_len
-= a_count
;
1040 if (a_count
> (user_size_t
)a_uio
->uio_resid_64
) {
1041 a_uio
->uio_offset
+= a_uio
->uio_resid_64
;
1042 a_uio
->uio_resid_64
= 0;
1045 a_uio
->uio_offset
+= a_count
;
1046 a_uio
->uio_resid_64
-= a_count
;
1050 * advance to next iovec if current one is totally consumed
1052 while (a_uio
->uio_iovcnt
> 0 && a_uio
->uio_iovs
.kiovp
->iov_len
== 0) {
1053 a_uio
->uio_iovcnt
--;
1054 if (a_uio
->uio_iovcnt
> 0) {
1055 a_uio
->uio_iovs
.kiovp
++;
1063 * uio_pushback - undo uncommitted I/O by subtracting from the
1064 * current base address and offset, and incrementing the residiual
1065 * IO. If the UIO was previously exhausted, this call will panic.
1066 * New code should not use this functionality.
1068 __private_extern__
void uio_pushback( uio_t a_uio
, user_size_t a_count
)
1071 if (a_uio
== NULL
) {
1072 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
1074 if (UIO_IS_32_BIT_SPACE(a_uio
) && a_count
> 0xFFFFFFFFull
) {
1075 panic("%s :%d - invalid count value \n", __FILE__
, __LINE__
);
1077 #endif /* LP64_DEBUG */
1079 if (a_uio
== NULL
|| a_count
== 0) {
1083 if (a_uio
->uio_iovcnt
< 1) {
1084 panic("Invalid uio for pushback");
1087 if (UIO_IS_USER_SPACE(a_uio
)) {
1088 a_uio
->uio_iovs
.uiovp
->iov_base
-= a_count
;
1089 a_uio
->uio_iovs
.uiovp
->iov_len
+= a_count
;
1092 a_uio
->uio_iovs
.kiovp
->iov_base
-= a_count
;
1093 a_uio
->uio_iovs
.kiovp
->iov_len
+= a_count
;
1096 a_uio
->uio_offset
-= a_count
;
1097 a_uio
->uio_resid_64
+= a_count
;
1104 * uio_duplicate - allocate a new uio and make a copy of the given uio_t.
1107 uio_t
uio_duplicate( uio_t a_uio
)
1112 if (a_uio
== NULL
) {
1116 my_uio
= (uio_t
) kalloc(a_uio
->uio_size
);
1118 panic("%s :%d - allocation failed\n", __FILE__
, __LINE__
);
1121 bcopy((void *)a_uio
, (void *)my_uio
, a_uio
->uio_size
);
1122 /* need to set our iovec pointer to point to first active iovec */
1123 if (my_uio
->uio_max_iovs
> 0) {
1124 my_uio
->uio_iovs
.uiovp
= (struct user_iovec
*)
1125 (((uint8_t *)my_uio
) + sizeof(struct uio
));
1127 /* advance to first nonzero iovec */
1128 if (my_uio
->uio_iovcnt
> 0) {
1129 for ( i
= 0; i
< my_uio
->uio_max_iovs
; i
++ ) {
1130 if (UIO_IS_USER_SPACE(a_uio
)) {
1131 if (my_uio
->uio_iovs
.uiovp
->iov_len
!= 0) {
1134 my_uio
->uio_iovs
.uiovp
++;
1137 if (my_uio
->uio_iovs
.kiovp
->iov_len
!= 0) {
1140 my_uio
->uio_iovs
.kiovp
++;
1146 my_uio
->uio_flags
= UIO_FLAGS_WE_ALLOCED
| UIO_FLAGS_INITED
;
1148 (void)hw_atomic_add(&uio_t_count
, 1);
1155 int copyin_user_iovec_array(user_addr_t uaddr
, int spacetype
, int count
, struct user_iovec
*dst
)
1157 size_t size_of_iovec
= ( spacetype
== UIO_USERSPACE64
? sizeof(struct user64_iovec
) : sizeof(struct user32_iovec
));
1161 // copyin to the front of "dst", without regard for putting records in the right places
1162 error
= copyin(uaddr
, dst
, count
* size_of_iovec
);
1166 // now, unpack the entries in reverse order, so we don't overwrite anything
1167 for (i
= count
- 1; i
>= 0; i
--) {
1168 if (spacetype
== UIO_USERSPACE64
) {
1169 struct user64_iovec iovec
= ((struct user64_iovec
*)dst
)[i
];
1170 dst
[i
].iov_base
= iovec
.iov_base
;
1171 dst
[i
].iov_len
= iovec
.iov_len
;
1173 struct user32_iovec iovec
= ((struct user32_iovec
*)dst
)[i
];
1174 dst
[i
].iov_base
= iovec
.iov_base
;
1175 dst
[i
].iov_len
= iovec
.iov_len
;