]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_subr.c
xnu-1228.tar.gz
[apple/xnu.git] / bsd / kern / kern_subr.c
1 /*
2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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
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>
74 #include <vm/pmap.h>
75 #include <sys/uio_internal.h>
76 #include <kern/kalloc.h>
77
78 #include <kdebug.h>
79
80 #include <sys/kdebug.h>
81 #define DBG_UIO_COPYOUT 16
82 #define DBG_UIO_COPYIN 17
83
84 #if DEBUG
85 #include <kern/simple_lock.h>
86
87 static uint32_t uio_t_count = 0;
88 #endif /* DEBUG */
89
90
91 /*
92 * Returns: 0 Success
93 * uiomove64:EFAULT
94 *
95 * Notes: The first argument should be a caddr_t, but const poisoning
96 * for typedef'ed types doesn't work in gcc.
97 */
98 int
99 uiomove(const char * cp, int n, uio_t uio)
100 {
101 return uiomove64((const addr64_t)((const unsigned int)cp), n, uio);
102 }
103
104 /*
105 * Returns: 0 Success
106 * EFAULT
107 * copyout:EFAULT
108 * copyin:EFAULT
109 * copywithin:EFAULT
110 * copypv:EFAULT
111 */
112 // LP64todo - fix this! 'n' should be int64_t?
113 int
114 uiomove64(const addr64_t c_cp, int n, struct uio *uio)
115 {
116 addr64_t cp = c_cp;
117 #if LP64KERN
118 uint64_t acnt;
119 #else
120 u_int acnt;
121 #endif
122 int error = 0;
123
124 #if DIAGNOSTIC
125 if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE)
126 panic("uiomove: mode");
127 #endif
128
129 #if LP64_DEBUG
130 if (IS_VALID_UIO_SEGFLG(uio->uio_segflg) == 0) {
131 panic("%s :%d - invalid uio_segflg\n", __FILE__, __LINE__);
132 }
133 #endif /* LP64_DEBUG */
134
135 while (n > 0 && uio_resid(uio)) {
136 acnt = uio_iov_len(uio);
137 if (acnt == 0) {
138 uio_next_iov(uio);
139 uio->uio_iovcnt--;
140 continue;
141 }
142 if (n > 0 && acnt > (uint64_t)n)
143 acnt = n;
144
145 switch (uio->uio_segflg) {
146
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)
151 {
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);
154
155 error = copyout( CAST_DOWN(caddr_t, cp), uio->uio_iovs.iov64p->iov_base, acnt );
156
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);
159 }
160 else
161 {
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);
164
165 error = copyin(uio->uio_iovs.iov64p->iov_base, CAST_DOWN(caddr_t, cp), acnt);
166
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);
169 }
170 if (error)
171 return (error);
172 break;
173
174 case UIO_USERSPACE32:
175 case UIO_USERISPACE32:
176 case UIO_USERSPACE:
177 case UIO_USERISPACE:
178 if (uio->uio_rw == UIO_READ)
179 {
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);
182
183 error = copyout( CAST_DOWN(caddr_t, cp), CAST_USER_ADDR_T(uio->uio_iovs.iov32p->iov_base), acnt );
184
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);
187 }
188 else
189 {
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);
192
193 error = copyin(CAST_USER_ADDR_T(uio->uio_iovs.iov32p->iov_base), CAST_DOWN(caddr_t, cp), acnt);
194
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);
197 }
198 if (error)
199 return (error);
200 break;
201
202 case UIO_SYSSPACE32:
203 case UIO_SYSSPACE:
204 if (uio->uio_rw == UIO_READ)
205 error = copywithin(CAST_DOWN(caddr_t, cp), (caddr_t)uio->uio_iovs.iov32p->iov_base,
206 acnt);
207 else
208 error = copywithin((caddr_t)uio->uio_iovs.iov32p->iov_base, CAST_DOWN(caddr_t, cp),
209 acnt);
210 break;
211
212 case UIO_PHYS_USERSPACE64:
213 if (uio->uio_rw == UIO_READ)
214 {
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);
217
218 error = copypv((addr64_t)cp, uio->uio_iovs.iov64p->iov_base, acnt, cppvPsrc | cppvNoRefSrc);
219 if (error) /* Copy physical to virtual */
220 error = EFAULT;
221
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);
224 }
225 else
226 {
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);
229
230 error = copypv(uio->uio_iovs.iov64p->iov_base, (addr64_t)cp, acnt, cppvPsnk | cppvNoRefSrc | cppvNoModSnk);
231 if (error) /* Copy virtual to physical */
232 error = EFAULT;
233
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);
236 }
237 if (error)
238 return (error);
239 break;
240
241 case UIO_PHYS_USERSPACE32:
242 case UIO_PHYS_USERSPACE:
243 if (uio->uio_rw == UIO_READ)
244 {
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);
247
248 error = copypv((addr64_t)cp, (addr64_t)uio->uio_iovs.iov32p->iov_base, acnt, cppvPsrc | cppvNoRefSrc);
249 if (error) /* Copy physical to virtual */
250 error = EFAULT;
251
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);
254 }
255 else
256 {
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);
259
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 */
262 error = EFAULT;
263
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);
266 }
267 if (error)
268 return (error);
269 break;
270
271 case UIO_PHYS_SYSSPACE32:
272 case UIO_PHYS_SYSSPACE:
273 if (uio->uio_rw == UIO_READ)
274 {
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);
277
278 error = copypv((addr64_t)cp, uio->uio_iovs.iov32p->iov_base, acnt, cppvKmap | cppvPsrc | cppvNoRefSrc);
279 if (error) /* Copy physical to virtual */
280 error = EFAULT;
281
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);
284 }
285 else
286 {
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);
289
290 error = copypv(uio->uio_iovs.iov32p->iov_base, (addr64_t)cp, acnt, cppvKmap | cppvPsnk | cppvNoRefSrc | cppvNoModSnk);
291 if (error) /* Copy virtual to physical */
292 error = EFAULT;
293
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);
296 }
297 if (error)
298 return (error);
299 break;
300
301 default:
302 break;
303 }
304 uio_iov_base_add(uio, acnt);
305 #if LP64KERN
306 uio_iov_len_add(uio, -((int64_t)acnt));
307 uio_setresid(uio, (uio_resid(uio) - ((int64_t)acnt)));
308 #else
309 uio_iov_len_add(uio, -((int)acnt));
310 uio_setresid(uio, (uio_resid(uio) - ((int)acnt)));
311 #endif
312 uio->uio_offset += acnt;
313 cp += acnt;
314 n -= acnt;
315 }
316 return (error);
317 }
318
319 /*
320 * Give next character to user as result of read.
321 */
322 int
323 ureadc(int c, struct uio *uio)
324 {
325 if (uio_resid(uio) <= 0)
326 panic("ureadc: non-positive resid");
327 again:
328 if (uio->uio_iovcnt == 0)
329 panic("ureadc: non-positive iovcnt");
330 if (uio_iov_len(uio) <= 0) {
331 uio->uio_iovcnt--;
332 uio_next_iov(uio);
333 goto again;
334 }
335 switch (uio->uio_segflg) {
336
337 case UIO_USERSPACE32:
338 case UIO_USERSPACE:
339 if (subyte(CAST_USER_ADDR_T(uio->uio_iovs.iov32p->iov_base), c) < 0)
340 return (EFAULT);
341 break;
342
343 case UIO_USERSPACE64:
344 if (subyte((user_addr_t)uio->uio_iovs.iov64p->iov_base, c) < 0)
345 return (EFAULT);
346 break;
347
348 case UIO_SYSSPACE32:
349 case UIO_SYSSPACE:
350 *((caddr_t)uio->uio_iovs.iov32p->iov_base) = c;
351 break;
352
353 case UIO_USERISPACE32:
354 case UIO_USERISPACE:
355 if (suibyte(CAST_USER_ADDR_T(uio->uio_iovs.iov32p->iov_base), c) < 0)
356 return (EFAULT);
357 break;
358
359 default:
360 break;
361 }
362 uio_iov_base_add(uio, 1);
363 uio_iov_len_add(uio, -1);
364 uio_setresid(uio, (uio_resid(uio) - 1));
365 uio->uio_offset++;
366 return (0);
367 }
368
369 #if defined(vax) || defined(ppc)
370 /* unused except by ct.c, other oddities XXX */
371 /*
372 * Get next character written in by user from uio.
373 */
374 int
375 uwritec(uio_t uio)
376 {
377 int c = 0;
378
379 if (uio_resid(uio) <= 0)
380 return (-1);
381 again:
382 if (uio->uio_iovcnt <= 0)
383 panic("uwritec: non-positive iovcnt");
384
385 if (uio_iov_len(uio) == 0) {
386 uio_next_iov(uio);
387 if (--uio->uio_iovcnt == 0)
388 return (-1);
389 goto again;
390 }
391 switch (uio->uio_segflg) {
392
393 case UIO_USERSPACE32:
394 case UIO_USERSPACE:
395 c = fubyte(CAST_USER_ADDR_T(uio->uio_iovs.iov32p->iov_base));
396 break;
397
398 case UIO_USERSPACE64:
399 c = fubyte((user_addr_t)uio->uio_iovs.iov64p->iov_base);
400 break;
401
402 case UIO_SYSSPACE32:
403 case UIO_SYSSPACE:
404 c = *((caddr_t)uio->uio_iovs.iov32p->iov_base) & 0377;
405 break;
406
407 case UIO_USERISPACE32:
408 case UIO_USERISPACE:
409 c = fuibyte(CAST_USER_ADDR_T(uio->uio_iovs.iov32p->iov_base));
410 break;
411
412 default:
413 c = 0; /* avoid uninitialized variable warning */
414 panic("uwritec: bogus uio_segflg");
415 break;
416 }
417 if (c < 0)
418 return (-1);
419 uio_iov_base_add(uio, 1);
420 uio_iov_len_add(uio, -1);
421 uio_setresid(uio, (uio_resid(uio) - 1));
422 uio->uio_offset++;
423 return (c);
424 }
425 #endif /* vax || ppc */
426
427 /*
428 * General routine to allocate a hash table.
429 */
430 void *
431 hashinit(int elements, int type, u_long *hashmask)
432 {
433 long hashsize;
434 LIST_HEAD(generic, generic) *hashtbl;
435 int i;
436
437 if (elements <= 0)
438 panic("hashinit: bad cnt");
439 for (hashsize = 1; hashsize <= elements; hashsize <<= 1)
440 continue;
441 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;
448 }
449 return (hashtbl);
450 }
451
452 /*
453 * uio_resid - return the residual IO value for the given uio_t
454 */
455 user_ssize_t uio_resid( uio_t a_uio )
456 {
457 #if DEBUG
458 if (a_uio == NULL) {
459 printf("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
460 }
461 /* if (IS_VALID_UIO_SEGFLG(a_uio->uio_segflg) == 0) { */
462 /* panic("%s :%d - invalid uio_segflg\n", __FILE__, __LINE__); */
463 /* } */
464 #endif /* DEBUG */
465
466 /* return 0 if there are no active iovecs */
467 if (a_uio == NULL) {
468 return( 0 );
469 }
470
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 );
474 #else
475 return( a_uio->uio_resid_64 );
476 #endif
477 }
478 return( (user_ssize_t)a_uio->uio_resid );
479 }
480
481 /*
482 * uio_setresid - set the residual IO value for the given uio_t
483 */
484 void uio_setresid( uio_t a_uio, user_ssize_t a_value )
485 {
486 #if DEBUG
487 if (a_uio == NULL) {
488 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
489 }
490 /* if (IS_VALID_UIO_SEGFLG(a_uio->uio_segflg) == 0) { */
491 /* panic("%s :%d - invalid uio_segflg\n", __FILE__, __LINE__); */
492 /* } */
493 #endif /* DEBUG */
494
495 if (a_uio == NULL) {
496 return;
497 }
498
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;
502 #else
503 a_uio->uio_resid_64 = a_value;
504 #endif
505 }
506 else {
507 a_uio->uio_resid = (int)a_value;
508 }
509 return;
510 }
511
512 /*
513 * uio_curriovbase - return the base address of the current iovec associated
514 * with the given uio_t. May return 0.
515 */
516 user_addr_t uio_curriovbase( uio_t a_uio )
517 {
518 #if LP64_DEBUG
519 if (a_uio == NULL) {
520 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
521 }
522 #endif /* LP64_DEBUG */
523
524 if (a_uio == NULL || a_uio->uio_iovcnt < 1) {
525 return(0);
526 }
527
528 if (UIO_IS_64_BIT_SPACE(a_uio)) {
529 return(a_uio->uio_iovs.uiovp->iov_base);
530 }
531 return((user_addr_t)((uintptr_t)a_uio->uio_iovs.kiovp->iov_base));
532
533 }
534
535 /*
536 * uio_curriovlen - return the length value of the current iovec associated
537 * with the given uio_t.
538 */
539 user_size_t uio_curriovlen( uio_t a_uio )
540 {
541 #if LP64_DEBUG
542 if (a_uio == NULL) {
543 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
544 }
545 #endif /* LP64_DEBUG */
546
547 if (a_uio == NULL || a_uio->uio_iovcnt < 1) {
548 return(0);
549 }
550
551 if (UIO_IS_64_BIT_SPACE(a_uio)) {
552 return(a_uio->uio_iovs.uiovp->iov_len);
553 }
554 return((user_size_t)a_uio->uio_iovs.kiovp->iov_len);
555 }
556
557 /*
558 * uio_setcurriovlen - set the length value of the current iovec associated
559 * with the given uio_t.
560 */
561 __private_extern__ void uio_setcurriovlen( uio_t a_uio, user_size_t a_value )
562 {
563 #if LP64_DEBUG
564 if (a_uio == NULL) {
565 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
566 }
567 #endif /* LP64_DEBUG */
568
569 if (a_uio == NULL) {
570 return;
571 }
572
573 if (UIO_IS_64_BIT_SPACE(a_uio)) {
574 a_uio->uio_iovs.uiovp->iov_len = a_value;
575 }
576 else {
577 #if LP64_DEBUG
578 if (a_value > 0xFFFFFFFFull) {
579 panic("%s :%d - invalid a_value\n", __FILE__, __LINE__);
580 }
581 #endif /* LP64_DEBUG */
582 a_uio->uio_iovs.kiovp->iov_len = (size_t)a_value;
583 }
584 return;
585 }
586
587 /*
588 * uio_iovcnt - return count of active iovecs for the given uio_t
589 */
590 int uio_iovcnt( uio_t a_uio )
591 {
592 #if LP64_DEBUG
593 if (a_uio == NULL) {
594 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
595 }
596 #endif /* LP64_DEBUG */
597
598 if (a_uio == NULL) {
599 return(0);
600 }
601
602 return( a_uio->uio_iovcnt );
603 }
604
605 /*
606 * uio_offset - return the current offset value for the given uio_t
607 */
608 off_t uio_offset( uio_t a_uio )
609 {
610 #if LP64_DEBUG
611 if (a_uio == NULL) {
612 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
613 }
614 #endif /* LP64_DEBUG */
615
616 if (a_uio == NULL) {
617 return(0);
618 }
619 return( a_uio->uio_offset );
620 }
621
622 /*
623 * uio_setoffset - set the current offset value for the given uio_t
624 */
625 void uio_setoffset( uio_t a_uio, off_t a_offset )
626 {
627 #if LP64_DEBUG
628 if (a_uio == NULL) {
629 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
630 }
631 #endif /* LP64_DEBUG */
632
633 if (a_uio == NULL) {
634 return;
635 }
636 a_uio->uio_offset = a_offset;
637 return;
638 }
639
640 /*
641 * uio_rw - return the read / write flag for the given uio_t
642 */
643 int uio_rw( uio_t a_uio )
644 {
645 #if LP64_DEBUG
646 if (a_uio == NULL) {
647 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
648 }
649 #endif /* LP64_DEBUG */
650
651 if (a_uio == NULL) {
652 return(-1);
653 }
654 return( a_uio->uio_rw );
655 }
656
657 /*
658 * uio_setrw - set the read / write flag for the given uio_t
659 */
660 void uio_setrw( uio_t a_uio, int a_value )
661 {
662 if (a_uio == NULL) {
663 #if LP64_DEBUG
664 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
665 #endif /* LP64_DEBUG */
666 return;
667 }
668
669 #if LP64_DEBUG
670 if (!(a_value == UIO_READ || a_value == UIO_WRITE)) {
671 panic("%s :%d - invalid a_value\n", __FILE__, __LINE__);
672 }
673 #endif /* LP64_DEBUG */
674
675 if (a_value == UIO_READ || a_value == UIO_WRITE) {
676 a_uio->uio_rw = a_value;
677 }
678 return;
679 }
680
681 /*
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).
684 */
685 int uio_isuserspace( uio_t a_uio )
686 {
687 if (a_uio == NULL) {
688 #if LP64_DEBUG
689 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
690 #endif /* LP64_DEBUG */
691 return(0);
692 }
693
694 if (UIO_SEG_IS_USER_SPACE(a_uio->uio_segflg)) {
695 return( 1 );
696 }
697 return( 0 );
698 }
699
700
701 /*
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.
706 */
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 */
711 {
712 void * my_buf_p;
713 int my_size;
714 uio_t my_uio;
715
716 my_size = UIO_SIZEOF(a_iovcount);
717 my_buf_p = kalloc(my_size);
718 my_uio = uio_createwithbuffer( a_iovcount,
719 a_offset,
720 a_spacetype,
721 a_iodirection,
722 my_buf_p,
723 my_size );
724 if (my_uio != 0) {
725 /* leave a note that we allocated this uio_t */
726 my_uio->uio_flags |= UIO_FLAGS_WE_ALLOCED;
727 #if DEBUG
728 (void)hw_atomic_add(&uio_t_count, 1);
729 #endif
730 }
731
732 return( my_uio );
733 }
734
735
736 /*
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.
742 */
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 */
750 {
751 uio_t my_uio = (uio_t) a_buf_p;
752 int my_size;
753
754 my_size = sizeof(struct uio) + (sizeof(struct user_iovec) * a_iovcount);
755 if (a_buffer_size < my_size) {
756 #if DEBUG
757 panic("%s :%d - a_buffer_size is too small\n", __FILE__, __LINE__);
758 #endif /* DEBUG */
759 return( NULL );
760 }
761 my_size = a_buffer_size;
762
763 #if DEBUG
764 if (my_uio == 0) {
765 panic("%s :%d - could not allocate uio_t\n", __FILE__, __LINE__);
766 }
767 if (!IS_VALID_UIO_SEGFLG(a_spacetype)) {
768 panic("%s :%d - invalid address space type\n", __FILE__, __LINE__);
769 }
770 if (!(a_iodirection == UIO_READ || a_iodirection == UIO_WRITE)) {
771 panic("%s :%d - invalid IO direction flag\n", __FILE__, __LINE__);
772 }
773 if (a_iovcount > UIO_MAXIOV) {
774 panic("%s :%d - invalid a_iovcount\n", __FILE__, __LINE__);
775 }
776 #endif /* DEBUG */
777
778 bzero(my_uio, my_size);
779 my_uio->uio_size = my_size;
780
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) {
784 case UIO_USERSPACE:
785 my_uio->uio_segflg = UIO_USERSPACE32;
786 case UIO_SYSSPACE:
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;
792 default:
793 my_uio->uio_segflg = a_spacetype;
794 break;
795 }
796
797 if (a_iovcount > 0) {
798 my_uio->uio_iovs.uiovp = (struct user_iovec *)
799 (((uint8_t *)my_uio) + sizeof(struct uio));
800 }
801 else {
802 my_uio->uio_iovs.uiovp = NULL;
803 }
804
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;
809
810 return( my_uio );
811 }
812
813 /*
814 * uio_spacetype - return the address space type for the given uio_t
815 */
816 int uio_spacetype( uio_t a_uio )
817 {
818 if (a_uio == NULL) {
819 #if LP64_DEBUG
820 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
821 #endif /* LP64_DEBUG */
822 return(-1);
823 }
824
825 return( a_uio->uio_segflg );
826 }
827
828 /*
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.
834 */
835 struct user_iovec * uio_iovsaddr( uio_t a_uio )
836 {
837 struct user_iovec * my_addr;
838
839 if (a_uio == NULL) {
840 return(NULL);
841 }
842
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;
846 }
847 else {
848 my_addr = (struct user_iovec *) (((uint8_t *)a_uio) + sizeof(struct uio));
849 }
850 return(my_addr);
851 }
852
853 /*
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.
859 */
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 */
864 {
865 vm_size_t my_size;
866 int my_max_iovs;
867 u_int32_t my_old_flags;
868
869 #if LP64_DEBUG
870 if (a_uio == NULL) {
871 panic("%s :%d - could not allocate uio_t\n", __FILE__, __LINE__);
872 }
873 if (!IS_VALID_UIO_SEGFLG(a_spacetype)) {
874 panic("%s :%d - invalid address space type\n", __FILE__, __LINE__);
875 }
876 if (!(a_iodirection == UIO_READ || a_iodirection == UIO_WRITE)) {
877 panic("%s :%d - invalid IO direction flag\n", __FILE__, __LINE__);
878 }
879 #endif /* LP64_DEBUG */
880
881 if (a_uio == NULL) {
882 return;
883 }
884
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));
894 }
895 else {
896 a_uio->uio_iovs.uiovp = NULL;
897 }
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;
902
903 return;
904 }
905
906 /*
907 * uio_free - free a uio_t allocated via uio_init. this also frees all
908 * associated iovecs.
909 */
910 void uio_free( uio_t a_uio )
911 {
912 #if DEBUG
913 if (a_uio == NULL) {
914 panic("%s :%d - passing NULL uio_t\n", __FILE__, __LINE__);
915 }
916 #endif /* LP64_DEBUG */
917
918 if (a_uio != NULL && (a_uio->uio_flags & UIO_FLAGS_WE_ALLOCED) != 0) {
919 #if DEBUG
920 if (hw_atomic_sub(&uio_t_count, 1) == UINT_MAX)
921 panic("%s :%d - uio_t_count underflow\n", __FILE__, __LINE__);
922 #endif
923 kfree(a_uio, a_uio->uio_size);
924 }
925
926
927 }
928
929 /*
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.
934 */
935 int uio_addiov( uio_t a_uio, user_addr_t a_baseaddr, user_size_t a_length )
936 {
937 int i;
938
939 if (a_uio == NULL) {
940 #if DEBUG
941 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
942 #endif /* LP64_DEBUG */
943 return(-1);
944 }
945
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;
951 a_uio->uio_iovcnt++;
952 #if 1 // LP64todo - remove this temp workaround once we go live with uio KPI
953 a_uio->uio_resid += a_length;
954 #else
955 a_uio->uio_resid_64 += a_length;
956 #endif
957 return( 0 );
958 }
959 }
960 }
961 else {
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);
966 a_uio->uio_iovcnt++;
967 a_uio->uio_resid += a_length;
968 return( 0 );
969 }
970 }
971 }
972
973 return( -1 );
974 }
975
976 /*
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.
982 */
983 int uio_getiov( uio_t a_uio,
984 int a_index,
985 user_addr_t * a_baseaddr_p,
986 user_size_t * a_length_p )
987 {
988 if (a_uio == NULL) {
989 #if DEBUG
990 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
991 #endif /* DEBUG */
992 return(-1);
993 }
994 if ( a_index < 0 || a_index >= a_uio->uio_iovcnt) {
995 return(-1);
996 }
997
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;
1001 }
1002 if (a_length_p != NULL) {
1003 *a_length_p = a_uio->uio_iovs.uiovp[a_index].iov_len;
1004 }
1005 }
1006 else {
1007 if (a_baseaddr_p != NULL) {
1008 *a_baseaddr_p = a_uio->uio_iovs.kiovp[a_index].iov_base;
1009 }
1010 if (a_length_p != NULL) {
1011 *a_length_p = a_uio->uio_iovs.kiovp[a_index].iov_len;
1012 }
1013 }
1014
1015 return( 0 );
1016 }
1017
1018 /*
1019 * uio_calculateresid - runs through all iovecs associated with this
1020 * uio_t and calculates (and sets) the residual IO count.
1021 */
1022 __private_extern__ void uio_calculateresid( uio_t a_uio )
1023 {
1024 int i;
1025
1026 if (a_uio == NULL) {
1027 #if LP64_DEBUG
1028 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
1029 #endif /* LP64_DEBUG */
1030 return;
1031 }
1032
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;
1037 #else
1038 a_uio->uio_resid_64 = 0;
1039 #endif
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;
1044 #else
1045 a_uio->uio_resid_64 += a_uio->uio_iovs.uiovp[i].iov_len;
1046 #endif
1047 }
1048 }
1049
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++;
1055 }
1056 }
1057 }
1058 else {
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;
1063 }
1064 }
1065
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++;
1071 }
1072 }
1073 }
1074
1075 return;
1076 }
1077
1078 /*
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
1083 * iovec (if any).
1084 * If the a_count passed in is 0, than only do the advancement
1085 * over any 0 length iovec's.
1086 */
1087 void uio_update( uio_t a_uio, user_size_t a_count )
1088 {
1089 #if LP64_DEBUG
1090 if (a_uio == NULL) {
1091 panic("%s :%d - invalid uio_t\n", __FILE__, __LINE__);
1092 }
1093 if (UIO_IS_32_BIT_SPACE(a_uio) && a_count > 0xFFFFFFFFull) {
1094 panic("%s :%d - invalid count value \n", __FILE__, __LINE__);
1095 }
1096 #endif /* LP64_DEBUG */
1097
1098 if (a_uio == NULL || a_uio->uio_iovcnt < 1) {
1099 return;
1100 }
1101
1102 if (UIO_IS_64_BIT_SPACE(a_uio)) {
1103 /*
1104 * if a_count == 0, then we are asking to skip over
1105 * any empty iovs
1106 */
1107 if (a_count) {
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;
1111 }
1112 else {
1113 a_uio->uio_iovs.uiovp->iov_base += a_count;
1114 a_uio->uio_iovs.uiovp->iov_len -= a_count;
1115 }
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;
1119 }
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;
1123 }
1124 else {
1125 a_uio->uio_offset += a_count;
1126 a_uio->uio_resid -= a_count;
1127 }
1128 #else
1129 if (a_uio->uio_resid_64 < 0) {
1130 a_uio->uio_resid_64 = 0;
1131 }
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;
1135 }
1136 else {
1137 a_uio->uio_offset += a_count;
1138 a_uio->uio_resid_64 -= a_count;
1139 }
1140 #endif // LP64todo
1141 }
1142 /*
1143 * advance to next iovec if current one is totally consumed
1144 */
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++;
1149 }
1150 }
1151 }
1152 else {
1153 /*
1154 * if a_count == 0, then we are asking to skip over
1155 * any empty iovs
1156 */
1157 if (a_count) {
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;
1161 }
1162 else {
1163 a_uio->uio_iovs.kiovp->iov_base += a_count;
1164 a_uio->uio_iovs.kiovp->iov_len -= a_count;
1165 }
1166 if (a_uio->uio_resid < 0) {
1167 a_uio->uio_resid = 0;
1168 }
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;
1172 }
1173 else {
1174 a_uio->uio_offset += a_count;
1175 a_uio->uio_resid -= a_count;
1176 }
1177 }
1178 /*
1179 * advance to next iovec if current one is totally consumed
1180 */
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++;
1185 }
1186 }
1187 }
1188 return;
1189 }
1190
1191
1192 /*
1193 * uio_duplicate - allocate a new uio and make a copy of the given uio_t.
1194 * may return NULL.
1195 */
1196 uio_t uio_duplicate( uio_t a_uio )
1197 {
1198 uio_t my_uio;
1199 int i;
1200
1201 if (a_uio == NULL) {
1202 return(NULL);
1203 }
1204
1205 my_uio = (uio_t) kalloc(a_uio->uio_size);
1206 if (my_uio == 0) {
1207 panic("%s :%d - allocation failed\n", __FILE__, __LINE__);
1208 }
1209
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));
1215
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) {
1221 break;
1222 }
1223 my_uio->uio_iovs.uiovp++;
1224 }
1225 else {
1226 if (my_uio->uio_iovs.kiovp->iov_len != 0) {
1227 break;
1228 }
1229 my_uio->uio_iovs.kiovp++;
1230 }
1231 }
1232 }
1233 }
1234
1235 my_uio->uio_flags = UIO_FLAGS_WE_ALLOCED | UIO_FLAGS_INITED;
1236
1237 return(my_uio);
1238 }
1239