]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_subr.c
xnu-7195.81.3.tar.gz
[apple/xnu.git] / bsd / kern / kern_subr.c
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
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.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
29/*
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.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
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.
53 *
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
64 * SUCH DAMAGE.
65 *
66 * @(#)kern_subr.c 8.3 (Berkeley) 1/21/94
67 */
68
cb323159
A
69#include <machine/atomic.h>
70
1c79356b
A
71#include <sys/param.h>
72#include <sys/systm.h>
91447636 73#include <sys/proc_internal.h>
1c79356b
A
74#include <sys/malloc.h>
75#include <sys/queue.h>
55e303ae 76#include <vm/pmap.h>
91447636
A
77#include <sys/uio_internal.h>
78#include <kern/kalloc.h>
1c79356b
A
79
80#include <kdebug.h>
81
82#include <sys/kdebug.h>
83#define DBG_UIO_COPYOUT 16
84#define DBG_UIO_COPYIN 17
85
91447636
A
86#if DEBUG
87#include <kern/simple_lock.h>
88
0a7de745 89static uint32_t uio_t_count = 0;
91447636
A
90#endif /* DEBUG */
91
b0d623f7
A
92#define IS_VALID_UIO_SEGFLG(segflg) \
93 ( (segflg) == UIO_USERSPACE || \
94 (segflg) == UIO_SYSSPACE || \
95 (segflg) == UIO_USERSPACE32 || \
96 (segflg) == UIO_USERSPACE64 || \
97 (segflg) == UIO_SYSSPACE32 || \
98 (segflg) == UIO_USERISPACE || \
99 (segflg) == UIO_PHYS_USERSPACE || \
100 (segflg) == UIO_PHYS_SYSSPACE || \
101 (segflg) == UIO_USERISPACE32 || \
102 (segflg) == UIO_PHYS_USERSPACE32 || \
103 (segflg) == UIO_USERISPACE64 || \
104 (segflg) == UIO_PHYS_USERSPACE64 )
de355530 105
2d21ac55
A
106/*
107 * Returns: 0 Success
108 * uiomove64:EFAULT
109 *
110 * Notes: The first argument should be a caddr_t, but const poisoning
111 * for typedef'ed types doesn't work in gcc.
112 */
1c79356b 113int
2d21ac55 114uiomove(const char * cp, int n, uio_t uio)
55e303ae 115{
b0d623f7 116 return uiomove64((const addr64_t)(uintptr_t)cp, n, uio);
55e303ae
A
117}
118
2d21ac55
A
119/*
120 * Returns: 0 Success
121 * EFAULT
122 * copyout:EFAULT
123 * copyin:EFAULT
124 * copywithin:EFAULT
125 * copypv:EFAULT
126 */
55e303ae 127int
2d21ac55 128uiomove64(const addr64_t c_cp, int n, struct uio *uio)
1c79356b 129{
2d21ac55 130 addr64_t cp = c_cp;
2d21ac55 131 uint64_t acnt;
1c79356b
A
132 int error = 0;
133
134#if DIAGNOSTIC
0a7de745 135 if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE) {
1c79356b 136 panic("uiomove: mode");
0a7de745 137 }
1c79356b
A
138#endif
139
91447636
A
140#if LP64_DEBUG
141 if (IS_VALID_UIO_SEGFLG(uio->uio_segflg) == 0) {
0a7de745 142 panic("%s :%d - invalid uio_segflg\n", __FILE__, __LINE__);
91447636
A
143 }
144#endif /* LP64_DEBUG */
145
146 while (n > 0 && uio_resid(uio)) {
b0d623f7
A
147 uio_update(uio, 0);
148 acnt = uio_curriovlen(uio);
91447636 149 if (acnt == 0) {
1c79356b
A
150 continue;
151 }
0a7de745 152 if (n > 0 && acnt > (uint64_t)n) {
91447636 153 acnt = n;
0a7de745 154 }
91447636 155
316670eb 156 switch ((int) uio->uio_segflg) {
91447636
A
157 case UIO_USERSPACE64:
158 case UIO_USERISPACE64:
91447636
A
159 case UIO_USERSPACE32:
160 case UIO_USERISPACE32:
1c79356b
A
161 case UIO_USERSPACE:
162 case UIO_USERISPACE:
b0d623f7 163 // LP64 - 3rd argument in debug code is 64 bit, expected to be 32 bit
0a7de745
A
164 if (uio->uio_rw == UIO_READ) {
165 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, DBG_UIO_COPYOUT)) | DBG_FUNC_START,
166 (int)cp, (uintptr_t)uio->uio_iovs.uiovp->iov_base, acnt, 0, 0);
167
f427ee49 168 error = copyout( CAST_DOWN(caddr_t, cp), uio->uio_iovs.uiovp->iov_base, (size_t)acnt );
0a7de745
A
169
170 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, DBG_UIO_COPYOUT)) | DBG_FUNC_END,
171 (int)cp, (uintptr_t)uio->uio_iovs.uiovp->iov_base, acnt, 0, 0);
172 } else {
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);
175
f427ee49 176 error = copyin(uio->uio_iovs.uiovp->iov_base, CAST_DOWN(caddr_t, cp), (size_t)acnt);
0a7de745
A
177
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);
180 }
181 if (error) {
182 return error;
183 }
1c79356b
A
184 break;
185
91447636 186 case UIO_SYSSPACE32:
1c79356b 187 case UIO_SYSSPACE:
0a7de745 188 if (uio->uio_rw == UIO_READ) {
b0d623f7 189 error = copywithin(CAST_DOWN(caddr_t, cp), CAST_DOWN(caddr_t, uio->uio_iovs.kiovp->iov_base),
f427ee49 190 (size_t)acnt);
0a7de745 191 } else {
b0d623f7 192 error = copywithin(CAST_DOWN(caddr_t, uio->uio_iovs.kiovp->iov_base), CAST_DOWN(caddr_t, cp),
f427ee49 193 (size_t)acnt);
0a7de745 194 }
1c79356b 195 break;
9bccf70c 196
91447636 197 case UIO_PHYS_USERSPACE64:
91447636 198 case UIO_PHYS_USERSPACE32:
1c79356b 199 case UIO_PHYS_USERSPACE:
f427ee49
A
200 acnt = MIN(acnt, UINT_MAX);
201
0a7de745
A
202 if (uio->uio_rw == UIO_READ) {
203 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, DBG_UIO_COPYOUT)) | DBG_FUNC_START,
204 (int)cp, (uintptr_t)uio->uio_iovs.uiovp->iov_base, acnt, 1, 0);
55e303ae 205
f427ee49 206 error = copypv((addr64_t)cp, uio->uio_iovs.uiovp->iov_base, (unsigned int)acnt, cppvPsrc | cppvNoRefSrc);
0a7de745
A
207 if (error) { /* Copy physical to virtual */
208 error = EFAULT;
209 }
55e303ae 210
0a7de745
A
211 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, DBG_UIO_COPYOUT)) | DBG_FUNC_END,
212 (int)cp, (uintptr_t)uio->uio_iovs.uiovp->iov_base, acnt, 1, 0);
213 } else {
214 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, DBG_UIO_COPYIN)) | DBG_FUNC_START,
215 (uintptr_t)uio->uio_iovs.uiovp->iov_base, (int)cp, acnt, 1, 0);
1c79356b 216
f427ee49 217 error = copypv(uio->uio_iovs.uiovp->iov_base, (addr64_t)cp, (unsigned int)acnt, cppvPsnk | cppvNoRefSrc | cppvNoModSnk);
0a7de745
A
218 if (error) { /* Copy virtual to physical */
219 error = EFAULT;
220 }
221
222 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, DBG_UIO_COPYIN)) | DBG_FUNC_END,
223 (uintptr_t)uio->uio_iovs.uiovp->iov_base, (int)cp, acnt, 1, 0);
224 }
225 if (error) {
226 return error;
227 }
55e303ae
A
228 break;
229
230 case UIO_PHYS_SYSSPACE:
f427ee49
A
231 acnt = MIN(acnt, UINT_MAX);
232
0a7de745
A
233 if (uio->uio_rw == UIO_READ) {
234 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, DBG_UIO_COPYOUT)) | DBG_FUNC_START,
235 (int)cp, (uintptr_t)uio->uio_iovs.kiovp->iov_base, acnt, 2, 0);
236
f427ee49 237 error = copypv((addr64_t)cp, uio->uio_iovs.kiovp->iov_base, (unsigned int)acnt, cppvKmap | cppvPsrc | cppvNoRefSrc);
0a7de745
A
238 if (error) { /* Copy physical to virtual */
239 error = EFAULT;
240 }
241
242 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, DBG_UIO_COPYOUT)) | DBG_FUNC_END,
243 (int)cp, (uintptr_t)uio->uio_iovs.kiovp->iov_base, acnt, 2, 0);
244 } else {
245 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, DBG_UIO_COPYIN)) | DBG_FUNC_START,
246 (uintptr_t)uio->uio_iovs.kiovp->iov_base, (int)cp, acnt, 2, 0);
247
f427ee49 248 error = copypv(uio->uio_iovs.kiovp->iov_base, (addr64_t)cp, (unsigned int)acnt, cppvKmap | cppvPsnk | cppvNoRefSrc | cppvNoModSnk);
0a7de745
A
249 if (error) { /* Copy virtual to physical */
250 error = EFAULT;
251 }
252
253 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, DBG_UIO_COPYIN)) | DBG_FUNC_END,
254 (uintptr_t)uio->uio_iovs.kiovp->iov_base, (int)cp, acnt, 2, 0);
255 }
256 if (error) {
257 return error;
258 }
1c79356b 259 break;
91447636
A
260
261 default:
262 break;
1c79356b 263 }
f427ee49 264 uio_update(uio, (user_size_t)acnt);
91447636
A
265 cp += acnt;
266 n -= acnt;
1c79356b 267 }
0a7de745 268 return error;
1c79356b
A
269}
270
271/*
272 * Give next character to user as result of read.
273 */
274int
2d21ac55 275ureadc(int c, struct uio *uio)
1c79356b 276{
0a7de745 277 if (uio_resid(uio) <= 0) {
1c79356b 278 panic("ureadc: non-positive resid");
0a7de745 279 }
b0d623f7 280 uio_update(uio, 0);
0a7de745 281 if (uio->uio_iovcnt == 0) {
1c79356b 282 panic("ureadc: non-positive iovcnt");
0a7de745
A
283 }
284 if (uio_curriovlen(uio) <= 0) {
b0d623f7 285 panic("ureadc: non-positive iovlen");
0a7de745 286 }
b0d623f7 287
316670eb 288 switch ((int) uio->uio_segflg) {
91447636 289 case UIO_USERSPACE32:
1c79356b 290 case UIO_USERSPACE:
91447636 291 case UIO_USERISPACE32:
1c79356b 292 case UIO_USERISPACE:
91447636 293 case UIO_USERSPACE64:
b0d623f7 294 case UIO_USERISPACE64:
0a7de745
A
295 if (subyte((user_addr_t)uio->uio_iovs.uiovp->iov_base, c) < 0) {
296 return EFAULT;
297 }
91447636
A
298 break;
299
300 case UIO_SYSSPACE32:
1c79356b 301 case UIO_SYSSPACE:
f427ee49 302 *(CAST_DOWN(caddr_t, uio->uio_iovs.kiovp->iov_base)) = (char)c;
1c79356b
A
303 break;
304
305 default:
1c79356b
A
306 break;
307 }
b0d623f7 308 uio_update(uio, 1);
0a7de745 309 return 0;
1c79356b 310}
1c79356b 311
f427ee49
A
312LIST_HEAD(generic_hash_head, generic);
313
1c79356b
A
314/*
315 * General routine to allocate a hash table.
316 */
317void *
f427ee49 318hashinit(int elements, int type __unused, u_long *hashmask)
1c79356b 319{
f427ee49
A
320 struct generic_hash_head *hashtbl;
321 vm_size_t hashsize;
1c79356b 322
0a7de745 323 if (elements <= 0) {
1c79356b 324 panic("hashinit: bad cnt");
0a7de745 325 }
f427ee49
A
326
327 hashsize = 1UL << (fls(elements) - 1);
328 hashtbl = kheap_alloc(KHEAP_DEFAULT, hashsize * sizeof(*hashtbl),
329 Z_WAITOK | Z_ZERO);
91447636 330 if (hashtbl != NULL) {
91447636
A
331 *hashmask = hashsize - 1;
332 }
0a7de745 333 return hashtbl;
1c79356b 334}
91447636 335
f427ee49
A
336void
337hashdestroy(void *hash, int type __unused, u_long hashmask)
338{
339 struct generic_hash_head *hashtbl = hash;
340 assert(powerof2(hashmask + 1));
341 kheap_free(KHEAP_DEFAULT, hashtbl, (hashmask + 1) * sizeof(*hashtbl));
342}
343
91447636
A
344/*
345 * uio_resid - return the residual IO value for the given uio_t
346 */
0a7de745
A
347user_ssize_t
348uio_resid( uio_t a_uio )
91447636
A
349{
350#if DEBUG
351 if (a_uio == NULL) {
0a7de745 352 printf("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
91447636 353 }
0a7de745
A
354/* if (IS_VALID_UIO_SEGFLG(a_uio->uio_segflg) == 0) { */
355/* panic("%s :%d - invalid uio_segflg\n", __FILE__, __LINE__); */
356/* } */
91447636
A
357#endif /* DEBUG */
358
359 /* return 0 if there are no active iovecs */
360 if (a_uio == NULL) {
0a7de745 361 return 0;
91447636
A
362 }
363
0a7de745 364 return a_uio->uio_resid_64;
91447636
A
365}
366
367/*
368 * uio_setresid - set the residual IO value for the given uio_t
369 */
0a7de745
A
370void
371uio_setresid( uio_t a_uio, user_ssize_t a_value )
91447636
A
372{
373#if DEBUG
374 if (a_uio == NULL) {
0a7de745 375 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
91447636 376 }
0a7de745
A
377/* if (IS_VALID_UIO_SEGFLG(a_uio->uio_segflg) == 0) { */
378/* panic("%s :%d - invalid uio_segflg\n", __FILE__, __LINE__); */
379/* } */
91447636
A
380#endif /* DEBUG */
381
382 if (a_uio == NULL) {
383 return;
384 }
385
b0d623f7 386 a_uio->uio_resid_64 = a_value;
91447636
A
387 return;
388}
389
91447636 390/*
0a7de745 391 * uio_curriovbase - return the base address of the current iovec associated
91447636
A
392 * with the given uio_t. May return 0.
393 */
0a7de745
A
394user_addr_t
395uio_curriovbase( uio_t a_uio )
91447636
A
396{
397#if LP64_DEBUG
398 if (a_uio == NULL) {
0a7de745 399 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
91447636
A
400 }
401#endif /* LP64_DEBUG */
402
403 if (a_uio == NULL || a_uio->uio_iovcnt < 1) {
0a7de745 404 return 0;
91447636 405 }
0a7de745 406
b0d623f7 407 if (UIO_IS_USER_SPACE(a_uio)) {
0a7de745 408 return a_uio->uio_iovs.uiovp->iov_base;
91447636 409 }
0a7de745 410 return (user_addr_t)a_uio->uio_iovs.kiovp->iov_base;
91447636
A
411}
412
413/*
0a7de745 414 * uio_curriovlen - return the length value of the current iovec associated
91447636
A
415 * with the given uio_t.
416 */
0a7de745
A
417user_size_t
418uio_curriovlen( uio_t a_uio )
91447636
A
419{
420#if LP64_DEBUG
421 if (a_uio == NULL) {
0a7de745 422 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
91447636
A
423 }
424#endif /* LP64_DEBUG */
425
426 if (a_uio == NULL || a_uio->uio_iovcnt < 1) {
0a7de745 427 return 0;
91447636 428 }
0a7de745 429
b0d623f7 430 if (UIO_IS_USER_SPACE(a_uio)) {
0a7de745 431 return a_uio->uio_iovs.uiovp->iov_len;
91447636 432 }
0a7de745 433 return (user_size_t)a_uio->uio_iovs.kiovp->iov_len;
91447636
A
434}
435
436/*
0a7de745 437 * uio_setcurriovlen - set the length value of the current iovec associated
91447636
A
438 * with the given uio_t.
439 */
0a7de745
A
440__private_extern__ void
441uio_setcurriovlen( uio_t a_uio, user_size_t a_value )
91447636
A
442{
443#if LP64_DEBUG
444 if (a_uio == NULL) {
0a7de745 445 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
91447636
A
446 }
447#endif /* LP64_DEBUG */
448
449 if (a_uio == NULL) {
0a7de745 450 return;
91447636
A
451 }
452
b0d623f7 453 if (UIO_IS_USER_SPACE(a_uio)) {
91447636 454 a_uio->uio_iovs.uiovp->iov_len = a_value;
0a7de745 455 } else {
91447636
A
456#if LP64_DEBUG
457 if (a_value > 0xFFFFFFFFull) {
0a7de745 458 panic("%s :%d - invalid a_value\n", __FILE__, __LINE__);
91447636
A
459 }
460#endif /* LP64_DEBUG */
461 a_uio->uio_iovs.kiovp->iov_len = (size_t)a_value;
462 }
463 return;
464}
465
466/*
467 * uio_iovcnt - return count of active iovecs for the given uio_t
468 */
0a7de745
A
469int
470uio_iovcnt( uio_t a_uio )
91447636
A
471{
472#if LP64_DEBUG
473 if (a_uio == NULL) {
0a7de745 474 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
91447636
A
475 }
476#endif /* LP64_DEBUG */
477
478 if (a_uio == NULL) {
0a7de745 479 return 0;
91447636
A
480 }
481
0a7de745 482 return a_uio->uio_iovcnt;
91447636
A
483}
484
485/*
486 * uio_offset - return the current offset value for the given uio_t
487 */
0a7de745
A
488off_t
489uio_offset( uio_t a_uio )
91447636
A
490{
491#if LP64_DEBUG
492 if (a_uio == NULL) {
0a7de745 493 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
91447636
A
494 }
495#endif /* LP64_DEBUG */
496
497 if (a_uio == NULL) {
0a7de745 498 return 0;
91447636 499 }
0a7de745 500 return a_uio->uio_offset;
91447636
A
501}
502
503/*
504 * uio_setoffset - set the current offset value for the given uio_t
505 */
0a7de745
A
506void
507uio_setoffset( uio_t a_uio, off_t a_offset )
91447636
A
508{
509#if LP64_DEBUG
510 if (a_uio == NULL) {
0a7de745 511 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
91447636
A
512 }
513#endif /* LP64_DEBUG */
514
515 if (a_uio == NULL) {
0a7de745 516 return;
91447636
A
517 }
518 a_uio->uio_offset = a_offset;
519 return;
520}
521
522/*
523 * uio_rw - return the read / write flag for the given uio_t
524 */
0a7de745
A
525int
526uio_rw( uio_t a_uio )
91447636
A
527{
528#if LP64_DEBUG
529 if (a_uio == NULL) {
0a7de745 530 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
91447636
A
531 }
532#endif /* LP64_DEBUG */
533
534 if (a_uio == NULL) {
0a7de745 535 return -1;
91447636 536 }
0a7de745 537 return a_uio->uio_rw;
91447636
A
538}
539
540/*
541 * uio_setrw - set the read / write flag for the given uio_t
542 */
0a7de745
A
543void
544uio_setrw( uio_t a_uio, int a_value )
91447636
A
545{
546 if (a_uio == NULL) {
547#if LP64_DEBUG
0a7de745 548 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
91447636
A
549#endif /* LP64_DEBUG */
550 return;
551 }
552
553#if LP64_DEBUG
554 if (!(a_value == UIO_READ || a_value == UIO_WRITE)) {
0a7de745 555 panic("%s :%d - invalid a_value\n", __FILE__, __LINE__);
91447636
A
556 }
557#endif /* LP64_DEBUG */
558
559 if (a_value == UIO_READ || a_value == UIO_WRITE) {
560 a_uio->uio_rw = a_value;
561 }
562 return;
563}
564
565/*
0a7de745 566 * uio_isuserspace - return non zero value if the address space
91447636
A
567 * flag is for a user address space (could be 32 or 64 bit).
568 */
0a7de745
A
569int
570uio_isuserspace( uio_t a_uio )
91447636
A
571{
572 if (a_uio == NULL) {
573#if LP64_DEBUG
0a7de745 574 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
91447636 575#endif /* LP64_DEBUG */
0a7de745 576 return 0;
91447636
A
577 }
578
579 if (UIO_SEG_IS_USER_SPACE(a_uio->uio_segflg)) {
0a7de745 580 return 1;
91447636 581 }
0a7de745 582 return 0;
91447636
A
583}
584
585
586/*
587 * uio_create - create an uio_t.
0a7de745 588 * Space is allocated to hold up to a_iovcount number of iovecs. The uio_t
91447636
A
589 * is not fully initialized until all iovecs are added using uio_addiov calls.
590 * a_iovcount is the maximum number of iovecs you may add.
591 */
0a7de745
A
592uio_t
593uio_create( int a_iovcount, /* number of iovecs */
594 off_t a_offset, /* current offset */
595 int a_spacetype, /* type of address space */
596 int a_iodirection ) /* read or write flag */
91447636 597{
0a7de745
A
598 void * my_buf_p;
599 size_t my_size;
600 uio_t my_uio;
601
2d21ac55 602 my_size = UIO_SIZEOF(a_iovcount);
91447636 603 my_buf_p = kalloc(my_size);
0a7de745
A
604 my_uio = uio_createwithbuffer( a_iovcount,
605 a_offset,
606 a_spacetype,
607 a_iodirection,
608 my_buf_p,
609 my_size );
91447636
A
610 if (my_uio != 0) {
611 /* leave a note that we allocated this uio_t */
612 my_uio->uio_flags |= UIO_FLAGS_WE_ALLOCED;
613#if DEBUG
cb323159 614 os_atomic_inc(&uio_t_count, relaxed);
91447636
A
615#endif
616 }
0a7de745
A
617
618 return my_uio;
91447636
A
619}
620
621
622/*
623 * uio_createwithbuffer - create an uio_t.
0a7de745 624 * Create a uio_t using the given buffer. The uio_t
91447636
A
625 * is not fully initialized until all iovecs are added using uio_addiov calls.
626 * a_iovcount is the maximum number of iovecs you may add.
627 * This call may fail if the given buffer is not large enough.
628 */
0a7de745
A
629__private_extern__ uio_t
630uio_createwithbuffer( int a_iovcount, /* number of iovecs */
631 off_t a_offset, /* current offset */
632 int a_spacetype, /* type of address space */
633 int a_iodirection, /* read or write flag */
634 void *a_buf_p, /* pointer to a uio_t buffer */
635 size_t a_buffer_size ) /* size of uio_t buffer */
91447636 636{
0a7de745
A
637 uio_t my_uio = (uio_t) a_buf_p;
638 size_t my_size;
639
f427ee49
A
640 assert(a_iovcount >= 0 && a_iovcount <= UIO_MAXIOV);
641 if (a_iovcount < 0 || a_iovcount > UIO_MAXIOV) {
642 return NULL;
643 }
644
b0d623f7 645 my_size = UIO_SIZEOF(a_iovcount);
f427ee49 646 assert(a_buffer_size >= my_size);
91447636 647 if (a_buffer_size < my_size) {
0a7de745 648 return NULL;
91447636
A
649 }
650 my_size = a_buffer_size;
0a7de745 651
f427ee49
A
652 assert(my_size <= INT_MAX);
653 if (my_size > INT_MAX) {
654 return NULL;
91447636 655 }
f427ee49
A
656
657 assert(my_uio != NULL);
658 assert(IS_VALID_UIO_SEGFLG(a_spacetype));
659 assert(a_iodirection == UIO_READ || a_iodirection == UIO_WRITE);
91447636
A
660
661 bzero(my_uio, my_size);
f427ee49 662 my_uio->uio_size = (int)my_size;
91447636 663
b0d623f7
A
664 /*
665 * we use uio_segflg to indicate if the uio_t is the new format or
666 * old (pre LP64 support) legacy format
667 * This switch statement should canonicalize incoming space type
668 * to one of UIO_USERSPACE32/64, UIO_PHYS_USERSPACE32/64, or
669 * UIO_SYSSPACE/UIO_PHYS_SYSSPACE
670 */
91447636
A
671 switch (a_spacetype) {
672 case UIO_USERSPACE:
673 my_uio->uio_segflg = UIO_USERSPACE32;
b0d623f7
A
674 break;
675 case UIO_SYSSPACE32:
676 my_uio->uio_segflg = UIO_SYSSPACE;
677 break;
91447636
A
678 case UIO_PHYS_USERSPACE:
679 my_uio->uio_segflg = UIO_PHYS_USERSPACE32;
b0d623f7 680 break;
91447636
A
681 default:
682 my_uio->uio_segflg = a_spacetype;
683 break;
684 }
685
686 if (a_iovcount > 0) {
687 my_uio->uio_iovs.uiovp = (struct user_iovec *)
0a7de745
A
688 (((uint8_t *)my_uio) + sizeof(struct uio));
689 } else {
91447636
A
690 my_uio->uio_iovs.uiovp = NULL;
691 }
692
693 my_uio->uio_max_iovs = a_iovcount;
694 my_uio->uio_offset = a_offset;
695 my_uio->uio_rw = a_iodirection;
696 my_uio->uio_flags = UIO_FLAGS_INITED;
697
0a7de745 698 return my_uio;
91447636
A
699}
700
701/*
702 * uio_spacetype - return the address space type for the given uio_t
703 */
0a7de745
A
704__private_extern__ int
705uio_spacetype( uio_t a_uio )
91447636
A
706{
707 if (a_uio == NULL) {
708#if LP64_DEBUG
0a7de745 709 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
91447636 710#endif /* LP64_DEBUG */
0a7de745 711 return -1;
91447636
A
712 }
713
0a7de745 714 return a_uio->uio_segflg;
91447636
A
715}
716
717/*
718 * uio_iovsaddr - get the address of the iovec array for the given uio_t.
719 * This returns the location of the iovecs within the uio.
720 * NOTE - for compatibility mode we just return the current value in uio_iovs
721 * which will increase as the IO is completed and is NOT embedded within the
722 * uio, it is a seperate array of one or more iovecs.
723 */
0a7de745
A
724__private_extern__ struct user_iovec *
725uio_iovsaddr( uio_t a_uio )
91447636 726{
0a7de745
A
727 struct user_iovec * my_addr;
728
91447636 729 if (a_uio == NULL) {
0a7de745 730 return NULL;
91447636 731 }
0a7de745 732
b0d623f7 733 if (UIO_SEG_IS_USER_SPACE(a_uio->uio_segflg)) {
91447636 734 /* we need this for compatibility mode. */
b0d623f7 735 my_addr = (struct user_iovec *) a_uio->uio_iovs.uiovp;
0a7de745 736 } else {
b0d623f7
A
737#if DEBUG
738 panic("uio_iovsaddr called for UIO_SYSSPACE request");
739#endif
740 my_addr = 0;
91447636 741 }
0a7de745 742 return my_addr;
91447636
A
743}
744
745/*
746 * uio_reset - reset an uio_t.
0a7de745
A
747 * Reset the given uio_t to initial values. The uio_t is not fully initialized
748 * until all iovecs are added using uio_addiov calls.
749 * The a_iovcount value passed in the uio_create is the maximum number of
91447636
A
750 * iovecs you may add.
751 */
0a7de745
A
752void
753uio_reset( uio_t a_uio,
754 off_t a_offset, /* current offset */
755 int a_spacetype, /* type of address space */
756 int a_iodirection ) /* read or write flag */
91447636 757{
0a7de745
A
758 vm_size_t my_size;
759 int my_max_iovs;
760 u_int32_t my_old_flags;
761
91447636
A
762#if LP64_DEBUG
763 if (a_uio == NULL) {
0a7de745 764 panic("%s :%d - could not allocate uio_t\n", __FILE__, __LINE__);
91447636
A
765 }
766 if (!IS_VALID_UIO_SEGFLG(a_spacetype)) {
0a7de745 767 panic("%s :%d - invalid address space type\n", __FILE__, __LINE__);
91447636
A
768 }
769 if (!(a_iodirection == UIO_READ || a_iodirection == UIO_WRITE)) {
0a7de745 770 panic("%s :%d - invalid IO direction flag\n", __FILE__, __LINE__);
91447636
A
771 }
772#endif /* LP64_DEBUG */
773
774 if (a_uio == NULL) {
775 return;
776 }
777
778 my_size = a_uio->uio_size;
779 my_old_flags = a_uio->uio_flags;
780 my_max_iovs = a_uio->uio_max_iovs;
781 bzero(a_uio, my_size);
f427ee49 782 a_uio->uio_size = (int)my_size;
b0d623f7
A
783
784 /*
785 * we use uio_segflg to indicate if the uio_t is the new format or
786 * old (pre LP64 support) legacy format
787 * This switch statement should canonicalize incoming space type
788 * to one of UIO_USERSPACE32/64, UIO_PHYS_USERSPACE32/64, or
789 * UIO_SYSSPACE/UIO_PHYS_SYSSPACE
790 */
791 switch (a_spacetype) {
792 case UIO_USERSPACE:
793 a_uio->uio_segflg = UIO_USERSPACE32;
794 break;
795 case UIO_SYSSPACE32:
796 a_uio->uio_segflg = UIO_SYSSPACE;
797 break;
798 case UIO_PHYS_USERSPACE:
799 a_uio->uio_segflg = UIO_PHYS_USERSPACE32;
800 break;
801 default:
802 a_uio->uio_segflg = a_spacetype;
803 break;
804 }
805
91447636
A
806 if (my_max_iovs > 0) {
807 a_uio->uio_iovs.uiovp = (struct user_iovec *)
0a7de745
A
808 (((uint8_t *)a_uio) + sizeof(struct uio));
809 } else {
91447636
A
810 a_uio->uio_iovs.uiovp = NULL;
811 }
b0d623f7 812
91447636
A
813 a_uio->uio_max_iovs = my_max_iovs;
814 a_uio->uio_offset = a_offset;
815 a_uio->uio_rw = a_iodirection;
816 a_uio->uio_flags = my_old_flags;
817
818 return;
819}
820
821/*
822 * uio_free - free a uio_t allocated via uio_init. this also frees all
0a7de745 823 * associated iovecs.
91447636 824 */
0a7de745
A
825void
826uio_free( uio_t a_uio )
91447636
A
827{
828#if DEBUG
829 if (a_uio == NULL) {
0a7de745 830 panic("%s :%d - passing NULL uio_t\n", __FILE__, __LINE__);
91447636
A
831 }
832#endif /* LP64_DEBUG */
833
834 if (a_uio != NULL && (a_uio->uio_flags & UIO_FLAGS_WE_ALLOCED) != 0) {
835#if DEBUG
cb323159 836 if (os_atomic_dec_orig(&uio_t_count, relaxed) == 0) {
0a7de745
A
837 panic("%s :%d - uio_t_count underflow\n", __FILE__, __LINE__);
838 }
91447636
A
839#endif
840 kfree(a_uio, a_uio->uio_size);
841 }
91447636
A
842}
843
844/*
845 * uio_addiov - add an iovec to the given uio_t. You may call this up to
0a7de745
A
846 * the a_iovcount number that was passed to uio_create. This call will
847 * increment the residual IO count as iovecs are added to the uio_t.
91447636
A
848 * returns 0 if add was successful else non zero.
849 */
0a7de745
A
850int
851uio_addiov( uio_t a_uio, user_addr_t a_baseaddr, user_size_t a_length )
91447636 852{
cb323159
A
853 int i;
854 user_size_t resid;
0a7de745 855
91447636
A
856 if (a_uio == NULL) {
857#if DEBUG
0a7de745 858 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
cb323159
A
859#endif
860 return -1;
861 }
862
863 if (os_add_overflow(a_length, a_uio->uio_resid_64, &resid)) {
864#if DEBUG
865 panic("%s :%d - invalid length %lu\n", __FILE__, __LINE__, (unsigned long)a_length);
866#endif
0a7de745 867 return -1;
91447636
A
868 }
869
b0d623f7 870 if (UIO_IS_USER_SPACE(a_uio)) {
0a7de745 871 for (i = 0; i < a_uio->uio_max_iovs; i++) {
91447636
A
872 if (a_uio->uio_iovs.uiovp[i].iov_len == 0 && a_uio->uio_iovs.uiovp[i].iov_base == 0) {
873 a_uio->uio_iovs.uiovp[i].iov_len = a_length;
874 a_uio->uio_iovs.uiovp[i].iov_base = a_baseaddr;
875 a_uio->uio_iovcnt++;
cb323159 876 a_uio->uio_resid_64 = resid;
0a7de745 877 return 0;
91447636
A
878 }
879 }
0a7de745
A
880 } else {
881 for (i = 0; i < a_uio->uio_max_iovs; i++) {
91447636 882 if (a_uio->uio_iovs.kiovp[i].iov_len == 0 && a_uio->uio_iovs.kiovp[i].iov_base == 0) {
b0d623f7
A
883 a_uio->uio_iovs.kiovp[i].iov_len = (u_int64_t)a_length;
884 a_uio->uio_iovs.kiovp[i].iov_base = (u_int64_t)a_baseaddr;
91447636 885 a_uio->uio_iovcnt++;
cb323159 886 a_uio->uio_resid_64 = resid;
0a7de745 887 return 0;
91447636
A
888 }
889 }
890 }
891
0a7de745 892 return -1;
91447636
A
893}
894
895/*
896 * uio_getiov - get iovec data associated with the given uio_t. Use
897 * a_index to iterate over each iovec (0 to (uio_iovcnt(uio_t) - 1)).
898 * a_baseaddr_p and a_length_p may be NULL.
0a7de745 899 * returns -1 when a_index is >= uio_t.uio_iovcnt or invalid uio_t.
91447636
A
900 * returns 0 when data is returned.
901 */
0a7de745
A
902int
903uio_getiov( uio_t a_uio,
904 int a_index,
905 user_addr_t * a_baseaddr_p,
906 user_size_t * a_length_p )
91447636
A
907{
908 if (a_uio == NULL) {
909#if DEBUG
0a7de745 910 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
91447636 911#endif /* DEBUG */
0a7de745
A
912 return -1;
913 }
914 if (a_index < 0 || a_index >= a_uio->uio_iovcnt) {
915 return -1;
91447636 916 }
91447636 917
b0d623f7 918 if (UIO_IS_USER_SPACE(a_uio)) {
0a7de745
A
919 if (a_baseaddr_p != NULL) {
920 *a_baseaddr_p = a_uio->uio_iovs.uiovp[a_index].iov_base;
921 }
922 if (a_length_p != NULL) {
923 *a_length_p = a_uio->uio_iovs.uiovp[a_index].iov_len;
924 }
925 } else {
926 if (a_baseaddr_p != NULL) {
f427ee49 927 *a_baseaddr_p = (user_addr_t)a_uio->uio_iovs.kiovp[a_index].iov_base;
0a7de745
A
928 }
929 if (a_length_p != NULL) {
f427ee49 930 *a_length_p = (user_size_t)a_uio->uio_iovs.kiovp[a_index].iov_len;
0a7de745
A
931 }
932 }
933
934 return 0;
91447636
A
935}
936
937/*
938 * uio_calculateresid - runs through all iovecs associated with this
939 * uio_t and calculates (and sets) the residual IO count.
940 */
0a7de745
A
941__private_extern__ int
942uio_calculateresid( uio_t a_uio )
91447636 943{
0a7de745
A
944 int i;
945 u_int64_t resid = 0;
946
91447636
A
947 if (a_uio == NULL) {
948#if LP64_DEBUG
0a7de745 949 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
91447636 950#endif /* LP64_DEBUG */
39236c6e 951 return EINVAL;
91447636
A
952 }
953
743b1565 954 a_uio->uio_iovcnt = a_uio->uio_max_iovs;
b0d623f7 955 if (UIO_IS_USER_SPACE(a_uio)) {
91447636 956 a_uio->uio_resid_64 = 0;
0a7de745 957 for (i = 0; i < a_uio->uio_max_iovs; i++) {
91447636 958 if (a_uio->uio_iovs.uiovp[i].iov_len != 0 && a_uio->uio_iovs.uiovp[i].iov_base != 0) {
0a7de745
A
959 if (a_uio->uio_iovs.uiovp[i].iov_len > LONG_MAX) {
960 return EINVAL;
961 }
39236c6e 962 resid += a_uio->uio_iovs.uiovp[i].iov_len;
0a7de745 963 if (resid > LONG_MAX) {
39236c6e 964 return EINVAL;
0a7de745 965 }
91447636
A
966 }
967 }
f427ee49 968 a_uio->uio_resid_64 = (user_size_t)resid;
743b1565
A
969
970 /* position to first non zero length iovec (4235922) */
971 while (a_uio->uio_iovcnt > 0 && a_uio->uio_iovs.uiovp->iov_len == 0) {
972 a_uio->uio_iovcnt--;
973 if (a_uio->uio_iovcnt > 0) {
974 a_uio->uio_iovs.uiovp++;
975 }
976 }
0a7de745 977 } else {
b0d623f7 978 a_uio->uio_resid_64 = 0;
0a7de745 979 for (i = 0; i < a_uio->uio_max_iovs; i++) {
91447636 980 if (a_uio->uio_iovs.kiovp[i].iov_len != 0 && a_uio->uio_iovs.kiovp[i].iov_base != 0) {
0a7de745 981 if (a_uio->uio_iovs.kiovp[i].iov_len > LONG_MAX) {
39236c6e 982 return EINVAL;
0a7de745 983 }
39236c6e 984 resid += a_uio->uio_iovs.kiovp[i].iov_len;
0a7de745 985 if (resid > LONG_MAX) {
39236c6e 986 return EINVAL;
0a7de745 987 }
91447636
A
988 }
989 }
f427ee49 990 a_uio->uio_resid_64 = (user_size_t)resid;
743b1565
A
991
992 /* position to first non zero length iovec (4235922) */
993 while (a_uio->uio_iovcnt > 0 && a_uio->uio_iovs.kiovp->iov_len == 0) {
994 a_uio->uio_iovcnt--;
995 if (a_uio->uio_iovcnt > 0) {
996 a_uio->uio_iovs.kiovp++;
997 }
998 }
91447636 999 }
743b1565 1000
39236c6e 1001 return 0;
91447636
A
1002}
1003
1004/*
1005 * uio_update - update the given uio_t for a_count of completed IO.
1006 * This call decrements the current iovec length and residual IO value
0a7de745 1007 * and increments the current iovec base address and offset value.
91447636
A
1008 * If the current iovec length is 0 then advance to the next
1009 * iovec (if any).
0a7de745 1010 * If the a_count passed in is 0, than only do the advancement
cc9f6e38 1011 * over any 0 length iovec's.
91447636 1012 */
0a7de745
A
1013void
1014uio_update( uio_t a_uio, user_size_t a_count )
91447636
A
1015{
1016#if LP64_DEBUG
1017 if (a_uio == NULL) {
0a7de745 1018 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
91447636
A
1019 }
1020 if (UIO_IS_32_BIT_SPACE(a_uio) && a_count > 0xFFFFFFFFull) {
0a7de745 1021 panic("%s :%d - invalid count value \n", __FILE__, __LINE__);
91447636
A
1022 }
1023#endif /* LP64_DEBUG */
1024
1025 if (a_uio == NULL || a_uio->uio_iovcnt < 1) {
1026 return;
1027 }
1028
b0d623f7 1029 if (UIO_IS_USER_SPACE(a_uio)) {
0a7de745 1030 /*
cc9f6e38
A
1031 * if a_count == 0, then we are asking to skip over
1032 * any empty iovs
1033 */
0a7de745
A
1034 if (a_count) {
1035 if (a_count > a_uio->uio_iovs.uiovp->iov_len) {
1036 a_uio->uio_iovs.uiovp->iov_base += a_uio->uio_iovs.uiovp->iov_len;
cc9f6e38 1037 a_uio->uio_iovs.uiovp->iov_len = 0;
0a7de745 1038 } else {
b0d623f7 1039 a_uio->uio_iovs.uiovp->iov_base += a_count;
cc9f6e38
A
1040 a_uio->uio_iovs.uiovp->iov_len -= a_count;
1041 }
cc9f6e38 1042 if (a_count > (user_size_t)a_uio->uio_resid_64) {
b0d623f7 1043 a_uio->uio_offset += a_uio->uio_resid_64;
cc9f6e38 1044 a_uio->uio_resid_64 = 0;
0a7de745 1045 } else {
b0d623f7 1046 a_uio->uio_offset += a_count;
cc9f6e38
A
1047 a_uio->uio_resid_64 -= a_count;
1048 }
cc9f6e38
A
1049 }
1050 /*
1051 * advance to next iovec if current one is totally consumed
1052 */
1053 while (a_uio->uio_iovcnt > 0 && a_uio->uio_iovs.uiovp->iov_len == 0) {
91447636
A
1054 a_uio->uio_iovcnt--;
1055 if (a_uio->uio_iovcnt > 0) {
1056 a_uio->uio_iovs.uiovp++;
1057 }
1058 }
0a7de745
A
1059 } else {
1060 /*
cc9f6e38
A
1061 * if a_count == 0, then we are asking to skip over
1062 * any empty iovs
1063 */
0a7de745
A
1064 if (a_count) {
1065 if (a_count > a_uio->uio_iovs.kiovp->iov_len) {
1066 a_uio->uio_iovs.kiovp->iov_base += a_uio->uio_iovs.kiovp->iov_len;
cc9f6e38 1067 a_uio->uio_iovs.kiovp->iov_len = 0;
0a7de745
A
1068 } else {
1069 a_uio->uio_iovs.kiovp->iov_base += a_count;
cc9f6e38
A
1070 a_uio->uio_iovs.kiovp->iov_len -= a_count;
1071 }
b0d623f7
A
1072 if (a_count > (user_size_t)a_uio->uio_resid_64) {
1073 a_uio->uio_offset += a_uio->uio_resid_64;
1074 a_uio->uio_resid_64 = 0;
0a7de745 1075 } else {
b0d623f7
A
1076 a_uio->uio_offset += a_count;
1077 a_uio->uio_resid_64 -= a_count;
cc9f6e38 1078 }
91447636 1079 }
cc9f6e38
A
1080 /*
1081 * advance to next iovec if current one is totally consumed
1082 */
1083 while (a_uio->uio_iovcnt > 0 && a_uio->uio_iovs.kiovp->iov_len == 0) {
91447636
A
1084 a_uio->uio_iovcnt--;
1085 if (a_uio->uio_iovcnt > 0) {
1086 a_uio->uio_iovs.kiovp++;
1087 }
1088 }
1089 }
1090 return;
1091}
1092
b0d623f7
A
1093/*
1094 * uio_pushback - undo uncommitted I/O by subtracting from the
1095 * current base address and offset, and incrementing the residiual
1096 * IO. If the UIO was previously exhausted, this call will panic.
1097 * New code should not use this functionality.
1098 */
0a7de745
A
1099__private_extern__ void
1100uio_pushback( uio_t a_uio, user_size_t a_count )
b0d623f7
A
1101{
1102#if LP64_DEBUG
1103 if (a_uio == NULL) {
0a7de745 1104 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
b0d623f7
A
1105 }
1106 if (UIO_IS_32_BIT_SPACE(a_uio) && a_count > 0xFFFFFFFFull) {
0a7de745 1107 panic("%s :%d - invalid count value \n", __FILE__, __LINE__);
b0d623f7
A
1108 }
1109#endif /* LP64_DEBUG */
1110
1111 if (a_uio == NULL || a_count == 0) {
1112 return;
1113 }
1114
1115 if (a_uio->uio_iovcnt < 1) {
1116 panic("Invalid uio for pushback");
1117 }
1118
1119 if (UIO_IS_USER_SPACE(a_uio)) {
1120 a_uio->uio_iovs.uiovp->iov_base -= a_count;
1121 a_uio->uio_iovs.uiovp->iov_len += a_count;
0a7de745 1122 } else {
b0d623f7
A
1123 a_uio->uio_iovs.kiovp->iov_base -= a_count;
1124 a_uio->uio_iovs.kiovp->iov_len += a_count;
1125 }
1126
1127 a_uio->uio_offset -= a_count;
1128 a_uio->uio_resid_64 += a_count;
1129
1130 return;
1131}
1132
91447636
A
1133
1134/*
1135 * uio_duplicate - allocate a new uio and make a copy of the given uio_t.
1136 * may return NULL.
1137 */
0a7de745
A
1138uio_t
1139uio_duplicate( uio_t a_uio )
91447636 1140{
0a7de745
A
1141 uio_t my_uio;
1142 int i;
91447636
A
1143
1144 if (a_uio == NULL) {
0a7de745 1145 return NULL;
91447636 1146 }
0a7de745 1147
91447636
A
1148 my_uio = (uio_t) kalloc(a_uio->uio_size);
1149 if (my_uio == 0) {
0a7de745 1150 panic("%s :%d - allocation failed\n", __FILE__, __LINE__);
91447636 1151 }
0a7de745 1152
91447636
A
1153 bcopy((void *)a_uio, (void *)my_uio, a_uio->uio_size);
1154 /* need to set our iovec pointer to point to first active iovec */
1155 if (my_uio->uio_max_iovs > 0) {
1156 my_uio->uio_iovs.uiovp = (struct user_iovec *)
0a7de745 1157 (((uint8_t *)my_uio) + sizeof(struct uio));
91447636
A
1158
1159 /* advance to first nonzero iovec */
1160 if (my_uio->uio_iovcnt > 0) {
0a7de745 1161 for (i = 0; i < my_uio->uio_max_iovs; i++) {
b0d623f7 1162 if (UIO_IS_USER_SPACE(a_uio)) {
91447636
A
1163 if (my_uio->uio_iovs.uiovp->iov_len != 0) {
1164 break;
1165 }
1166 my_uio->uio_iovs.uiovp++;
0a7de745 1167 } else {
91447636
A
1168 if (my_uio->uio_iovs.kiovp->iov_len != 0) {
1169 break;
1170 }
1171 my_uio->uio_iovs.kiovp++;
1172 }
1173 }
1174 }
1175 }
1176
2d21ac55 1177 my_uio->uio_flags = UIO_FLAGS_WE_ALLOCED | UIO_FLAGS_INITED;
39236c6e 1178#if DEBUG
cb323159 1179 os_atomic_inc(&uio_t_count, relaxed);
39236c6e
A
1180#endif
1181
2d21ac55 1182
0a7de745 1183 return my_uio;
91447636
A
1184}
1185
0a7de745
A
1186int
1187copyin_user_iovec_array(user_addr_t uaddr, int spacetype, int count, struct user_iovec *dst)
b0d623f7 1188{
0a7de745 1189 size_t size_of_iovec = (spacetype == UIO_USERSPACE64 ? sizeof(struct user64_iovec) : sizeof(struct user32_iovec));
b0d623f7
A
1190 int error;
1191 int i;
1192
1193 // copyin to the front of "dst", without regard for putting records in the right places
1194 error = copyin(uaddr, dst, count * size_of_iovec);
0a7de745
A
1195 if (error) {
1196 return error;
1197 }
b0d623f7
A
1198
1199 // now, unpack the entries in reverse order, so we don't overwrite anything
1200 for (i = count - 1; i >= 0; i--) {
1201 if (spacetype == UIO_USERSPACE64) {
1202 struct user64_iovec iovec = ((struct user64_iovec *)dst)[i];
f427ee49
A
1203 dst[i].iov_base = (user_addr_t)iovec.iov_base;
1204 dst[i].iov_len = (user_size_t)iovec.iov_len;
b0d623f7
A
1205 } else {
1206 struct user32_iovec iovec = ((struct user32_iovec *)dst)[i];
1207 dst[i].iov_base = iovec.iov_base;
0a7de745 1208 dst[i].iov_len = iovec.iov_len;
b0d623f7
A
1209 }
1210 }
1211
0a7de745 1212 return 0;
b0d623f7 1213}