2 * Copyright (c) 2000-2015 Apple 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, 1989, 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 * @(#)sys_generic.c 8.9 (Berkeley) 2/14/95
69 * NOTICE: This file was modified by SPARTA, Inc. in 2006 to introduce
70 * support for mandatory and extensible security protections. This notice
71 * is included in support of clause 2.2 (b) of the Apple Public License,
75 #include <sys/param.h>
76 #include <sys/systm.h>
77 #include <sys/filedesc.h>
78 #include <sys/ioctl.h>
79 #include <sys/file_internal.h>
80 #include <sys/proc_internal.h>
81 #include <sys/socketvar.h>
82 #include <sys/uio_internal.h>
83 #include <sys/kernel.h>
84 #include <sys/guarded.h>
86 #include <sys/malloc.h>
87 #include <sys/sysproto.h>
89 #include <sys/mount_internal.h>
90 #include <sys/protosw.h>
93 #include <sys/kdebug.h>
95 #include <sys/event.h>
96 #include <sys/eventvar.h>
98 #include <sys/kauth.h>
100 #include <machine/smp.h>
101 #include <mach/mach_types.h>
102 #include <kern/kern_types.h>
103 #include <kern/assert.h>
104 #include <kern/kalloc.h>
105 #include <kern/thread.h>
106 #include <kern/clock.h>
107 #include <kern/ledger.h>
108 #include <kern/task.h>
109 #include <kern/telemetry.h>
110 #include <kern/waitq.h>
111 #include <kern/sched_prim.h>
112 #include <kern/mpsc_queue.h>
113 #include <kern/debug.h>
115 #include <sys/mbuf.h>
116 #include <sys/domain.h>
117 #include <sys/socket.h>
118 #include <sys/socketvar.h>
119 #include <sys/errno.h>
120 #include <sys/syscall.h>
121 #include <sys/pipe.h>
123 #include <security/audit/audit.h>
126 #include <net/route.h>
128 #include <netinet/in.h>
129 #include <netinet/in_systm.h>
130 #include <netinet/ip.h>
131 #include <netinet/in_pcb.h>
132 #include <netinet/ip_var.h>
133 #include <netinet/ip6.h>
134 #include <netinet/tcp.h>
135 #include <netinet/tcp_fsm.h>
136 #include <netinet/tcp_seq.h>
137 #include <netinet/tcp_timer.h>
138 #include <netinet/tcp_var.h>
139 #include <netinet/tcpip.h>
140 #include <netinet/tcp_debug.h>
141 /* for wait queue based select */
142 #include <kern/waitq.h>
143 #include <sys/vnode_internal.h>
144 /* for remote time api*/
145 #include <kern/remote_time.h>
147 #include <sys/log_data.h>
150 #include <security/mac_framework.h>
153 /* for entitlement check */
154 #include <IOKit/IOBSD.h>
156 * If you need accounting for KM_SELECT consider using
157 * KALLOC_HEAP_DEFINE to define a view.
159 #define KM_SELECT KHEAP_DEFAULT
161 /* XXX should be in a header file somewhere */
162 extern kern_return_t
IOBSDGetPlatformUUID(__darwin_uuid_t uuid
, mach_timespec_t timeoutp
);
164 int rd_uio(struct proc
*p
, int fdes
, uio_t uio
, int is_preadv
, user_ssize_t
*retval
);
165 int wr_uio(struct proc
*p
, int fdes
, uio_t uio
, int is_pwritev
, user_ssize_t
*retval
);
166 int do_uiowrite(struct proc
*p
, struct fileproc
*fp
, uio_t uio
, int flags
, user_ssize_t
*retval
);
168 __private_extern__
int dofileread(vfs_context_t ctx
, struct fileproc
*fp
,
169 user_addr_t bufp
, user_size_t nbyte
,
170 off_t offset
, int flags
, user_ssize_t
*retval
);
171 __private_extern__
int dofilewrite(vfs_context_t ctx
, struct fileproc
*fp
,
172 user_addr_t bufp
, user_size_t nbyte
,
173 off_t offset
, int flags
, user_ssize_t
*retval
);
174 static int preparefileread(struct proc
*p
, struct fileproc
**fp_ret
, int fd
, int check_for_vnode
);
176 /* Conflict wait queue for when selects collide (opaque type) */
177 struct waitq select_conflict_queue
;
180 * Init routine called from bsd_init.c
182 void select_waitq_init(void);
184 select_waitq_init(void)
186 waitq_init(&select_conflict_queue
, SYNC_POLICY_FIFO
);
189 #define f_flag fp_glob->fg_flag
190 #define f_type fp_glob->fg_ops->fo_type
191 #define f_cred fp_glob->fg_cred
192 #define f_ops fp_glob->fg_ops
193 #define f_data fp_glob->fg_data
199 * preparefileread:EBADF
200 * preparefileread:ESPIPE
201 * preparefileread:ENXIO
202 * preparefileread:EBADF
206 read(struct proc
*p
, struct read_args
*uap
, user_ssize_t
*retval
)
208 __pthread_testcancel(1);
209 return read_nocancel(p
, (struct read_nocancel_args
*)uap
, retval
);
213 read_nocancel(struct proc
*p
, struct read_nocancel_args
*uap
, user_ssize_t
*retval
)
218 struct vfs_context context
;
220 if ((error
= preparefileread(p
, &fp
, fd
, 0))) {
224 context
= *(vfs_context_current());
225 context
.vc_ucred
= fp
->fp_glob
->fg_cred
;
227 error
= dofileread(&context
, fp
, uap
->cbuf
, uap
->nbyte
,
228 (off_t
)-1, 0, retval
);
230 fp_drop(p
, fd
, fp
, 0);
239 * preparefileread:EBADF
240 * preparefileread:ESPIPE
241 * preparefileread:ENXIO
242 * preparefileread:EBADF
246 pread(struct proc
*p
, struct pread_args
*uap
, user_ssize_t
*retval
)
248 __pthread_testcancel(1);
249 return pread_nocancel(p
, (struct pread_nocancel_args
*)uap
, retval
);
253 pread_nocancel(struct proc
*p
, struct pread_nocancel_args
*uap
, user_ssize_t
*retval
)
255 struct fileproc
*fp
= NULL
; /* fp set by preparefileread() */
258 struct vfs_context context
;
260 if ((error
= preparefileread(p
, &fp
, fd
, 1))) {
264 context
= *(vfs_context_current());
265 context
.vc_ucred
= fp
->fp_glob
->fg_cred
;
267 error
= dofileread(&context
, fp
, uap
->buf
, uap
->nbyte
,
268 uap
->offset
, FOF_OFFSET
, retval
);
270 fp_drop(p
, fd
, fp
, 0);
272 KERNEL_DEBUG_CONSTANT((BSDDBG_CODE(DBG_BSD_SC_EXTENDED_INFO
, SYS_pread
) | DBG_FUNC_NONE
),
273 uap
->fd
, uap
->nbyte
, (unsigned int)((uap
->offset
>> 32)), (unsigned int)(uap
->offset
), 0);
280 * Code common for read and pread
291 preparefileread(struct proc
*p
, struct fileproc
**fp_ret
, int fd
, int check_for_pread
)
301 error
= fp_lookup(p
, fd
, &fp
, 1);
307 if ((fp
->f_flag
& FREAD
) == 0) {
311 if (check_for_pread
&& (fp
->f_type
!= DTYPE_VNODE
)) {
315 if (fp
->f_type
== DTYPE_VNODE
) {
316 vp
= (struct vnode
*)fp
->fp_glob
->fg_data
;
318 if (check_for_pread
&& (vnode_isfifo(vp
))) {
322 if (check_for_pread
&& (vp
->v_flag
& VISTTY
)) {
334 fp_drop(p
, fd
, fp
, 1);
345 __private_extern__
int
346 dofileread(vfs_context_t ctx
, struct fileproc
*fp
,
347 user_addr_t bufp
, user_size_t nbyte
, off_t offset
, int flags
,
348 user_ssize_t
*retval
)
351 user_ssize_t bytecnt
;
353 char uio_buf
[UIO_SIZEOF(1)];
355 if (nbyte
> INT_MAX
) {
359 if (IS_64BIT_PROCESS(vfs_context_proc(ctx
))) {
360 auio
= uio_createwithbuffer(1, offset
, UIO_USERSPACE64
, UIO_READ
,
361 &uio_buf
[0], sizeof(uio_buf
));
363 auio
= uio_createwithbuffer(1, offset
, UIO_USERSPACE32
, UIO_READ
,
364 &uio_buf
[0], sizeof(uio_buf
));
366 if (uio_addiov(auio
, bufp
, nbyte
) != 0) {
373 if ((error
= fo_read(fp
, auio
, flags
, ctx
))) {
374 if (uio_resid(auio
) != bytecnt
&& (error
== ERESTART
||
375 error
== EINTR
|| error
== EWOULDBLOCK
)) {
379 bytecnt
-= uio_resid(auio
);
392 * preparefileread:EBADF
393 * preparefileread:ESPIPE
394 * preparefileread:ENXIO
395 * preparefileread:EBADF
400 readv_preadv_uio(struct proc
*p
, int fdes
,
401 user_addr_t user_iovp
, int iovcnt
, off_t offset
, int is_preadv
,
402 user_ssize_t
*retval
)
406 struct user_iovec
*iovp
;
408 /* Verify range before calling uio_create() */
409 if (iovcnt
<= 0 || iovcnt
> UIO_MAXIOV
) {
413 /* allocate a uio large enough to hold the number of iovecs passed */
414 auio
= uio_create(iovcnt
, offset
,
415 (IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
),
418 /* get location of iovecs within the uio. then copyin the iovecs from
421 iovp
= uio_iovsaddr(auio
);
424 goto ExitThisRoutine
;
426 error
= copyin_user_iovec_array(user_iovp
,
427 IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
,
430 goto ExitThisRoutine
;
433 /* finalize uio_t for use and do the IO
435 error
= uio_calculateresid(auio
);
437 goto ExitThisRoutine
;
439 error
= rd_uio(p
, fdes
, auio
, is_preadv
, retval
);
449 * Scatter read system call.
452 readv(struct proc
*p
, struct readv_args
*uap
, user_ssize_t
*retval
)
454 __pthread_testcancel(1);
455 return readv_nocancel(p
, (struct readv_nocancel_args
*)uap
, retval
);
459 readv_nocancel(struct proc
*p
, struct readv_nocancel_args
*uap
, user_ssize_t
*retval
)
461 return readv_preadv_uio(p
, uap
->fd
, uap
->iovp
, uap
->iovcnt
, 0, 0, retval
);
468 sys_preadv(struct proc
*p
, struct preadv_args
*uap
, user_ssize_t
*retval
)
470 __pthread_testcancel(1);
471 return sys_preadv_nocancel(p
, (struct preadv_nocancel_args
*)uap
, retval
);
475 sys_preadv_nocancel(struct proc
*p
, struct preadv_nocancel_args
*uap
, user_ssize_t
*retval
)
477 return readv_preadv_uio(p
, uap
->fd
, uap
->iovp
, uap
->iovcnt
, uap
->offset
, 1, retval
);
489 write(struct proc
*p
, struct write_args
*uap
, user_ssize_t
*retval
)
491 __pthread_testcancel(1);
492 return write_nocancel(p
, (struct write_nocancel_args
*)uap
, retval
);
496 write_nocancel(struct proc
*p
, struct write_nocancel_args
*uap
, user_ssize_t
*retval
)
504 error
= fp_lookup(p
, fd
, &fp
, 0);
508 if ((fp
->f_flag
& FWRITE
) == 0) {
510 } else if (fp_isguarded(fp
, GUARD_WRITE
)) {
512 error
= fp_guard_exception(p
, fd
, fp
, kGUARD_EXC_WRITE
);
515 struct vfs_context context
= *(vfs_context_current());
516 context
.vc_ucred
= fp
->fp_glob
->fg_cred
;
518 error
= dofilewrite(&context
, fp
, uap
->cbuf
, uap
->nbyte
,
519 (off_t
)-1, 0, retval
);
521 fp_drop(p
, fd
, fp
, 0);
537 pwrite(struct proc
*p
, struct pwrite_args
*uap
, user_ssize_t
*retval
)
539 __pthread_testcancel(1);
540 return pwrite_nocancel(p
, (struct pwrite_nocancel_args
*)uap
, retval
);
544 pwrite_nocancel(struct proc
*p
, struct pwrite_nocancel_args
*uap
, user_ssize_t
*retval
)
549 vnode_t vp
= (vnode_t
)0;
553 error
= fp_get_ftype(p
, fd
, DTYPE_VNODE
, ESPIPE
, &fp
);
558 if ((fp
->f_flag
& FWRITE
) == 0) {
560 } else if (fp_isguarded(fp
, GUARD_WRITE
)) {
562 error
= fp_guard_exception(p
, fd
, fp
, kGUARD_EXC_WRITE
);
565 struct vfs_context context
= *vfs_context_current();
566 context
.vc_ucred
= fp
->fp_glob
->fg_cred
;
568 vp
= (vnode_t
)fp
->fp_glob
->fg_data
;
569 if (vnode_isfifo(vp
)) {
573 if ((vp
->v_flag
& VISTTY
)) {
577 if (uap
->offset
== (off_t
)-1) {
582 error
= dofilewrite(&context
, fp
, uap
->buf
, uap
->nbyte
,
583 uap
->offset
, FOF_OFFSET
, retval
);
586 fp_drop(p
, fd
, fp
, 0);
588 KERNEL_DEBUG_CONSTANT((BSDDBG_CODE(DBG_BSD_SC_EXTENDED_INFO
, SYS_pwrite
) | DBG_FUNC_NONE
),
589 uap
->fd
, uap
->nbyte
, (unsigned int)((uap
->offset
>> 32)), (unsigned int)(uap
->offset
), 0);
598 * <fo_write>:??? [indirect through struct fileops]
600 __private_extern__
int
601 dofilewrite(vfs_context_t ctx
, struct fileproc
*fp
,
602 user_addr_t bufp
, user_size_t nbyte
, off_t offset
, int flags
,
603 user_ssize_t
*retval
)
607 user_ssize_t bytecnt
;
608 char uio_buf
[UIO_SIZEOF(1)];
610 if (nbyte
> INT_MAX
) {
615 if (IS_64BIT_PROCESS(vfs_context_proc(ctx
))) {
616 auio
= uio_createwithbuffer(1, offset
, UIO_USERSPACE64
, UIO_WRITE
,
617 &uio_buf
[0], sizeof(uio_buf
));
619 auio
= uio_createwithbuffer(1, offset
, UIO_USERSPACE32
, UIO_WRITE
,
620 &uio_buf
[0], sizeof(uio_buf
));
622 if (uio_addiov(auio
, bufp
, nbyte
) != 0) {
628 if ((error
= fo_write(fp
, auio
, flags
, ctx
))) {
629 if (uio_resid(auio
) != bytecnt
&& (error
== ERESTART
||
630 error
== EINTR
|| error
== EWOULDBLOCK
)) {
633 /* The socket layer handles SIGPIPE */
634 if (error
== EPIPE
&& fp
->f_type
!= DTYPE_SOCKET
&&
635 (fp
->fp_glob
->fg_lflags
& FG_NOSIGPIPE
) == 0) {
636 /* XXX Raise the signal on the thread? */
637 psignal(vfs_context_proc(ctx
), SIGPIPE
);
640 bytecnt
-= uio_resid(auio
);
642 os_atomic_or(&fp
->fp_glob
->fg_flag
, FWASWRITTEN
, relaxed
);
655 * fp_guard_exception:???
658 preparefilewrite(struct proc
*p
, struct fileproc
**fp_ret
, int fd
, int check_for_pwrite
)
668 error
= fp_lookup(p
, fd
, &fp
, 1);
674 if ((fp
->f_flag
& FWRITE
) == 0) {
676 goto ExitThisRoutine
;
678 if (fp_isguarded(fp
, GUARD_WRITE
)) {
679 error
= fp_guard_exception(p
, fd
, fp
, kGUARD_EXC_WRITE
);
680 goto ExitThisRoutine
;
682 if (check_for_pwrite
) {
683 if (fp
->f_type
!= DTYPE_VNODE
) {
685 goto ExitThisRoutine
;
688 vp
= (vnode_t
)fp
->fp_glob
->fg_data
;
689 if (vnode_isfifo(vp
)) {
691 goto ExitThisRoutine
;
693 if ((vp
->v_flag
& VISTTY
)) {
695 goto ExitThisRoutine
;
705 fp_drop(p
, fd
, fp
, 1);
711 writev_prwritev_uio(struct proc
*p
, int fd
,
712 user_addr_t user_iovp
, int iovcnt
, off_t offset
, int is_pwritev
,
713 user_ssize_t
*retval
)
717 struct user_iovec
*iovp
;
719 /* Verify range before calling uio_create() */
720 if (iovcnt
<= 0 || iovcnt
> UIO_MAXIOV
|| offset
< 0) {
724 /* allocate a uio large enough to hold the number of iovecs passed */
725 auio
= uio_create(iovcnt
, offset
,
726 (IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
),
729 /* get location of iovecs within the uio. then copyin the iovecs from
732 iovp
= uio_iovsaddr(auio
);
735 goto ExitThisRoutine
;
737 error
= copyin_user_iovec_array(user_iovp
,
738 IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
,
741 goto ExitThisRoutine
;
744 /* finalize uio_t for use and do the IO
746 error
= uio_calculateresid(auio
);
748 goto ExitThisRoutine
;
751 error
= wr_uio(p
, fd
, auio
, is_pwritev
, retval
);
761 * Gather write system call
764 writev(struct proc
*p
, struct writev_args
*uap
, user_ssize_t
*retval
)
766 __pthread_testcancel(1);
767 return writev_nocancel(p
, (struct writev_nocancel_args
*)uap
, retval
);
771 writev_nocancel(struct proc
*p
, struct writev_nocancel_args
*uap
, user_ssize_t
*retval
)
773 return writev_prwritev_uio(p
, uap
->fd
, uap
->iovp
, uap
->iovcnt
, 0, 0, retval
);
777 * Pwritev system call
780 sys_pwritev(struct proc
*p
, struct pwritev_args
*uap
, user_ssize_t
*retval
)
782 __pthread_testcancel(1);
783 return sys_pwritev_nocancel(p
, (struct pwritev_nocancel_args
*)uap
, retval
);
787 sys_pwritev_nocancel(struct proc
*p
, struct pwritev_nocancel_args
*uap
, user_ssize_t
*retval
)
789 return writev_prwritev_uio(p
, uap
->fd
, uap
->iovp
, uap
->iovcnt
, uap
->offset
, 1, retval
);
794 * preparefileread:EBADF
795 * preparefileread:ESPIPE
796 * preparefileread:ENXIO
797 * preparefileread:???
801 wr_uio(struct proc
*p
, int fd
, uio_t uio
, int is_pwritev
, user_ssize_t
*retval
)
807 if ((error
= preparefilewrite(p
, &fp
, fd
, is_pwritev
))) {
811 flags
= is_pwritev
? FOF_OFFSET
: 0;
812 error
= do_uiowrite(p
, fp
, uio
, flags
, retval
);
814 fp_drop(p
, fd
, fp
, 0);
820 do_uiowrite(struct proc
*p
, struct fileproc
*fp
, uio_t uio
, int flags
, user_ssize_t
*retval
)
824 struct vfs_context context
= *vfs_context_current();
826 count
= uio_resid(uio
);
828 context
.vc_ucred
= fp
->f_cred
;
829 error
= fo_write(fp
, uio
, flags
, &context
);
831 if (uio_resid(uio
) != count
&& (error
== ERESTART
||
832 error
== EINTR
|| error
== EWOULDBLOCK
)) {
835 /* The socket layer handles SIGPIPE */
836 if (error
== EPIPE
&& fp
->f_type
!= DTYPE_SOCKET
&&
837 (fp
->fp_glob
->fg_lflags
& FG_NOSIGPIPE
) == 0) {
841 count
-= uio_resid(uio
);
843 os_atomic_or(&fp
->fp_glob
->fg_flag
, FWASWRITTEN
, relaxed
);
852 * preparefileread:EBADF
853 * preparefileread:ESPIPE
854 * preparefileread:ENXIO
858 rd_uio(struct proc
*p
, int fdes
, uio_t uio
, int is_preadv
, user_ssize_t
*retval
)
863 struct vfs_context context
= *vfs_context_current();
865 if ((error
= preparefileread(p
, &fp
, fdes
, is_preadv
))) {
869 count
= uio_resid(uio
);
871 context
.vc_ucred
= fp
->f_cred
;
873 int flags
= is_preadv
? FOF_OFFSET
: 0;
874 error
= fo_read(fp
, uio
, flags
, &context
);
877 if (uio_resid(uio
) != count
&& (error
== ERESTART
||
878 error
== EINTR
|| error
== EWOULDBLOCK
)) {
882 *retval
= count
- uio_resid(uio
);
884 fp_drop(p
, fdes
, fp
, 0);
899 * fp_lookup:EBADF Bad file descriptor
903 ioctl(struct proc
*p
, struct ioctl_args
*uap
, __unused
int32_t *retval
)
905 struct fileproc
*fp
= NULL
;
908 caddr_t datap
= NULL
, memp
= NULL
;
909 boolean_t is64bit
= FALSE
;
911 #define STK_PARAMS 128
912 char stkbuf
[STK_PARAMS
] = {};
914 u_long com
= uap
->com
;
915 struct vfs_context context
= *vfs_context_current();
917 AUDIT_ARG(fd
, uap
->fd
);
918 AUDIT_ARG(addr
, uap
->data
);
920 is64bit
= proc_is64bit(p
);
923 AUDIT_ARG(value64
, com
);
925 AUDIT_ARG(cmd
, CAST_DOWN_EXPLICIT(int, com
));
927 #endif /* CONFIG_AUDIT */
930 * Interpret high order word to find amount of data to be
931 * copied to/from the user's address space.
933 size
= IOCPARM_LEN(com
);
934 if (size
> IOCPARM_MAX
) {
937 if (size
> sizeof(stkbuf
)) {
938 memp
= (caddr_t
)kheap_alloc(KHEAP_TEMP
, size
, Z_WAITOK
);
948 error
= copyin(uap
->data
, datap
, size
);
953 /* XXX - IOC_IN and no size? we should proably return an error here!! */
955 *(user_addr_t
*)datap
= uap
->data
;
957 *(uint32_t *)datap
= (uint32_t)uap
->data
;
960 } else if ((com
& IOC_OUT
) && size
) {
962 * Zero the buffer so the user always
963 * gets back something deterministic.
966 } else if (com
& IOC_VOID
) {
967 /* XXX - this is odd since IOC_VOID means no parameters */
969 *(user_addr_t
*)datap
= uap
->data
;
971 *(uint32_t *)datap
= (uint32_t)uap
->data
;
976 error
= fp_lookup(p
, fd
, &fp
, 1);
982 AUDIT_ARG(file
, p
, fp
);
984 if ((fp
->f_flag
& (FREAD
| FWRITE
)) == 0) {
989 context
.vc_ucred
= fp
->fp_glob
->fg_cred
;
992 error
= mac_file_check_ioctl(context
.vc_ucred
, fp
->fp_glob
, com
);
1000 *fdflags(p
, fd
) &= ~UF_EXCLOSE
;
1004 *fdflags(p
, fd
) |= UF_EXCLOSE
;
1008 // FIXME (rdar://54898652)
1010 // this code is broken if fnctl(F_SETFL), ioctl() are
1011 // called concurrently for the same fileglob.
1012 if ((tmp
= *(int *)datap
)) {
1013 os_atomic_or(&fp
->f_flag
, FNONBLOCK
, relaxed
);
1015 os_atomic_andnot(&fp
->f_flag
, FNONBLOCK
, relaxed
);
1017 error
= fo_ioctl(fp
, FIONBIO
, (caddr_t
)&tmp
, &context
);
1021 // FIXME (rdar://54898652)
1023 // this code is broken if fnctl(F_SETFL), ioctl() are
1024 // called concurrently for the same fileglob.
1025 if ((tmp
= *(int *)datap
)) {
1026 os_atomic_or(&fp
->f_flag
, FASYNC
, relaxed
);
1028 os_atomic_andnot(&fp
->f_flag
, FASYNC
, relaxed
);
1030 error
= fo_ioctl(fp
, FIOASYNC
, (caddr_t
)&tmp
, &context
);
1034 tmp
= *(int *)datap
;
1035 if (fp
->f_type
== DTYPE_SOCKET
) {
1036 ((struct socket
*)fp
->f_data
)->so_pgid
= tmp
;
1039 if (fp
->f_type
== DTYPE_PIPE
) {
1040 error
= fo_ioctl(fp
, TIOCSPGRP
, (caddr_t
)&tmp
, &context
);
1046 struct proc
*p1
= proc_find(tmp
);
1054 error
= fo_ioctl(fp
, TIOCSPGRP
, (caddr_t
)&tmp
, &context
);
1058 if (fp
->f_type
== DTYPE_SOCKET
) {
1059 *(int *)datap
= ((struct socket
*)fp
->f_data
)->so_pgid
;
1062 error
= fo_ioctl(fp
, TIOCGPGRP
, datap
, &context
);
1063 *(int *)datap
= -*(int *)datap
;
1067 error
= fo_ioctl(fp
, com
, datap
, &context
);
1069 * Copy any data to user, size was
1070 * already set and checked above.
1072 if (error
== 0 && (com
& IOC_OUT
) && size
) {
1073 error
= copyout(datap
, uap
->data
, (u_int
)size
);
1078 fp_drop(p
, fd
, fp
, 1);
1083 kheap_free(KHEAP_TEMP
, memp
, size
);
1088 int selwait
, nselcoll
;
1089 #define SEL_FIRSTPASS 1
1090 #define SEL_SECONDPASS 2
1091 extern int selcontinue(int error
);
1092 extern int selprocess(int error
, int sel_pass
);
1093 static int selscan(struct proc
*p
, struct _select
* sel
, struct _select_data
* seldata
,
1094 int nfd
, int32_t *retval
, int sel_pass
, struct waitq_set
*wqset
);
1095 static int selcount(struct proc
*p
, u_int32_t
*ibits
, int nfd
, int *count
);
1096 static int seldrop_locked(struct proc
*p
, u_int32_t
*ibits
, int nfd
, int lim
, int *need_wakeup
);
1097 static int seldrop(struct proc
*p
, u_int32_t
*ibits
, int nfd
, int lim
);
1098 static int select_internal(struct proc
*p
, struct select_nocancel_args
*uap
, uint64_t timeout
, int32_t *retval
);
1101 * Select system call.
1103 * Returns: 0 Success
1104 * EINVAL Invalid argument
1105 * EAGAIN Nonconformant error if allocation fails
1108 select(struct proc
*p
, struct select_args
*uap
, int32_t *retval
)
1110 __pthread_testcancel(1);
1111 return select_nocancel(p
, (struct select_nocancel_args
*)uap
, retval
);
1115 select_nocancel(struct proc
*p
, struct select_nocancel_args
*uap
, int32_t *retval
)
1117 uint64_t timeout
= 0;
1122 if (IS_64BIT_PROCESS(p
)) {
1123 struct user64_timeval atv64
;
1124 err
= copyin(uap
->tv
, (caddr_t
)&atv64
, sizeof(atv64
));
1125 /* Loses resolution - assume timeout < 68 years */
1126 atv
.tv_sec
= (__darwin_time_t
)atv64
.tv_sec
;
1127 atv
.tv_usec
= atv64
.tv_usec
;
1129 struct user32_timeval atv32
;
1130 err
= copyin(uap
->tv
, (caddr_t
)&atv32
, sizeof(atv32
));
1131 atv
.tv_sec
= atv32
.tv_sec
;
1132 atv
.tv_usec
= atv32
.tv_usec
;
1138 if (itimerfix(&atv
)) {
1143 clock_absolutetime_interval_to_deadline(tvtoabstime(&atv
), &timeout
);
1146 return select_internal(p
, uap
, timeout
, retval
);
1150 pselect(struct proc
*p
, struct pselect_args
*uap
, int32_t *retval
)
1152 __pthread_testcancel(1);
1153 return pselect_nocancel(p
, (struct pselect_nocancel_args
*)uap
, retval
);
1157 pselect_nocancel(struct proc
*p
, struct pselect_nocancel_args
*uap
, int32_t *retval
)
1161 uint64_t timeout
= 0;
1166 if (IS_64BIT_PROCESS(p
)) {
1167 struct user64_timespec ts64
;
1168 err
= copyin(uap
->ts
, (caddr_t
)&ts64
, sizeof(ts64
));
1169 ts
.tv_sec
= (__darwin_time_t
)ts64
.tv_sec
;
1170 ts
.tv_nsec
= (long)ts64
.tv_nsec
;
1172 struct user32_timespec ts32
;
1173 err
= copyin(uap
->ts
, (caddr_t
)&ts32
, sizeof(ts32
));
1174 ts
.tv_sec
= ts32
.tv_sec
;
1175 ts
.tv_nsec
= ts32
.tv_nsec
;
1181 if (!timespec_is_valid(&ts
)) {
1184 clock_absolutetime_interval_to_deadline(tstoabstime(&ts
), &timeout
);
1187 ut
= get_bsdthread_info(current_thread());
1189 if (uap
->mask
!= USER_ADDR_NULL
) {
1190 /* save current mask, then copyin and set new mask */
1192 err
= copyin(uap
->mask
, &newset
, sizeof(sigset_t
));
1196 ut
->uu_oldmask
= ut
->uu_sigmask
;
1197 ut
->uu_flag
|= UT_SAS_OLDMASK
;
1198 ut
->uu_sigmask
= (newset
& ~sigcantmask
);
1201 err
= select_internal(p
, (struct select_nocancel_args
*)uap
, timeout
, retval
);
1203 if (err
!= EINTR
&& ut
->uu_flag
& UT_SAS_OLDMASK
) {
1205 * Restore old mask (direct return case). NOTE: EINTR can also be returned
1206 * if the thread is cancelled. In that case, we don't reset the signal
1207 * mask to its original value (which usually happens in the signal
1208 * delivery path). This behavior is permitted by POSIX.
1210 ut
->uu_sigmask
= ut
->uu_oldmask
;
1212 ut
->uu_flag
&= ~UT_SAS_OLDMASK
;
1219 select_cleanup_uthread(struct _select
*sel
)
1221 kheap_free(KHEAP_DATA_BUFFERS
, sel
->ibits
, 2 * sel
->nbytes
);
1222 sel
->ibits
= sel
->obits
= NULL
;
1227 select_grow_uthread_cache(struct _select
*sel
, uint32_t nbytes
)
1231 buf
= kheap_alloc(KHEAP_DATA_BUFFERS
, 2 * nbytes
, Z_WAITOK
| Z_ZERO
);
1233 select_cleanup_uthread(sel
);
1235 sel
->obits
= buf
+ nbytes
/ sizeof(uint32_t);
1236 sel
->nbytes
= nbytes
;
1243 select_bzero_uthread_cache(struct _select
*sel
)
1245 bzero(sel
->ibits
, sel
->nbytes
* 2);
1249 * Generic implementation of {,p}select. Care: we type-pun uap across the two
1250 * syscalls, which differ slightly. The first 4 arguments (nfds and the fd sets)
1251 * are identical. The 5th (timeout) argument points to different types, so we
1252 * unpack in the syscall-specific code, but the generic code still does a null
1253 * check on this argument to determine if a timeout was specified.
1256 select_internal(struct proc
*p
, struct select_nocancel_args
*uap
, uint64_t timeout
, int32_t *retval
)
1261 struct uthread
*uth
;
1262 struct _select
*sel
;
1263 struct _select_data
*seldata
;
1267 th_act
= current_thread();
1268 uth
= get_bsdthread_info(th_act
);
1269 sel
= &uth
->uu_select
;
1270 seldata
= &uth
->uu_save
.uus_select_data
;
1273 seldata
->args
= uap
;
1274 seldata
->retval
= retval
;
1275 seldata
->wqp
= NULL
;
1282 /* select on thread of process that already called proc_exit() */
1283 if (p
->p_fd
== NULL
) {
1287 if (uap
->nd
> p
->p_fd
->fd_nfiles
) {
1288 uap
->nd
= p
->p_fd
->fd_nfiles
; /* forgiving; slightly wrong */
1290 nw
= howmany(uap
->nd
, NFDBITS
);
1291 ni
= nw
* sizeof(fd_mask
);
1294 * if the previously allocated space for the bits is smaller than
1295 * what is requested or no space has yet been allocated for this
1296 * thread, allocate enough space now.
1298 * Note: If this process fails, select() will return EAGAIN; this
1299 * is the same thing pool() returns in a no-memory situation, but
1300 * it is not a POSIX compliant error code for select().
1302 if (sel
->nbytes
< (3 * ni
)) {
1303 if (!select_grow_uthread_cache(sel
, 3 * ni
)) {
1307 select_bzero_uthread_cache(sel
);
1311 * get the bits from the user address space
1313 #define getbits(name, x) \
1315 if (uap->name && (error = copyin(uap->name, \
1316 (caddr_t)&sel->ibits[(x) * nw], ni))) \
1317 goto continuation; \
1325 seldata
->abstime
= timeout
;
1327 if ((error
= selcount(p
, sel
->ibits
, uap
->nd
, &count
))) {
1332 * We need an array of waitq pointers. This is due to the new way
1333 * in which waitqs are linked to sets. When a thread selects on a
1334 * file descriptor, a waitq (embedded in a selinfo structure) is
1335 * added to the thread's local waitq set. There is no longer any
1336 * way to directly iterate over all members of a given waitq set.
1337 * The process of linking a waitq into a set may allocate a link
1338 * table object. Because we can't iterate over all the waitqs to
1339 * which our thread waitq set belongs, we need a way of removing
1342 * Thus we need a buffer which will hold one waitq pointer
1343 * per FD being selected. During the tear-down phase we can use
1344 * these pointers to dis-associate the underlying selinfo's waitq
1345 * from our thread's waitq set.
1347 * Because we also need to allocate a waitq set for this thread,
1348 * we use a bare buffer pointer to hold all the memory. Note that
1349 * this memory is cached in the thread pointer and not reaped until
1350 * the thread exists. This is generally OK because threads that
1351 * call select tend to keep calling select repeatedly.
1353 sz
= ALIGN(sizeof(struct waitq_set
)) + (count
* sizeof(uint64_t));
1354 if (sz
> uth
->uu_wqstate_sz
) {
1355 /* (re)allocate a buffer to hold waitq pointers */
1356 if (uth
->uu_wqset
) {
1357 if (waitq_set_is_valid(uth
->uu_wqset
)) {
1358 waitq_set_deinit(uth
->uu_wqset
);
1360 kheap_free(KM_SELECT
, uth
->uu_wqset
, uth
->uu_wqstate_sz
);
1361 } else if (uth
->uu_wqstate_sz
&& !uth
->uu_wqset
) {
1362 panic("select: thread structure corrupt! "
1363 "uu_wqstate_sz:%ld, wqstate_buf == NULL",
1364 uth
->uu_wqstate_sz
);
1366 uth
->uu_wqstate_sz
= sz
;
1367 uth
->uu_wqset
= kheap_alloc(KM_SELECT
, sz
, Z_WAITOK
);
1368 if (!uth
->uu_wqset
) {
1369 panic("can't allocate %ld bytes for wqstate buffer",
1370 uth
->uu_wqstate_sz
);
1372 waitq_set_init(uth
->uu_wqset
,
1373 SYNC_POLICY_FIFO
| SYNC_POLICY_PREPOST
, NULL
, NULL
);
1376 if (!waitq_set_is_valid(uth
->uu_wqset
)) {
1377 waitq_set_init(uth
->uu_wqset
,
1378 SYNC_POLICY_FIFO
| SYNC_POLICY_PREPOST
, NULL
, NULL
);
1381 /* the last chunk of our buffer is an array of waitq pointers */
1382 seldata
->wqp
= (uint64_t *)((char *)(uth
->uu_wqset
) + ALIGN(sizeof(struct waitq_set
)));
1383 bzero(seldata
->wqp
, sz
- ALIGN(sizeof(struct waitq_set
)));
1385 seldata
->count
= count
;
1391 * We have already cleaned up any state we established,
1392 * either locally or as a result of selcount(). We don't
1393 * need to wait_subqueue_unlink_all(), since we haven't set
1394 * anything at this point.
1399 return selprocess(0, SEL_FIRSTPASS
);
1403 selcontinue(int error
)
1405 return selprocess(error
, SEL_SECONDPASS
);
1412 * Parameters: error The error code from our caller
1413 * sel_pass The pass we are on
1416 selprocess(int error
, int sel_pass
)
1421 struct uthread
*uth
;
1423 struct select_nocancel_args
*uap
;
1425 struct _select
*sel
;
1426 struct _select_data
*seldata
;
1431 wait_result_t wait_result
;
1434 th_act
= current_thread();
1435 uth
= get_bsdthread_info(th_act
);
1436 sel
= &uth
->uu_select
;
1437 seldata
= &uth
->uu_save
.uus_select_data
;
1438 uap
= seldata
->args
;
1439 retval
= seldata
->retval
;
1441 if ((error
!= 0) && (sel_pass
== SEL_FIRSTPASS
)) {
1444 if (seldata
->count
== 0) {
1453 OSBitOrAtomic(P_SELECT
, &p
->p_flag
);
1455 /* skip scans if the select is just for timeouts */
1456 if (seldata
->count
) {
1457 error
= selscan(p
, sel
, seldata
, uap
->nd
, retval
, sel_pass
, uth
->uu_wqset
);
1458 if (error
|| *retval
) {
1461 if (prepost
|| somewakeup
) {
1463 * if the select of log, then we can wakeup and
1464 * discover some one else already read the data;
1465 * go to select again if time permits
1476 clock_get_uptime(&now
);
1477 if (now
>= seldata
->abstime
) {
1483 /* cleanup obits and try again */
1485 sel_pass
= SEL_FIRSTPASS
;
1490 * To effect a poll, the timeout argument should be
1491 * non-nil, pointing to a zero-valued timeval structure.
1493 if (uap
->tv
&& seldata
->abstime
== 0) {
1497 /* No spurious wakeups due to colls,no need to check for them */
1498 if ((sel_pass
== SEL_SECONDPASS
) || ((p
->p_flag
& P_SELECT
) == 0)) {
1499 sel_pass
= SEL_FIRSTPASS
;
1503 OSBitAndAtomic(~((uint32_t)P_SELECT
), &p
->p_flag
);
1505 /* if the select is just for timeout skip check */
1506 if (seldata
->count
&& (sel_pass
== SEL_SECONDPASS
)) {
1507 panic("selprocess: 2nd pass assertwaiting");
1510 /* waitq_set has waitqueue as first element */
1511 wait_result
= waitq_assert_wait64_leeway((struct waitq
*)uth
->uu_wqset
,
1512 NO_EVENT64
, THREAD_ABORTSAFE
,
1513 TIMEOUT_URGENCY_USER_NORMAL
,
1516 if (wait_result
!= THREAD_AWAKENED
) {
1517 /* there are no preposted events */
1518 error
= tsleep1(NULL
, PSOCK
| PCATCH
,
1519 "select", 0, selcontinue
);
1526 sel_pass
= SEL_SECONDPASS
;
1534 seldrop(p
, sel
->ibits
, uap
->nd
, seldata
->count
);
1535 waitq_set_deinit(uth
->uu_wqset
);
1537 * zero out the waitq pointer array to avoid use-after free
1538 * errors in the selcount error path (seldrop_locked) if/when
1539 * the thread re-calls select().
1541 bzero((void *)uth
->uu_wqset
, uth
->uu_wqstate_sz
);
1543 OSBitAndAtomic(~((uint32_t)P_SELECT
), &p
->p_flag
);
1544 /* select is not restarted after signals... */
1545 if (error
== ERESTART
) {
1548 if (error
== EWOULDBLOCK
) {
1551 nw
= howmany(uap
->nd
, NFDBITS
);
1552 ni
= nw
* sizeof(fd_mask
);
1554 #define putbits(name, x) \
1556 if (uap->name && (error2 = \
1557 copyout((caddr_t)&sel->obits[(x) * nw], uap->name, ni))) \
1570 if (error
!= EINTR
&& sel_pass
== SEL_SECONDPASS
&& uth
->uu_flag
& UT_SAS_OLDMASK
) {
1571 /* restore signal mask - continuation case */
1572 uth
->uu_sigmask
= uth
->uu_oldmask
;
1573 uth
->uu_oldmask
= 0;
1574 uth
->uu_flag
&= ~UT_SAS_OLDMASK
;
1582 * remove the fileproc's underlying waitq from the supplied waitq set;
1583 * clear FP_INSELECT when appropriate
1586 * fp File proc that is potentially currently in select
1587 * wqset Waitq set to which the fileproc may belong
1588 * (usually this is the thread's private waitq set)
1590 * proc_fdlock is held
1593 selunlinkfp(struct fileproc
*fp
, uint64_t wqp_id
, struct waitq_set
*wqset
)
1595 int valid_set
= waitq_set_is_valid(wqset
);
1596 int valid_q
= !!wqp_id
;
1599 * This could be called (from selcount error path) before we setup
1600 * the thread's wqset. Check the wqset passed in, and only unlink if
1604 /* unlink the underlying waitq from the input set (thread waitq set) */
1605 if (valid_q
&& valid_set
) {
1606 waitq_unlink_by_prepost_id(wqp_id
, wqset
);
1609 /* allow passing a invalid fp for seldrop unwind */
1610 if (!(fp
->fp_flags
& (FP_INSELECT
| FP_SELCONFLICT
))) {
1615 * We can always remove the conflict queue from our thread's set: this
1616 * will not affect other threads that potentially need to be awoken on
1617 * the conflict queue during a fileproc_drain - those sets will still
1618 * be linked with the global conflict queue, and the last waiter
1619 * on the fp clears the CONFLICT marker.
1621 if (valid_set
&& (fp
->fp_flags
& FP_SELCONFLICT
)) {
1622 waitq_unlink(&select_conflict_queue
, wqset
);
1626 * This isn't quite right - we don't actually know if this
1627 * fileproc is in another select or not! Here we just assume
1628 * that if we were the first thread to select on the FD, then
1629 * we'll be the one to clear this flag...
1631 if (valid_set
&& fp
->fp_wset
== (void *)wqset
) {
1632 fp
->fp_flags
&= ~FP_INSELECT
;
1638 * connect a fileproc to the given wqset, potentially bridging to a waitq
1639 * pointed to indirectly by wq_data
1642 * fp File proc potentially currently in select
1643 * wq_data Pointer to a pointer to a waitq (could be NULL)
1644 * wqset Waitq set to which the fileproc should now belong
1645 * (usually this is the thread's private waitq set)
1648 * proc_fdlock is held
1651 sellinkfp(struct fileproc
*fp
, void **wq_data
, struct waitq_set
*wqset
)
1653 struct waitq
*f_wq
= NULL
;
1655 if ((fp
->fp_flags
& FP_INSELECT
) != FP_INSELECT
) {
1657 panic("non-null data:%p on fp:%p not in select?!"
1658 "(wqset:%p)", wq_data
, fp
, wqset
);
1663 if ((fp
->fp_flags
& FP_SELCONFLICT
) == FP_SELCONFLICT
) {
1664 waitq_link(&select_conflict_queue
, wqset
, WAITQ_SHOULD_LOCK
, NULL
);
1668 * The wq_data parameter has potentially been set by selrecord called
1669 * from a subsystems fo_select() function. If the subsystem does not
1670 * call selrecord, then wq_data will be NULL
1672 * Use memcpy to get the value into a proper pointer because
1673 * wq_data most likely points to a stack variable that could be
1674 * unaligned on 32-bit systems.
1677 memcpy(&f_wq
, wq_data
, sizeof(f_wq
));
1678 if (!waitq_is_valid(f_wq
)) {
1683 /* record the first thread's wqset in the fileproc structure */
1685 fp
->fp_wset
= (void *)wqset
;
1688 /* handles NULL f_wq */
1689 return waitq_get_prepost_id(f_wq
);
1696 * Parameters: p Process performing the select
1697 * sel The per-thread select context structure
1698 * nfd The number of file descriptors to scan
1699 * retval The per thread system call return area
1700 * sel_pass Which pass this is; allowed values are
1701 * SEL_FIRSTPASS and SEL_SECONDPASS
1702 * wqset The per thread wait queue set
1704 * Returns: 0 Success
1705 * EIO Invalid p->p_fd field XXX Obsolete?
1706 * EBADF One of the files in the bit vector is
1710 selscan(struct proc
*p
, struct _select
*sel
, struct _select_data
* seldata
,
1711 int nfd
, int32_t *retval
, int sel_pass
, struct waitq_set
*wqset
)
1713 struct filedesc
*fdp
= p
->p_fd
;
1716 struct fileproc
*fp
;
1717 int n
= 0; /* count of bits */
1718 int nc
= 0; /* bit vector offset (nc'th bit) */
1719 static int flag
[3] = { FREAD
, FWRITE
, 0 };
1720 u_int32_t
*iptr
, *optr
;
1722 u_int32_t
*ibits
, *obits
;
1723 uint64_t reserved_link
, *rl_ptr
= NULL
;
1725 struct vfs_context context
= *vfs_context_current();
1728 * Problems when reboot; due to MacOSX signal probs
1729 * in Beaker1C ; verify that the p->p_fd is valid
1738 nw
= howmany(nfd
, NFDBITS
);
1740 count
= seldata
->count
;
1749 for (msk
= 0; msk
< 3; msk
++) {
1750 iptr
= (u_int32_t
*)&ibits
[msk
* nw
];
1751 optr
= (u_int32_t
*)&obits
[msk
* nw
];
1753 for (i
= 0; i
< nfd
; i
+= NFDBITS
) {
1754 bits
= iptr
[i
/ NFDBITS
];
1756 while ((j
= ffs(bits
)) && (fd
= i
+ --j
) < nfd
) {
1759 fp
= fp_get_noref_locked(p
, fd
);
1762 * If we abort because of a bad
1763 * fd, let the caller unwind...
1768 if (sel_pass
== SEL_SECONDPASS
) {
1771 selunlinkfp(fp
, seldata
->wqp
[nc
], wqset
);
1773 reserved_link
= waitq_link_reserve((struct waitq
*)wqset
);
1774 rl_ptr
= &reserved_link
;
1775 if (fp
->fp_flags
& FP_INSELECT
) {
1776 /* someone is already in select on this fp */
1777 fp
->fp_flags
|= FP_SELCONFLICT
;
1779 fp
->fp_flags
|= FP_INSELECT
;
1782 waitq_set_lazy_init_link(wqset
);
1785 context
.vc_ucred
= fp
->f_cred
;
1788 * stash this value b/c fo_select may replace
1789 * reserved_link with a pointer to a waitq object
1791 uint64_t rsvd
= reserved_link
;
1793 /* The select; set the bit, if true */
1794 if (fp
->f_ops
&& fp
->f_type
1795 && fo_select(fp
, flag
[msk
], rl_ptr
, &context
)) {
1796 optr
[fd
/ NFDBITS
] |= (1U << (fd
% NFDBITS
));
1799 if (sel_pass
== SEL_FIRSTPASS
) {
1800 waitq_link_release(rsvd
);
1802 * If the fp's supporting selinfo structure was linked
1803 * to this thread's waitq set, then 'reserved_link'
1804 * will have been updated by selrecord to be a pointer
1805 * to the selinfo's waitq.
1807 if (reserved_link
== rsvd
) {
1808 rl_ptr
= NULL
; /* fo_select never called selrecord() */
1811 * Hook up the thread's waitq set either to
1812 * the fileproc structure, or to the global
1813 * conflict queue: but only on the first
1816 seldata
->wqp
[nc
] = sellinkfp(fp
, (void **)rl_ptr
, wqset
);
1828 static int poll_callback(struct kevent_qos_s
*, kevent_ctx_t
);
1831 poll(struct proc
*p
, struct poll_args
*uap
, int32_t *retval
)
1833 __pthread_testcancel(1);
1834 return poll_nocancel(p
, (struct poll_nocancel_args
*)uap
, retval
);
1839 poll_nocancel(struct proc
*p
, struct poll_nocancel_args
*uap
, int32_t *retval
)
1841 struct pollfd
*fds
= NULL
;
1842 struct kqueue
*kq
= NULL
;
1843 int ncoll
, error
= 0;
1844 u_int nfds
= uap
->nfds
;
1846 rlim_t nofile
= proc_limitgetcur(p
, RLIMIT_NOFILE
, TRUE
);
1847 size_t ni
= nfds
* sizeof(struct pollfd
);
1850 * This is kinda bogus. We have fd limits, but that is not
1851 * really related to the size of the pollfd array. Make sure
1852 * we let the process use at least FD_SETSIZE entries and at
1853 * least enough for the current limits. We want to be reasonably
1854 * safe, but not overly restrictive.
1856 if (nfds
> OPEN_MAX
||
1857 (nfds
> nofile
&& (proc_suser(p
) || nfds
> FD_SETSIZE
))) {
1861 kq
= kqueue_alloc(p
);
1867 fds
= kheap_alloc(KHEAP_TEMP
, ni
, Z_WAITOK
);
1873 error
= copyin(uap
->fds
, fds
, nfds
* sizeof(struct pollfd
));
1879 /* JMM - all this P_SELECT stuff is bogus */
1881 OSBitOrAtomic(P_SELECT
, &p
->p_flag
);
1882 for (u_int i
= 0; i
< nfds
; i
++) {
1883 short events
= fds
[i
].events
;
1884 __assert_only
int rc
;
1886 /* per spec, ignore fd values below zero */
1887 if (fds
[i
].fd
< 0) {
1892 /* convert the poll event into a kqueue kevent */
1893 struct kevent_qos_s kev
= {
1895 .flags
= EV_ADD
| EV_ONESHOT
| EV_POLL
,
1896 .udata
= CAST_USER_ADDR_T(&fds
[i
])
1899 /* Handle input events */
1900 if (events
& (POLLIN
| POLLRDNORM
| POLLPRI
| POLLRDBAND
| POLLHUP
)) {
1901 kev
.filter
= EVFILT_READ
;
1902 if (events
& (POLLPRI
| POLLRDBAND
)) {
1903 kev
.flags
|= EV_OOBAND
;
1905 rc
= kevent_register(kq
, &kev
, NULL
);
1906 assert((rc
& FILTER_REGISTER_WAIT
) == 0);
1909 /* Handle output events */
1910 if ((kev
.flags
& EV_ERROR
) == 0 &&
1911 (events
& (POLLOUT
| POLLWRNORM
| POLLWRBAND
))) {
1912 kev
.filter
= EVFILT_WRITE
;
1913 rc
= kevent_register(kq
, &kev
, NULL
);
1914 assert((rc
& FILTER_REGISTER_WAIT
) == 0);
1917 /* Handle BSD extension vnode events */
1918 if ((kev
.flags
& EV_ERROR
) == 0 &&
1919 (events
& (POLLEXTEND
| POLLATTRIB
| POLLNLINK
| POLLWRITE
))) {
1920 kev
.filter
= EVFILT_VNODE
;
1922 if (events
& POLLEXTEND
) {
1923 kev
.fflags
|= NOTE_EXTEND
;
1925 if (events
& POLLATTRIB
) {
1926 kev
.fflags
|= NOTE_ATTRIB
;
1928 if (events
& POLLNLINK
) {
1929 kev
.fflags
|= NOTE_LINK
;
1931 if (events
& POLLWRITE
) {
1932 kev
.fflags
|= NOTE_WRITE
;
1934 rc
= kevent_register(kq
, &kev
, NULL
);
1935 assert((rc
& FILTER_REGISTER_WAIT
) == 0);
1938 if (kev
.flags
& EV_ERROR
) {
1939 fds
[i
].revents
= POLLNVAL
;
1947 * Did we have any trouble registering?
1948 * If user space passed 0 FDs, then respect any timeout value passed.
1949 * This is an extremely inefficient sleep. If user space passed one or
1950 * more FDs, and we had trouble registering _all_ of them, then bail
1951 * out. If a subset of the provided FDs failed to register, then we
1952 * will still call the kqueue_scan function.
1954 if (nfds
&& (rfds
== nfds
)) {
1958 /* scan for, and possibly wait for, the kevents to trigger */
1959 kevent_ctx_t kectx
= kevent_get_context(current_thread());
1960 *kectx
= (struct kevent_ctx_s
){
1961 .kec_process_noutputs
= rfds
,
1962 .kec_process_flags
= KEVENT_FLAG_POLL
,
1963 .kec_deadline
= 0, /* wait forever */
1967 * If any events have trouble registering, an event has fired and we
1968 * shouldn't wait for events in kqueue_scan.
1971 kectx
->kec_process_flags
|= KEVENT_FLAG_IMMEDIATE
;
1972 } else if (uap
->timeout
!= -1) {
1973 clock_interval_to_deadline(uap
->timeout
, NSEC_PER_MSEC
,
1974 &kectx
->kec_deadline
);
1977 error
= kqueue_scan(kq
, kectx
->kec_process_flags
, kectx
, poll_callback
);
1978 rfds
= kectx
->kec_process_noutputs
;
1981 OSBitAndAtomic(~((uint32_t)P_SELECT
), &p
->p_flag
);
1982 /* poll is not restarted after signals... */
1983 if (error
== ERESTART
) {
1987 error
= copyout(fds
, uap
->fds
, nfds
* sizeof(struct pollfd
));
1992 kheap_free(KHEAP_TEMP
, fds
, ni
);
1999 poll_callback(struct kevent_qos_s
*kevp
, kevent_ctx_t kectx
)
2001 struct pollfd
*fds
= CAST_DOWN(struct pollfd
*, kevp
->udata
);
2002 short prev_revents
= fds
->revents
;
2005 /* convert the results back into revents */
2006 if (kevp
->flags
& EV_EOF
) {
2007 fds
->revents
|= POLLHUP
;
2009 if (kevp
->flags
& EV_ERROR
) {
2010 fds
->revents
|= POLLERR
;
2013 switch (kevp
->filter
) {
2015 if (fds
->revents
& POLLHUP
) {
2016 mask
= (POLLIN
| POLLRDNORM
| POLLPRI
| POLLRDBAND
);
2018 mask
= (POLLIN
| POLLRDNORM
);
2019 if (kevp
->flags
& EV_OOBAND
) {
2020 mask
|= (POLLPRI
| POLLRDBAND
);
2023 fds
->revents
|= (fds
->events
& mask
);
2027 if (!(fds
->revents
& POLLHUP
)) {
2028 fds
->revents
|= (fds
->events
& (POLLOUT
| POLLWRNORM
| POLLWRBAND
));
2033 if (kevp
->fflags
& NOTE_EXTEND
) {
2034 fds
->revents
|= (fds
->events
& POLLEXTEND
);
2036 if (kevp
->fflags
& NOTE_ATTRIB
) {
2037 fds
->revents
|= (fds
->events
& POLLATTRIB
);
2039 if (kevp
->fflags
& NOTE_LINK
) {
2040 fds
->revents
|= (fds
->events
& POLLNLINK
);
2042 if (kevp
->fflags
& NOTE_WRITE
) {
2043 fds
->revents
|= (fds
->events
& POLLWRITE
);
2048 if (fds
->revents
!= 0 && prev_revents
== 0) {
2049 kectx
->kec_process_noutputs
++;
2056 seltrue(__unused dev_t dev
, __unused
int flag
, __unused
struct proc
*p
)
2064 * Count the number of bits set in the input bit vector, and establish an
2065 * outstanding fp->fp_iocount for each of the descriptors which will be in
2066 * use in the select operation.
2068 * Parameters: p The process doing the select
2069 * ibits The input bit vector
2070 * nfd The number of fd's in the vector
2071 * countp Pointer to where to store the bit count
2073 * Returns: 0 Success
2074 * EIO Bad per process open file table
2075 * EBADF One of the bits in the input bit vector
2076 * references an invalid fd
2078 * Implicit: *countp (modified) Count of fd's
2080 * Notes: This function is the first pass under the proc_fdlock() that
2081 * permits us to recognize invalid descriptors in the bit vector;
2082 * the may, however, not remain valid through the drop and
2083 * later reacquisition of the proc_fdlock().
2086 selcount(struct proc
*p
, u_int32_t
*ibits
, int nfd
, int *countp
)
2088 struct filedesc
*fdp
= p
->p_fd
;
2091 struct fileproc
*fp
;
2096 int need_wakeup
= 0;
2099 * Problems when reboot; due to MacOSX signal probs
2100 * in Beaker1C ; verify that the p->p_fd is valid
2106 nw
= howmany(nfd
, NFDBITS
);
2109 for (msk
= 0; msk
< 3; msk
++) {
2110 iptr
= (u_int32_t
*)&ibits
[msk
* nw
];
2111 for (i
= 0; i
< nfd
; i
+= NFDBITS
) {
2112 bits
= iptr
[i
/ NFDBITS
];
2113 while ((j
= ffs(bits
)) && (fd
= i
+ --j
) < nfd
) {
2116 fp
= fp_get_noref_locked(p
, fd
);
2122 os_ref_retain_locked(&fp
->fp_iocount
);
2136 /* Ignore error return; it's already EBADF */
2137 (void)seldrop_locked(p
, ibits
, nfd
, n
, &need_wakeup
);
2142 wakeup(&p
->p_fpdrainwait
);
2151 * Drop outstanding wait queue references set up during selscan(); drop the
2152 * outstanding per fileproc fp_iocount picked up during the selcount().
2154 * Parameters: p Process performing the select
2155 * ibits Input bit bector of fd's
2156 * nfd Number of fd's
2157 * lim Limit to number of vector entries to
2158 * consider, or -1 for "all"
2160 * need_wakeup Pointer to flag to set to do a wakeup
2161 * if f_iocont on any descriptor goes to 0
2163 * Returns: 0 Success
2164 * EBADF One or more fds in the bit vector
2165 * were invalid, but the rest
2166 * were successfully dropped
2168 * Notes: An fd make become bad while the proc_fdlock() is not held,
2169 * if a multithreaded application closes the fd out from under
2170 * the in progress select. In this case, we still have to
2171 * clean up after the set up on the remaining fds.
2174 seldrop_locked(struct proc
*p
, u_int32_t
*ibits
, int nfd
, int lim
, int *need_wakeup
)
2176 struct filedesc
*fdp
= p
->p_fd
;
2177 int msk
, i
, j
, nc
, fd
;
2179 struct fileproc
*fp
;
2183 uthread_t uth
= get_bsdthread_info(current_thread());
2184 struct _select_data
*seldata
;
2189 * Problems when reboot; due to MacOSX signal probs
2190 * in Beaker1C ; verify that the p->p_fd is valid
2196 nw
= howmany(nfd
, NFDBITS
);
2197 seldata
= &uth
->uu_save
.uus_select_data
;
2200 for (msk
= 0; msk
< 3; msk
++) {
2201 iptr
= (u_int32_t
*)&ibits
[msk
* nw
];
2202 for (i
= 0; i
< nfd
; i
+= NFDBITS
) {
2203 bits
= iptr
[i
/ NFDBITS
];
2204 while ((j
= ffs(bits
)) && (fd
= i
+ --j
) < nfd
) {
2207 * If we've already dropped as many as were
2208 * counted/scanned, then we are done.
2215 * We took an I/O reference in selcount,
2216 * so the fp can't possibly be NULL.
2218 fp
= fp_get_noref_locked_with_iocount(p
, fd
);
2220 seldata
->wqp
? seldata
->wqp
[nc
] : 0,
2225 const os_ref_count_t refc
= os_ref_release_locked(&fp
->fp_iocount
);
2227 panic("fp_iocount overdecrement!");
2232 * The last iocount is responsible for clearing
2233 * selconfict flag - even if we didn't set it -
2234 * and is also responsible for waking up anyone
2235 * waiting on iocounts to drain.
2237 if (fp
->fp_flags
& FP_SELCONFLICT
) {
2238 fp
->fp_flags
&= ~FP_SELCONFLICT
;
2240 if (p
->p_fpdrainwait
) {
2241 p
->p_fpdrainwait
= 0;
2254 seldrop(struct proc
*p
, u_int32_t
*ibits
, int nfd
, int lim
)
2257 int need_wakeup
= 0;
2260 error
= seldrop_locked(p
, ibits
, nfd
, lim
, &need_wakeup
);
2263 wakeup(&p
->p_fpdrainwait
);
2269 * Record a select request.
2272 selrecord(__unused
struct proc
*selector
, struct selinfo
*sip
, void *s_data
)
2274 thread_t cur_act
= current_thread();
2275 struct uthread
* ut
= get_bsdthread_info(cur_act
);
2276 /* on input, s_data points to the 64-bit ID of a reserved link object */
2277 uint64_t *reserved_link
= (uint64_t *)s_data
;
2279 /* need to look at collisions */
2281 /*do not record if this is second pass of select */
2286 if ((sip
->si_flags
& SI_INITED
) == 0) {
2287 waitq_init(&sip
->si_waitq
, SYNC_POLICY_FIFO
);
2288 sip
->si_flags
|= SI_INITED
;
2289 sip
->si_flags
&= ~SI_CLEAR
;
2292 if (sip
->si_flags
& SI_RECORDED
) {
2293 sip
->si_flags
|= SI_COLL
;
2295 sip
->si_flags
&= ~SI_COLL
;
2298 sip
->si_flags
|= SI_RECORDED
;
2299 /* note: this checks for pre-existing linkage */
2300 waitq_link(&sip
->si_waitq
, ut
->uu_wqset
,
2301 WAITQ_SHOULD_LOCK
, reserved_link
);
2304 * Always consume the reserved link.
2305 * We can always call waitq_link_release() safely because if
2306 * waitq_link is successful, it consumes the link and resets the
2307 * value to 0, in which case our call to release becomes a no-op.
2308 * If waitq_link fails, then the following release call will actually
2309 * release the reserved link object.
2311 waitq_link_release(*reserved_link
);
2315 * Use the s_data pointer as an output parameter as well
2316 * This avoids changing the prototype for this function which is
2317 * used by many kexts. We need to surface the waitq object
2318 * associated with the selinfo we just added to the thread's select
2319 * set. New waitq sets do not have back-pointers to set members, so
2320 * the only way to clear out set linkage objects is to go from the
2321 * waitq to the set. We use a memcpy because s_data could be
2322 * pointing to an unaligned value on the stack
2323 * (especially on 32-bit systems)
2325 void *wqptr
= (void *)&sip
->si_waitq
;
2326 memcpy((void *)s_data
, (void *)&wqptr
, sizeof(void *));
2332 selwakeup(struct selinfo
*sip
)
2334 if ((sip
->si_flags
& SI_INITED
) == 0) {
2338 if (sip
->si_flags
& SI_COLL
) {
2340 sip
->si_flags
&= ~SI_COLL
;
2342 /* will not support */
2343 //wakeup((caddr_t)&selwait);
2347 if (sip
->si_flags
& SI_RECORDED
) {
2348 waitq_wakeup64_all(&sip
->si_waitq
, NO_EVENT64
,
2349 THREAD_AWAKENED
, WAITQ_ALL_PRIORITIES
);
2350 sip
->si_flags
&= ~SI_RECORDED
;
2355 selthreadclear(struct selinfo
*sip
)
2359 if ((sip
->si_flags
& SI_INITED
) == 0) {
2362 if (sip
->si_flags
& SI_RECORDED
) {
2364 sip
->si_flags
&= ~(SI_RECORDED
| SI_COLL
);
2366 sip
->si_flags
|= SI_CLEAR
;
2367 sip
->si_flags
&= ~SI_INITED
;
2369 wq
= &sip
->si_waitq
;
2372 * Higher level logic may have a handle on this waitq's prepost ID,
2373 * but that's OK because the waitq_deinit will remove/invalidate the
2374 * prepost object (as well as mark the waitq invalid). This de-couples
2375 * us from any callers that may have a handle to this waitq via the
2385 * Description: Get the host UUID from IOKit and return it to user space.
2387 * Parameters: uuid_buf Pointer to buffer to receive UUID
2388 * timeout Timespec for timout
2390 * Returns: 0 Success
2391 * EWOULDBLOCK Timeout is too short
2392 * copyout:EFAULT Bad user buffer
2393 * mac_system_check_info:EPERM Client not allowed to perform this operation
2395 * Notes: A timeout seems redundant, since if it's tolerable to not
2396 * have a system UUID in hand, then why ask for one?
2399 gethostuuid(struct proc
*p
, struct gethostuuid_args
*uap
, __unused
int32_t *retval
)
2403 mach_timespec_t mach_ts
; /* for IOKit call */
2404 __darwin_uuid_t uuid_kern
= {}; /* for IOKit call */
2406 /* Check entitlement */
2407 if (!IOTaskHasEntitlement(current_task(), "com.apple.private.getprivatesysid")) {
2408 #if !defined(XNU_TARGET_OS_OSX)
2410 if ((error
= mac_system_check_info(kauth_cred_get(), "hw.uuid")) != 0) {
2411 /* EPERM invokes userspace upcall if present */
2418 /* Convert the 32/64 bit timespec into a mach_timespec_t */
2419 if (proc_is64bit(p
)) {
2420 struct user64_timespec ts
;
2421 error
= copyin(uap
->timeoutp
, &ts
, sizeof(ts
));
2425 mach_ts
.tv_sec
= (unsigned int)ts
.tv_sec
;
2426 mach_ts
.tv_nsec
= (clock_res_t
)ts
.tv_nsec
;
2428 struct user32_timespec ts
;
2429 error
= copyin(uap
->timeoutp
, &ts
, sizeof(ts
));
2433 mach_ts
.tv_sec
= ts
.tv_sec
;
2434 mach_ts
.tv_nsec
= ts
.tv_nsec
;
2437 /* Call IOKit with the stack buffer to get the UUID */
2438 kret
= IOBSDGetPlatformUUID(uuid_kern
, mach_ts
);
2441 * If we get it, copy out the data to the user buffer; note that a
2442 * uuid_t is an array of characters, so this is size invariant for
2445 if (kret
== KERN_SUCCESS
) {
2446 error
= copyout(uuid_kern
, uap
->uuid_buf
, sizeof(uuid_kern
));
2448 error
= EWOULDBLOCK
;
2457 * Description: Omnibus system call for ledger operations
2460 ledger(struct proc
*p
, struct ledger_args
*args
, __unused
int32_t *retval
)
2465 int rval
, pid
, len
, error
;
2467 struct ledger_limit_args lla
;
2472 /* Finish copying in the necessary args before taking the proc lock */
2475 if (args
->cmd
== LEDGER_ENTRY_INFO
) {
2476 error
= copyin(args
->arg3
, (char *)&len
, sizeof(len
));
2477 } else if (args
->cmd
== LEDGER_TEMPLATE_INFO
) {
2478 error
= copyin(args
->arg2
, (char *)&len
, sizeof(len
));
2479 } else if (args
->cmd
== LEDGER_LIMIT
)
2481 { error
= copyin(args
->arg2
, (char *)&lla
, sizeof(lla
));}
2485 else if ((args
->cmd
< 0) || (args
->cmd
> LEDGER_MAX_CMD
)) {
2497 if (args
->cmd
!= LEDGER_TEMPLATE_INFO
) {
2498 pid
= (int)args
->arg1
;
2499 proc
= proc_find(pid
);
2505 error
= mac_proc_check_ledger(p
, proc
, args
->cmd
);
2515 switch (args
->cmd
) {
2517 case LEDGER_LIMIT
: {
2518 if (!kauth_cred_issuser(kauth_cred_get())) {
2521 rval
= ledger_limit(task
, &lla
);
2527 struct ledger_info info
= {};
2529 rval
= ledger_info(task
, &info
);
2532 rval
= copyout(&info
, args
->arg2
,
2538 case LEDGER_ENTRY_INFO
: {
2542 rval
= ledger_get_task_entry_info_multiple(task
, &buf
, &len
);
2544 if ((rval
== 0) && (len
>= 0)) {
2545 sz
= len
* sizeof(struct ledger_entry_info
);
2546 rval
= copyout(buf
, args
->arg2
, sz
);
2547 kheap_free(KHEAP_DATA_BUFFERS
, buf
, sz
);
2550 rval
= copyout(&len
, args
->arg3
, sizeof(len
));
2555 case LEDGER_TEMPLATE_INFO
: {
2559 rval
= ledger_template_info(&buf
, &len
);
2560 if ((rval
== 0) && (len
>= 0)) {
2561 sz
= len
* sizeof(struct ledger_template_info
);
2562 rval
= copyout(buf
, args
->arg1
, sz
);
2563 kheap_free(KHEAP_DATA_BUFFERS
, buf
, sz
);
2566 rval
= copyout(&len
, args
->arg2
, sizeof(len
));
2572 panic("ledger syscall logic error -- command type %d", args
->cmd
);
2581 telemetry(__unused
struct proc
*p
, struct telemetry_args
*args
, __unused
int32_t *retval
)
2585 switch (args
->cmd
) {
2586 #if CONFIG_TELEMETRY
2587 case TELEMETRY_CMD_TIMER_EVENT
:
2588 error
= telemetry_timer_event(args
->deadline
, args
->interval
, args
->leeway
);
2590 case TELEMETRY_CMD_PMI_SETUP
:
2591 error
= telemetry_pmi_setup((enum telemetry_pmi
)args
->deadline
, args
->interval
);
2593 #endif /* CONFIG_TELEMETRY */
2594 case TELEMETRY_CMD_VOUCHER_NAME
:
2595 if (thread_set_voucher_name((mach_port_name_t
)args
->deadline
)) {
2611 * Description: syscall to access kernel logging from userspace
2614 * tag - used for syncing with userspace on the version.
2615 * flags - flags used by the syscall.
2616 * buffer - userspace address of string to copy.
2617 * size - size of buffer.
2620 log_data(__unused
struct proc
*p
, struct log_data_args
*args
, int *retval
)
2622 unsigned int tag
= args
->tag
;
2623 unsigned int flags
= args
->flags
;
2624 user_addr_t buffer
= args
->buffer
;
2625 unsigned int size
= args
->size
;
2627 char *log_msg
= NULL
;
2632 * Tag synchronize the syscall version with userspace.
2633 * Tag == 0 => flags == OS_LOG_TYPE
2640 * OS_LOG_TYPE are defined in libkern/os/log.h
2641 * In userspace they are defined in libtrace/os/log.h
2643 if (flags
!= OS_LOG_TYPE_DEFAULT
&&
2644 flags
!= OS_LOG_TYPE_INFO
&&
2645 flags
!= OS_LOG_TYPE_DEBUG
&&
2646 flags
!= OS_LOG_TYPE_ERROR
&&
2647 flags
!= OS_LOG_TYPE_FAULT
) {
2655 /* truncate to OS_LOG_DATA_MAX_SIZE */
2656 if (size
> OS_LOG_DATA_MAX_SIZE
) {
2657 printf("%s: WARNING msg is going to be truncated from %u to %u\n",
2658 __func__
, size
, OS_LOG_DATA_MAX_SIZE
);
2659 size
= OS_LOG_DATA_MAX_SIZE
;
2662 log_msg
= kheap_alloc(KHEAP_TEMP
, size
, Z_WAITOK
);
2667 error
= copyin(buffer
, log_msg
, size
);
2672 log_msg
[size
- 1] = '\0';
2675 * This will log to dmesg and logd.
2676 * The call will fail if the current
2677 * process is not a driverKit process.
2679 os_log_driverKit(&ret
, OS_LOG_DEFAULT
, (os_log_type_t
)flags
, "%s", log_msg
);
2682 if (log_msg
!= NULL
) {
2683 kheap_free(KHEAP_TEMP
, log_msg
, size
);
2689 #if DEVELOPMENT || DEBUG
2690 #if CONFIG_WAITQ_DEBUG
2691 static uint64_t g_wqset_num
= 0;
2694 struct waitq_set
*wqset
;
2697 static queue_head_t g_wqset_list
;
2698 static struct waitq_set
*g_waitq_set
= NULL
;
2700 static inline struct waitq_set
*
2701 sysctl_get_wqset(int idx
)
2703 struct g_wqset
*gwqs
;
2706 queue_init(&g_wqset_list
);
2709 /* don't bother with locks: this is test-only code! */
2710 qe_foreach_element(gwqs
, &g_wqset_list
, link
) {
2711 if ((int)(wqset_id(gwqs
->wqset
) & 0xffffffff) == idx
) {
2716 /* allocate a new one */
2718 gwqs
= (struct g_wqset
*)kalloc(sizeof(*gwqs
));
2719 assert(gwqs
!= NULL
);
2721 gwqs
->wqset
= waitq_set_alloc(SYNC_POLICY_FIFO
| SYNC_POLICY_PREPOST
, NULL
);
2722 enqueue_tail(&g_wqset_list
, &gwqs
->link
);
2723 printf("[WQ]: created new waitq set 0x%llx\n", wqset_id(gwqs
->wqset
));
2728 #define MAX_GLOBAL_TEST_QUEUES 64
2729 static int g_wq_init
= 0;
2730 static struct waitq g_wq
[MAX_GLOBAL_TEST_QUEUES
];
2732 static inline struct waitq
*
2733 global_test_waitq(int idx
)
2741 for (int i
= 0; i
< MAX_GLOBAL_TEST_QUEUES
; i
++) {
2742 waitq_init(&g_wq
[i
], SYNC_POLICY_FIFO
);
2746 return &g_wq
[idx
% MAX_GLOBAL_TEST_QUEUES
];
2749 static int sysctl_waitq_wakeup_one SYSCTL_HANDLER_ARGS
2751 #pragma unused(oidp, arg1, arg2)
2754 struct waitq
*waitq
;
2756 int64_t event64
= 0;
2758 error
= SYSCTL_IN(req
, &event64
, sizeof(event64
));
2764 return SYSCTL_OUT(req
, &event64
, sizeof(event64
));
2768 index
= (int)((-event64
) & 0xffffffff);
2769 waitq
= wqset_waitq(sysctl_get_wqset(index
));
2772 index
= (int)event64
;
2773 waitq
= global_test_waitq(index
);
2778 printf("[WQ]: Waking one thread on waitq [%d] event:0x%llx\n",
2780 kr
= waitq_wakeup64_one(waitq
, (event64_t
)event64
, THREAD_AWAKENED
,
2781 WAITQ_ALL_PRIORITIES
);
2782 printf("[WQ]: \tkr=%d\n", kr
);
2784 return SYSCTL_OUT(req
, &kr
, sizeof(kr
));
2786 SYSCTL_PROC(_kern
, OID_AUTO
, waitq_wakeup_one
, CTLTYPE_QUAD
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
2787 0, 0, sysctl_waitq_wakeup_one
, "Q", "wakeup one thread waiting on given event");
2790 static int sysctl_waitq_wakeup_all SYSCTL_HANDLER_ARGS
2792 #pragma unused(oidp, arg1, arg2)
2795 struct waitq
*waitq
;
2797 int64_t event64
= 0;
2799 error
= SYSCTL_IN(req
, &event64
, sizeof(event64
));
2805 return SYSCTL_OUT(req
, &event64
, sizeof(event64
));
2809 index
= (int)((-event64
) & 0xffffffff);
2810 waitq
= wqset_waitq(sysctl_get_wqset(index
));
2813 index
= (int)event64
;
2814 waitq
= global_test_waitq(index
);
2819 printf("[WQ]: Waking all threads on waitq [%d] event:0x%llx\n",
2821 kr
= waitq_wakeup64_all(waitq
, (event64_t
)event64
,
2822 THREAD_AWAKENED
, WAITQ_ALL_PRIORITIES
);
2823 printf("[WQ]: \tkr=%d\n", kr
);
2825 return SYSCTL_OUT(req
, &kr
, sizeof(kr
));
2827 SYSCTL_PROC(_kern
, OID_AUTO
, waitq_wakeup_all
, CTLTYPE_QUAD
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
2828 0, 0, sysctl_waitq_wakeup_all
, "Q", "wakeup all threads waiting on given event");
2831 static int sysctl_waitq_wait SYSCTL_HANDLER_ARGS
2833 #pragma unused(oidp, arg1, arg2)
2836 struct waitq
*waitq
;
2838 int64_t event64
= 0;
2840 error
= SYSCTL_IN(req
, &event64
, sizeof(event64
));
2846 return SYSCTL_OUT(req
, &event64
, sizeof(event64
));
2850 index
= (int)((-event64
) & 0xffffffff);
2851 waitq
= wqset_waitq(sysctl_get_wqset(index
));
2854 index
= (int)event64
;
2855 waitq
= global_test_waitq(index
);
2860 printf("[WQ]: Current thread waiting on waitq [%d] event:0x%llx\n",
2862 kr
= waitq_assert_wait64(waitq
, (event64_t
)event64
, THREAD_INTERRUPTIBLE
, 0);
2863 if (kr
== THREAD_WAITING
) {
2864 thread_block(THREAD_CONTINUE_NULL
);
2866 printf("[WQ]: \tWoke Up: kr=%d\n", kr
);
2868 return SYSCTL_OUT(req
, &kr
, sizeof(kr
));
2870 SYSCTL_PROC(_kern
, OID_AUTO
, waitq_wait
, CTLTYPE_QUAD
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
2871 0, 0, sysctl_waitq_wait
, "Q", "start waiting on given event");
2874 static int sysctl_wqset_select SYSCTL_HANDLER_ARGS
2876 #pragma unused(oidp, arg1, arg2)
2878 struct waitq_set
*wqset
;
2879 uint64_t event64
= 0;
2881 error
= SYSCTL_IN(req
, &event64
, sizeof(event64
));
2890 wqset
= sysctl_get_wqset((int)(event64
& 0xffffffff));
2891 g_waitq_set
= wqset
;
2893 event64
= wqset_id(wqset
);
2894 printf("[WQ]: selected wqset 0x%llx\n", event64
);
2898 event64
= wqset_id(g_waitq_set
);
2900 event64
= (uint64_t)(-1);
2903 return SYSCTL_OUT(req
, &event64
, sizeof(event64
));
2905 SYSCTL_PROC(_kern
, OID_AUTO
, wqset_select
, CTLTYPE_QUAD
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
2906 0, 0, sysctl_wqset_select
, "Q", "select/create a global waitq set");
2909 static int sysctl_waitq_link SYSCTL_HANDLER_ARGS
2911 #pragma unused(oidp, arg1, arg2)
2914 struct waitq
*waitq
;
2915 struct waitq_set
*wqset
;
2917 uint64_t reserved_link
= 0;
2918 int64_t event64
= 0;
2920 error
= SYSCTL_IN(req
, &event64
, sizeof(event64
));
2926 return SYSCTL_OUT(req
, &event64
, sizeof(event64
));
2930 g_waitq_set
= sysctl_get_wqset(1);
2932 wqset
= g_waitq_set
;
2935 struct waitq_set
*tmp
;
2936 index
= (int)((-event64
) & 0xffffffff);
2937 tmp
= sysctl_get_wqset(index
);
2941 waitq
= wqset_waitq(tmp
);
2944 index
= (int)event64
;
2945 waitq
= global_test_waitq(index
);
2948 printf("[WQ]: linking waitq [%d] to global wqset (0x%llx)\n",
2949 index
, wqset_id(wqset
));
2950 reserved_link
= waitq_link_reserve(waitq
);
2951 kr
= waitq_link(waitq
, wqset
, WAITQ_SHOULD_LOCK
, &reserved_link
);
2952 waitq_link_release(reserved_link
);
2954 printf("[WQ]: \tkr=%d\n", kr
);
2957 return SYSCTL_OUT(req
, &kr
, sizeof(kr
));
2959 SYSCTL_PROC(_kern
, OID_AUTO
, waitq_link
, CTLTYPE_QUAD
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
2960 0, 0, sysctl_waitq_link
, "Q", "link global waitq to test waitq set");
2963 static int sysctl_waitq_unlink SYSCTL_HANDLER_ARGS
2965 #pragma unused(oidp, arg1, arg2)
2968 struct waitq
*waitq
;
2969 struct waitq_set
*wqset
;
2971 uint64_t event64
= 0;
2973 error
= SYSCTL_IN(req
, &event64
, sizeof(event64
));
2979 return SYSCTL_OUT(req
, &event64
, sizeof(event64
));
2983 g_waitq_set
= sysctl_get_wqset(1);
2985 wqset
= g_waitq_set
;
2987 index
= (int)event64
;
2988 waitq
= global_test_waitq(index
);
2990 printf("[WQ]: unlinking waitq [%d] from global wqset (0x%llx)\n",
2991 index
, wqset_id(wqset
));
2993 kr
= waitq_unlink(waitq
, wqset
);
2994 printf("[WQ]: \tkr=%d\n", kr
);
2996 return SYSCTL_OUT(req
, &kr
, sizeof(kr
));
2998 SYSCTL_PROC(_kern
, OID_AUTO
, waitq_unlink
, CTLTYPE_QUAD
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
2999 0, 0, sysctl_waitq_unlink
, "Q", "unlink global waitq from test waitq set");
3002 static int sysctl_waitq_clear_prepost SYSCTL_HANDLER_ARGS
3004 #pragma unused(oidp, arg1, arg2)
3005 struct waitq
*waitq
;
3006 uint64_t event64
= 0;
3009 error
= SYSCTL_IN(req
, &event64
, sizeof(event64
));
3015 return SYSCTL_OUT(req
, &event64
, sizeof(event64
));
3018 index
= (int)event64
;
3019 waitq
= global_test_waitq(index
);
3021 printf("[WQ]: clearing prepost on waitq [%d]\n", index
);
3022 waitq_clear_prepost(waitq
);
3024 return SYSCTL_OUT(req
, &event64
, sizeof(event64
));
3026 SYSCTL_PROC(_kern
, OID_AUTO
, waitq_clear_prepost
, CTLTYPE_QUAD
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
3027 0, 0, sysctl_waitq_clear_prepost
, "Q", "clear prepost on given waitq");
3030 static int sysctl_wqset_unlink_all SYSCTL_HANDLER_ARGS
3032 #pragma unused(oidp, arg1, arg2)
3034 struct waitq_set
*wqset
;
3036 uint64_t event64
= 0;
3038 error
= SYSCTL_IN(req
, &event64
, sizeof(event64
));
3044 return SYSCTL_OUT(req
, &event64
, sizeof(event64
));
3048 g_waitq_set
= sysctl_get_wqset(1);
3050 wqset
= g_waitq_set
;
3052 printf("[WQ]: unlinking all queues from global wqset (0x%llx)\n",
3055 kr
= waitq_set_unlink_all(wqset
);
3056 printf("[WQ]: \tkr=%d\n", kr
);
3058 return SYSCTL_OUT(req
, &kr
, sizeof(kr
));
3060 SYSCTL_PROC(_kern
, OID_AUTO
, wqset_unlink_all
, CTLTYPE_QUAD
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
3061 0, 0, sysctl_wqset_unlink_all
, "Q", "unlink all queues from test waitq set");
3064 static int sysctl_wqset_clear_preposts SYSCTL_HANDLER_ARGS
3066 #pragma unused(oidp, arg1, arg2)
3067 struct waitq_set
*wqset
= NULL
;
3068 uint64_t event64
= 0;
3071 error
= SYSCTL_IN(req
, &event64
, sizeof(event64
));
3080 index
= (int)((event64
) & 0xffffffff);
3081 wqset
= sysctl_get_wqset(index
);
3082 assert(wqset
!= NULL
);
3084 printf("[WQ]: clearing preposts on wqset 0x%llx\n", wqset_id(wqset
));
3085 waitq_set_clear_preposts(wqset
);
3089 event64
= wqset_id(wqset
);
3091 event64
= (uint64_t)(-1);
3094 return SYSCTL_OUT(req
, &event64
, sizeof(event64
));
3096 SYSCTL_PROC(_kern
, OID_AUTO
, wqset_clear_preposts
, CTLTYPE_QUAD
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
3097 0, 0, sysctl_wqset_clear_preposts
, "Q", "clear preposts on given waitq set");
3099 #endif /* CONFIG_WAITQ_DEBUG */
3102 sysctl_waitq_set_nelem SYSCTL_HANDLER_ARGS
3104 #pragma unused(oidp, arg1, arg2)
3108 if (req
->newptr
!= USER_ADDR_NULL
) {
3112 nelem
= sysctl_helper_waitq_set_nelem();
3114 return SYSCTL_OUT(req
, &nelem
, sizeof(nelem
));
3117 SYSCTL_PROC(_kern
, OID_AUTO
, n_ltable_entries
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
3118 0, 0, sysctl_waitq_set_nelem
, "I", "ltable elementis currently used");
3122 sysctl_mpsc_test_pingpong SYSCTL_HANDLER_ARGS
3124 #pragma unused(oidp, arg1, arg2)
3128 error
= SYSCTL_IN(req
, &value
, sizeof(value
));
3133 if (error
== 0 && req
->newptr
) {
3134 error
= mpsc_test_pingpong(value
, &value
);
3136 error
= SYSCTL_OUT(req
, &value
, sizeof(value
));
3142 SYSCTL_PROC(_kern
, OID_AUTO
, mpsc_test_pingpong
, CTLTYPE_QUAD
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
3143 0, 0, sysctl_mpsc_test_pingpong
, "Q", "MPSC tests: pingpong");
3145 #endif /* DEVELOPMENT || DEBUG */
3148 SYSCTL_NODE(_machdep
, OID_AUTO
, remotetime
, CTLFLAG_RD
| CTLFLAG_LOCKED
, 0, "Remote time api");
3150 #if DEVELOPMENT || DEBUG
3151 #if CONFIG_MACH_BRIDGE_SEND_TIME
3152 extern _Atomic
uint32_t bt_init_flag
;
3153 extern uint32_t mach_bridge_timer_enable(uint32_t, int);
3155 SYSCTL_INT(_machdep_remotetime
, OID_AUTO
, bridge_timer_init_flag
,
3156 CTLFLAG_RD
| CTLFLAG_LOCKED
, &bt_init_flag
, 0, "");
3158 static int sysctl_mach_bridge_timer_enable SYSCTL_HANDLER_ARGS
3160 #pragma unused(oidp, arg1, arg2)
3163 /* User is querying buffer size */
3164 if (req
->oldptr
== USER_ADDR_NULL
&& req
->newptr
== USER_ADDR_NULL
) {
3165 req
->oldidx
= sizeof(value
);
3168 if (os_atomic_load(&bt_init_flag
, acquire
)) {
3171 error
= SYSCTL_IN(req
, &new_value
, sizeof(new_value
));
3175 if (new_value
== 0 || new_value
== 1) {
3176 value
= mach_bridge_timer_enable(new_value
, 1);
3181 value
= mach_bridge_timer_enable(0, 0);
3184 error
= SYSCTL_OUT(req
, &value
, sizeof(value
));
3188 SYSCTL_PROC(_machdep_remotetime
, OID_AUTO
, bridge_timer_enable
,
3189 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
3190 0, 0, sysctl_mach_bridge_timer_enable
, "I", "");
3192 #endif /* CONFIG_MACH_BRIDGE_SEND_TIME */
3194 static int sysctl_mach_bridge_remote_time SYSCTL_HANDLER_ARGS
3196 #pragma unused(oidp, arg1, arg2)
3197 uint64_t ltime
= 0, rtime
= 0;
3198 if (req
->oldptr
== USER_ADDR_NULL
) {
3199 req
->oldidx
= sizeof(rtime
);
3203 int error
= SYSCTL_IN(req
, <ime
, sizeof(ltime
));
3208 rtime
= mach_bridge_remote_time(ltime
);
3209 return SYSCTL_OUT(req
, &rtime
, sizeof(rtime
));
3211 SYSCTL_PROC(_machdep_remotetime
, OID_AUTO
, mach_bridge_remote_time
,
3212 CTLTYPE_QUAD
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
3213 0, 0, sysctl_mach_bridge_remote_time
, "Q", "");
3215 #endif /* DEVELOPMENT || DEBUG */
3217 #if CONFIG_MACH_BRIDGE_RECV_TIME
3218 extern struct bt_params
bt_params_get_latest(void);
3220 static int sysctl_mach_bridge_conversion_params SYSCTL_HANDLER_ARGS
3222 #pragma unused(oidp, arg1, arg2)
3223 struct bt_params params
= {};
3224 if (req
->oldptr
== USER_ADDR_NULL
) {
3225 req
->oldidx
= sizeof(struct bt_params
);
3231 params
= bt_params_get_latest();
3232 return SYSCTL_OUT(req
, ¶ms
, MIN(sizeof(params
), req
->oldlen
));
3235 SYSCTL_PROC(_machdep_remotetime
, OID_AUTO
, conversion_params
,
3236 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_LOCKED
, 0,
3237 0, sysctl_mach_bridge_conversion_params
, "S,bt_params", "");
3239 #endif /* CONFIG_MACH_BRIDGE_RECV_TIME */
3241 #if DEVELOPMENT || DEBUG
3243 #include <pexpert/pexpert.h>
3244 extern int32_t sysctl_get_bound_cpuid(void);
3245 extern kern_return_t
sysctl_thread_bind_cpuid(int32_t cpuid
);
3247 sysctl_kern_sched_thread_bind_cpu SYSCTL_HANDLER_ARGS
3249 #pragma unused(oidp, arg1, arg2)
3252 * DO NOT remove this bootarg guard or make this non-development.
3253 * This kind of binding should only be used for tests and
3254 * experiments in a custom configuration, never shipping code.
3257 if (!PE_parse_boot_argn("enable_skstb", NULL
, 0)) {
3261 int32_t cpuid
= sysctl_get_bound_cpuid();
3265 int error
= sysctl_io_number(req
, cpuid
, sizeof cpuid
, &new_value
, &changed
);
3271 kern_return_t kr
= sysctl_thread_bind_cpuid(new_value
);
3273 if (kr
== KERN_NOT_SUPPORTED
) {
3277 if (kr
== KERN_INVALID_VALUE
) {
3285 SYSCTL_PROC(_kern
, OID_AUTO
, sched_thread_bind_cpu
, CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
3286 0, 0, sysctl_kern_sched_thread_bind_cpu
, "I", "");
3289 extern char sysctl_get_bound_cluster_type(void);
3290 extern void sysctl_thread_bind_cluster_type(char cluster_type
);
3292 sysctl_kern_sched_thread_bind_cluster_type SYSCTL_HANDLER_ARGS
3294 #pragma unused(oidp, arg1, arg2)
3297 if (!PE_parse_boot_argn("enable_skstb", NULL
, 0)) {
3301 int error
= SYSCTL_IN(req
, buff
, 1);
3305 char cluster_type
= buff
[0];
3311 sysctl_thread_bind_cluster_type(cluster_type
);
3313 cluster_type
= sysctl_get_bound_cluster_type();
3314 buff
[0] = cluster_type
;
3316 return SYSCTL_OUT(req
, buff
, 1);
3319 SYSCTL_PROC(_kern
, OID_AUTO
, sched_thread_bind_cluster_type
, CTLTYPE_STRING
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
3320 0, 0, sysctl_kern_sched_thread_bind_cluster_type
, "A", "");
3322 extern char sysctl_get_task_cluster_type(void);
3323 extern void sysctl_task_set_cluster_type(char cluster_type
);
3325 sysctl_kern_sched_task_set_cluster_type SYSCTL_HANDLER_ARGS
3327 #pragma unused(oidp, arg1, arg2)
3330 if (!PE_parse_boot_argn("enable_skstsct", NULL
, 0)) {
3334 int error
= SYSCTL_IN(req
, buff
, 1);
3338 char cluster_type
= buff
[0];
3344 sysctl_task_set_cluster_type(cluster_type
);
3346 cluster_type
= sysctl_get_task_cluster_type();
3347 buff
[0] = cluster_type
;
3349 return SYSCTL_OUT(req
, buff
, 1);
3352 SYSCTL_PROC(_kern
, OID_AUTO
, sched_task_set_cluster_type
, CTLTYPE_STRING
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
3353 0, 0, sysctl_kern_sched_task_set_cluster_type
, "A", "");
3355 #if CONFIG_SCHED_EDGE
3358 * Edge Scheduler Sysctls
3360 * The Edge scheduler uses edge configurations to decide feasability of
3361 * migrating threads across clusters. The sysctls allow dynamic configuration
3362 * of the edge properties and edge weights. This configuration is typically
3363 * updated via callouts from CLPC.
3365 * <Edge Multi-cluster Support Needed>
3367 extern sched_clutch_edge sched_edge_config_e_to_p
;
3368 extern sched_clutch_edge sched_edge_config_p_to_e
;
3369 extern kern_return_t
sched_edge_sysctl_configure_e_to_p(uint64_t);
3370 extern kern_return_t
sched_edge_sysctl_configure_p_to_e(uint64_t);
3371 extern sched_clutch_edge
sched_edge_e_to_p(void);
3372 extern sched_clutch_edge
sched_edge_p_to_e(void);
3374 static int sysctl_sched_edge_config_e_to_p SYSCTL_HANDLER_ARGS
3376 #pragma unused(oidp, arg1, arg2)
3379 int64_t edge_config
= 0;
3381 error
= SYSCTL_IN(req
, &edge_config
, sizeof(edge_config
));
3387 edge_config
= sched_edge_e_to_p().sce_edge_packed
;
3388 return SYSCTL_OUT(req
, &edge_config
, sizeof(edge_config
));
3391 kr
= sched_edge_sysctl_configure_e_to_p(edge_config
);
3392 return SYSCTL_OUT(req
, &kr
, sizeof(kr
));
3394 SYSCTL_PROC(_kern
, OID_AUTO
, sched_edge_config_e_to_p
, CTLTYPE_QUAD
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
3395 0, 0, sysctl_sched_edge_config_e_to_p
, "Q", "Edge Scheduler Config for E-to-P cluster");
3397 static int sysctl_sched_edge_config_p_to_e SYSCTL_HANDLER_ARGS
3399 #pragma unused(oidp, arg1, arg2)
3402 int64_t edge_config
= 0;
3404 error
= SYSCTL_IN(req
, &edge_config
, sizeof(edge_config
));
3410 edge_config
= sched_edge_p_to_e().sce_edge_packed
;
3411 return SYSCTL_OUT(req
, &edge_config
, sizeof(edge_config
));
3414 kr
= sched_edge_sysctl_configure_p_to_e(edge_config
);
3415 return SYSCTL_OUT(req
, &kr
, sizeof(kr
));
3417 SYSCTL_PROC(_kern
, OID_AUTO
, sched_edge_config_p_to_e
, CTLTYPE_QUAD
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
3418 0, 0, sysctl_sched_edge_config_p_to_e
, "Q", "Edge Scheduler Config for P-to-E cluster");
3420 extern int sched_edge_restrict_ut
;
3421 SYSCTL_INT(_kern
, OID_AUTO
, sched_edge_restrict_ut
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &sched_edge_restrict_ut
, 0, "Edge Scheduler Restrict UT Threads");
3422 extern int sched_edge_restrict_bg
;
3423 SYSCTL_INT(_kern
, OID_AUTO
, sched_edge_restrict_bg
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &sched_edge_restrict_ut
, 0, "Edge Scheduler Restrict BG Threads");
3424 extern int sched_edge_migrate_ipi_immediate
;
3425 SYSCTL_INT(_kern
, OID_AUTO
, sched_edge_migrate_ipi_immediate
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &sched_edge_migrate_ipi_immediate
, 0, "Edge Scheduler uses immediate IPIs for migration event based on execution latency");
3427 #endif /* CONFIG_SCHED_EDGE */
3429 #endif /* __AMP__ */
3431 /* used for testing by exception_tests */
3432 extern uint32_t ipc_control_port_options
;
3433 SYSCTL_INT(_kern
, OID_AUTO
, ipc_control_port_options
,
3434 CTLFLAG_RD
| CTLFLAG_LOCKED
, &ipc_control_port_options
, 0, "");
3436 #endif /* DEVELOPMENT || DEBUG */
3438 extern uint32_t task_exc_guard_default
;
3440 SYSCTL_INT(_kern
, OID_AUTO
, task_exc_guard_default
,
3441 CTLFLAG_RD
| CTLFLAG_LOCKED
, &task_exc_guard_default
, 0, "");
3445 sysctl_kern_tcsm_available SYSCTL_HANDLER_ARGS
3447 #pragma unused(oidp, arg1, arg2)
3448 uint32_t value
= machine_csv(CPUVN_CI
) ? 1 : 0;
3454 return SYSCTL_OUT(req
, &value
, sizeof(value
));
3456 SYSCTL_PROC(_kern
, OID_AUTO
, tcsm_available
,
3457 CTLTYPE_INT
| CTLFLAG_RD
| CTLFLAG_LOCKED
| CTLFLAG_MASKED
| CTLFLAG_ANYBODY
,
3458 0, 0, sysctl_kern_tcsm_available
, "I", "");
3462 sysctl_kern_tcsm_enable SYSCTL_HANDLER_ARGS
3464 #pragma unused(oidp, arg1, arg2)
3465 uint32_t soflags
= 0;
3466 uint32_t old_value
= thread_get_no_smt() ? 1 : 0;
3468 int error
= SYSCTL_IN(req
, &soflags
, sizeof(soflags
));
3473 if (soflags
&& machine_csv(CPUVN_CI
)) {
3474 thread_set_no_smt(true);
3475 machine_tecs(current_thread());
3478 return SYSCTL_OUT(req
, &old_value
, sizeof(old_value
));
3480 SYSCTL_PROC(_kern
, OID_AUTO
, tcsm_enable
,
3481 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_LOCKED
| CTLFLAG_MASKED
| CTLFLAG_ANYBODY
,
3482 0, 0, sysctl_kern_tcsm_enable
, "I", "");
3485 #if DEVELOPMENT || DEBUG
3486 extern void sysctl_task_set_no_smt(char no_smt
);
3487 extern char sysctl_task_get_no_smt(void);
3490 sysctl_kern_sched_task_set_no_smt SYSCTL_HANDLER_ARGS
3492 #pragma unused(oidp, arg1, arg2)
3495 int error
= SYSCTL_IN(req
, buff
, 1);
3499 char no_smt
= buff
[0];
3505 sysctl_task_set_no_smt(no_smt
);
3507 no_smt
= sysctl_task_get_no_smt();
3510 return SYSCTL_OUT(req
, buff
, 1);
3513 SYSCTL_PROC(_kern
, OID_AUTO
, sched_task_set_no_smt
, CTLTYPE_STRING
| CTLFLAG_RW
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
,
3514 0, 0, sysctl_kern_sched_task_set_no_smt
, "A", "");
3517 sysctl_kern_sched_thread_set_no_smt(__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
3519 int new_value
, changed
;
3520 int old_value
= thread_get_no_smt() ? 1 : 0;
3521 int error
= sysctl_io_number(req
, old_value
, sizeof(int), &new_value
, &changed
);
3524 thread_set_no_smt(!!new_value
);
3530 SYSCTL_PROC(_kern
, OID_AUTO
, sched_thread_set_no_smt
,
3531 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
,
3532 0, 0, sysctl_kern_sched_thread_set_no_smt
, "I", "");
3535 sysctl_kern_debug_get_preoslog SYSCTL_HANDLER_ARGS
3537 #pragma unused(oidp, arg1, arg2)
3538 static bool oneshot_executed
= false;
3539 size_t preoslog_size
= 0;
3540 const char *preoslog
= NULL
;
3542 // DumpPanic pases a non-zero write value when it needs oneshot behaviour
3544 uint8_t oneshot
= 0;
3545 int error
= SYSCTL_IN(req
, &oneshot
, sizeof(oneshot
));
3551 if (!OSCompareAndSwap8(false, true, &oneshot_executed
)) {
3557 preoslog
= sysctl_debug_get_preoslog(&preoslog_size
);
3558 if (preoslog
== NULL
|| preoslog_size
== 0) {
3562 if (req
->oldptr
== USER_ADDR_NULL
) {
3563 req
->oldidx
= preoslog_size
;
3567 return SYSCTL_OUT(req
, preoslog
, preoslog_size
);
3570 SYSCTL_PROC(_kern
, OID_AUTO
, preoslog
, CTLTYPE_OPAQUE
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
3571 0, 0, sysctl_kern_debug_get_preoslog
, "-", "");
3574 sysctl_kern_task_set_filter_msg_flag SYSCTL_HANDLER_ARGS
3576 #pragma unused(oidp, arg1, arg2)
3577 int new_value
, changed
;
3578 int old_value
= task_get_filter_msg_flag(current_task()) ? 1 : 0;
3579 int error
= sysctl_io_number(req
, old_value
, sizeof(int), &new_value
, &changed
);
3582 task_set_filter_msg_flag(current_task(), !!new_value
);
3588 SYSCTL_PROC(_kern
, OID_AUTO
, task_set_filter_msg_flag
, CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
3589 0, 0, sysctl_kern_task_set_filter_msg_flag
, "I", "");
3591 #endif /* DEVELOPMENT || DEBUG */