]>
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;
95 * Notes: The first argument should be a caddr_t, but const poisoning
96 * for typedef'ed types doesn't work in gcc.
99 uiomove(const char * cp
, int n
, uio_t uio
)
101 return uiomove64((const addr64_t
)((const unsigned int)cp
), n
, uio
);
112 // LP64todo - fix this! 'n' should be int64_t?
114 uiomove64(const addr64_t c_cp
, int n
, struct uio
*uio
)
125 if (uio
->uio_rw
!= UIO_READ
&& uio
->uio_rw
!= UIO_WRITE
)
126 panic("uiomove: mode");
130 if (IS_VALID_UIO_SEGFLG(uio
->uio_segflg
) == 0) {
131 panic("%s :%d - invalid uio_segflg\n", __FILE__
, __LINE__
);
133 #endif /* LP64_DEBUG */
135 while (n
> 0 && uio_resid(uio
)) {
136 acnt
= uio_iov_len(uio
);
142 if (n
> 0 && acnt
> (uint64_t)n
)
145 switch (uio
->uio_segflg
) {
147 case UIO_USERSPACE64
:
148 case UIO_USERISPACE64
:
149 // LP64 - 3rd argument in debug code is 64 bit, expected to be 32 bit
150 if (uio
->uio_rw
== UIO_READ
)
152 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYOUT
)) | DBG_FUNC_START
,
153 (int)cp
, (int)uio
->uio_iovs
.iov64p
->iov_base
, acnt
, 0,0);
155 error
= copyout( CAST_DOWN(caddr_t
, cp
), uio
->uio_iovs
.iov64p
->iov_base
, acnt
);
157 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYOUT
)) | DBG_FUNC_END
,
158 (int)cp
, (int)uio
->uio_iovs
.iov64p
->iov_base
, acnt
, 0,0);
162 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYIN
)) | DBG_FUNC_START
,
163 (int)uio
->uio_iovs
.iov64p
->iov_base
, (int)cp
, acnt
, 0,0);
165 error
= copyin(uio
->uio_iovs
.iov64p
->iov_base
, CAST_DOWN(caddr_t
, cp
), acnt
);
167 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYIN
)) | DBG_FUNC_END
,
168 (int)uio
->uio_iovs
.iov64p
->iov_base
, (int)cp
, acnt
, 0,0);
174 case UIO_USERSPACE32
:
175 case UIO_USERISPACE32
:
178 if (uio
->uio_rw
== UIO_READ
)
180 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYOUT
)) | DBG_FUNC_START
,
181 (int)cp
, (int)uio
->uio_iovs
.iov32p
->iov_base
, acnt
, 0,0);
183 error
= copyout( CAST_DOWN(caddr_t
, cp
), CAST_USER_ADDR_T(uio
->uio_iovs
.iov32p
->iov_base
), acnt
);
185 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYOUT
)) | DBG_FUNC_END
,
186 (int)cp
, (int)uio
->uio_iovs
.iov32p
->iov_base
, acnt
, 0,0);
190 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYIN
)) | DBG_FUNC_START
,
191 (int)uio
->uio_iovs
.iov32p
->iov_base
, (int)cp
, acnt
, 0,0);
193 error
= copyin(CAST_USER_ADDR_T(uio
->uio_iovs
.iov32p
->iov_base
), CAST_DOWN(caddr_t
, cp
), acnt
);
195 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYIN
)) | DBG_FUNC_END
,
196 (int)uio
->uio_iovs
.iov32p
->iov_base
, (int)cp
, acnt
, 0,0);
204 if (uio
->uio_rw
== UIO_READ
)
205 error
= copywithin(CAST_DOWN(caddr_t
, cp
), (caddr_t
)uio
->uio_iovs
.iov32p
->iov_base
,
208 error
= copywithin((caddr_t
)uio
->uio_iovs
.iov32p
->iov_base
, CAST_DOWN(caddr_t
, cp
),
212 case UIO_PHYS_USERSPACE64
:
213 if (uio
->uio_rw
== UIO_READ
)
215 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYOUT
)) | DBG_FUNC_START
,
216 (int)cp
, (int)uio
->uio_iovs
.iov64p
->iov_base
, acnt
, 1,0);
218 error
= copypv((addr64_t
)cp
, uio
->uio_iovs
.iov64p
->iov_base
, acnt
, cppvPsrc
| cppvNoRefSrc
);
219 if (error
) /* Copy physical to virtual */
222 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYOUT
)) | DBG_FUNC_END
,
223 (int)cp
, (int)uio
->uio_iovs
.iov64p
->iov_base
, acnt
, 1,0);
227 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYIN
)) | DBG_FUNC_START
,
228 (int)uio
->uio_iovs
.iov64p
->iov_base
, (int)cp
, acnt
, 1,0);
230 error
= copypv(uio
->uio_iovs
.iov64p
->iov_base
, (addr64_t
)cp
, acnt
, cppvPsnk
| cppvNoRefSrc
| cppvNoModSnk
);
231 if (error
) /* Copy virtual to physical */
234 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYIN
)) | DBG_FUNC_END
,
235 (int)uio
->uio_iovs
.iov64p
->iov_base
, (int)cp
, acnt
, 1,0);
241 case UIO_PHYS_USERSPACE32
:
242 case UIO_PHYS_USERSPACE
:
243 if (uio
->uio_rw
== UIO_READ
)
245 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYOUT
)) | DBG_FUNC_START
,
246 (int)cp
, (int)uio
->uio_iovs
.iov32p
->iov_base
, acnt
, 1,0);
248 error
= copypv((addr64_t
)cp
, (addr64_t
)uio
->uio_iovs
.iov32p
->iov_base
, acnt
, cppvPsrc
| cppvNoRefSrc
);
249 if (error
) /* Copy physical to virtual */
252 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYOUT
)) | DBG_FUNC_END
,
253 (int)cp
, (int)uio
->uio_iovs
.iov32p
->iov_base
, acnt
, 1,0);
257 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYIN
)) | DBG_FUNC_START
,
258 (int)uio
->uio_iovs
.iov32p
->iov_base
, (int)cp
, acnt
, 1,0);
260 error
= copypv((addr64_t
)uio
->uio_iovs
.iov32p
->iov_base
, (addr64_t
)cp
, acnt
, cppvPsnk
| cppvNoRefSrc
| cppvNoModSnk
);
261 if (error
) /* Copy virtual to physical */
264 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYIN
)) | DBG_FUNC_END
,
265 (int)uio
->uio_iovs
.iov32p
->iov_base
, (int)cp
, acnt
, 1,0);
271 case UIO_PHYS_SYSSPACE32
:
272 case UIO_PHYS_SYSSPACE
:
273 if (uio
->uio_rw
== UIO_READ
)
275 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYOUT
)) | DBG_FUNC_START
,
276 (int)cp
, (int)uio
->uio_iovs
.iov32p
->iov_base
, acnt
, 2,0);
278 error
= copypv((addr64_t
)cp
, uio
->uio_iovs
.iov32p
->iov_base
, acnt
, cppvKmap
| cppvPsrc
| cppvNoRefSrc
);
279 if (error
) /* Copy physical to virtual */
282 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYOUT
)) | DBG_FUNC_END
,
283 (int)cp
, (int)uio
->uio_iovs
.iov32p
->iov_base
, acnt
, 2,0);
287 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYIN
)) | DBG_FUNC_START
,
288 (int)uio
->uio_iovs
.iov32p
->iov_base
, (int)cp
, acnt
, 2,0);
290 error
= copypv(uio
->uio_iovs
.iov32p
->iov_base
, (addr64_t
)cp
, acnt
, cppvKmap
| cppvPsnk
| cppvNoRefSrc
| cppvNoModSnk
);
291 if (error
) /* Copy virtual to physical */
294 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, DBG_UIO_COPYIN
)) | DBG_FUNC_END
,
295 (int)uio
->uio_iovs
.iov32p
->iov_base
, (int)cp
, acnt
, 2,0);
304 uio_iov_base_add(uio
, acnt
);
306 uio_iov_len_add(uio
, -((int64_t)acnt
));
307 uio_setresid(uio
, (uio_resid(uio
) - ((int64_t)acnt
)));
309 uio_iov_len_add(uio
, -((int)acnt
));
310 uio_setresid(uio
, (uio_resid(uio
) - ((int)acnt
)));
312 uio
->uio_offset
+= acnt
;
320 * Give next character to user as result of read.
323 ureadc(int c
, struct uio
*uio
)
325 if (uio_resid(uio
) <= 0)
326 panic("ureadc: non-positive resid");
328 if (uio
->uio_iovcnt
== 0)
329 panic("ureadc: non-positive iovcnt");
330 if (uio_iov_len(uio
) <= 0) {
335 switch (uio
->uio_segflg
) {
337 case UIO_USERSPACE32
:
339 if (subyte(CAST_USER_ADDR_T(uio
->uio_iovs
.iov32p
->iov_base
), c
) < 0)
343 case UIO_USERSPACE64
:
344 if (subyte((user_addr_t
)uio
->uio_iovs
.iov64p
->iov_base
, c
) < 0)
350 *((caddr_t
)uio
->uio_iovs
.iov32p
->iov_base
) = c
;
353 case UIO_USERISPACE32
:
355 if (suibyte(CAST_USER_ADDR_T(uio
->uio_iovs
.iov32p
->iov_base
), c
) < 0)
362 uio_iov_base_add(uio
, 1);
363 uio_iov_len_add(uio
, -1);
364 uio_setresid(uio
, (uio_resid(uio
) - 1));
369 #if defined(vax) || defined(ppc)
370 /* unused except by ct.c, other oddities XXX */
372 * Get next character written in by user from uio.
379 if (uio_resid(uio
) <= 0)
382 if (uio
->uio_iovcnt
<= 0)
383 panic("uwritec: non-positive iovcnt");
385 if (uio_iov_len(uio
) == 0) {
387 if (--uio
->uio_iovcnt
== 0)
391 switch (uio
->uio_segflg
) {
393 case UIO_USERSPACE32
:
395 c
= fubyte(CAST_USER_ADDR_T(uio
->uio_iovs
.iov32p
->iov_base
));
398 case UIO_USERSPACE64
:
399 c
= fubyte((user_addr_t
)uio
->uio_iovs
.iov64p
->iov_base
);
404 c
= *((caddr_t
)uio
->uio_iovs
.iov32p
->iov_base
) & 0377;
407 case UIO_USERISPACE32
:
409 c
= fuibyte(CAST_USER_ADDR_T(uio
->uio_iovs
.iov32p
->iov_base
));
413 c
= 0; /* avoid uninitialized variable warning */
414 panic("uwritec: bogus uio_segflg");
419 uio_iov_base_add(uio
, 1);
420 uio_iov_len_add(uio
, -1);
421 uio_setresid(uio
, (uio_resid(uio
) - 1));
425 #endif /* vax || ppc */
428 * General routine to allocate a hash table.
431 hashinit(int elements
, int type
, u_long
*hashmask
)
434 LIST_HEAD(generic
, generic
) *hashtbl
;
438 panic("hashinit: bad cnt");
439 for (hashsize
= 1; hashsize
<= elements
; hashsize
<<= 1)
442 MALLOC(hashtbl
, struct generic
*,
443 (u_long
)hashsize
* sizeof(*hashtbl
), type
, M_WAITOK
|M_ZERO
);
444 if (hashtbl
!= NULL
) {
445 for (i
= 0; i
< hashsize
; i
++)
446 LIST_INIT(&hashtbl
[i
]);
447 *hashmask
= hashsize
- 1;
453 * uio_resid - return the residual IO value for the given uio_t
455 user_ssize_t
uio_resid( uio_t a_uio
)
459 printf("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
461 /* if (IS_VALID_UIO_SEGFLG(a_uio->uio_segflg) == 0) { */
462 /* panic("%s :%d - invalid uio_segflg\n", __FILE__, __LINE__); */
466 /* return 0 if there are no active iovecs */
471 if (UIO_IS_64_BIT_SPACE(a_uio
)) {
472 #if 1 // LP64todo - remove this temp workaround once we go live with uio KPI
473 return( (user_ssize_t
)a_uio
->uio_resid
);
475 return( a_uio
->uio_resid_64
);
478 return( (user_ssize_t
)a_uio
->uio_resid
);
482 * uio_setresid - set the residual IO value for the given uio_t
484 void uio_setresid( uio_t a_uio
, user_ssize_t a_value
)
488 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
490 /* if (IS_VALID_UIO_SEGFLG(a_uio->uio_segflg) == 0) { */
491 /* panic("%s :%d - invalid uio_segflg\n", __FILE__, __LINE__); */
499 if (UIO_IS_64_BIT_SPACE(a_uio
)) {
500 #if 1 // LP64todo - remove this temp workaround once we go live with uio KPI
501 a_uio
->uio_resid
= (int)a_value
;
503 a_uio
->uio_resid_64
= a_value
;
507 a_uio
->uio_resid
= (int)a_value
;
513 * uio_curriovbase - return the base address of the current iovec associated
514 * with the given uio_t. May return 0.
516 user_addr_t
uio_curriovbase( uio_t a_uio
)
520 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
522 #endif /* LP64_DEBUG */
524 if (a_uio
== NULL
|| a_uio
->uio_iovcnt
< 1) {
528 if (UIO_IS_64_BIT_SPACE(a_uio
)) {
529 return(a_uio
->uio_iovs
.uiovp
->iov_base
);
531 return((user_addr_t
)((uintptr_t)a_uio
->uio_iovs
.kiovp
->iov_base
));
536 * uio_curriovlen - return the length value of the current iovec associated
537 * with the given uio_t.
539 user_size_t
uio_curriovlen( uio_t a_uio
)
543 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
545 #endif /* LP64_DEBUG */
547 if (a_uio
== NULL
|| a_uio
->uio_iovcnt
< 1) {
551 if (UIO_IS_64_BIT_SPACE(a_uio
)) {
552 return(a_uio
->uio_iovs
.uiovp
->iov_len
);
554 return((user_size_t
)a_uio
->uio_iovs
.kiovp
->iov_len
);
558 * uio_setcurriovlen - set the length value of the current iovec associated
559 * with the given uio_t.
561 __private_extern__
void uio_setcurriovlen( uio_t a_uio
, user_size_t a_value
)
565 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
567 #endif /* LP64_DEBUG */
573 if (UIO_IS_64_BIT_SPACE(a_uio
)) {
574 a_uio
->uio_iovs
.uiovp
->iov_len
= a_value
;
578 if (a_value
> 0xFFFFFFFFull
) {
579 panic("%s :%d - invalid a_value\n", __FILE__
, __LINE__
);
581 #endif /* LP64_DEBUG */
582 a_uio
->uio_iovs
.kiovp
->iov_len
= (size_t)a_value
;
588 * uio_iovcnt - return count of active iovecs for the given uio_t
590 int uio_iovcnt( uio_t a_uio
)
594 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
596 #endif /* LP64_DEBUG */
602 return( a_uio
->uio_iovcnt
);
606 * uio_offset - return the current offset value for the given uio_t
608 off_t
uio_offset( uio_t a_uio
)
612 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
614 #endif /* LP64_DEBUG */
619 return( a_uio
->uio_offset
);
623 * uio_setoffset - set the current offset value for the given uio_t
625 void uio_setoffset( uio_t a_uio
, off_t a_offset
)
629 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
631 #endif /* LP64_DEBUG */
636 a_uio
->uio_offset
= a_offset
;
641 * uio_rw - return the read / write flag for the given uio_t
643 int uio_rw( uio_t a_uio
)
647 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
649 #endif /* LP64_DEBUG */
654 return( a_uio
->uio_rw
);
658 * uio_setrw - set the read / write flag for the given uio_t
660 void uio_setrw( uio_t a_uio
, int a_value
)
664 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
665 #endif /* LP64_DEBUG */
670 if (!(a_value
== UIO_READ
|| a_value
== UIO_WRITE
)) {
671 panic("%s :%d - invalid a_value\n", __FILE__
, __LINE__
);
673 #endif /* LP64_DEBUG */
675 if (a_value
== UIO_READ
|| a_value
== UIO_WRITE
) {
676 a_uio
->uio_rw
= a_value
;
682 * uio_isuserspace - return non zero value if the address space
683 * flag is for a user address space (could be 32 or 64 bit).
685 int uio_isuserspace( uio_t a_uio
)
689 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
690 #endif /* LP64_DEBUG */
694 if (UIO_SEG_IS_USER_SPACE(a_uio
->uio_segflg
)) {
702 * uio_create - create an uio_t.
703 * Space is allocated to hold up to a_iovcount number of iovecs. The uio_t
704 * is not fully initialized until all iovecs are added using uio_addiov calls.
705 * a_iovcount is the maximum number of iovecs you may add.
707 uio_t
uio_create( int a_iovcount
, /* number of iovecs */
708 off_t a_offset
, /* current offset */
709 int a_spacetype
, /* type of address space */
710 int a_iodirection
) /* read or write flag */
716 my_size
= UIO_SIZEOF(a_iovcount
);
717 my_buf_p
= kalloc(my_size
);
718 my_uio
= uio_createwithbuffer( a_iovcount
,
725 /* leave a note that we allocated this uio_t */
726 my_uio
->uio_flags
|= UIO_FLAGS_WE_ALLOCED
;
728 (void)hw_atomic_add(&uio_t_count
, 1);
737 * uio_createwithbuffer - create an uio_t.
738 * Create a uio_t using the given buffer. The uio_t
739 * is not fully initialized until all iovecs are added using uio_addiov calls.
740 * a_iovcount is the maximum number of iovecs you may add.
741 * This call may fail if the given buffer is not large enough.
743 __private_extern__ uio_t
744 uio_createwithbuffer( int a_iovcount
, /* number of iovecs */
745 off_t a_offset
, /* current offset */
746 int a_spacetype
, /* type of address space */
747 int a_iodirection
, /* read or write flag */
748 void *a_buf_p
, /* pointer to a uio_t buffer */
749 int a_buffer_size
) /* size of uio_t buffer */
751 uio_t my_uio
= (uio_t
) a_buf_p
;
754 my_size
= sizeof(struct uio
) + (sizeof(struct user_iovec
) * a_iovcount
);
755 if (a_buffer_size
< my_size
) {
757 panic("%s :%d - a_buffer_size is too small\n", __FILE__
, __LINE__
);
761 my_size
= a_buffer_size
;
765 panic("%s :%d - could not allocate uio_t\n", __FILE__
, __LINE__
);
767 if (!IS_VALID_UIO_SEGFLG(a_spacetype
)) {
768 panic("%s :%d - invalid address space type\n", __FILE__
, __LINE__
);
770 if (!(a_iodirection
== UIO_READ
|| a_iodirection
== UIO_WRITE
)) {
771 panic("%s :%d - invalid IO direction flag\n", __FILE__
, __LINE__
);
773 if (a_iovcount
> UIO_MAXIOV
) {
774 panic("%s :%d - invalid a_iovcount\n", __FILE__
, __LINE__
);
778 bzero(my_uio
, my_size
);
779 my_uio
->uio_size
= my_size
;
781 /* we use uio_segflg to indicate if the uio_t is the new format or */
782 /* old (pre LP64 support) legacy format */
783 switch (a_spacetype
) {
785 my_uio
->uio_segflg
= UIO_USERSPACE32
;
787 my_uio
->uio_segflg
= UIO_SYSSPACE32
;
788 case UIO_PHYS_USERSPACE
:
789 my_uio
->uio_segflg
= UIO_PHYS_USERSPACE32
;
790 case UIO_PHYS_SYSSPACE
:
791 my_uio
->uio_segflg
= UIO_PHYS_SYSSPACE32
;
793 my_uio
->uio_segflg
= a_spacetype
;
797 if (a_iovcount
> 0) {
798 my_uio
->uio_iovs
.uiovp
= (struct user_iovec
*)
799 (((uint8_t *)my_uio
) + sizeof(struct uio
));
802 my_uio
->uio_iovs
.uiovp
= NULL
;
805 my_uio
->uio_max_iovs
= a_iovcount
;
806 my_uio
->uio_offset
= a_offset
;
807 my_uio
->uio_rw
= a_iodirection
;
808 my_uio
->uio_flags
= UIO_FLAGS_INITED
;
814 * uio_spacetype - return the address space type for the given uio_t
816 int uio_spacetype( uio_t a_uio
)
820 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
821 #endif /* LP64_DEBUG */
825 return( a_uio
->uio_segflg
);
829 * uio_iovsaddr - get the address of the iovec array for the given uio_t.
830 * This returns the location of the iovecs within the uio.
831 * NOTE - for compatibility mode we just return the current value in uio_iovs
832 * which will increase as the IO is completed and is NOT embedded within the
833 * uio, it is a seperate array of one or more iovecs.
835 struct user_iovec
* uio_iovsaddr( uio_t a_uio
)
837 struct user_iovec
* my_addr
;
843 if (a_uio
->uio_segflg
== UIO_USERSPACE
|| a_uio
->uio_segflg
== UIO_SYSSPACE
) {
844 /* we need this for compatibility mode. */
845 my_addr
= (struct user_iovec
*) a_uio
->uio_iovs
.iovp
;
848 my_addr
= (struct user_iovec
*) (((uint8_t *)a_uio
) + sizeof(struct uio
));
854 * uio_reset - reset an uio_t.
855 * Reset the given uio_t to initial values. The uio_t is not fully initialized
856 * until all iovecs are added using uio_addiov calls.
857 * The a_iovcount value passed in the uio_create is the maximum number of
858 * iovecs you may add.
860 void uio_reset( uio_t a_uio
,
861 off_t a_offset
, /* current offset */
862 int a_spacetype
, /* type of address space */
863 int a_iodirection
) /* read or write flag */
867 u_int32_t my_old_flags
;
871 panic("%s :%d - could not allocate uio_t\n", __FILE__
, __LINE__
);
873 if (!IS_VALID_UIO_SEGFLG(a_spacetype
)) {
874 panic("%s :%d - invalid address space type\n", __FILE__
, __LINE__
);
876 if (!(a_iodirection
== UIO_READ
|| a_iodirection
== UIO_WRITE
)) {
877 panic("%s :%d - invalid IO direction flag\n", __FILE__
, __LINE__
);
879 #endif /* LP64_DEBUG */
885 my_size
= a_uio
->uio_size
;
886 my_old_flags
= a_uio
->uio_flags
;
887 my_max_iovs
= a_uio
->uio_max_iovs
;
888 bzero(a_uio
, my_size
);
889 a_uio
->uio_size
= my_size
;
890 a_uio
->uio_segflg
= a_spacetype
;
891 if (my_max_iovs
> 0) {
892 a_uio
->uio_iovs
.uiovp
= (struct user_iovec
*)
893 (((uint8_t *)a_uio
) + sizeof(struct uio
));
896 a_uio
->uio_iovs
.uiovp
= NULL
;
898 a_uio
->uio_max_iovs
= my_max_iovs
;
899 a_uio
->uio_offset
= a_offset
;
900 a_uio
->uio_rw
= a_iodirection
;
901 a_uio
->uio_flags
= my_old_flags
;
907 * uio_free - free a uio_t allocated via uio_init. this also frees all
910 void uio_free( uio_t a_uio
)
914 panic("%s :%d - passing NULL uio_t\n", __FILE__
, __LINE__
);
916 #endif /* LP64_DEBUG */
918 if (a_uio
!= NULL
&& (a_uio
->uio_flags
& UIO_FLAGS_WE_ALLOCED
) != 0) {
920 if (hw_atomic_sub(&uio_t_count
, 1) == UINT_MAX
)
921 panic("%s :%d - uio_t_count underflow\n", __FILE__
, __LINE__
);
923 kfree(a_uio
, a_uio
->uio_size
);
930 * uio_addiov - add an iovec to the given uio_t. You may call this up to
931 * the a_iovcount number that was passed to uio_create. This call will
932 * increment the residual IO count as iovecs are added to the uio_t.
933 * returns 0 if add was successful else non zero.
935 int uio_addiov( uio_t a_uio
, user_addr_t a_baseaddr
, user_size_t a_length
)
941 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
942 #endif /* LP64_DEBUG */
946 if (UIO_IS_64_BIT_SPACE(a_uio
)) {
947 for ( i
= 0; i
< a_uio
->uio_max_iovs
; i
++ ) {
948 if (a_uio
->uio_iovs
.uiovp
[i
].iov_len
== 0 && a_uio
->uio_iovs
.uiovp
[i
].iov_base
== 0) {
949 a_uio
->uio_iovs
.uiovp
[i
].iov_len
= a_length
;
950 a_uio
->uio_iovs
.uiovp
[i
].iov_base
= a_baseaddr
;
952 #if 1 // LP64todo - remove this temp workaround once we go live with uio KPI
953 a_uio
->uio_resid
+= a_length
;
955 a_uio
->uio_resid_64
+= a_length
;
962 for ( i
= 0; i
< a_uio
->uio_max_iovs
; i
++ ) {
963 if (a_uio
->uio_iovs
.kiovp
[i
].iov_len
== 0 && a_uio
->uio_iovs
.kiovp
[i
].iov_base
== 0) {
964 a_uio
->uio_iovs
.kiovp
[i
].iov_len
= (u_int32_t
)a_length
;
965 a_uio
->uio_iovs
.kiovp
[i
].iov_base
= (u_int32_t
)((uintptr_t)a_baseaddr
);
967 a_uio
->uio_resid
+= a_length
;
977 * uio_getiov - get iovec data associated with the given uio_t. Use
978 * a_index to iterate over each iovec (0 to (uio_iovcnt(uio_t) - 1)).
979 * a_baseaddr_p and a_length_p may be NULL.
980 * returns -1 when a_index is >= uio_t.uio_iovcnt or invalid uio_t.
981 * returns 0 when data is returned.
983 int uio_getiov( uio_t a_uio
,
985 user_addr_t
* a_baseaddr_p
,
986 user_size_t
* a_length_p
)
990 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
994 if ( a_index
< 0 || a_index
>= a_uio
->uio_iovcnt
) {
998 if (UIO_IS_64_BIT_SPACE(a_uio
)) {
999 if (a_baseaddr_p
!= NULL
) {
1000 *a_baseaddr_p
= a_uio
->uio_iovs
.uiovp
[a_index
].iov_base
;
1002 if (a_length_p
!= NULL
) {
1003 *a_length_p
= a_uio
->uio_iovs
.uiovp
[a_index
].iov_len
;
1007 if (a_baseaddr_p
!= NULL
) {
1008 *a_baseaddr_p
= a_uio
->uio_iovs
.kiovp
[a_index
].iov_base
;
1010 if (a_length_p
!= NULL
) {
1011 *a_length_p
= a_uio
->uio_iovs
.kiovp
[a_index
].iov_len
;
1019 * uio_calculateresid - runs through all iovecs associated with this
1020 * uio_t and calculates (and sets) the residual IO count.
1022 __private_extern__
void uio_calculateresid( uio_t a_uio
)
1026 if (a_uio
== NULL
) {
1028 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
1029 #endif /* LP64_DEBUG */
1033 a_uio
->uio_iovcnt
= a_uio
->uio_max_iovs
;
1034 if (UIO_IS_64_BIT_SPACE(a_uio
)) {
1035 #if 1 // LP64todo - remove this temp workaround once we go live with uio KPI
1036 a_uio
->uio_resid
= 0;
1038 a_uio
->uio_resid_64
= 0;
1040 for ( i
= 0; i
< a_uio
->uio_max_iovs
; i
++ ) {
1041 if (a_uio
->uio_iovs
.uiovp
[i
].iov_len
!= 0 && a_uio
->uio_iovs
.uiovp
[i
].iov_base
!= 0) {
1042 #if 1 // LP64todo - remove this temp workaround once we go live with uio KPI
1043 a_uio
->uio_resid
+= a_uio
->uio_iovs
.uiovp
[i
].iov_len
;
1045 a_uio
->uio_resid_64
+= a_uio
->uio_iovs
.uiovp
[i
].iov_len
;
1050 /* position to first non zero length iovec (4235922) */
1051 while (a_uio
->uio_iovcnt
> 0 && a_uio
->uio_iovs
.uiovp
->iov_len
== 0) {
1052 a_uio
->uio_iovcnt
--;
1053 if (a_uio
->uio_iovcnt
> 0) {
1054 a_uio
->uio_iovs
.uiovp
++;
1059 a_uio
->uio_resid
= 0;
1060 for ( i
= 0; i
< a_uio
->uio_max_iovs
; i
++ ) {
1061 if (a_uio
->uio_iovs
.kiovp
[i
].iov_len
!= 0 && a_uio
->uio_iovs
.kiovp
[i
].iov_base
!= 0) {
1062 a_uio
->uio_resid
+= a_uio
->uio_iovs
.kiovp
[i
].iov_len
;
1066 /* position to first non zero length iovec (4235922) */
1067 while (a_uio
->uio_iovcnt
> 0 && a_uio
->uio_iovs
.kiovp
->iov_len
== 0) {
1068 a_uio
->uio_iovcnt
--;
1069 if (a_uio
->uio_iovcnt
> 0) {
1070 a_uio
->uio_iovs
.kiovp
++;
1079 * uio_update - update the given uio_t for a_count of completed IO.
1080 * This call decrements the current iovec length and residual IO value
1081 * and increments the current iovec base address and offset value.
1082 * If the current iovec length is 0 then advance to the next
1084 * If the a_count passed in is 0, than only do the advancement
1085 * over any 0 length iovec's.
1087 void uio_update( uio_t a_uio
, user_size_t a_count
)
1090 if (a_uio
== NULL
) {
1091 panic("%s :%d - invalid uio_t\n", __FILE__
, __LINE__
);
1093 if (UIO_IS_32_BIT_SPACE(a_uio
) && a_count
> 0xFFFFFFFFull
) {
1094 panic("%s :%d - invalid count value \n", __FILE__
, __LINE__
);
1096 #endif /* LP64_DEBUG */
1098 if (a_uio
== NULL
|| a_uio
->uio_iovcnt
< 1) {
1102 if (UIO_IS_64_BIT_SPACE(a_uio
)) {
1104 * if a_count == 0, then we are asking to skip over
1108 if (a_count
> a_uio
->uio_iovs
.uiovp
->iov_len
) {
1109 a_uio
->uio_iovs
.uiovp
->iov_base
+= a_uio
->uio_iovs
.uiovp
->iov_len
;
1110 a_uio
->uio_iovs
.uiovp
->iov_len
= 0;
1113 a_uio
->uio_iovs
.uiovp
->iov_base
+= a_count
;
1114 a_uio
->uio_iovs
.uiovp
->iov_len
-= a_count
;
1116 #if 1 // LP64todo - remove this temp workaround once we go live with uio KPI
1117 if (a_uio
->uio_resid
< 0) {
1118 a_uio
->uio_resid
= 0;
1120 if (a_count
> (user_size_t
)a_uio
->uio_resid
) {
1121 a_uio
->uio_offset
+= a_uio
->uio_resid
;
1122 a_uio
->uio_resid
= 0;
1125 a_uio
->uio_offset
+= a_count
;
1126 a_uio
->uio_resid
-= a_count
;
1129 if (a_uio
->uio_resid_64
< 0) {
1130 a_uio
->uio_resid_64
= 0;
1132 if (a_count
> (user_size_t
)a_uio
->uio_resid_64
) {
1133 a_uio
->uio_offset
+= a_uio
->uio_resid_64
;
1134 a_uio
->uio_resid_64
= 0;
1137 a_uio
->uio_offset
+= a_count
;
1138 a_uio
->uio_resid_64
-= a_count
;
1143 * advance to next iovec if current one is totally consumed
1145 while (a_uio
->uio_iovcnt
> 0 && a_uio
->uio_iovs
.uiovp
->iov_len
== 0) {
1146 a_uio
->uio_iovcnt
--;
1147 if (a_uio
->uio_iovcnt
> 0) {
1148 a_uio
->uio_iovs
.uiovp
++;
1154 * if a_count == 0, then we are asking to skip over
1158 if (a_count
> a_uio
->uio_iovs
.kiovp
->iov_len
) {
1159 a_uio
->uio_iovs
.kiovp
->iov_base
+= a_uio
->uio_iovs
.kiovp
->iov_len
;
1160 a_uio
->uio_iovs
.kiovp
->iov_len
= 0;
1163 a_uio
->uio_iovs
.kiovp
->iov_base
+= a_count
;
1164 a_uio
->uio_iovs
.kiovp
->iov_len
-= a_count
;
1166 if (a_uio
->uio_resid
< 0) {
1167 a_uio
->uio_resid
= 0;
1169 if (a_count
> (user_size_t
)a_uio
->uio_resid
) {
1170 a_uio
->uio_offset
+= a_uio
->uio_resid
;
1171 a_uio
->uio_resid
= 0;
1174 a_uio
->uio_offset
+= a_count
;
1175 a_uio
->uio_resid
-= a_count
;
1179 * advance to next iovec if current one is totally consumed
1181 while (a_uio
->uio_iovcnt
> 0 && a_uio
->uio_iovs
.kiovp
->iov_len
== 0) {
1182 a_uio
->uio_iovcnt
--;
1183 if (a_uio
->uio_iovcnt
> 0) {
1184 a_uio
->uio_iovs
.kiovp
++;
1193 * uio_duplicate - allocate a new uio and make a copy of the given uio_t.
1196 uio_t
uio_duplicate( uio_t a_uio
)
1201 if (a_uio
== NULL
) {
1205 my_uio
= (uio_t
) kalloc(a_uio
->uio_size
);
1207 panic("%s :%d - allocation failed\n", __FILE__
, __LINE__
);
1210 bcopy((void *)a_uio
, (void *)my_uio
, a_uio
->uio_size
);
1211 /* need to set our iovec pointer to point to first active iovec */
1212 if (my_uio
->uio_max_iovs
> 0) {
1213 my_uio
->uio_iovs
.uiovp
= (struct user_iovec
*)
1214 (((uint8_t *)my_uio
) + sizeof(struct uio
));
1216 /* advance to first nonzero iovec */
1217 if (my_uio
->uio_iovcnt
> 0) {
1218 for ( i
= 0; i
< my_uio
->uio_max_iovs
; i
++ ) {
1219 if (UIO_IS_64_BIT_SPACE(a_uio
)) {
1220 if (my_uio
->uio_iovs
.uiovp
->iov_len
!= 0) {
1223 my_uio
->uio_iovs
.uiovp
++;
1226 if (my_uio
->uio_iovs
.kiovp
->iov_len
!= 0) {
1229 my_uio
->uio_iovs
.kiovp
++;
1235 my_uio
->uio_flags
= UIO_FLAGS_WE_ALLOCED
| UIO_FLAGS_INITED
;