xref: /xnu-12377.81.4/bsd/kern/kern_sysctl.c (revision 043036a2b3718f7f0be807e2870f8f47d3fa0796)
1 /*
2  * Copyright (c) 2000-2025 Apple 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, 1989, 1993
31  *	The Regents of the University of California.  All rights reserved.
32  *
33  * This code is derived from software contributed to Berkeley by
34  * Mike Karels at Berkeley Software Design, Inc.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  * 3. All advertising materials mentioning features or use of this software
45  *    must display the following acknowledgement:
46  *	This product includes software developed by the University of
47  *	California, Berkeley and its contributors.
48  * 4. Neither the name of the University nor the names of its contributors
49  *    may be used to endorse or promote products derived from this software
50  *    without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62  * SUCH DAMAGE.
63  *
64  *	@(#)kern_sysctl.c	8.4 (Berkeley) 4/14/94
65  */
66 /*
67  * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
68  * support for mandatory and extensible security protections.  This notice
69  * is included in support of clause 2.2 (b) of the Apple Public License,
70  * Version 2.0.
71  */
72 
73 /*
74  * DEPRECATED sysctl system call code
75  *
76  * Everything in this file is deprecated. Sysctls should be handled
77  * by the code in kern_newsysctl.c.
78  * The remaining "case" sections are supposed to be converted into
79  * SYSCTL_*-style definitions, and as soon as all of them are gone,
80  * this source file is supposed to die.
81  *
82  * DO NOT ADD ANY MORE "case" SECTIONS TO THIS FILE, instead define
83  * your sysctl with SYSCTL_INT, SYSCTL_PROC etc. in your source file.
84  */
85 
86 #include <sys/param.h>
87 #include <sys/systm.h>
88 #include <sys/kernel.h>
89 #include <sys/malloc.h>
90 #include <sys/proc_internal.h>
91 #include <sys/kauth.h>
92 #include <sys/file_internal.h>
93 #include <sys/vnode_internal.h>
94 #include <sys/unistd.h>
95 #include <sys/buf.h>
96 #include <sys/ioctl.h>
97 #include <sys/namei.h>
98 #include <sys/tty.h>
99 #include <sys/disklabel.h>
100 #include <sys/vm.h>
101 #include <sys/sysctl.h>
102 #include <sys/user.h>
103 #include <sys/aio_kern.h>
104 #include <sys/reboot.h>
105 #include <sys/memory_maintenance.h>
106 #include <sys/priv.h>
107 #include <sys/ubc.h> /* mach_to_bsd_errno */
108 
109 #include <stdatomic.h>
110 #include <uuid/uuid.h>
111 
112 #include <security/audit/audit.h>
113 #include <kern/kalloc.h>
114 
115 #include <machine/smp.h>
116 #include <machine/atomic.h>
117 #include <machine/config.h>
118 #include <mach/machine.h>
119 #include <mach/mach_host.h>
120 #include <mach/mach_types.h>
121 #include <mach/processor_info.h>
122 #include <mach/vm_param.h>
123 #include <kern/debug.h>
124 #include <kern/mach_param.h>
125 #include <kern/task.h>
126 #include <kern/thread.h>
127 #include <kern/thread_group.h>
128 #include <kern/processor.h>
129 #include <kern/cpu_number.h>
130 #include <kern/sched_prim.h>
131 #include <kern/workload_config.h>
132 #include <kern/iotrace.h>
133 #include <vm/vm_kern_xnu.h>
134 #include <vm/vm_map_xnu.h>
135 #include <mach/host_info.h>
136 #include <mach/exclaves.h>
137 #include <kern/hvg_hypercall.h>
138 #include <kdp/sk_core.h>
139 
140 #if DEVELOPMENT || DEBUG
141 #include <kern/ext_paniclog.h>
142 #endif
143 
144 #include <sys/mount_internal.h>
145 #include <sys/kdebug.h>
146 #include <sys/kern_debug.h>
147 #include <sys/kern_sysctl.h>
148 #include <sys/variant_internal.h>
149 
150 #include <IOKit/IOPlatformExpert.h>
151 #include <pexpert/pexpert.h>
152 
153 #include <machine/machine_routines.h>
154 #include <machine/exec.h>
155 
156 #include <nfs/nfs_conf.h>
157 
158 #include <vm/vm_protos.h>
159 #include <vm/vm_page.h>
160 #include <vm/vm_pageout_xnu.h>
161 #include <vm/vm_compressor_algorithms_xnu.h>
162 #include <vm/vm_compressor_xnu.h>
163 #include <sys/imgsrc.h>
164 #include <kern/timer_call.h>
165 #include <sys/codesign.h>
166 #include <IOKit/IOBSD.h>
167 #if CONFIG_CSR
168 #include <sys/csr.h>
169 #endif
170 
171 #if defined(__i386__) || defined(__x86_64__)
172 #include <i386/cpuid.h>
173 #endif
174 
175 #if CONFIG_FREEZE
176 #include <sys/kern_memorystatus.h>
177 #endif
178 #if HAS_UPSI_FAILURE_INJECTION
179 #include <kern/upsi.h>
180 #endif
181 
182 #if KPERF
183 #include <kperf/kperf.h>
184 #endif
185 
186 #if HYPERVISOR
187 #include <kern/hv_support.h>
188 #endif
189 
190 
191 #include <corecrypto/ccsha2.h>
192 
193 /*
194  * deliberately setting max requests to really high number
195  * so that runaway settings do not cause MALLOC overflows
196  */
197 #define AIO_MAX_REQUESTS (128 * CONFIG_AIO_MAX)
198 
199 extern int aio_max_requests;
200 extern int aio_max_requests_per_process;
201 extern int aio_worker_threads;
202 extern int lowpri_IO_window_msecs;
203 extern int lowpri_IO_delay_msecs;
204 #if DEVELOPMENT || DEBUG
205 extern int nx_enabled;
206 #endif
207 extern int speculative_reads_disabled;
208 extern unsigned int speculative_prefetch_max;
209 extern unsigned int speculative_prefetch_max_iosize;
210 extern unsigned int preheat_max_bytes;
211 extern unsigned int preheat_min_bytes;
212 extern long numvnodes;
213 extern long freevnodes;
214 extern long num_recycledvnodes;
215 
216 extern uuid_string_t bootsessionuuid_string;
217 
218 extern unsigned int vm_max_delayed_work_limit;
219 extern unsigned int vm_max_batch;
220 
221 extern unsigned int vm_page_free_min;
222 extern unsigned int vm_page_free_target;
223 extern unsigned int vm_page_free_reserved;
224 extern unsigned int vm_page_max_speculative_age_q;
225 
226 static uint64_t userspacereboottime = 0;
227 static unsigned int userspacerebootpurpose = 0;
228 
229 #if (DEVELOPMENT || DEBUG)
230 extern uint32_t vm_page_creation_throttled_hard;
231 extern uint32_t vm_page_creation_throttled_soft;
232 #endif /* DEVELOPMENT || DEBUG */
233 
234 #if DEVELOPMENT || DEBUG
235 extern bool bootarg_hide_process_traced;
236 #endif
237 
238 /*
239  * Conditionally allow dtrace to see these functions for debugging purposes.
240  */
241 #ifdef STATIC
242 #undef STATIC
243 #endif
244 #if 0
245 #define STATIC
246 #else
247 #define STATIC static
248 #endif
249 
250 extern boolean_t    mach_timer_coalescing_enabled;
251 
252 extern uint64_t timer_deadline_tracking_bin_1, timer_deadline_tracking_bin_2;
253 
254 STATIC void
255 fill_user32_eproc(proc_t, struct user32_eproc *__restrict);
256 STATIC void
257 fill_user32_externproc(proc_t, struct user32_extern_proc *__restrict);
258 STATIC void
259 fill_user64_eproc(proc_t, struct user64_eproc *__restrict);
260 STATIC void
261 fill_user64_proc(proc_t, struct user64_kinfo_proc *__restrict);
262 STATIC void
263 fill_user64_externproc(proc_t, struct user64_extern_proc *__restrict);
264 STATIC void
265 fill_user32_proc(proc_t, struct user32_kinfo_proc *__restrict);
266 
267 #if CONFIG_NETBOOT
268 extern int
269 netboot_root(void);
270 #endif
271 int
272 sysctl_procargs(int *name, u_int namelen, user_addr_t where,
273     size_t *sizep, proc_t cur_proc);
274 STATIC int
275 sysctl_procargsx(int *name, u_int namelen, user_addr_t where, size_t *sizep,
276     proc_t cur_proc, int argc_yes);
277 int
278 sysctl_struct(user_addr_t oldp, size_t *oldlenp, user_addr_t newp,
279     size_t newlen, void *sp, int len);
280 
281 STATIC int sysdoproc_filt_KERN_PROC_PID(proc_t p, void * arg);
282 STATIC int sysdoproc_filt_KERN_PROC_PGRP(proc_t p, void * arg);
283 STATIC int sysdoproc_filt_KERN_PROC_TTY(proc_t p, void * arg);
284 STATIC int  sysdoproc_filt_KERN_PROC_UID(proc_t p, void * arg);
285 STATIC int  sysdoproc_filt_KERN_PROC_RUID(proc_t p, void * arg);
286 int sysdoproc_callback(proc_t p, void *arg);
287 
288 #if CONFIG_THREAD_GROUPS && (DEVELOPMENT || DEBUG)
289 STATIC int sysctl_get_thread_group_id SYSCTL_HANDLER_ARGS;
290 #endif
291 
292 /* forward declarations for non-static STATIC */
293 STATIC void fill_loadavg64(struct loadavg *la, struct user64_loadavg *la64);
294 STATIC void fill_loadavg32(struct loadavg *la, struct user32_loadavg *la32);
295 STATIC int sysctl_handle_kern_threadname(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
296 STATIC int sysctl_sched_stats(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
297 STATIC int sysctl_sched_stats_enable(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
298 #if COUNT_SYSCALLS
299 STATIC int sysctl_docountsyscalls SYSCTL_HANDLER_ARGS;
300 #endif  /* COUNT_SYSCALLS */
301 #if defined(XNU_TARGET_OS_OSX)
302 STATIC int sysctl_doprocargs SYSCTL_HANDLER_ARGS;
303 #endif  /* defined(XNU_TARGET_OS_OSX) */
304 STATIC int sysctl_doprocargs2 SYSCTL_HANDLER_ARGS;
305 STATIC int sysctl_prochandle SYSCTL_HANDLER_ARGS;
306 STATIC int sysctl_aiomax(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
307 STATIC int sysctl_aioprocmax(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
308 STATIC int sysctl_aiothreads(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
309 STATIC int sysctl_maxproc(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
310 STATIC int sysctl_osversion(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
311 STATIC int sysctl_sysctl_bootargs(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
312 STATIC int sysctl_maxvnodes(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
313 STATIC int sysctl_securelvl(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
314 STATIC int sysctl_domainname(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
315 STATIC int sysctl_hostname(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
316 STATIC int sysctl_procname(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
317 STATIC int sysctl_boottime(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
318 STATIC int sysctl_bootuuid(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
319 STATIC int sysctl_symfile(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
320 #if CONFIG_NETBOOT
321 STATIC int sysctl_netboot(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
322 #endif
323 #ifdef CONFIG_IMGSRC_ACCESS
324 STATIC int sysctl_imgsrcdev(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
325 #endif
326 STATIC int sysctl_usrstack(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
327 STATIC int sysctl_usrstack64(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
328 #if CONFIG_COREDUMP || CONFIG_UCOREDUMP
329 STATIC int sysctl_coredump(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
330 STATIC int sysctl_suid_coredump(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
331 #if CONFIG_UCOREDUMP
332 STATIC int sysctl_ucoredump(struct sysctl_oid *, void *, int, struct sysctl_req *);
333 #endif
334 #endif
335 STATIC int sysctl_delayterm(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
336 STATIC int sysctl_rage_vnode(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
337 STATIC int sysctl_kern_check_openevt(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
338 #if DEVELOPMENT || DEBUG
339 STATIC int sysctl_nx(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
340 #endif
341 STATIC int sysctl_loadavg(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
342 STATIC int sysctl_vm_toggle_address_reuse(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
343 STATIC int sysctl_swapusage(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
344 STATIC int fetch_process_cputype( proc_t cur_proc, int *name, u_int namelen, cpu_type_t *cputype);
345 STATIC int sysctl_sysctl_native(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
346 STATIC int sysctl_sysctl_cputype(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
347 STATIC int sysctl_safeboot(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
348 STATIC int sysctl_singleuser(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
349 STATIC int sysctl_minimalboot(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
350 STATIC int sysctl_slide(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
351 
352 #ifdef CONFIG_XNUPOST
353 #include <tests/xnupost.h>
354 
355 STATIC int sysctl_debug_test_oslog_ctl(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
356 STATIC int sysctl_debug_test_stackshot_mutex_owner(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
357 STATIC int sysctl_debug_test_stackshot_rwlck_owner(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req);
358 #endif
359 
360 extern void IORegistrySetOSBuildVersion(char * build_version);
361 extern int IOParseWorkloadConfig(workload_config_ctx_t *ctx, const char * buffer, size_t size);
362 extern int IOUnparseWorkloadConfig(char *buffer, size_t *size);
363 
364 STATIC void
fill_loadavg64(struct loadavg * la,struct user64_loadavg * la64)365 fill_loadavg64(struct loadavg *la, struct user64_loadavg *la64)
366 {
367 	la64->ldavg[0]  = la->ldavg[0];
368 	la64->ldavg[1]  = la->ldavg[1];
369 	la64->ldavg[2]  = la->ldavg[2];
370 	la64->fscale    = (user64_long_t)la->fscale;
371 }
372 
373 STATIC void
fill_loadavg32(struct loadavg * la,struct user32_loadavg * la32)374 fill_loadavg32(struct loadavg *la, struct user32_loadavg *la32)
375 {
376 	la32->ldavg[0]  = la->ldavg[0];
377 	la32->ldavg[1]  = la->ldavg[1];
378 	la32->ldavg[2]  = la->ldavg[2];
379 	la32->fscale    = (user32_long_t)la->fscale;
380 }
381 
382 #if COUNT_SYSCALLS
383 extern int do_count_syscalls;
384 #endif
385 
386 #ifdef INSECURE
387 int securelevel = -1;
388 #else
389 int securelevel;
390 #endif
391 
392 STATIC int
sysctl_handle_kern_threadname(__unused struct sysctl_oid * oidp,__unused void * arg1,__unused int arg2,struct sysctl_req * req)393 sysctl_handle_kern_threadname(  __unused struct sysctl_oid *oidp, __unused void *arg1,
394     __unused int arg2, struct sysctl_req *req)
395 {
396 	int error;
397 	struct uthread *ut = current_uthread();
398 	user_addr_t oldp = 0, newp = 0;
399 	size_t *oldlenp = NULL;
400 	size_t newlen = 0;
401 
402 	oldp = req->oldptr;
403 	oldlenp = &(req->oldlen);
404 	newp = req->newptr;
405 	newlen = req->newlen;
406 
407 	/* We want the current length, and maybe the string itself */
408 	if (oldlenp) {
409 		/* if we have no thread name yet tell'em we want MAXTHREADNAMESIZE - 1 */
410 		size_t currlen = MAXTHREADNAMESIZE - 1;
411 
412 		if (ut->pth_name) {
413 			/* use length of current thread name */
414 			currlen = strlen(ut->pth_name);
415 		}
416 		if (oldp) {
417 			if (*oldlenp < currlen) {
418 				return ENOMEM;
419 			}
420 			/* NOTE - we do not copy the NULL terminator */
421 			if (ut->pth_name) {
422 				error = copyout(ut->pth_name, oldp, currlen);
423 				if (error) {
424 					return error;
425 				}
426 			}
427 		}
428 		/* return length of thread name minus NULL terminator (just like strlen)  */
429 		req->oldidx = currlen;
430 	}
431 
432 	/* We want to set the name to something */
433 	if (newp) {
434 		if (newlen > (MAXTHREADNAMESIZE - 1)) {
435 			return ENAMETOOLONG;
436 		}
437 		if (!ut->pth_name) {
438 			char *tmp_pth_name = (char *)kalloc_data(MAXTHREADNAMESIZE,
439 			    Z_WAITOK | Z_ZERO);
440 			if (!tmp_pth_name) {
441 				return ENOMEM;
442 			}
443 			if (!OSCompareAndSwapPtr(NULL, tmp_pth_name, &ut->pth_name)) {
444 				kfree_data(tmp_pth_name, MAXTHREADNAMESIZE);
445 				return EBUSY;
446 			}
447 		} else {
448 			kernel_debug_string_simple(TRACE_STRING_THREADNAME_PREV, ut->pth_name);
449 			bzero(ut->pth_name, MAXTHREADNAMESIZE);
450 		}
451 		error = copyin(newp, ut->pth_name, newlen);
452 		if (error) {
453 			return error;
454 		}
455 
456 		kernel_debug_string_simple(TRACE_STRING_THREADNAME, ut->pth_name);
457 	}
458 
459 	return 0;
460 }
461 
462 SYSCTL_PROC(_kern, KERN_THREADNAME, threadname, CTLFLAG_ANYBODY | CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0, sysctl_handle_kern_threadname, "A", "");
463 
464 #define WORKLOAD_CONFIG_MAX_SIZE (128 * 1024 * 1024)
465 
466 /* Called locked - sysctl defined without CTLFLAG_LOCKED. */
467 static int
468 sysctl_workload_config SYSCTL_HANDLER_ARGS
469 {
470 #pragma unused(arg1, arg2)
471 
472 	char *plist_blob = NULL;
473 	kern_return_t ret = KERN_FAILURE;
474 	int error = -1;
475 
476 	/* Only allow reading of workload config on non-RELEASE kernels. */
477 #if DEVELOPMENT || DEBUG
478 
479 	const size_t buf_size = req->oldlen;
480 
481 	if (!req->oldptr) {
482 		/* Just looking for the size to allocate. */
483 		size_t size = 0;
484 		ret = IOUnparseWorkloadConfig(NULL, &size);
485 		if (ret != KERN_SUCCESS) {
486 			return ENOMEM;
487 		}
488 
489 		error = SYSCTL_OUT(req, NULL, size);
490 		if (error) {
491 			return error;
492 		}
493 	} else {
494 		if (buf_size > (WORKLOAD_CONFIG_MAX_SIZE - 1) ||
495 		    buf_size == 0) {
496 			return EINVAL;
497 		}
498 
499 		plist_blob = kalloc_data(buf_size, Z_WAITOK | Z_ZERO);
500 		if (!plist_blob) {
501 			return ENOMEM;
502 		}
503 
504 		size_t size = buf_size;
505 		ret = IOUnparseWorkloadConfig(plist_blob, &size);
506 		if (ret != KERN_SUCCESS) {
507 			kfree_data(plist_blob, buf_size);
508 			return ENOMEM;
509 		}
510 
511 		error = SYSCTL_OUT(req, plist_blob, MIN(buf_size, size));
512 
513 		/* If the buffer was too small to fit the entire config. */
514 		if (buf_size < size) {
515 			error = ENOMEM;
516 		}
517 
518 		kfree_data(plist_blob, buf_size);
519 		if (error) {
520 			return error;
521 		}
522 	}
523 #endif /* DEVELOPMENT || DEBUG */
524 
525 	if (req->newptr) {
526 		size_t newlen = req->newlen;
527 		if (newlen > (WORKLOAD_CONFIG_MAX_SIZE - 1)) {
528 			return EINVAL;
529 		}
530 
531 
532 		workload_config_ctx_t *ctx = NULL;
533 		/*
534 		 * Only allow workload_config_boot to be loaded once at boot by launchd.
535 		 */
536 		if (current_proc() == initproc &&
537 		    !workload_config_initialized(&workload_config_boot)) {
538 			ctx = &workload_config_boot;
539 		} else {
540 #if DEVELOPMENT || DEBUG
541 			/*
542 			 * Use the devel config context otherwise. If a devel config has been
543 			 * initialized it will be used for lookups in place of the boot config.
544 			 */
545 			ctx = &workload_config_devel;
546 			if (workload_config_initialized(ctx)) {
547 				workload_config_free(ctx);
548 			}
549 
550 			/* The devel context can be explicitly cleared by an empty string. */
551 			if (newlen == 1) {
552 				return 0;
553 			}
554 #else
555 			return EINVAL;
556 #endif
557 		}
558 
559 		plist_blob = kalloc_data(newlen + 1, Z_WAITOK | Z_ZERO);
560 		if (!plist_blob) {
561 			return ENOMEM;
562 		}
563 		error = copyin(req->newptr, plist_blob, newlen);
564 		if (error) {
565 			kfree_data(plist_blob, newlen + 1);
566 			return error;
567 		}
568 		plist_blob[newlen] = '\0';
569 		ret = IOParseWorkloadConfig(ctx, plist_blob, newlen + 1);
570 
571 		kfree_data(plist_blob, newlen + 1);
572 		return ret == KERN_SUCCESS ? 0 : EINVAL;
573 	}
574 
575 	return 0;
576 }
577 
578 SYSCTL_PROC(_kern, OID_AUTO, workload_config, CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MASKED,
579     0, 0, sysctl_workload_config, "A", "global workgroup configuration plist load/unload");
580 
581 #define BSD_HOST 1
582 STATIC int
sysctl_sched_stats(__unused struct sysctl_oid * oidp,__unused void * arg1,__unused int arg2,struct sysctl_req * req)583 sysctl_sched_stats(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
584 {
585 	host_basic_info_data_t hinfo;
586 	kern_return_t kret;
587 	uint32_t size;
588 	uint32_t buf_size = 0;
589 	int changed;
590 	mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
591 	struct _processor_statistics_np *buf;
592 	int error;
593 
594 	kret = host_info((host_t)BSD_HOST, HOST_BASIC_INFO, (host_info_t)&hinfo, &count);
595 	if (kret != KERN_SUCCESS) {
596 		return EINVAL;
597 	}
598 
599 	size = sizeof(struct _processor_statistics_np) * (hinfo.logical_cpu_max + 2); /* One for RT Queue, One for Fair Share Queue */
600 
601 	if (req->oldlen < size) {
602 		return EINVAL;
603 	}
604 
605 	buf_size = size;
606 	buf = (struct _processor_statistics_np *)kalloc_data(buf_size, Z_ZERO | Z_WAITOK);
607 
608 	kret = get_sched_statistics(buf, &size);
609 	if (kret != KERN_SUCCESS) {
610 		error = EINVAL;
611 		goto out;
612 	}
613 
614 	error = sysctl_io_opaque(req, buf, size, &changed);
615 	if (error) {
616 		goto out;
617 	}
618 
619 	if (changed) {
620 		panic("Sched info changed?!");
621 	}
622 out:
623 	kfree_data(buf, buf_size);
624 	return error;
625 }
626 
627 SYSCTL_PROC(_kern, OID_AUTO, sched_stats, CTLFLAG_LOCKED, 0, 0, sysctl_sched_stats, "-", "");
628 
629 STATIC int
sysctl_sched_stats_enable(__unused struct sysctl_oid * oidp,__unused void * arg1,__unused int arg2,__unused struct sysctl_req * req)630 sysctl_sched_stats_enable(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, __unused struct sysctl_req *req)
631 {
632 	boolean_t active;
633 	int res;
634 
635 	if (req->newlen != sizeof(active)) {
636 		return EINVAL;
637 	}
638 
639 	res = copyin(req->newptr, &active, sizeof(active));
640 	if (res != 0) {
641 		return res;
642 	}
643 
644 	return set_sched_stats_active(active);
645 }
646 
647 SYSCTL_PROC(_kern, OID_AUTO, sched_stats_enable, CTLFLAG_LOCKED | CTLFLAG_WR, 0, 0, sysctl_sched_stats_enable, "-", "");
648 
649 extern uint32_t sched_debug_flags;
650 SYSCTL_INT(_debug, OID_AUTO, sched, CTLFLAG_RW | CTLFLAG_LOCKED, &sched_debug_flags, 0, "scheduler debug");
651 
652 #if (DEBUG || DEVELOPMENT)
653 extern boolean_t doprnt_hide_pointers;
654 SYSCTL_INT(_debug, OID_AUTO, hide_kernel_pointers, CTLFLAG_RW | CTLFLAG_LOCKED, &doprnt_hide_pointers, 0, "hide kernel pointers from log");
655 #endif
656 
657 
658 extern int get_kernel_symfile(proc_t, char **);
659 
660 #if COUNT_SYSCALLS
661 #define KERN_COUNT_SYSCALLS (KERN_OSTYPE + 1000)
662 
663 extern const unsigned int     nsysent;
664 extern int syscalls_log[];
665 extern const char *syscallnames[];
666 
667 STATIC int
668 sysctl_docountsyscalls SYSCTL_HANDLER_ARGS
669 {
670 	__unused int cmd = oidp->oid_arg2;      /* subcommand*/
671 	__unused int *name = arg1;      /* oid element argument vector */
672 	__unused int namelen = arg2;    /* number of oid element arguments */
673 	int error, changed;
674 
675 	int tmp;
676 
677 	/* valid values passed in:
678 	 * = 0 means don't keep called counts for each bsd syscall
679 	 * > 0 means keep called counts for each bsd syscall
680 	 * = 2 means dump current counts to the system log
681 	 * = 3 means reset all counts
682 	 * for example, to dump current counts:
683 	 *		sysctl -w kern.count_calls=2
684 	 */
685 	error = sysctl_io_number(req, do_count_syscalls,
686 	    sizeof(do_count_syscalls), &tmp, &changed);
687 
688 	if (error != 0 || !changed) {
689 		return error;
690 	}
691 
692 	if (tmp == 1) {
693 		do_count_syscalls = 1;
694 	} else if (tmp == 0 || tmp == 2 || tmp == 3) {
695 		for (int i = 0; i < nsysent; i++) {
696 			if (syscalls_log[i] != 0) {
697 				if (tmp == 2) {
698 					printf("%d calls - name %s \n", syscalls_log[i], syscallnames[i]);
699 				} else {
700 					syscalls_log[i] = 0;
701 				}
702 			}
703 		}
704 		do_count_syscalls = (tmp != 0);
705 	}
706 
707 	return error;
708 }
709 SYSCTL_PROC(_kern, KERN_COUNT_SYSCALLS, count_syscalls, CTLTYPE_NODE | CTLFLAG_RD | CTLFLAG_LOCKED,
710     0,                          /* Pointer argument (arg1) */
711     0,                          /* Integer argument (arg2) */
712     sysctl_docountsyscalls,     /* Handler function */
713     NULL,                       /* Data pointer */
714     "");
715 #endif  /* COUNT_SYSCALLS */
716 
717 /*
718  * The following sysctl_* functions should not be used
719  * any more, as they can only cope with callers in
720  * user mode: Use new-style
721  *  sysctl_io_number()
722  *  sysctl_io_string()
723  *  sysctl_io_opaque()
724  * instead.
725  */
726 
727 STATIC int
sysdoproc_filt_KERN_PROC_PID(proc_t p,void * arg)728 sysdoproc_filt_KERN_PROC_PID(proc_t p, void * arg)
729 {
730 	if (proc_getpid(p) != (pid_t)*(int*)arg) {
731 		return 0;
732 	} else {
733 		return 1;
734 	}
735 }
736 
737 STATIC int
sysdoproc_filt_KERN_PROC_PGRP(proc_t p,void * arg)738 sysdoproc_filt_KERN_PROC_PGRP(proc_t p, void * arg)
739 {
740 	if (p->p_pgrpid != (pid_t)*(int*)arg) {
741 		return 0;
742 	} else {
743 		return 1;
744 	}
745 }
746 
747 STATIC int
sysdoproc_filt_KERN_PROC_TTY(proc_t p,void * arg)748 sysdoproc_filt_KERN_PROC_TTY(proc_t p, void * arg)
749 {
750 	struct pgrp *pg;
751 	dev_t dev = NODEV;
752 
753 	if ((p->p_flag & P_CONTROLT) && (pg = proc_pgrp(p, NULL)) != PGRP_NULL) {
754 		dev = os_atomic_load(&pg->pg_session->s_ttydev, relaxed);
755 		pgrp_rele(pg);
756 	}
757 
758 	return dev != NODEV && dev == (dev_t)*(int *)arg;
759 }
760 
761 STATIC int
sysdoproc_filt_KERN_PROC_UID(proc_t p,void * arg)762 sysdoproc_filt_KERN_PROC_UID(proc_t p, void * arg)
763 {
764 	uid_t uid;
765 
766 	smr_proc_task_enter();
767 	uid = kauth_cred_getuid(proc_ucred_smr(p));
768 	smr_proc_task_leave();
769 
770 	if (uid != (uid_t)*(int*)arg) {
771 		return 0;
772 	} else {
773 		return 1;
774 	}
775 }
776 
777 
778 STATIC int
sysdoproc_filt_KERN_PROC_RUID(proc_t p,void * arg)779 sysdoproc_filt_KERN_PROC_RUID(proc_t p, void * arg)
780 {
781 	uid_t ruid;
782 
783 	smr_proc_task_enter();
784 	ruid = kauth_cred_getruid(proc_ucred_smr(p));
785 	smr_proc_task_leave();
786 
787 	if (ruid != (uid_t)*(int*)arg) {
788 		return 0;
789 	} else {
790 		return 1;
791 	}
792 }
793 
794 /*
795  * try over estimating by 5 procs
796  */
797 #define KERN_PROCSLOP (5 * sizeof(struct kinfo_proc))
798 struct sysdoproc_args {
799 	size_t buflen;
800 	void *kprocp;
801 	boolean_t is_64_bit;
802 	user_addr_t dp;
803 	size_t needed;
804 	unsigned int sizeof_kproc;
805 	int *errorp;
806 	int uidcheck;
807 	int ruidcheck;
808 	int ttycheck;
809 	int uidval;
810 };
811 
812 int
sysdoproc_callback(proc_t p,void * arg)813 sysdoproc_callback(proc_t p, void *arg)
814 {
815 	struct sysdoproc_args *args = arg;
816 
817 	if (args->buflen >= args->sizeof_kproc) {
818 		if ((args->ruidcheck != 0) && (sysdoproc_filt_KERN_PROC_RUID(p, &args->uidval) == 0)) {
819 			return PROC_RETURNED;
820 		}
821 		if ((args->uidcheck != 0) && (sysdoproc_filt_KERN_PROC_UID(p, &args->uidval) == 0)) {
822 			return PROC_RETURNED;
823 		}
824 		if ((args->ttycheck != 0) && (sysdoproc_filt_KERN_PROC_TTY(p, &args->uidval) == 0)) {
825 			return PROC_RETURNED;
826 		}
827 
828 		bzero(args->kprocp, args->sizeof_kproc);
829 		if (args->is_64_bit) {
830 			fill_user64_proc(p, args->kprocp);
831 		} else {
832 			fill_user32_proc(p, args->kprocp);
833 		}
834 		int error = copyout(args->kprocp, args->dp, args->sizeof_kproc);
835 		if (error) {
836 			*args->errorp = error;
837 			return PROC_RETURNED_DONE;
838 		}
839 		args->dp += args->sizeof_kproc;
840 		args->buflen -= args->sizeof_kproc;
841 	}
842 	args->needed += args->sizeof_kproc;
843 	return PROC_RETURNED;
844 }
845 
846 SYSCTL_NODE(_kern, KERN_PROC, proc, CTLFLAG_RD | CTLFLAG_LOCKED, 0, "");
847 STATIC int
848 sysctl_prochandle SYSCTL_HANDLER_ARGS
849 {
850 	int cmd = oidp->oid_arg2;       /* subcommand for multiple nodes */
851 	int *name = arg1;               /* oid element argument vector */
852 	int namelen = arg2;             /* number of oid element arguments */
853 	user_addr_t where = req->oldptr;/* user buffer copy out address */
854 
855 	user_addr_t dp = where;
856 	size_t needed = 0;
857 	size_t buflen = where != USER_ADDR_NULL ? req->oldlen : 0;
858 	int error = 0;
859 	boolean_t is_64_bit = proc_is64bit(current_proc());
860 	struct user32_kinfo_proc  user32_kproc;
861 	struct user64_kinfo_proc  user_kproc;
862 	int sizeof_kproc;
863 	void *kprocp;
864 	int (*filterfn)(proc_t, void *) = 0;
865 	struct sysdoproc_args args;
866 	int uidcheck = 0;
867 	int ruidcheck = 0;
868 	int ttycheck = 0;
869 
870 	if (namelen != 1 && !(namelen == 0 && cmd == KERN_PROC_ALL)) {
871 		return EINVAL;
872 	}
873 
874 	if (is_64_bit) {
875 		sizeof_kproc = sizeof(user_kproc);
876 		kprocp = &user_kproc;
877 	} else {
878 		sizeof_kproc = sizeof(user32_kproc);
879 		kprocp = &user32_kproc;
880 	}
881 
882 	switch (cmd) {
883 	case KERN_PROC_PID:
884 		filterfn = sysdoproc_filt_KERN_PROC_PID;
885 		break;
886 
887 	case KERN_PROC_PGRP:
888 		filterfn = sysdoproc_filt_KERN_PROC_PGRP;
889 		break;
890 
891 	case KERN_PROC_TTY:
892 		ttycheck = 1;
893 		break;
894 
895 	case KERN_PROC_UID:
896 		uidcheck = 1;
897 		break;
898 
899 	case KERN_PROC_RUID:
900 		ruidcheck = 1;
901 		break;
902 
903 	case KERN_PROC_ALL:
904 		break;
905 
906 	default:
907 		/* must be kern.proc.<unknown> */
908 		return ENOTSUP;
909 	}
910 
911 	error = 0;
912 	args.buflen = buflen;
913 	args.kprocp = kprocp;
914 	args.is_64_bit = is_64_bit;
915 	args.dp = dp;
916 	args.needed = needed;
917 	args.errorp = &error;
918 	args.uidcheck = uidcheck;
919 	args.ruidcheck = ruidcheck;
920 	args.ttycheck = ttycheck;
921 	args.sizeof_kproc = sizeof_kproc;
922 	if (namelen) {
923 		args.uidval = name[0];
924 	}
925 
926 	proc_iterate((PROC_ALLPROCLIST | PROC_ZOMBPROCLIST),
927 	    sysdoproc_callback, &args, filterfn, name);
928 
929 	if (error) {
930 		return error;
931 	}
932 
933 	dp = args.dp;
934 	needed = args.needed;
935 
936 	if (where != USER_ADDR_NULL) {
937 		req->oldlen = dp - where;
938 		if (needed > req->oldlen) {
939 			return ENOMEM;
940 		}
941 	} else {
942 		needed += KERN_PROCSLOP;
943 		req->oldlen = needed;
944 	}
945 	/* adjust index so we return the right required/consumed amount */
946 	req->oldidx += req->oldlen;
947 	return 0;
948 }
949 
950 
951 /*
952  * We specify the subcommand code for multiple nodes as the 'req->arg2' value
953  * in the sysctl declaration itself, which comes into the handler function
954  * as 'oidp->oid_arg2'.
955  *
956  * For these particular sysctls, since they have well known OIDs, we could
957  * have just obtained it from the '((int *)arg1)[0]' parameter, but that would
958  * not demonstrate how to handle multiple sysctls that used OID_AUTO instead
959  * of a well known value with a common handler function.  This is desirable,
960  * because we want well known values to "go away" at some future date.
961  *
962  * It should be noted that the value of '((int *)arg1)[1]' is used for many
963  * an integer parameter to the subcommand for many of these sysctls; we'd
964  * rather have used '((int *)arg1)[0]' for that, or even better, an element
965  * in a structure passed in as the the 'newp' argument to sysctlbyname(3),
966  * and then use leaf-node permissions enforcement, but that would have
967  * necessitated modifying user space code to correspond to the interface
968  * change, and we are striving for binary backward compatibility here; even
969  * though these are SPI, and not intended for use by user space applications
970  * which are not themselves system tools or libraries, some applications
971  * have erroneously used them.
972  */
973 SYSCTL_PROC(_kern_proc, KERN_PROC_ALL, all, CTLTYPE_NODE | CTLFLAG_RD | CTLFLAG_LOCKED,
974     0,                          /* Pointer argument (arg1) */
975     KERN_PROC_ALL,              /* Integer argument (arg2) */
976     sysctl_prochandle,          /* Handler function */
977     NULL,                       /* Data is size variant on ILP32/LP64 */
978     "");
979 SYSCTL_PROC(_kern_proc, KERN_PROC_PID, pid, CTLTYPE_NODE | CTLFLAG_RD | CTLFLAG_LOCKED,
980     0,                          /* Pointer argument (arg1) */
981     KERN_PROC_PID,              /* Integer argument (arg2) */
982     sysctl_prochandle,          /* Handler function */
983     NULL,                       /* Data is size variant on ILP32/LP64 */
984     "");
985 SYSCTL_PROC(_kern_proc, KERN_PROC_TTY, tty, CTLTYPE_NODE | CTLFLAG_RD | CTLFLAG_LOCKED,
986     0,                          /* Pointer argument (arg1) */
987     KERN_PROC_TTY,              /* Integer argument (arg2) */
988     sysctl_prochandle,          /* Handler function */
989     NULL,                       /* Data is size variant on ILP32/LP64 */
990     "");
991 SYSCTL_PROC(_kern_proc, KERN_PROC_PGRP, pgrp, CTLTYPE_NODE | CTLFLAG_RD | CTLFLAG_LOCKED,
992     0,                          /* Pointer argument (arg1) */
993     KERN_PROC_PGRP,             /* Integer argument (arg2) */
994     sysctl_prochandle,          /* Handler function */
995     NULL,                       /* Data is size variant on ILP32/LP64 */
996     "");
997 SYSCTL_PROC(_kern_proc, KERN_PROC_UID, uid, CTLTYPE_NODE | CTLFLAG_RD | CTLFLAG_LOCKED,
998     0,                          /* Pointer argument (arg1) */
999     KERN_PROC_UID,              /* Integer argument (arg2) */
1000     sysctl_prochandle,          /* Handler function */
1001     NULL,                       /* Data is size variant on ILP32/LP64 */
1002     "");
1003 SYSCTL_PROC(_kern_proc, KERN_PROC_RUID, ruid, CTLTYPE_NODE | CTLFLAG_RD | CTLFLAG_LOCKED,
1004     0,                          /* Pointer argument (arg1) */
1005     KERN_PROC_RUID,             /* Integer argument (arg2) */
1006     sysctl_prochandle,          /* Handler function */
1007     NULL,                       /* Data is size variant on ILP32/LP64 */
1008     "");
1009 SYSCTL_PROC(_kern_proc, KERN_PROC_LCID, lcid, CTLTYPE_NODE | CTLFLAG_RD | CTLFLAG_LOCKED,
1010     0,                          /* Pointer argument (arg1) */
1011     KERN_PROC_LCID,             /* Integer argument (arg2) */
1012     sysctl_prochandle,          /* Handler function */
1013     NULL,                       /* Data is size variant on ILP32/LP64 */
1014     "");
1015 
1016 
1017 /*
1018  * Fill in non-zero fields of an eproc structure for the specified process.
1019  */
1020 STATIC void
fill_user32_eproc(proc_t p,struct user32_eproc * __restrict ep)1021 fill_user32_eproc(proc_t p, struct user32_eproc *__restrict ep)
1022 {
1023 	struct pgrp *pg;
1024 	struct session *sessp;
1025 	kauth_cred_t my_cred;
1026 
1027 	pg = proc_pgrp(p, &sessp);
1028 
1029 	if (pg != PGRP_NULL) {
1030 		ep->e_pgid = p->p_pgrpid;
1031 		ep->e_jobc = pg->pg_jobc;
1032 		if (sessp->s_ttyvp) {
1033 			ep->e_flag = EPROC_CTTY;
1034 		}
1035 	}
1036 
1037 	ep->e_ppid = p->p_ppid;
1038 
1039 	smr_proc_task_enter();
1040 	my_cred = proc_ucred_smr(p);
1041 
1042 	/* A fake historical pcred */
1043 	ep->e_pcred.p_ruid = kauth_cred_getruid(my_cred);
1044 	ep->e_pcred.p_svuid = kauth_cred_getsvuid(my_cred);
1045 	ep->e_pcred.p_rgid = kauth_cred_getrgid(my_cred);
1046 	ep->e_pcred.p_svgid = kauth_cred_getsvgid(my_cred);
1047 
1048 	/* A fake historical *kauth_cred_t */
1049 	unsigned long refcnt = os_atomic_load(&my_cred->cr_ref, relaxed);
1050 	ep->e_ucred.cr_ref = (uint32_t)MIN(refcnt, UINT32_MAX);
1051 	ep->e_ucred.cr_uid = kauth_cred_getuid(my_cred);
1052 	ep->e_ucred.cr_ngroups = (short)posix_cred_get(my_cred)->cr_ngroups;
1053 	bcopy(posix_cred_get(my_cred)->cr_groups,
1054 	    ep->e_ucred.cr_groups, NGROUPS * sizeof(gid_t));
1055 
1056 	my_cred = NOCRED;
1057 	smr_proc_task_leave();
1058 
1059 	ep->e_tdev = NODEV;
1060 	if (pg != PGRP_NULL) {
1061 		if (p->p_flag & P_CONTROLT) {
1062 			session_lock(sessp);
1063 			ep->e_tdev = os_atomic_load(&sessp->s_ttydev, relaxed);
1064 			ep->e_tpgid = sessp->s_ttypgrpid;
1065 			session_unlock(sessp);
1066 		}
1067 		if (SESS_LEADER(p, sessp)) {
1068 			ep->e_flag |= EPROC_SLEADER;
1069 		}
1070 		pgrp_rele(pg);
1071 	}
1072 }
1073 
1074 /*
1075  * Fill in non-zero fields of an LP64 eproc structure for the specified process.
1076  */
1077 STATIC void
fill_user64_eproc(proc_t p,struct user64_eproc * __restrict ep)1078 fill_user64_eproc(proc_t p, struct user64_eproc *__restrict ep)
1079 {
1080 	struct pgrp *pg;
1081 	struct session *sessp;
1082 	kauth_cred_t my_cred;
1083 
1084 	pg = proc_pgrp(p, &sessp);
1085 
1086 	if (pg != PGRP_NULL) {
1087 		ep->e_pgid = p->p_pgrpid;
1088 		ep->e_jobc = pg->pg_jobc;
1089 		if (sessp->s_ttyvp) {
1090 			ep->e_flag = EPROC_CTTY;
1091 		}
1092 	}
1093 
1094 	ep->e_ppid = p->p_ppid;
1095 
1096 	smr_proc_task_enter();
1097 	my_cred = proc_ucred_smr(p);
1098 
1099 	/* A fake historical pcred */
1100 	ep->e_pcred.p_ruid = kauth_cred_getruid(my_cred);
1101 	ep->e_pcred.p_svuid = kauth_cred_getsvuid(my_cred);
1102 	ep->e_pcred.p_rgid = kauth_cred_getrgid(my_cred);
1103 	ep->e_pcred.p_svgid = kauth_cred_getsvgid(my_cred);
1104 
1105 	/* A fake historical *kauth_cred_t */
1106 	unsigned long refcnt = os_atomic_load(&my_cred->cr_ref, relaxed);
1107 	ep->e_ucred.cr_ref = (uint32_t)MIN(refcnt, UINT32_MAX);
1108 	ep->e_ucred.cr_uid = kauth_cred_getuid(my_cred);
1109 	ep->e_ucred.cr_ngroups = (short)posix_cred_get(my_cred)->cr_ngroups;
1110 	bcopy(posix_cred_get(my_cred)->cr_groups,
1111 	    ep->e_ucred.cr_groups, NGROUPS * sizeof(gid_t));
1112 
1113 	my_cred = NOCRED;
1114 	smr_proc_task_leave();
1115 
1116 	ep->e_tdev = NODEV;
1117 	if (pg != PGRP_NULL) {
1118 		if (p->p_flag & P_CONTROLT) {
1119 			session_lock(sessp);
1120 			ep->e_tdev = os_atomic_load(&sessp->s_ttydev, relaxed);
1121 			ep->e_tpgid = sessp->s_ttypgrpid;
1122 			session_unlock(sessp);
1123 		}
1124 		if (SESS_LEADER(p, sessp)) {
1125 			ep->e_flag |= EPROC_SLEADER;
1126 		}
1127 		pgrp_rele(pg);
1128 	}
1129 }
1130 
1131 /*
1132  * Fill in an eproc structure for the specified process.
1133  * bzeroed by our caller, so only set non-zero fields.
1134  */
1135 STATIC void
fill_user32_externproc(proc_t p,struct user32_extern_proc * __restrict exp)1136 fill_user32_externproc(proc_t p, struct user32_extern_proc *__restrict exp)
1137 {
1138 	exp->p_starttime.tv_sec = (user32_time_t)p->p_start.tv_sec;
1139 	exp->p_starttime.tv_usec = p->p_start.tv_usec;
1140 	exp->p_flag = p->p_flag;
1141 #if DEVELOPMENT || DEBUG
1142 	if (p->p_lflag & P_LTRACED && !bootarg_hide_process_traced) {
1143 #else
1144 	if (p->p_lflag & P_LTRACED) {
1145 #endif
1146 		exp->p_flag |= P_TRACED;
1147 	}
1148 	if (p->p_lflag & P_LPPWAIT) {
1149 		exp->p_flag |= P_PPWAIT;
1150 	}
1151 	if (p->p_lflag & P_LEXIT) {
1152 		exp->p_flag |= P_WEXIT;
1153 	}
1154 	exp->p_stat = p->p_stat;
1155 	exp->p_pid = proc_getpid(p);
1156 #if DEVELOPMENT || DEBUG
1157 	if (bootarg_hide_process_traced) {
1158 		exp->p_oppid = 0;
1159 	} else
1160 #endif
1161 	{
1162 		exp->p_oppid = p->p_oppid;
1163 	}
1164 	/* Mach related  */
1165 	exp->p_debugger = p->p_debugger;
1166 	exp->sigwait = p->sigwait;
1167 	/* scheduling */
1168 #ifdef _PROC_HAS_SCHEDINFO_
1169 	exp->p_estcpu = p->p_estcpu;
1170 	exp->p_pctcpu = p->p_pctcpu;
1171 	exp->p_slptime = p->p_slptime;
1172 #endif
1173 	exp->p_realtimer.it_interval.tv_sec =
1174 	    (user32_time_t)p->p_realtimer.it_interval.tv_sec;
1175 	exp->p_realtimer.it_interval.tv_usec =
1176 	    (__int32_t)p->p_realtimer.it_interval.tv_usec;
1177 
1178 	exp->p_realtimer.it_value.tv_sec =
1179 	    (user32_time_t)p->p_realtimer.it_value.tv_sec;
1180 	exp->p_realtimer.it_value.tv_usec =
1181 	    (__int32_t)p->p_realtimer.it_value.tv_usec;
1182 
1183 	exp->p_rtime.tv_sec = (user32_time_t)p->p_rtime.tv_sec;
1184 	exp->p_rtime.tv_usec = (__int32_t)p->p_rtime.tv_usec;
1185 
1186 	exp->p_sigignore = p->p_sigignore;
1187 	exp->p_sigcatch = p->p_sigcatch;
1188 	exp->p_priority = p->p_priority;
1189 	exp->p_nice = p->p_nice;
1190 	bcopy(&p->p_comm, &exp->p_comm, MAXCOMLEN);
1191 	exp->p_xstat = (u_short)MIN(p->p_xstat, USHRT_MAX);
1192 	exp->p_acflag = p->p_acflag;
1193 }
1194 
1195 /*
1196  * Fill in an LP64 version of extern_proc structure for the specified process.
1197  */
1198 STATIC void
1199 fill_user64_externproc(proc_t p, struct user64_extern_proc *__restrict exp)
1200 {
1201 	exp->p_starttime.tv_sec = p->p_start.tv_sec;
1202 	exp->p_starttime.tv_usec = p->p_start.tv_usec;
1203 	exp->p_flag = p->p_flag;
1204 #if DEVELOPMENT || DEBUG
1205 	if (p->p_lflag & P_LTRACED && !bootarg_hide_process_traced) {
1206 #else
1207 	if (p->p_lflag & P_LTRACED) {
1208 #endif
1209 		exp->p_flag |= P_TRACED;
1210 	}
1211 	if (p->p_lflag & P_LPPWAIT) {
1212 		exp->p_flag |= P_PPWAIT;
1213 	}
1214 	if (p->p_lflag & P_LEXIT) {
1215 		exp->p_flag |= P_WEXIT;
1216 	}
1217 	exp->p_stat = p->p_stat;
1218 	exp->p_pid = proc_getpid(p);
1219 #if DEVELOPMENT || DEBUG
1220 	if (bootarg_hide_process_traced) {
1221 		exp->p_oppid = 0;
1222 	} else
1223 #endif
1224 	{
1225 		exp->p_oppid = p->p_oppid;
1226 	}
1227 	/* Mach related  */
1228 	exp->p_debugger = p->p_debugger;
1229 	exp->sigwait = p->sigwait;
1230 	/* scheduling */
1231 #ifdef _PROC_HAS_SCHEDINFO_
1232 	exp->p_estcpu = p->p_estcpu;
1233 	exp->p_pctcpu = p->p_pctcpu;
1234 	exp->p_slptime = p->p_slptime;
1235 #endif
1236 	exp->p_realtimer.it_interval.tv_sec = p->p_realtimer.it_interval.tv_sec;
1237 	exp->p_realtimer.it_interval.tv_usec = p->p_realtimer.it_interval.tv_usec;
1238 
1239 	exp->p_realtimer.it_value.tv_sec = p->p_realtimer.it_value.tv_sec;
1240 	exp->p_realtimer.it_value.tv_usec = p->p_realtimer.it_value.tv_usec;
1241 
1242 	exp->p_rtime.tv_sec = p->p_rtime.tv_sec;
1243 	exp->p_rtime.tv_usec = p->p_rtime.tv_usec;
1244 
1245 	exp->p_sigignore = p->p_sigignore;
1246 	exp->p_sigcatch = p->p_sigcatch;
1247 	exp->p_priority = p->p_priority;
1248 	exp->p_nice = p->p_nice;
1249 	bcopy(&p->p_comm, &exp->p_comm, MAXCOMLEN);
1250 	exp->p_xstat = (u_short)MIN(p->p_xstat, USHRT_MAX);
1251 	exp->p_acflag = p->p_acflag;
1252 }
1253 
1254 STATIC void
1255 fill_user32_proc(proc_t p, struct user32_kinfo_proc *__restrict kp)
1256 {
1257 	/* on a 64 bit kernel, 32 bit users get some truncated information */
1258 	fill_user32_externproc(p, &kp->kp_proc);
1259 	fill_user32_eproc(p, &kp->kp_eproc);
1260 }
1261 
1262 STATIC void
1263 fill_user64_proc(proc_t p, struct user64_kinfo_proc *__restrict kp)
1264 {
1265 	fill_user64_externproc(p, &kp->kp_proc);
1266 	fill_user64_eproc(p, &kp->kp_eproc);
1267 }
1268 
1269 #if defined(XNU_TARGET_OS_OSX)
1270 /*
1271  * Return the top *sizep bytes of the user stack, or the entire area of the
1272  * user stack down through the saved exec_path, whichever is smaller.
1273  */
1274 STATIC int
1275 sysctl_doprocargs SYSCTL_HANDLER_ARGS
1276 {
1277 	__unused int cmd = oidp->oid_arg2;      /* subcommand*/
1278 	int *name = arg1;               /* oid element argument vector */
1279 	int namelen = arg2;             /* number of oid element arguments */
1280 	user_addr_t oldp = req->oldptr; /* user buffer copy out address */
1281 	size_t *oldlenp = &req->oldlen; /* user buffer copy out size */
1282 //	user_addr_t newp = req->newptr;	/* user buffer copy in address */
1283 //	size_t newlen = req->newlen;	/* user buffer copy in size */
1284 	int error;
1285 
1286 	error =  sysctl_procargsx( name, namelen, oldp, oldlenp, current_proc(), 0);
1287 
1288 	/* adjust index so we return the right required/consumed amount */
1289 	if (!error) {
1290 		req->oldidx += req->oldlen;
1291 	}
1292 
1293 	return error;
1294 }
1295 SYSCTL_PROC(_kern, KERN_PROCARGS, procargs, CTLTYPE_NODE | CTLFLAG_RD | CTLFLAG_LOCKED,
1296     0,                          /* Pointer argument (arg1) */
1297     0,                          /* Integer argument (arg2) */
1298     sysctl_doprocargs,          /* Handler function */
1299     NULL,                       /* Data pointer */
1300     "");
1301 #endif  /* defined(XNU_TARGET_OS_OSX) */
1302 
1303 STATIC int
1304 sysctl_doprocargs2 SYSCTL_HANDLER_ARGS
1305 {
1306 	__unused int cmd = oidp->oid_arg2;      /* subcommand*/
1307 	int *name = arg1;               /* oid element argument vector */
1308 	int namelen = arg2;             /* number of oid element arguments */
1309 	user_addr_t oldp = req->oldptr; /* user buffer copy out address */
1310 	size_t *oldlenp = &req->oldlen; /* user buffer copy out size */
1311 //	user_addr_t newp = req->newptr;	/* user buffer copy in address */
1312 //	size_t newlen = req->newlen;	/* user buffer copy in size */
1313 	int error;
1314 
1315 	error = sysctl_procargsx( name, namelen, oldp, oldlenp, current_proc(), 1);
1316 
1317 	/* adjust index so we return the right required/consumed amount */
1318 	if (!error) {
1319 		req->oldidx += req->oldlen;
1320 	}
1321 
1322 	return error;
1323 }
1324 SYSCTL_PROC(_kern, KERN_PROCARGS2, procargs2, CTLTYPE_NODE | CTLFLAG_RD | CTLFLAG_LOCKED,
1325     0,                          /* Pointer argument (arg1) */
1326     0,                          /* Integer argument (arg2) */
1327     sysctl_doprocargs2,         /* Handler function */
1328     NULL,                       /* Data pointer */
1329     "");
1330 
1331 #define SYSCTL_PROCARGS_READ_ENVVARS_ENTITLEMENT "com.apple.private.read-environment-variables"
1332 STATIC int
1333 sysctl_procargsx(int *name, u_int namelen, user_addr_t where,
1334     size_t *sizep, proc_t cur_proc, int argc_yes)
1335 {
1336 	assert(sizep != NULL);
1337 	proc_t p = NULL;
1338 	size_t buflen = where != USER_ADDR_NULL ? *sizep : 0;
1339 	int error = 0;
1340 	struct _vm_map *proc_map = NULL;
1341 	struct task * task;
1342 	vm_map_copy_t   tmp = NULL;
1343 	user_addr_t     arg_addr;
1344 	size_t          arg_size;
1345 	caddr_t data;
1346 	size_t argslen = 0;
1347 	size_t size = 0;
1348 	vm_offset_t     copy_start = 0, copy_end;
1349 	vm_offset_t     smallbuffer_start;
1350 	kern_return_t ret;
1351 	int pid;
1352 	uid_t uid;
1353 	int argc = -1;
1354 	size_t argvsize;
1355 	size_t remaining;
1356 	size_t current_arg_index;
1357 	size_t current_arg_len;
1358 	const char * current_arg;
1359 	bool omit_env_vars = true;
1360 	user_addr_t user_stack;
1361 	vm_map_offset_t effective_page_mask;
1362 
1363 	if (namelen < 1) {
1364 		error = EINVAL;
1365 		goto finish;
1366 	}
1367 
1368 	if (argc_yes) {
1369 		buflen -= sizeof(int);          /* reserve first word to return argc */
1370 	}
1371 	/* we only care about buflen when where (oldp from sysctl) is not NULL. */
1372 	/* when where (oldp from sysctl) is NULL and sizep (oldlenp from sysctl */
1373 	/* is not NULL then the caller wants us to return the length needed to */
1374 	/* hold the data we would return */
1375 	if (where != USER_ADDR_NULL && (buflen <= 0 || buflen > ARG_MAX)) {
1376 		error = EINVAL;
1377 		goto finish;
1378 	}
1379 
1380 	/*
1381 	 *	Lookup process by pid
1382 	 */
1383 	pid = name[0];
1384 	p = proc_find(pid);
1385 	if (p == NULL) {
1386 		error = EINVAL;
1387 		goto finish;
1388 	}
1389 
1390 	/* Allow reading environment variables if any of the following are true:
1391 	 * - kernel is DEVELOPMENT || DEBUG
1392 	 * - target process is same as current_proc()
1393 	 * - target process is not cs_restricted
1394 	 * - SIP is off
1395 	 * - caller has an entitlement
1396 	 */
1397 
1398 #if DEVELOPMENT || DEBUG
1399 	omit_env_vars = false;
1400 #endif
1401 	if (p == current_proc() ||
1402 	    !cs_restricted(p) ||
1403 #if CONFIG_CSR
1404 	    csr_check(CSR_ALLOW_UNRESTRICTED_DTRACE) == 0 ||
1405 #endif
1406 	    IOCurrentTaskHasEntitlement(SYSCTL_PROCARGS_READ_ENVVARS_ENTITLEMENT)
1407 	    ) {
1408 		omit_env_vars = false;
1409 	}
1410 
1411 	/*
1412 	 *	Copy the top N bytes of the stack.
1413 	 *	On all machines we have so far, the stack grows
1414 	 *	downwards.
1415 	 *
1416 	 *	If the user expects no more than N bytes of
1417 	 *	argument list, use that as a guess for the
1418 	 *	size.
1419 	 */
1420 
1421 	if (!p->user_stack) {
1422 		error = EINVAL;
1423 		goto finish;
1424 	}
1425 
1426 	/* save off argc, argslen, user_stack before releasing the proc */
1427 	argc = p->p_argc;
1428 	argslen = p->p_argslen;
1429 	user_stack = p->user_stack;
1430 
1431 	/*
1432 	 * When these sysctls were introduced, the first string in the strings
1433 	 * section was just the bare path of the executable.  However, for security
1434 	 * reasons we now prefix this string with executable_path= so it can be
1435 	 * parsed getenv style.  To avoid binary compatability issues with exising
1436 	 * callers of this sysctl, we strip it off here.
1437 	 * (rdar://problem/13746466)
1438 	 */
1439 #define        EXECUTABLE_KEY "executable_path="
1440 	argslen -= strlen(EXECUTABLE_KEY);
1441 
1442 	if (where == USER_ADDR_NULL && !omit_env_vars) {
1443 		/* caller only wants to know length of proc args data.
1444 		 * If we don't need to omit environment variables, we can skip
1445 		 * copying the target process stack */
1446 		goto calculate_size;
1447 	}
1448 
1449 	smr_proc_task_enter();
1450 	uid = kauth_cred_getuid(proc_ucred_smr(p));
1451 	smr_proc_task_leave();
1452 
1453 	if ((uid != kauth_cred_getuid(kauth_cred_get()))
1454 	    && suser(kauth_cred_get(), &cur_proc->p_acflag)) {
1455 		error = EINVAL;
1456 		goto finish;
1457 	}
1458 
1459 	/*
1460 	 *	Before we can block (any VM code), make another
1461 	 *	reference to the map to keep it alive.  We do
1462 	 *	that by getting a reference on the task itself.
1463 	 *
1464 	 *	Additionally, if the task is not IPC active, we
1465 	 *	must fail early. Other tasks can't yet look up
1466 	 *	this task's task port to make Mach API calls, so
1467 	 *	we shouldn't make such calls on their behalf.
1468 	 */
1469 	task = proc_task(p);
1470 	if (task == NULL || !task_is_ipc_active(task)) {
1471 		error = EINVAL;
1472 		goto finish;
1473 	}
1474 
1475 	/*
1476 	 * Once we have a task reference we can convert that into a
1477 	 * map reference, which we will use in the calls below.  The
1478 	 * task/process may change its map after we take this reference
1479 	 * (see execve), but the worst that will happen then is a return
1480 	 * of stale info (which is always a possibility).
1481 	 */
1482 	task_reference(task);
1483 	proc_rele(p);
1484 	p = NULL;
1485 	proc_map = get_task_map_reference(task);
1486 	task_deallocate(task);
1487 
1488 	if (proc_map == NULL) {
1489 		error = EINVAL;
1490 		goto finish;
1491 	}
1492 
1493 	effective_page_mask = vm_map_page_mask(proc_map);
1494 
1495 	arg_size = vm_map_round_page(argslen, effective_page_mask);
1496 
1497 	arg_addr = user_stack - arg_size;
1498 
1499 	ret = kmem_alloc(kernel_map, &copy_start, arg_size,
1500 	    KMA_DATA | KMA_ZERO, VM_KERN_MEMORY_BSD);
1501 	if (ret != KERN_SUCCESS) {
1502 		error = ENOMEM;
1503 		goto finish;
1504 	}
1505 
1506 	copy_end = copy_start + arg_size;
1507 
1508 	if (vm_map_copyin(proc_map, (vm_map_address_t)arg_addr,
1509 	    (vm_map_size_t)arg_size, FALSE, &tmp) != KERN_SUCCESS) {
1510 		error = EIO;
1511 		goto finish;
1512 	}
1513 
1514 	/*
1515 	 *	Now that we've done the copyin from the process'
1516 	 *	map, we can release the reference to it.
1517 	 */
1518 	vm_map_deallocate(proc_map);
1519 	proc_map = NULL;
1520 
1521 	if (vm_map_copy_overwrite(kernel_map,
1522 	    (vm_map_address_t)copy_start,
1523 	    tmp, (vm_map_size_t) arg_size,
1524 #if HAS_MTE
1525 	    FALSE,
1526 #endif
1527 	    FALSE) != KERN_SUCCESS) {
1528 		error = EIO;
1529 		goto finish;
1530 	}
1531 	/* tmp was consumed */
1532 	tmp = NULL;
1533 
1534 	if (omit_env_vars) {
1535 		argvsize = 0;
1536 
1537 		/* Iterate over everything in argv, plus one for the bare executable path */
1538 		for (current_arg_index = 0; current_arg_index < argc + 1 && argvsize < argslen; ++current_arg_index) {
1539 			current_arg = (const char *)(copy_end - argslen) + argvsize;
1540 			remaining = argslen - argvsize;
1541 			current_arg_len = strnlen(current_arg, remaining);
1542 			if (current_arg_len < remaining) {
1543 				/* We have space for the null terminator */
1544 				current_arg_len += 1;
1545 
1546 				if (current_arg_index == 0) {
1547 					/* The bare executable path may have multiple null bytes after it for alignment */
1548 					while (current_arg_len < remaining && current_arg[current_arg_len] == 0) {
1549 						current_arg_len += 1;
1550 					}
1551 				}
1552 			}
1553 			argvsize += current_arg_len;
1554 		}
1555 		assert(argvsize <= argslen);
1556 
1557 		/* Adjust argslen and copy_end to make the copyout range extend to the end of argv */
1558 		copy_end = copy_end - argslen + argvsize;
1559 		argslen = argvsize;
1560 	}
1561 
1562 	if (where == USER_ADDR_NULL) {
1563 		/* Skip copyout */
1564 		goto calculate_size;
1565 	}
1566 
1567 	if (buflen >= argslen) {
1568 		data = (caddr_t) (copy_end - argslen);
1569 		size = argslen;
1570 	} else {
1571 		/*
1572 		 * Before rdar://25397314, this function contained incorrect logic when buflen is less
1573 		 * than argslen. The problem was that it copied in `buflen` bytes from the end of the target
1574 		 * process user stack into the beginning of a buffer of size round_page(buflen), and then
1575 		 * copied out `buflen` bytes from the end of this buffer. The effect of this was that
1576 		 * the caller of this sysctl would get zeros at the end of their buffer.
1577 		 *
1578 		 * To preserve this behavior, bzero everything from copy_end-round_page(buflen)+buflen to the
1579 		 * end of the buffer. This emulates copying in only `buflen` bytes.
1580 		 *
1581 		 *
1582 		 * In the old code:
1583 		 *
1584 		 *   copy_start     .... size: round_page(buflen) ....        copy_end
1585 		 *      [---copied in data (size: buflen)---|--- zeros ----------]
1586 		 *                           ^
1587 		 *                          data = copy_end - buflen
1588 		 *
1589 		 *
1590 		 * In the new code:
1591 		 *   copy_start        .... size: round_page(p->argslen) ....                full copy_end
1592 		 *      ^         ....................... p->argslen ...............................^
1593 		 *      ^         ^                                         truncated copy_end      ^
1594 		 *      ^         ^                                                 ^               ^
1595 		 *      ^         ................  argslen  ........................               ^
1596 		 *      ^         ^                                                 ^               ^
1597 		 *      [-------copied in data (size: round_page(p->argslen))-------:----env vars---]
1598 		 *                                ^            ^
1599 		 *                                ^         data = copy_end - buflen
1600 		 *                smallbuffer_start = max(copy_end - round_page(buflen), copy_start)
1601 		 *
1602 		 *
1603 		 * Full copy_end: copy_end calculated from copy_start + round_page(p->argslen)
1604 		 * Truncated copy_end: copy_end after truncation to remove environment variables.
1605 		 *
1606 		 * If environment variables were omitted, then we use the truncated copy_end, otherwise
1607 		 * we use full copy_end.
1608 		 *
1609 		 * smallbuffer_start: represents where copy_start would be in the old code.
1610 		 * data: The beginning of the region we copyout
1611 		 */
1612 		smallbuffer_start = copy_end - vm_map_round_page(buflen, effective_page_mask);
1613 		if (smallbuffer_start < copy_start) {
1614 			smallbuffer_start = copy_start;
1615 		}
1616 		bzero((void *)(smallbuffer_start + buflen), copy_end - (smallbuffer_start + buflen));
1617 		data = (caddr_t) (copy_end - buflen);
1618 		size = buflen;
1619 	}
1620 
1621 	if (argc_yes) {
1622 		/* Put processes argc as the first word in the copyout buffer */
1623 		suword(where, argc);
1624 		error = copyout(data, (where + sizeof(int)), size);
1625 		size += sizeof(int);
1626 	} else {
1627 		error = copyout(data, where, size);
1628 
1629 		/*
1630 		 * Make the old PROCARGS work to return the executable's path
1631 		 * But, only if there is enough space in the provided buffer
1632 		 *
1633 		 * on entry: data [possibily] points to the beginning of the path
1634 		 *
1635 		 * Note: we keep all pointers&sizes aligned to word boundries
1636 		 */
1637 		if ((!error) && (buflen > 0 && (u_int)buflen > size)) {
1638 			int binPath_sz, alignedBinPath_sz = 0;
1639 			int extraSpaceNeeded, addThis;
1640 			user_addr_t placeHere;
1641 			char * str = (char *) data;
1642 			size_t max_len = size;
1643 
1644 			/* Some apps are really bad about messing up their stacks
1645 			 *  So, we have to be extra careful about getting the length
1646 			 *  of the executing binary.  If we encounter an error, we bail.
1647 			 */
1648 
1649 			/* Limit ourselves to PATH_MAX paths */
1650 			if (max_len > PATH_MAX) {
1651 				max_len = PATH_MAX;
1652 			}
1653 
1654 			binPath_sz = 0;
1655 
1656 			while ((binPath_sz < max_len - 1) && (*str++ != 0)) {
1657 				binPath_sz++;
1658 			}
1659 
1660 			/* If we have a NUL terminator, copy it, too */
1661 			if (binPath_sz < max_len - 1) {
1662 				binPath_sz += 1;
1663 			}
1664 
1665 			/* Pre-Flight the space requiremnts */
1666 
1667 			/* Account for the padding that fills out binPath to the next word */
1668 			alignedBinPath_sz += (binPath_sz & (sizeof(int) - 1)) ? (sizeof(int) - (binPath_sz & (sizeof(int) - 1))) : 0;
1669 
1670 			placeHere = where + size;
1671 
1672 			/* Account for the bytes needed to keep placeHere word aligned */
1673 			addThis = (placeHere & (sizeof(int) - 1)) ? (sizeof(int) - (placeHere & (sizeof(int) - 1))) : 0;
1674 
1675 			/* Add up all the space that is needed */
1676 			extraSpaceNeeded = alignedBinPath_sz + addThis + binPath_sz + (4 * sizeof(int));
1677 
1678 			/* is there is room to tack on argv[0]? */
1679 			if ((buflen & ~(sizeof(int) - 1)) >= (size + extraSpaceNeeded)) {
1680 				placeHere += addThis;
1681 				suword(placeHere, 0);
1682 				placeHere += sizeof(int);
1683 				suword(placeHere, 0xBFFF0000);
1684 				placeHere += sizeof(int);
1685 				suword(placeHere, 0);
1686 				placeHere += sizeof(int);
1687 				error = copyout(data, placeHere, binPath_sz);
1688 				if (!error) {
1689 					placeHere += binPath_sz;
1690 					suword(placeHere, 0);
1691 					size += extraSpaceNeeded;
1692 				}
1693 			}
1694 		}
1695 	}
1696 
1697 calculate_size:
1698 	/* Size has already been calculated for the where != NULL case */
1699 	if (where == USER_ADDR_NULL) {
1700 		size = argslen;
1701 		if (argc_yes) {
1702 			size += sizeof(int);
1703 		} else {
1704 			/*
1705 			 * old PROCARGS will return the executable's path and plus some
1706 			 * extra space for work alignment and data tags
1707 			 */
1708 			size += PATH_MAX + (6 * sizeof(int));
1709 		}
1710 		size += (size & (sizeof(int) - 1)) ? (sizeof(int) - (size & (sizeof(int) - 1))) : 0;
1711 	}
1712 
1713 	*sizep = size;
1714 
1715 finish:
1716 	if (p != NULL) {
1717 		proc_rele(p);
1718 	}
1719 	if (tmp != NULL) {
1720 		vm_map_copy_discard(tmp);
1721 	}
1722 	if (proc_map != NULL) {
1723 		vm_map_deallocate(proc_map);
1724 	}
1725 	if (copy_start != (vm_offset_t) 0) {
1726 		kmem_free(kernel_map, copy_start, arg_size);
1727 	}
1728 	return error;
1729 }
1730 
1731 
1732 /*
1733  * Max number of concurrent aio requests
1734  */
1735 STATIC int
1736 sysctl_aiomax
1737 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
1738 {
1739 	int new_value, changed;
1740 	int error = sysctl_io_number(req, aio_max_requests, sizeof(int), &new_value, &changed);
1741 	if (changed) {
1742 		/* make sure the system-wide limit is greater than the per process limit */
1743 		if (new_value >= aio_max_requests_per_process && new_value <= AIO_MAX_REQUESTS) {
1744 			aio_max_requests = new_value;
1745 		} else {
1746 			error = EINVAL;
1747 		}
1748 	}
1749 	return error;
1750 }
1751 
1752 
1753 /*
1754  * Max number of concurrent aio requests per process
1755  */
1756 STATIC int
1757 sysctl_aioprocmax
1758 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
1759 {
1760 	int new_value, changed;
1761 	int error = sysctl_io_number(req, aio_max_requests_per_process, sizeof(int), &new_value, &changed);
1762 	if (changed) {
1763 		/* make sure per process limit is less than the system-wide limit */
1764 		if (new_value <= aio_max_requests && new_value >= AIO_LISTIO_MAX) {
1765 			aio_max_requests_per_process = new_value;
1766 		} else {
1767 			error = EINVAL;
1768 		}
1769 	}
1770 	return error;
1771 }
1772 
1773 
1774 /*
1775  * Max number of async IO worker threads
1776  */
1777 STATIC int
1778 sysctl_aiothreads
1779 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
1780 {
1781 	int new_value, changed;
1782 	int error = sysctl_io_number(req, aio_worker_threads, sizeof(int), &new_value, &changed);
1783 	if (changed) {
1784 		/* we only allow an increase in the number of worker threads */
1785 		if (new_value > aio_worker_threads) {
1786 			_aio_create_worker_threads((new_value - aio_worker_threads));
1787 			aio_worker_threads = new_value;
1788 		} else {
1789 			error = EINVAL;
1790 		}
1791 	}
1792 	return error;
1793 }
1794 
1795 
1796 /*
1797  * System-wide limit on the max number of processes
1798  */
1799 STATIC int
1800 sysctl_maxproc
1801 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
1802 {
1803 	int new_value, changed;
1804 	int error = sysctl_io_number(req, maxproc, sizeof(int), &new_value, &changed);
1805 	if (changed) {
1806 		AUDIT_ARG(value32, new_value);
1807 		/* make sure the system-wide limit is less than the configured hard
1808 		 *  limit set at kernel compilation */
1809 		if (new_value <= hard_maxproc && new_value > 0) {
1810 			maxproc = new_value;
1811 		} else {
1812 			error = EINVAL;
1813 		}
1814 	}
1815 	return error;
1816 }
1817 
1818 #if CONFIG_SCHED_SMT
1819 STATIC int
1820 sysctl_sched_enable_smt
1821 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
1822 {
1823 	int new_value, changed;
1824 	int error = sysctl_io_number(req, sched_enable_smt, sizeof(int), &new_value, &changed);
1825 	if (error) {
1826 		return error;
1827 	}
1828 	kern_return_t kret = KERN_SUCCESS;
1829 	if (changed) {
1830 		AUDIT_ARG(value32, new_value);
1831 		if (new_value == 0) {
1832 			sched_enable_smt = 0;
1833 			kret = enable_smt_processors(false);
1834 		} else {
1835 			sched_enable_smt = 1;
1836 			kret = enable_smt_processors(true);
1837 		}
1838 	}
1839 	switch (kret) {
1840 	case KERN_SUCCESS:
1841 		error = 0;
1842 		break;
1843 	case KERN_INVALID_ARGUMENT:
1844 		error = EINVAL;
1845 		break;
1846 	case KERN_FAILURE:
1847 		error = EBUSY;
1848 		break;
1849 	default:
1850 		error = ENOENT;
1851 		break;
1852 	}
1853 	return error;
1854 }
1855 #else /* CONFIG_SCHED_SMT */
1856 STATIC int
1857 sysctl_sched_enable_smt
1858 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, __unused struct sysctl_req *req)
1859 {
1860 	return 0;
1861 }
1862 #endif /* CONFIG_SCHED_SMT */
1863 
1864 SYSCTL_STRING(_kern, KERN_OSTYPE, ostype,
1865     CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
1866     ostype, 0, "");
1867 SYSCTL_STRING(_kern, KERN_OSRELEASE, osrelease,
1868     CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
1869     osrelease, 0, "");
1870 SYSCTL_INT(_kern, KERN_OSREV, osrevision,
1871     CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
1872     (int *)NULL, BSD, "");
1873 SYSCTL_STRING(_kern, KERN_VERSION, version,
1874     CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
1875     version, 0, "");
1876 SYSCTL_STRING(_kern, OID_AUTO, uuid,
1877     CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
1878     &kernel_uuid_string[0], 0, "");
1879 
1880 SYSCTL_STRING(_kern, OID_AUTO, osbuildconfig,
1881     CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLFLAG_MASKED,
1882     &osbuild_config[0], 0, "");
1883 
1884 #if DEBUG
1885 #ifndef DKPR
1886 #define DKPR 1
1887 #endif
1888 #endif
1889 
1890 #if DKPR
1891 int debug_kprint_syscall = 0;
1892 char debug_kprint_syscall_process[MAXCOMLEN + 1];
1893 
1894 /* Thread safe: bits and string value are not used to reclaim state */
1895 SYSCTL_INT(_debug, OID_AUTO, kprint_syscall,
1896     CTLFLAG_RW | CTLFLAG_LOCKED, &debug_kprint_syscall, 0, "kprintf syscall tracing");
1897 SYSCTL_STRING(_debug, OID_AUTO, kprint_syscall_process,
1898     CTLFLAG_RW | CTLFLAG_LOCKED, debug_kprint_syscall_process, sizeof(debug_kprint_syscall_process),
1899     "name of process for kprintf syscall tracing");
1900 
1901 int
1902 debug_kprint_current_process(const char **namep)
1903 {
1904 	struct proc *p = current_proc();
1905 
1906 	if (p == NULL) {
1907 		return 0;
1908 	}
1909 
1910 	if (debug_kprint_syscall_process[0]) {
1911 		/* user asked to scope tracing to a particular process name */
1912 		if (0 == strncmp(debug_kprint_syscall_process,
1913 		    p->p_comm, sizeof(debug_kprint_syscall_process))) {
1914 			/* no value in telling the user that we traced what they asked */
1915 			if (namep) {
1916 				*namep = NULL;
1917 			}
1918 
1919 			return 1;
1920 		} else {
1921 			return 0;
1922 		}
1923 	}
1924 
1925 	/* trace all processes. Tell user what we traced */
1926 	if (namep) {
1927 		*namep = p->p_comm;
1928 	}
1929 
1930 	return 1;
1931 }
1932 #endif
1933 
1934 /* PR-5293665: need to use a callback function for kern.osversion to set
1935  * osversion in IORegistry */
1936 
1937 STATIC int
1938 sysctl_osversion(__unused struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req)
1939 {
1940 	int rval = 0;
1941 
1942 	rval = sysctl_handle_string(oidp, arg1, arg2, req);
1943 
1944 	if (req->newptr) {
1945 		IORegistrySetOSBuildVersion((char *)arg1);
1946 	}
1947 
1948 	return rval;
1949 }
1950 
1951 SYSCTL_PROC(_kern, KERN_OSVERSION, osversion,
1952     CTLFLAG_RW | CTLFLAG_KERN | CTLTYPE_STRING | CTLFLAG_LOCKED,
1953     osversion, 256 /* OSVERSIZE*/,
1954     sysctl_osversion, "A", "");
1955 
1956 static bool
1957 _already_set_or_not_launchd(struct sysctl_req *req, char *val)
1958 {
1959 	if (req->newptr != 0) {
1960 		/*
1961 		 * Can only ever be set by launchd, and only once at boot.
1962 		 */
1963 		if (proc_getpid(req->p) != 1 || val[0] != '\0') {
1964 			return true;
1965 		}
1966 	}
1967 	return false;
1968 }
1969 
1970 #define kRootsInstalledReadWriteEntitlement "com.apple.private.roots-installed-read-write"
1971 #define kRootsInstalledReadOnlyEntitlement "com.apple.private.roots-installed-read-only"
1972 uint64_t roots_installed = 0;
1973 
1974 static int
1975 sysctl_roots_installed
1976 (__unused struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req)
1977 {
1978 	int error = 0;
1979 
1980 	if (req->newptr != 0) {
1981 		/* a ReadWrite entitlement is required for updating this syscl
1982 		 * meanwhile, only allow write once
1983 		 */
1984 		if (!IOCurrentTaskHasEntitlement(kRootsInstalledReadWriteEntitlement) || (roots_installed != 0)) {
1985 			return EPERM;
1986 		}
1987 	} else {
1988 		/* for reader of this sysctl, need either ReadWrite or ReadOnly entitlement */
1989 		if (!IOCurrentTaskHasEntitlement(kRootsInstalledReadWriteEntitlement) &&
1990 		    !IOCurrentTaskHasEntitlement(kRootsInstalledReadOnlyEntitlement)) {
1991 			return EPERM;
1992 		}
1993 	}
1994 
1995 	error = sysctl_handle_quad(oidp, arg1, arg2, req);
1996 
1997 	return error;
1998 }
1999 
2000 SYSCTL_PROC(_kern, OID_AUTO, roots_installed,
2001     CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED,
2002     &roots_installed, sizeof(roots_installed),
2003     sysctl_roots_installed, "Q", "");
2004 
2005 #if XNU_TARGET_OS_OSX
2006 static int
2007 sysctl_system_version_compat
2008 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
2009 {
2010 	int oldval = (task_has_system_version_compat_enabled(current_task()));
2011 	int new_value = 0, changed = 0;
2012 
2013 	int error = sysctl_io_number(req, oldval, sizeof(int), &new_value, &changed);
2014 	if (changed) {
2015 		task_set_system_version_compat_enabled(current_task(), (new_value));
2016 	}
2017 	return error;
2018 }
2019 
2020 SYSCTL_PROC(_kern, OID_AUTO, system_version_compat,
2021     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED,
2022     0, 0, sysctl_system_version_compat, "A", "");
2023 #endif /* XNU_TARGET_OS_OSX */
2024 
2025 #if XNU_TARGET_OS_OSX || defined(XNU_EXPERIMENTAL_SYSTEM_VERSION_COMPAT)
2026 char osproductversioncompat[48] = { '\0' };
2027 
2028 static int
2029 sysctl_osproductversioncompat(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req)
2030 {
2031 	if (_already_set_or_not_launchd(req, osproductversioncompat)) {
2032 		return EPERM;
2033 	}
2034 	return sysctl_handle_string(oidp, arg1, arg2, req);
2035 }
2036 
2037 
2038 SYSCTL_PROC(_kern, OID_AUTO, osproductversioncompat,
2039     CTLFLAG_RW | CTLFLAG_KERN | CTLTYPE_STRING | CTLFLAG_LOCKED,
2040     osproductversioncompat, sizeof(osproductversioncompat),
2041     sysctl_osproductversioncompat, "A", "The ProductVersion from SystemVersionCompat.plist");
2042 #endif /* XNU_TARGET_OS_OSX || defined(XNU_EXPERIMENTAL_SYSTEM_VERSION_COMPAT) */
2043 
2044 char osproductversion[48] = { '\0' };
2045 
2046 static char iossupportversion_string[48] = { '\0' };
2047 
2048 #if defined(XNU_EXPERIMENTAL_SYSTEM_VERSION_COMPAT)
2049 /*
2050  * Equivalent to dyld_program_sdk_at_least(dyld_fall_2025_os_versions).
2051  */
2052 static bool
2053 proc_2025_fall_os_sdk_or_later(struct proc *p)
2054 {
2055 	const uint32_t proc_sdk_ver = proc_sdk(p);
2056 
2057 	switch (proc_platform(p)) {
2058 	case PLATFORM_MACOS:
2059 		return proc_sdk_ver >= 0x00100000; // DYLD_MACOSX_VERSION_16_0
2060 	case PLATFORM_IOS:
2061 	case PLATFORM_IOSSIMULATOR:
2062 	case PLATFORM_MACCATALYST:
2063 		return proc_sdk_ver >= 0x00130000; // DYLD_IOS_VERSION_19_0
2064 	case PLATFORM_BRIDGEOS:
2065 		return proc_sdk_ver >= 0x000a0000; // DYLD_BRIDGEOS_VERSION_10_0
2066 	case PLATFORM_TVOS:
2067 	case PLATFORM_TVOSSIMULATOR:
2068 		return proc_sdk_ver >= 0x00130000; // DYLD_TVOS_VERSION_19_0
2069 	case PLATFORM_WATCHOS:
2070 	case PLATFORM_WATCHOSSIMULATOR:
2071 		return proc_sdk_ver >= 0x000c0000; // DYLD_WATCHOS_VERSION_12_0
2072 	default:
2073 		return true;
2074 	}
2075 }
2076 #endif /* defined(XNU_EXPERIMENTAL_SYSTEM_VERSION_COMPAT) */
2077 
2078 static int
2079 sysctl_osproductversion(__unused struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req)
2080 {
2081 	if (_already_set_or_not_launchd(req, osproductversion)) {
2082 		return EPERM;
2083 	}
2084 
2085 #if XNU_TARGET_OS_OSX
2086 	if (task_has_system_version_compat_enabled(current_task()) && (osproductversioncompat[0] != '\0')) {
2087 		return sysctl_handle_string(oidp, osproductversioncompat, arg2, req);
2088 	}
2089 #endif /* XNU_TARGET_OS_OSX */
2090 
2091 #if defined(XNU_TARGET_OS_XR)
2092 	if (proc_platform(req->p) == PLATFORM_IOS && (iossupportversion_string[0] != '\0')) {
2093 		return sysctl_handle_string(oidp, iossupportversion_string, arg2, req);
2094 	}
2095 #endif /* defined(XNU_TARGET_OS_XR) */
2096 
2097 #if defined(XNU_EXPERIMENTAL_SYSTEM_VERSION_COMPAT)
2098 	if (!proc_2025_fall_os_sdk_or_later(req->p) && (osproductversioncompat[0] != '\0')) {
2099 		return sysctl_handle_string(oidp, osproductversioncompat, arg2, req);
2100 	}
2101 #endif /* defined(XNU_EXPERIMENTAL_SYSTEM_VERSION_COMPAT) */
2102 
2103 	return sysctl_handle_string(oidp, arg1, arg2, req);
2104 }
2105 
2106 #if XNU_TARGET_OS_OSX
2107 static_assert(sizeof(osproductversioncompat) == sizeof(osproductversion),
2108     "osproductversion size matches osproductversioncompat size");
2109 #endif
2110 
2111 SYSCTL_PROC(_kern, OID_AUTO, osproductversion,
2112     CTLFLAG_RW | CTLFLAG_KERN | CTLTYPE_STRING | CTLFLAG_LOCKED,
2113     osproductversion, sizeof(osproductversion),
2114     sysctl_osproductversion, "A", "The ProductVersion from SystemVersion.plist");
2115 
2116 char osreleasetype[OSRELEASETYPE_SIZE] = { '\0' };
2117 
2118 STATIC int
2119 sysctl_osreleasetype(__unused struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req)
2120 {
2121 	if (_already_set_or_not_launchd(req, osreleasetype)) {
2122 		return EPERM;
2123 	}
2124 	return sysctl_handle_string(oidp, arg1, arg2, req);
2125 }
2126 
2127 void reset_osreleasetype(void);
2128 
2129 void
2130 reset_osreleasetype(void)
2131 {
2132 	memset(osreleasetype, 0, sizeof(osreleasetype));
2133 }
2134 
2135 SYSCTL_PROC(_kern, OID_AUTO, osreleasetype,
2136     CTLFLAG_RW | CTLFLAG_KERN | CTLTYPE_STRING | CTLFLAG_LOCKED,
2137     osreleasetype, sizeof(osreleasetype),
2138     sysctl_osreleasetype, "A", "The ReleaseType from SystemVersion.plist");
2139 
2140 STATIC int
2141 sysctl_iossupportversion(__unused struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req)
2142 {
2143 	if (_already_set_or_not_launchd(req, iossupportversion_string)) {
2144 		return EPERM;
2145 	}
2146 
2147 #if defined(XNU_TARGET_OS_XR)
2148 	if (proc_platform(req->p) == PLATFORM_IOS) {
2149 		/* return empty string for iOS processes to match how this would behave on iOS */
2150 		return sysctl_handle_string(oidp, "", arg2, req);
2151 	} else {
2152 		/* native processes see the actual value */
2153 		return sysctl_handle_string(oidp, arg1, arg2, req);
2154 	}
2155 #else
2156 	return sysctl_handle_string(oidp, arg1, arg2, req);
2157 #endif
2158 }
2159 
2160 SYSCTL_PROC(_kern, OID_AUTO, iossupportversion,
2161     CTLFLAG_RW | CTLFLAG_KERN | CTLTYPE_STRING | CTLFLAG_LOCKED,
2162     iossupportversion_string, sizeof(iossupportversion_string),
2163     sysctl_iossupportversion, "A", "The iOSSupportVersion from SystemVersion.plist");
2164 
2165 static uint64_t osvariant_status = 0;
2166 
2167 STATIC int
2168 sysctl_osvariant_status(__unused struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req)
2169 {
2170 	if (req->newptr != 0) {
2171 		/*
2172 		 * Can only ever be set by launchd, and only once.
2173 		 * Reset by usrctl() -> reset_osvariant_status() during
2174 		 * userspace reboot, since userspace could reboot into
2175 		 * a different variant.
2176 		 */
2177 		if (proc_getpid(req->p) != 1 || osvariant_status != 0) {
2178 			return EPERM;
2179 		}
2180 	}
2181 
2182 	int err = sysctl_handle_quad(oidp, arg1, arg2, req);
2183 
2184 	reset_debug_syscall_rejection_mode();
2185 
2186 	return err;
2187 }
2188 
2189 SYSCTL_PROC(_kern, OID_AUTO, osvariant_status,
2190     CTLFLAG_RW | CTLTYPE_QUAD | CTLFLAG_LOCKED | CTLFLAG_MASKED,
2191     &osvariant_status, sizeof(osvariant_status),
2192     sysctl_osvariant_status, "Q", "Opaque flags used to cache OS variant information");
2193 
2194 static bool
2195 _os_variant_check_disabled(enum os_variant_property property)
2196 {
2197 	return (osvariant_status >> (32 + property)) & 0x1;
2198 }
2199 
2200 static bool
2201 _os_variant_has(enum os_variant_status_flags_positions p)
2202 {
2203 	return ((osvariant_status >> (p * OS_VARIANT_STATUS_BIT_WIDTH)) & OS_VARIANT_STATUS_MASK) == OS_VARIANT_S_YES;
2204 }
2205 
2206 bool
2207 os_variant_has_internal_diagnostics(__unused const char *subsystem)
2208 {
2209 	if (_os_variant_check_disabled(OS_VARIANT_PROPERTY_DIAGNOSTICS)) {
2210 		return false;
2211 	}
2212 #if XNU_TARGET_OS_OSX
2213 	return _os_variant_has(OS_VARIANT_SFP_INTERNAL_CONTENT) || _os_variant_has(OS_VARIANT_SFP_INTERNAL_DIAGS_PROFILE);
2214 #else
2215 	return _os_variant_has(OS_VARIANT_SFP_INTERNAL_RELEASE_TYPE);
2216 #endif /* XNU_TARGET_OS_OSX */
2217 }
2218 
2219 void reset_osvariant_status(void);
2220 
2221 void
2222 reset_osvariant_status(void)
2223 {
2224 	osvariant_status = 0;
2225 	reset_debug_syscall_rejection_mode();
2226 }
2227 
2228 extern void commpage_update_dyld_flags(uint64_t);
2229 TUNABLE_WRITEABLE(uint64_t, dyld_flags, "dyld_flags", 0);
2230 
2231 STATIC int
2232 sysctl_dyld_flags(__unused struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req)
2233 {
2234 	/*
2235 	 * Can only ever be set by launchd, possibly several times
2236 	 * as dyld may change its mind after a userspace reboot.
2237 	 */
2238 	if (req->newptr != 0 && proc_getpid(req->p) != 1) {
2239 		return EPERM;
2240 	}
2241 
2242 	int res = sysctl_handle_quad(oidp, arg1, arg2, req);
2243 	if (req->newptr && res == 0) {
2244 		commpage_update_dyld_flags(dyld_flags);
2245 	}
2246 	return res;
2247 }
2248 
2249 SYSCTL_PROC(_kern, OID_AUTO, dyld_flags,
2250     CTLFLAG_RW | CTLTYPE_QUAD | CTLFLAG_LOCKED | CTLFLAG_MASKED,
2251     &dyld_flags, sizeof(dyld_flags),
2252     sysctl_dyld_flags, "Q", "Opaque flags used to cache dyld system-wide configuration");
2253 
2254 #if defined(XNU_TARGET_OS_BRIDGE)
2255 char macosproductversion[MACOS_VERS_LEN] = { '\0' };
2256 
2257 SYSCTL_STRING(_kern, OID_AUTO, macosproductversion,
2258     CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
2259     &macosproductversion[0], MACOS_VERS_LEN, "The currently running macOS ProductVersion (from SystemVersion.plist on macOS)");
2260 
2261 char macosversion[MACOS_VERS_LEN] = { '\0' };
2262 
2263 SYSCTL_STRING(_kern, OID_AUTO, macosversion,
2264     CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
2265     &macosversion[0], MACOS_VERS_LEN, "The currently running macOS build version");
2266 #endif
2267 
2268 STATIC int
2269 sysctl_sysctl_bootargs
2270 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
2271 {
2272 	int error;
2273 	char buf[BOOT_LINE_LENGTH];
2274 
2275 	strlcpy(buf, PE_boot_args(), BOOT_LINE_LENGTH);
2276 	error = sysctl_io_string(req, buf, BOOT_LINE_LENGTH, 0, NULL);
2277 	return error;
2278 }
2279 
2280 SYSCTL_PROC(_kern, OID_AUTO, bootargs,
2281     CTLFLAG_LOCKED | CTLFLAG_RD | CTLFLAG_KERN | CTLTYPE_STRING,
2282     NULL, 0,
2283     sysctl_sysctl_bootargs, "A", "bootargs");
2284 
2285 STATIC int
2286 sysctl_kernelcacheuuid(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req)
2287 {
2288 	int rval = ENOENT;
2289 	if (kernelcache_uuid_valid) {
2290 		rval = sysctl_handle_string(oidp, arg1, arg2, req);
2291 	}
2292 	return rval;
2293 }
2294 
2295 SYSCTL_PROC(_kern, OID_AUTO, kernelcacheuuid,
2296     CTLFLAG_RD | CTLFLAG_KERN | CTLTYPE_STRING | CTLFLAG_LOCKED,
2297     kernelcache_uuid_string, sizeof(kernelcache_uuid_string),
2298     sysctl_kernelcacheuuid, "A", "");
2299 
2300 STATIC int
2301 sysctl_systemfilesetuuid(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req)
2302 {
2303 	int rval = ENOENT;
2304 	if (pageablekc_uuid_valid) {
2305 		rval = sysctl_handle_string(oidp, arg1, arg2, req);
2306 	}
2307 	return rval;
2308 }
2309 
2310 SYSCTL_PROC(_kern, OID_AUTO, systemfilesetuuid,
2311     CTLFLAG_RD | CTLFLAG_KERN | CTLTYPE_STRING | CTLFLAG_LOCKED,
2312     pageablekc_uuid_string, sizeof(pageablekc_uuid_string),
2313     sysctl_systemfilesetuuid, "A", "");
2314 
2315 STATIC int
2316 sysctl_auxiliaryfilesetuuid(struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req)
2317 {
2318 	int rval = ENOENT;
2319 	if (auxkc_uuid_valid) {
2320 		rval = sysctl_handle_string(oidp, arg1, arg2, req);
2321 	}
2322 	return rval;
2323 }
2324 
2325 SYSCTL_PROC(_kern, OID_AUTO, auxiliaryfilesetuuid,
2326     CTLFLAG_RD | CTLFLAG_KERN | CTLTYPE_STRING | CTLFLAG_LOCKED,
2327     auxkc_uuid_string, sizeof(auxkc_uuid_string),
2328     sysctl_auxiliaryfilesetuuid, "A", "");
2329 
2330 STATIC int
2331 sysctl_filesetuuid(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
2332 {
2333 	int rval = ENOENT;
2334 	kc_format_t kcformat;
2335 	kernel_mach_header_t *mh;
2336 	void *uuid = NULL;
2337 	unsigned long uuidlen = 0;
2338 	uuid_string_t uuid_str;
2339 
2340 	if (!PE_get_primary_kc_format(&kcformat) || kcformat != KCFormatFileset) {
2341 		return rval;
2342 	}
2343 
2344 	mh = (kernel_mach_header_t *)PE_get_kc_header(KCKindPrimary);
2345 	uuid = getuuidfromheader(mh, &uuidlen);
2346 
2347 	if ((uuid != NULL) && (uuidlen == sizeof(uuid_t))) {
2348 		uuid_unparse_upper(*(uuid_t *)uuid, uuid_str);
2349 		rval = sysctl_io_string(req, (char *)uuid_str, sizeof(uuid_str), 0, NULL);
2350 	}
2351 
2352 	return rval;
2353 }
2354 
2355 SYSCTL_PROC(_kern, OID_AUTO, filesetuuid,
2356     CTLFLAG_RD | CTLFLAG_KERN | CTLTYPE_STRING | CTLFLAG_LOCKED,
2357     NULL, 0,
2358     sysctl_filesetuuid, "A", "");
2359 
2360 
2361 SYSCTL_INT(_kern, KERN_MAXFILES, maxfiles,
2362     CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
2363     &maxfiles, 0, "");
2364 SYSCTL_INT(_kern, KERN_ARGMAX, argmax,
2365     CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
2366     (int *)NULL, ARG_MAX, "");
2367 SYSCTL_INT(_kern, KERN_POSIX1, posix1version,
2368     CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
2369     (int *)NULL, _POSIX_VERSION, "");
2370 SYSCTL_INT(_kern, KERN_NGROUPS, ngroups,
2371     CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
2372     (int *)NULL, NGROUPS_MAX, "");
2373 SYSCTL_INT(_kern, KERN_JOB_CONTROL, job_control,
2374     CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
2375     (int *)NULL, 1, "");
2376 #if 1   /* _POSIX_SAVED_IDS from <unistd.h> */
2377 SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids,
2378     CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
2379     (int *)NULL, 1, "");
2380 #else
2381 SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids,
2382     CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
2383     NULL, 0, "");
2384 #endif
2385 SYSCTL_INT(_kern, OID_AUTO, num_files,
2386     CTLFLAG_RD | CTLFLAG_LOCKED,
2387     &nfiles, 0, "");
2388 SYSCTL_COMPAT_INT(_kern, OID_AUTO, num_vnodes,
2389     CTLFLAG_RD | CTLFLAG_LOCKED,
2390     &numvnodes, 0, "");
2391 SYSCTL_INT(_kern, OID_AUTO, num_tasks,
2392     CTLFLAG_RD | CTLFLAG_LOCKED,
2393     &task_max, 0, "");
2394 SYSCTL_INT(_kern, OID_AUTO, num_threads,
2395     CTLFLAG_RD | CTLFLAG_LOCKED,
2396     &thread_max, 0, "");
2397 SYSCTL_INT(_kern, OID_AUTO, num_taskthreads,
2398     CTLFLAG_RD | CTLFLAG_LOCKED,
2399     &task_threadmax, 0, "");
2400 SYSCTL_LONG(_kern, OID_AUTO, num_recycledvnodes,
2401     CTLFLAG_RD | CTLFLAG_LOCKED,
2402     &num_recycledvnodes, "");
2403 SYSCTL_COMPAT_INT(_kern, OID_AUTO, free_vnodes,
2404     CTLFLAG_RD | CTLFLAG_LOCKED,
2405     &freevnodes, 0, "");
2406 
2407 STATIC int
2408 sysctl_maxvnodes(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
2409 {
2410 	int oldval = desiredvnodes;
2411 	int error = sysctl_io_number(req, desiredvnodes, sizeof(int), &desiredvnodes, NULL);
2412 
2413 	if (oldval != desiredvnodes) {
2414 		resize_namecache(desiredvnodes);
2415 	}
2416 
2417 	return error;
2418 }
2419 
2420 SYSCTL_INT(_kern, OID_AUTO, namecache_disabled,
2421     CTLFLAG_RW | CTLFLAG_LOCKED,
2422     &nc_disabled, 0, "");
2423 
2424 SYSCTL_PROC(_kern, KERN_MAXVNODES, maxvnodes,
2425     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
2426     0, 0, sysctl_maxvnodes, "I", "");
2427 
2428 SYSCTL_PROC(_kern, KERN_MAXPROC, maxproc,
2429     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
2430     0, 0, sysctl_maxproc, "I", "");
2431 
2432 SYSCTL_PROC(_kern, KERN_AIOMAX, aiomax,
2433     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
2434     0, 0, sysctl_aiomax, "I", "");
2435 
2436 SYSCTL_PROC(_kern, KERN_AIOPROCMAX, aioprocmax,
2437     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
2438     0, 0, sysctl_aioprocmax, "I", "");
2439 
2440 SYSCTL_PROC(_kern, KERN_AIOTHREADS, aiothreads,
2441     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
2442     0, 0, sysctl_aiothreads, "I", "");
2443 
2444 SYSCTL_PROC(_kern, OID_AUTO, sched_enable_smt,
2445     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN,
2446     0, 0, sysctl_sched_enable_smt, "I", "");
2447 
2448 extern int sched_allow_NO_SMT_threads;
2449 SYSCTL_INT(_kern, OID_AUTO, sched_allow_NO_SMT_threads,
2450     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
2451     &sched_allow_NO_SMT_threads, 0, "");
2452 
2453 extern int sched_avoid_cpu0;
2454 SYSCTL_INT(_kern, OID_AUTO, sched_rt_avoid_cpu0,
2455     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
2456     &sched_avoid_cpu0, 0, "If 1, choose cpu0 after all other primaries; if 2, choose cpu0 and cpu1 last, after all other cpus including secondaries");
2457 
2458 #if (DEVELOPMENT || DEBUG)
2459 
2460 static int
2461 sysctl_kern_max_unsafe_rt_quanta(__unused struct sysctl_oid *oidp,
2462     __unused void *arg1, __unused int arg2, struct sysctl_req *req)
2463 {
2464 	extern void sched_set_max_unsafe_rt_quanta(int);
2465 	extern int max_unsafe_rt_quanta;
2466 
2467 	int new_value, changed;
2468 	int old_value = max_unsafe_rt_quanta;
2469 	int error = sysctl_io_number(req, old_value, sizeof(int), &new_value,
2470 	    &changed);
2471 	if (changed) {
2472 		sched_set_max_unsafe_rt_quanta(new_value);
2473 	}
2474 
2475 	return error;
2476 }
2477 
2478 SYSCTL_PROC(_kern, OID_AUTO, max_unsafe_rt_quanta,
2479     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
2480     0, 0, sysctl_kern_max_unsafe_rt_quanta, "I",
2481     "Number of quanta to allow a realtime "
2482     "thread to run before being penalized");
2483 
2484 static int
2485 sysctl_kern_max_unsafe_fixed_quanta(__unused struct sysctl_oid *oidp,
2486     __unused void *arg1, __unused int arg2, struct sysctl_req *req)
2487 {
2488 	extern void sched_set_max_unsafe_fixed_quanta(int);
2489 	extern int max_unsafe_fixed_quanta;
2490 
2491 	int new_value, changed;
2492 	int old_value = max_unsafe_fixed_quanta;
2493 	int error = sysctl_io_number(req, old_value, sizeof(int), &new_value,
2494 	    &changed);
2495 	if (changed) {
2496 		sched_set_max_unsafe_fixed_quanta(new_value);
2497 	}
2498 
2499 	return error;
2500 }
2501 
2502 SYSCTL_PROC(_kern, OID_AUTO, max_unsafe_fixed_quanta,
2503     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
2504     0, 0, sysctl_kern_max_unsafe_fixed_quanta, "I",
2505     "Number of quanta to allow a fixed sched mode "
2506     "thread to run before being penalized");
2507 
2508 static int
2509 sysctl_kern_quantum_us(__unused struct sysctl_oid *oidp, __unused void *arg1,
2510     __unused int arg2, struct sysctl_req *req)
2511 {
2512 	const uint64_t quantum_us = sched_get_quantum_us();
2513 
2514 	return sysctl_io_number(req, quantum_us, sizeof(quantum_us), NULL, NULL);
2515 }
2516 
2517 SYSCTL_PROC(_kern, OID_AUTO, quantum_us,
2518     CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_LOCKED,
2519     0, 0, sysctl_kern_quantum_us, "Q",
2520     "Length of scheduling quantum in microseconds");
2521 
2522 extern int smt_sched_bonus_16ths;
2523 SYSCTL_INT(_kern, OID_AUTO, smt_sched_bonus_16ths,
2524     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
2525     &smt_sched_bonus_16ths, 0, "");
2526 
2527 extern int smt_timeshare_enabled;
2528 SYSCTL_INT(_kern, OID_AUTO, sched_smt_timeshare_enable,
2529     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
2530     &smt_timeshare_enabled, 0, "");
2531 
2532 extern int sched_smt_balance;
2533 SYSCTL_INT(_kern, OID_AUTO, sched_smt_balance,
2534     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
2535     &sched_smt_balance, 0, "");
2536 extern int sched_allow_rt_smt;
2537 SYSCTL_INT(_kern, OID_AUTO, sched_allow_rt_smt,
2538     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
2539     &sched_allow_rt_smt, 0, "");
2540 extern int sched_backup_cpu_timeout_count;
2541 SYSCTL_INT(_kern, OID_AUTO, sched_backup_cpu_timeout_count,
2542     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
2543     &sched_backup_cpu_timeout_count, 0, "The maximum number of 10us delays before allowing a backup cpu to select a thread");
2544 #if __arm64__
2545 /* Scheduler perfcontrol callouts sysctls */
2546 SYSCTL_DECL(_kern_perfcontrol_callout);
2547 SYSCTL_NODE(_kern, OID_AUTO, perfcontrol_callout, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
2548     "scheduler perfcontrol callouts");
2549 
2550 extern int perfcontrol_callout_stats_enabled;
2551 SYSCTL_INT(_kern_perfcontrol_callout, OID_AUTO, stats_enabled,
2552     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
2553     &perfcontrol_callout_stats_enabled, 0, "");
2554 
2555 extern uint64_t perfcontrol_callout_stat_avg(perfcontrol_callout_type_t type,
2556     perfcontrol_callout_stat_t stat);
2557 
2558 /* On-Core Callout */
2559 STATIC int
2560 sysctl_perfcontrol_callout_stat
2561 (__unused struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req)
2562 {
2563 	perfcontrol_callout_stat_t stat = (perfcontrol_callout_stat_t)arg1;
2564 	perfcontrol_callout_type_t type = (perfcontrol_callout_type_t)arg2;
2565 	return sysctl_io_number(req, (int)perfcontrol_callout_stat_avg(type, stat),
2566 	           sizeof(int), NULL, NULL);
2567 }
2568 
2569 SYSCTL_PROC(_kern_perfcontrol_callout, OID_AUTO, oncore_instr,
2570     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
2571     (void *)PERFCONTROL_STAT_INSTRS, PERFCONTROL_CALLOUT_ON_CORE,
2572     sysctl_perfcontrol_callout_stat, "I", "");
2573 SYSCTL_PROC(_kern_perfcontrol_callout, OID_AUTO, oncore_cycles,
2574     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
2575     (void *)PERFCONTROL_STAT_CYCLES, PERFCONTROL_CALLOUT_ON_CORE,
2576     sysctl_perfcontrol_callout_stat, "I", "");
2577 SYSCTL_PROC(_kern_perfcontrol_callout, OID_AUTO, offcore_instr,
2578     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
2579     (void *)PERFCONTROL_STAT_INSTRS, PERFCONTROL_CALLOUT_OFF_CORE,
2580     sysctl_perfcontrol_callout_stat, "I", "");
2581 SYSCTL_PROC(_kern_perfcontrol_callout, OID_AUTO, offcore_cycles,
2582     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
2583     (void *)PERFCONTROL_STAT_CYCLES, PERFCONTROL_CALLOUT_OFF_CORE,
2584     sysctl_perfcontrol_callout_stat, "I", "");
2585 SYSCTL_PROC(_kern_perfcontrol_callout, OID_AUTO, context_instr,
2586     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
2587     (void *)PERFCONTROL_STAT_INSTRS, PERFCONTROL_CALLOUT_CONTEXT,
2588     sysctl_perfcontrol_callout_stat, "I", "");
2589 SYSCTL_PROC(_kern_perfcontrol_callout, OID_AUTO, context_cycles,
2590     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
2591     (void *)PERFCONTROL_STAT_CYCLES, PERFCONTROL_CALLOUT_CONTEXT,
2592     sysctl_perfcontrol_callout_stat, "I", "");
2593 SYSCTL_PROC(_kern_perfcontrol_callout, OID_AUTO, update_instr,
2594     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
2595     (void *)PERFCONTROL_STAT_INSTRS, PERFCONTROL_CALLOUT_STATE_UPDATE,
2596     sysctl_perfcontrol_callout_stat, "I", "");
2597 SYSCTL_PROC(_kern_perfcontrol_callout, OID_AUTO, update_cycles,
2598     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
2599     (void *)PERFCONTROL_STAT_CYCLES, PERFCONTROL_CALLOUT_STATE_UPDATE,
2600     sysctl_perfcontrol_callout_stat, "I", "");
2601 
2602 #if __AMP__
2603 #if !CONFIG_CLUTCH
2604 extern int sched_amp_idle_steal;
2605 SYSCTL_INT(_kern, OID_AUTO, sched_amp_idle_steal,
2606     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
2607     &sched_amp_idle_steal, 0, "");
2608 extern int sched_amp_spill_steal;
2609 SYSCTL_INT(_kern, OID_AUTO, sched_amp_spill_steal,
2610     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
2611     &sched_amp_spill_steal, 0, "");
2612 extern int sched_amp_spill_count;
2613 SYSCTL_INT(_kern, OID_AUTO, sched_amp_spill_count,
2614     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
2615     &sched_amp_spill_count, 0, "");
2616 #endif /* !CONFIG_CLUTCH */
2617 extern int sched_amp_spill_deferred_ipi;
2618 SYSCTL_INT(_kern, OID_AUTO, sched_amp_spill_deferred_ipi,
2619     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
2620     &sched_amp_spill_deferred_ipi, 0, "");
2621 extern int sched_amp_pcores_preempt_immediate_ipi;
2622 SYSCTL_INT(_kern, OID_AUTO, sched_amp_pcores_preempt_immediate_ipi,
2623     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
2624     &sched_amp_pcores_preempt_immediate_ipi, 0, "");
2625 #endif /* __AMP__ */
2626 #endif /* __arm64__ */
2627 
2628 #if __arm64__
2629 extern int legacy_footprint_entitlement_mode;
2630 SYSCTL_INT(_kern, OID_AUTO, legacy_footprint_entitlement_mode,
2631     CTLFLAG_KERN | CTLFLAG_RD | CTLFLAG_LOCKED,
2632     &legacy_footprint_entitlement_mode, 0, "");
2633 #endif /* __arm64__ */
2634 
2635 /*
2636  * Realtime threads are ordered by highest priority first then,
2637  * for threads of the same priority, by earliest deadline first.
2638  * But if sched_rt_runq_strict_priority is false (the default),
2639  * a lower priority thread with an earlier deadline will be preferred
2640  * over a higher priority thread with a later deadline, as long as
2641  * both threads' computations will fit before the later deadline.
2642  */
2643 extern int sched_rt_runq_strict_priority;
2644 SYSCTL_INT(_kern, OID_AUTO, sched_rt_runq_strict_priority,
2645     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
2646     &sched_rt_runq_strict_priority, 0, "");
2647 
2648 static int
2649 sysctl_kern_sched_rt_n_backup_processors(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
2650 {
2651 	int new_value, changed;
2652 	int old_value = sched_get_rt_n_backup_processors();
2653 	int error = sysctl_io_number(req, old_value, sizeof(int), &new_value, &changed);
2654 	if (changed) {
2655 		sched_set_rt_n_backup_processors(new_value);
2656 	}
2657 
2658 	return error;
2659 }
2660 
2661 SYSCTL_PROC(_kern, OID_AUTO, sched_rt_n_backup_processors,
2662     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
2663     0, 0, sysctl_kern_sched_rt_n_backup_processors, "I", "");
2664 
2665 static int
2666 sysctl_kern_sched_rt_deadline_epsilon_us(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
2667 {
2668 	int new_value, changed;
2669 	int old_value = sched_get_rt_deadline_epsilon();
2670 	int error = sysctl_io_number(req, old_value, sizeof(int), &new_value, &changed);
2671 	if (changed) {
2672 		sched_set_rt_deadline_epsilon(new_value);
2673 	}
2674 
2675 	return error;
2676 }
2677 
2678 SYSCTL_PROC(_kern, OID_AUTO, sched_rt_deadline_epsilon_us,
2679     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
2680     0, 0, sysctl_kern_sched_rt_deadline_epsilon_us, "I", "");
2681 
2682 extern int sched_idle_delay_cpuid;
2683 SYSCTL_INT(_kern, OID_AUTO, sched_idle_delay_cpuid,
2684     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
2685     &sched_idle_delay_cpuid, 0, "This cpuid will be delayed by 500us on exiting idle, to simulate interrupt or preemption delays when testing the scheduler");
2686 
2687 static int
2688 sysctl_kern_sched_powered_cores(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
2689 {
2690 	int new_value, changed;
2691 	int old_value = sched_get_powered_cores();
2692 	int error = sysctl_io_number(req, old_value, sizeof(int), &new_value, &changed);
2693 	if (changed) {
2694 		if (!PE_parse_boot_argn("enable_skstb", NULL, 0)) {
2695 			return ENOTSUP;
2696 		}
2697 
2698 		sched_set_powered_cores(new_value);
2699 	}
2700 
2701 	return error;
2702 }
2703 
2704 SYSCTL_PROC(_kern, OID_AUTO, sched_powered_cores,
2705     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
2706     0, 0, sysctl_kern_sched_powered_cores, "I", "");
2707 
2708 #if __arm64__
2709 
2710 static int
2711 sysctl_kern_update_sched_recommended_cores(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
2712 {
2713 	uint64_t new_value;
2714 	int changed;
2715 	uint64_t old_value = sched_sysctl_get_recommended_cores();
2716 	int error = sysctl_io_number(req, old_value, sizeof(uint64_t), &new_value, &changed);
2717 	if (changed) {
2718 		if (!PE_parse_boot_argn("enable_skstb", NULL, 0)) {
2719 			return ENOTSUP;
2720 		}
2721 
2722 		sched_perfcontrol_update_recommended_cores_reason(new_value, REASON_CLPC_USER, 0);
2723 	}
2724 
2725 	return error;
2726 }
2727 
2728 SYSCTL_PROC(_kern, OID_AUTO, sched_update_recommended_cores,
2729     CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED,
2730     0, 0, sysctl_kern_update_sched_recommended_cores, "I", "");
2731 
2732 #endif /* __arm64__ */
2733 
2734 #endif /* (DEVELOPMENT || DEBUG) */
2735 
2736 extern uint64_t sysctl_sched_recommended_cores;
2737 SYSCTL_QUAD(_kern, OID_AUTO, sched_recommended_cores,
2738     CTLFLAG_KERN | CTLFLAG_RD | CTLFLAG_LOCKED,
2739     &sysctl_sched_recommended_cores, "");
2740 
2741 static int
2742 sysctl_kern_suspend_cluster_powerdown(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
2743 {
2744 	int new_value, changed;
2745 	int old_value = get_cluster_powerdown_user_suspended();
2746 	int error = sysctl_io_number(req, old_value, sizeof(int), &new_value, &changed);
2747 	if (!error && changed) {
2748 		if (new_value > 0) {
2749 			error = suspend_cluster_powerdown_from_user();
2750 		} else {
2751 			error = resume_cluster_powerdown_from_user();
2752 		}
2753 		if (error) {
2754 			error = EALREADY;
2755 		}
2756 	}
2757 
2758 	return error;
2759 }
2760 
2761 SYSCTL_PROC(_kern, OID_AUTO, suspend_cluster_powerdown,
2762     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
2763     0, 0, sysctl_kern_suspend_cluster_powerdown, "I", "");
2764 
2765 
2766 STATIC int
2767 sysctl_securelvl
2768 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
2769 {
2770 	int new_value, changed;
2771 	int error = sysctl_io_number(req, securelevel, sizeof(int), &new_value, &changed);
2772 	if (changed) {
2773 		if (!(new_value < securelevel && proc_getpid(req->p) != 1)) {
2774 			proc_list_lock();
2775 			securelevel = new_value;
2776 			proc_list_unlock();
2777 		} else {
2778 			error = EPERM;
2779 		}
2780 	}
2781 	return error;
2782 }
2783 
2784 SYSCTL_PROC(_kern, KERN_SECURELVL, securelevel,
2785     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
2786     0, 0, sysctl_securelvl, "I", "");
2787 
2788 
2789 STATIC int
2790 sysctl_domainname
2791 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
2792 {
2793 	int error, changed;
2794 	char tmpname[MAXHOSTNAMELEN] = {};
2795 
2796 	lck_mtx_lock(&domainname_lock);
2797 	strlcpy(tmpname, domainname, sizeof(tmpname));
2798 	lck_mtx_unlock(&domainname_lock);
2799 
2800 	error = sysctl_io_string(req, tmpname, sizeof(tmpname), 0, &changed);
2801 	if (!error && changed) {
2802 		lck_mtx_lock(&domainname_lock);
2803 		strlcpy(domainname, tmpname, sizeof(domainname));
2804 		lck_mtx_unlock(&domainname_lock);
2805 	}
2806 	return error;
2807 }
2808 
2809 SYSCTL_PROC(_kern, KERN_DOMAINNAME, nisdomainname,
2810     CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_LOCKED,
2811     0, 0, sysctl_domainname, "A", "");
2812 
2813 SYSCTL_COMPAT_INT(_kern, KERN_HOSTID, hostid,
2814     CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
2815     &hostid, 0, "");
2816 
2817 STATIC int
2818 sysctl_hostname
2819 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
2820 {
2821 	int error, changed;
2822 	char tmpname[MAXHOSTNAMELEN] = {};
2823 	const char * name;
2824 
2825 #if  XNU_TARGET_OS_OSX
2826 	name = hostname;
2827 #else /* XNU_TARGET_OS_OSX */
2828 #define ENTITLEMENT_USER_ASSIGNED_DEVICE_NAME                           \
2829 	"com.apple.developer.device-information.user-assigned-device-name"
2830 	if (csproc_get_platform_binary(current_proc()) ||
2831 	    IOCurrentTaskHasEntitlement(ENTITLEMENT_USER_ASSIGNED_DEVICE_NAME)) {
2832 		name = hostname;
2833 	} else {
2834 		/* Deny writes if we don't pass entitlement check */
2835 		if (req->newptr) {
2836 			return EPERM;
2837 		}
2838 
2839 		name = "localhost";
2840 	}
2841 #endif /* ! XNU_TARGET_OS_OSX */
2842 
2843 	lck_mtx_lock(&hostname_lock);
2844 	strlcpy(tmpname, name, sizeof(tmpname));
2845 	lck_mtx_unlock(&hostname_lock);
2846 
2847 	error = sysctl_io_string(req, tmpname, sizeof(tmpname), 1, &changed);
2848 	if (!error && changed) {
2849 		lck_mtx_lock(&hostname_lock);
2850 		strlcpy(hostname, tmpname, sizeof(hostname));
2851 		lck_mtx_unlock(&hostname_lock);
2852 	}
2853 	return error;
2854 }
2855 
2856 SYSCTL_PROC(_kern, KERN_HOSTNAME, hostname,
2857     CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_LOCKED,
2858     0, 0, sysctl_hostname, "A", "");
2859 
2860 STATIC int
2861 sysctl_procname
2862 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
2863 {
2864 	/* Original code allowed writing, I'm copying this, although this all makes
2865 	 *  no sense to me. Besides, this sysctl is never used. */
2866 	return sysctl_io_string(req, &req->p->p_name[0], (2 * MAXCOMLEN + 1), 1, NULL);
2867 }
2868 
2869 SYSCTL_PROC(_kern, KERN_PROCNAME, procname,
2870     CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED,
2871     0, 0, sysctl_procname, "A", "");
2872 
2873 SYSCTL_INT(_kern, KERN_SPECULATIVE_READS, speculative_reads_disabled,
2874     CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
2875     &speculative_reads_disabled, 0, "");
2876 
2877 SYSCTL_UINT(_kern, OID_AUTO, preheat_max_bytes,
2878     CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
2879     &preheat_max_bytes, 0, "");
2880 
2881 SYSCTL_UINT(_kern, OID_AUTO, preheat_min_bytes,
2882     CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
2883     &preheat_min_bytes, 0, "");
2884 
2885 SYSCTL_UINT(_kern, OID_AUTO, speculative_prefetch_max,
2886     CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
2887     &speculative_prefetch_max, 0, "");
2888 
2889 SYSCTL_UINT(_kern, OID_AUTO, speculative_prefetch_max_iosize,
2890     CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
2891     &speculative_prefetch_max_iosize, 0, "");
2892 
2893 SYSCTL_UINT(_kern, OID_AUTO, vm_page_free_target,
2894     CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
2895     &vm_page_free_target, 0, "");
2896 
2897 SYSCTL_UINT(_kern, OID_AUTO, vm_page_free_min,
2898     CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
2899     &vm_page_free_min, 0, "");
2900 
2901 SYSCTL_UINT(_kern, OID_AUTO, vm_page_free_reserved,
2902     CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
2903     &vm_page_free_reserved, 0, "");
2904 
2905 SYSCTL_UINT(_kern, OID_AUTO, vm_page_speculative_percentage,
2906     CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
2907     &vm_pageout_state.vm_page_speculative_percentage, 0, "");
2908 
2909 SYSCTL_UINT(_kern, OID_AUTO, vm_page_speculative_q_age_ms,
2910     CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
2911     &vm_pageout_state.vm_page_speculative_q_age_ms, 0, "");
2912 
2913 #if (DEVELOPMENT || DEBUG)
2914 SYSCTL_UINT(_kern, OID_AUTO, vm_page_max_speculative_age_q,
2915     CTLFLAG_RD,
2916     &vm_page_max_speculative_age_q, 0, "");
2917 #endif /* (DEVELOPMENT || DEBUG) */
2918 
2919 SYSCTL_UINT(_kern, OID_AUTO, vm_max_delayed_work_limit,
2920     CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
2921     &vm_max_delayed_work_limit, 0, "");
2922 
2923 SYSCTL_UINT(_kern, OID_AUTO, vm_max_batch,
2924     CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
2925     &vm_max_batch, 0, "");
2926 
2927 SYSCTL_STRING(_kern, OID_AUTO, bootsessionuuid,
2928     CTLFLAG_RD | CTLFLAG_LOCKED,
2929     &bootsessionuuid_string, sizeof(bootsessionuuid_string), "");
2930 
2931 
2932 STATIC int
2933 sysctl_boottime
2934 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
2935 {
2936 	struct timeval tv;
2937 	boottime_timeval(&tv);
2938 	struct proc *p = req->p;
2939 
2940 	if (proc_is64bit(p)) {
2941 		struct user64_timeval t = {};
2942 		t.tv_sec = tv.tv_sec;
2943 		t.tv_usec = tv.tv_usec;
2944 		return sysctl_io_opaque(req, &t, sizeof(t), NULL);
2945 	} else {
2946 		struct user32_timeval t = {};
2947 		t.tv_sec = (user32_time_t)tv.tv_sec;
2948 		t.tv_usec = tv.tv_usec;
2949 		return sysctl_io_opaque(req, &t, sizeof(t), NULL);
2950 	}
2951 }
2952 
2953 SYSCTL_PROC(_kern, KERN_BOOTTIME, boottime,
2954     CTLTYPE_STRUCT | CTLFLAG_KERN | CTLFLAG_RD | CTLFLAG_LOCKED,
2955     0, 0, sysctl_boottime, "S,timeval", "");
2956 
2957 extern bool IOGetBootUUID(char *);
2958 
2959 /* non-static: written by imageboot.c */
2960 uuid_string_t fake_bootuuid;
2961 
2962 STATIC int
2963 sysctl_bootuuid
2964 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
2965 {
2966 	int error = ENOENT;
2967 
2968 	/* check the first byte to see if the string has been
2969 	 * populated. this is a uuid_STRING_t, this check would
2970 	 * not work with a uuid_t.
2971 	 */
2972 	if (fake_bootuuid[0] != '\0') {
2973 		error = sysctl_io_string(req, fake_bootuuid, 0, 0, NULL);
2974 		goto out;
2975 	}
2976 
2977 	uuid_string_t uuid_string;
2978 	if (IOGetBootUUID(uuid_string)) {
2979 		uuid_t boot_uuid;
2980 		error = uuid_parse(uuid_string, boot_uuid);
2981 		if (!error) {
2982 			error = sysctl_io_string(req, __DECONST(char *, uuid_string), 0, 0, NULL);
2983 		}
2984 	}
2985 
2986 out:
2987 	return error;
2988 }
2989 
2990 SYSCTL_PROC(_kern, OID_AUTO, bootuuid,
2991     CTLTYPE_STRING | CTLFLAG_KERN | CTLFLAG_RD | CTLFLAG_LOCKED,
2992     0, 0, sysctl_bootuuid, "A", "");
2993 
2994 
2995 extern bool IOGetApfsPrebootUUID(char *);
2996 extern bool IOGetAssociatedApfsVolgroupUUID(char *);
2997 
2998 STATIC int
2999 sysctl_apfsprebootuuid
3000 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
3001 {
3002 	int error = ENOENT;
3003 
3004 	uuid_string_t uuid_string;
3005 	if (IOGetApfsPrebootUUID(uuid_string)) {
3006 		uuid_t apfs_preboot_uuid;
3007 		error = uuid_parse(uuid_string, apfs_preboot_uuid);
3008 		if (!error) {
3009 			error = sysctl_io_string(req, __DECONST(char *, uuid_string), 0, 0, NULL);
3010 		}
3011 	}
3012 
3013 	return error;
3014 }
3015 
3016 SYSCTL_PROC(_kern, OID_AUTO, apfsprebootuuid,
3017     CTLTYPE_STRING | CTLFLAG_KERN | CTLFLAG_RD | CTLFLAG_LOCKED,
3018     0, 0, sysctl_apfsprebootuuid, "A", "");
3019 
3020 STATIC int
3021 sysctl_targetsystemvolgroupuuid
3022 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
3023 {
3024 	int error = ENOENT;
3025 
3026 	uuid_string_t uuid_string;
3027 	if (IOGetApfsPrebootUUID(uuid_string)) {
3028 		uuid_t apfs_preboot_uuid;
3029 		error = uuid_parse(uuid_string, apfs_preboot_uuid);
3030 		if (!error) {
3031 			error = sysctl_io_string(req, __DECONST(char *, uuid_string), 0, 0, NULL);
3032 		}
3033 	} else {
3034 		/*
3035 		 * In special boot modes, such as kcgen-mode, the
3036 		 * apfs-preboot-uuid property will not be set. Instead, a
3037 		 * different property, associated-volume-group, will be set
3038 		 * which indicates the UUID of the VolumeGroup containing the
3039 		 * system volume into which you will boot.
3040 		 */
3041 		if (IOGetAssociatedApfsVolgroupUUID(uuid_string)) {
3042 			uuid_t apfs_preboot_uuid;
3043 			error = uuid_parse(uuid_string, apfs_preboot_uuid);
3044 			if (!error) {
3045 				error = sysctl_io_string(req, __DECONST(char *, uuid_string), 0, 0, NULL);
3046 			}
3047 		}
3048 	}
3049 
3050 	return error;
3051 }
3052 
3053 SYSCTL_PROC(_kern, OID_AUTO, targetsystemvolgroupuuid,
3054     CTLTYPE_STRING | CTLFLAG_KERN | CTLFLAG_RD | CTLFLAG_MASKED | CTLFLAG_LOCKED,
3055     0, 0, sysctl_targetsystemvolgroupuuid, "A", "");
3056 
3057 
3058 extern bool IOGetBootManifestHash(char *, size_t *);
3059 extern bool IOGetBootObjectsPath(char *);
3060 
3061 STATIC int
3062 sysctl_bootobjectspath
3063 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
3064 {
3065 	int error = ENOENT;
3066 
3067 #if defined(__x86_64__)
3068 	/* auth-root-dmg is used for the Intel BaseSystem in some flows,
3069 	 * e.g. createinstallmedia and as part of upgrading from 10.15 or earlier
3070 	 * under these scenarios, set_fake_bootuuid will be called when pivoting to
3071 	 * the new root filesystem. need honor the fake bootuuid.
3072 	 */
3073 	if (fake_bootuuid[0] != '\0') {
3074 		error = sysctl_io_string(req, fake_bootuuid, 0, 0, NULL);
3075 	} else {
3076 		/* for intel mac, boot objects reside in [preboot volume]/[bootuuid]
3077 		 * bootuuid and apfsprebootuuid are populated by efiboot and they are alias.
3078 		 */
3079 		uuid_string_t uuid_string;
3080 		if (IOGetBootUUID(uuid_string)) {
3081 			uuid_t boot_uuid;
3082 			error = uuid_parse(uuid_string, boot_uuid);
3083 			if (!error) {
3084 				error = sysctl_io_string(req, (char *)uuid_string, 0, 0, NULL);
3085 			}
3086 		}
3087 	}
3088 #else
3089 	char boot_obj_path[MAXPATHLEN] = { "\0" };
3090 	static const char kAsciiHexChars[] = "0123456789ABCDEF";
3091 	unsigned int i, j;
3092 
3093 	/* Hashed with SHA2-384 or SHA1, boot manifest hash is 48 bytes or 20 bytes
3094 	 * hence, need a 97 bytes char array for the string.
3095 	 */
3096 	size_t hash_data_size = CCSHA384_OUTPUT_SIZE;
3097 	char hash_data[CCSHA384_OUTPUT_SIZE] = { "\0" };
3098 	char boot_manifest_hash[CCSHA384_OUTPUT_SIZE * 2 + 1] = { "\0" };;
3099 
3100 	/* for Apple Silicon Macs, there is a boot-objects-path under IODeviceTree:/chosen
3101 	 * and boot objects reside in [preboot volume]/[boot-objects-path]
3102 	 * for embedded platforms, there would be a boot-manifest-hash under IODeviceTree:/chosen
3103 	 * and boot objects reside in [preboot volume]/[boot-manifest-hash]
3104 	 */
3105 	if (IOGetBootObjectsPath(boot_obj_path)) {
3106 		error = sysctl_io_string(req, (char *)boot_obj_path, 0, 0, NULL);
3107 	} else if (IOGetBootManifestHash(hash_data, &hash_data_size)) {
3108 		j = 0;
3109 		for (i = 0; i < hash_data_size; ++i) {
3110 			char octet = hash_data[i];
3111 			boot_manifest_hash[j++] = kAsciiHexChars[((octet & 0xF0) >> 4)];
3112 			boot_manifest_hash[j++] = kAsciiHexChars[(octet & 0x0F)];
3113 		}
3114 		/* make sure string has null termination */
3115 		boot_manifest_hash[j] = '\0';
3116 		error = sysctl_io_string(req, (char *)boot_manifest_hash, 0, 0, NULL);
3117 	}
3118 #endif
3119 	return error;
3120 }
3121 
3122 SYSCTL_PROC(_kern, OID_AUTO, bootobjectspath,
3123     CTLTYPE_STRING | CTLFLAG_KERN | CTLFLAG_RD | CTLFLAG_LOCKED,
3124     0, 0, sysctl_bootobjectspath, "A", "");
3125 
3126 
3127 STATIC int
3128 sysctl_symfile
3129 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
3130 {
3131 	char *str;
3132 	int error = get_kernel_symfile(req->p, &str);
3133 	if (error) {
3134 		return error;
3135 	}
3136 	return sysctl_io_string(req, str, 0, 0, NULL);
3137 }
3138 
3139 
3140 SYSCTL_PROC(_kern, KERN_SYMFILE, symfile,
3141     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_LOCKED,
3142     0, 0, sysctl_symfile, "A", "");
3143 
3144 #if CONFIG_NETBOOT
3145 STATIC int
3146 sysctl_netboot
3147 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
3148 {
3149 	return sysctl_io_number(req, netboot_root(), sizeof(int), NULL, NULL);
3150 }
3151 
3152 SYSCTL_PROC(_kern, KERN_NETBOOT, netboot,
3153     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
3154     0, 0, sysctl_netboot, "I", "");
3155 #endif
3156 
3157 #ifdef CONFIG_IMGSRC_ACCESS
3158 /*
3159  * Legacy--act as if only one layer of nesting is possible.
3160  */
3161 STATIC int
3162 sysctl_imgsrcdev
3163 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
3164 {
3165 	vfs_context_t ctx = vfs_context_current();
3166 	vnode_t devvp;
3167 	int result;
3168 
3169 	if (!vfs_context_issuser(ctx)) {
3170 		return EPERM;
3171 	}
3172 
3173 	if (imgsrc_rootvnodes[0] == NULL) {
3174 		return ENOENT;
3175 	}
3176 
3177 	result = vnode_getwithref(imgsrc_rootvnodes[0]);
3178 	if (result != 0) {
3179 		return result;
3180 	}
3181 
3182 	devvp = vnode_mount(imgsrc_rootvnodes[0])->mnt_devvp;
3183 	result = vnode_getwithref(devvp);
3184 	if (result != 0) {
3185 		goto out;
3186 	}
3187 
3188 	result = sysctl_io_number(req, vnode_specrdev(devvp), sizeof(dev_t), NULL, NULL);
3189 
3190 	vnode_put(devvp);
3191 out:
3192 	vnode_put(imgsrc_rootvnodes[0]);
3193 	return result;
3194 }
3195 
3196 SYSCTL_PROC(_kern, OID_AUTO, imgsrcdev,
3197     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
3198     0, 0, sysctl_imgsrcdev, "I", "");
3199 
3200 STATIC int
3201 sysctl_imgsrcinfo
3202 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
3203 {
3204 	int error;
3205 	struct imgsrc_info info[MAX_IMAGEBOOT_NESTING] = {};    /* 2 for now, no problem */
3206 	uint32_t i;
3207 	vnode_t rvp, devvp;
3208 
3209 	if (imgsrc_rootvnodes[0] == NULLVP) {
3210 		return ENXIO;
3211 	}
3212 
3213 	for (i = 0; i < MAX_IMAGEBOOT_NESTING; i++) {
3214 		/*
3215 		 * Go get the root vnode.
3216 		 */
3217 		rvp = imgsrc_rootvnodes[i];
3218 		if (rvp == NULLVP) {
3219 			break;
3220 		}
3221 
3222 		error = vnode_get(rvp);
3223 		if (error != 0) {
3224 			return error;
3225 		}
3226 
3227 		/*
3228 		 * For now, no getting at a non-local volume.
3229 		 */
3230 		devvp = vnode_mount(rvp)->mnt_devvp;
3231 		if (devvp == NULL) {
3232 			vnode_put(rvp);
3233 			return EINVAL;
3234 		}
3235 
3236 		error = vnode_getwithref(devvp);
3237 		if (error != 0) {
3238 			vnode_put(rvp);
3239 			return error;
3240 		}
3241 
3242 		/*
3243 		 * Fill in info.
3244 		 */
3245 		info[i].ii_dev = vnode_specrdev(devvp);
3246 		info[i].ii_flags = 0;
3247 		info[i].ii_height = i;
3248 		bzero(info[i].ii_reserved, sizeof(info[i].ii_reserved));
3249 
3250 		vnode_put(devvp);
3251 		vnode_put(rvp);
3252 	}
3253 
3254 	return sysctl_io_opaque(req, info, i * sizeof(info[0]), NULL);
3255 }
3256 
3257 SYSCTL_PROC(_kern, OID_AUTO, imgsrcinfo,
3258     CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_LOCKED,
3259     0, 0, sysctl_imgsrcinfo, "I", "");
3260 
3261 #endif /* CONFIG_IMGSRC_ACCESS */
3262 
3263 
3264 SYSCTL_DECL(_kern_timer);
3265 SYSCTL_NODE(_kern, OID_AUTO, timer, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "timer");
3266 
3267 
3268 SYSCTL_INT(_kern_timer, OID_AUTO, coalescing_enabled,
3269     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
3270     &mach_timer_coalescing_enabled, 0, "");
3271 
3272 SYSCTL_QUAD(_kern_timer, OID_AUTO, deadline_tracking_bin_1,
3273     CTLFLAG_RW | CTLFLAG_LOCKED,
3274     &timer_deadline_tracking_bin_1, "");
3275 SYSCTL_QUAD(_kern_timer, OID_AUTO, deadline_tracking_bin_2,
3276     CTLFLAG_RW | CTLFLAG_LOCKED,
3277     &timer_deadline_tracking_bin_2, "");
3278 
3279 SYSCTL_DECL(_kern_timer_longterm);
3280 SYSCTL_NODE(_kern_timer, OID_AUTO, longterm, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "longterm");
3281 
3282 
3283 /* Must match definition in osfmk/kern/timer_call.c */
3284 enum {
3285 	THRESHOLD, QCOUNT,
3286 	ENQUEUES, DEQUEUES, ESCALATES, SCANS, PREEMPTS,
3287 	LATENCY, LATENCY_MIN, LATENCY_MAX, LONG_TERM_SCAN_LIMIT,
3288 	LONG_TERM_SCAN_INTERVAL, LONG_TERM_SCAN_PAUSES,
3289 	SCAN_LIMIT, SCAN_INTERVAL, SCAN_PAUSES, SCAN_POSTPONES,
3290 };
3291 extern uint64_t timer_sysctl_get(int);
3292 extern kern_return_t timer_sysctl_set(int, uint64_t);
3293 
3294 STATIC int
3295 sysctl_timer
3296 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
3297 {
3298 	int             oid = (int)arg1;
3299 	uint64_t        value = timer_sysctl_get(oid);
3300 	uint64_t        new_value;
3301 	int             error;
3302 	int             changed;
3303 
3304 	error = sysctl_io_number(req, value, sizeof(value), &new_value, &changed);
3305 	if (changed) {
3306 		kern_return_t kr = timer_sysctl_set(oid, new_value);
3307 		error = mach_to_bsd_errno(kr);
3308 	}
3309 
3310 	return error;
3311 }
3312 
3313 SYSCTL_PROC(_kern_timer_longterm, OID_AUTO, threshold,
3314     CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED,
3315     (void *) THRESHOLD, 0, sysctl_timer, "Q", "");
3316 SYSCTL_PROC(_kern_timer_longterm, OID_AUTO, scan_limit,
3317     CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED,
3318     (void *) LONG_TERM_SCAN_LIMIT, 0, sysctl_timer, "Q", "");
3319 SYSCTL_PROC(_kern_timer_longterm, OID_AUTO, scan_interval,
3320     CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED,
3321     (void *) LONG_TERM_SCAN_INTERVAL, 0, sysctl_timer, "Q", "");
3322 
3323 SYSCTL_PROC(_kern_timer_longterm, OID_AUTO, qlen,
3324     CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_LOCKED,
3325     (void *) QCOUNT, 0, sysctl_timer, "Q", "");
3326 SYSCTL_PROC(_kern_timer_longterm, OID_AUTO, scan_pauses,
3327     CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_LOCKED,
3328     (void *) LONG_TERM_SCAN_PAUSES, 0, sysctl_timer, "Q", "");
3329 
3330 #if  DEBUG
3331 SYSCTL_PROC(_kern_timer_longterm, OID_AUTO, enqueues,
3332     CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_LOCKED,
3333     (void *) ENQUEUES, 0, sysctl_timer, "Q", "");
3334 SYSCTL_PROC(_kern_timer_longterm, OID_AUTO, dequeues,
3335     CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_LOCKED,
3336     (void *) DEQUEUES, 0, sysctl_timer, "Q", "");
3337 SYSCTL_PROC(_kern_timer_longterm, OID_AUTO, escalates,
3338     CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_LOCKED,
3339     (void *) ESCALATES, 0, sysctl_timer, "Q", "");
3340 SYSCTL_PROC(_kern_timer_longterm, OID_AUTO, scans,
3341     CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_LOCKED,
3342     (void *) SCANS, 0, sysctl_timer, "Q", "");
3343 SYSCTL_PROC(_kern_timer_longterm, OID_AUTO, preempts,
3344     CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_LOCKED,
3345     (void *) PREEMPTS, 0, sysctl_timer, "Q", "");
3346 SYSCTL_PROC(_kern_timer_longterm, OID_AUTO, latency,
3347     CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_LOCKED,
3348     (void *) LATENCY, 0, sysctl_timer, "Q", "");
3349 SYSCTL_PROC(_kern_timer_longterm, OID_AUTO, latency_min,
3350     CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_LOCKED,
3351     (void *) LATENCY_MIN, 0, sysctl_timer, "Q", "");
3352 SYSCTL_PROC(_kern_timer_longterm, OID_AUTO, latency_max,
3353     CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_LOCKED,
3354     (void *) LATENCY_MAX, 0, sysctl_timer, "Q", "");
3355 #endif /* DEBUG */
3356 
3357 SYSCTL_PROC(_kern_timer, OID_AUTO, scan_limit,
3358     CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED,
3359     (void *) SCAN_LIMIT, 0, sysctl_timer, "Q", "");
3360 SYSCTL_PROC(_kern_timer, OID_AUTO, scan_interval,
3361     CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED,
3362     (void *) SCAN_INTERVAL, 0, sysctl_timer, "Q", "");
3363 SYSCTL_PROC(_kern_timer, OID_AUTO, scan_pauses,
3364     CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_LOCKED,
3365     (void *) SCAN_PAUSES, 0, sysctl_timer, "Q", "");
3366 SYSCTL_PROC(_kern_timer, OID_AUTO, scan_postpones,
3367     CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_LOCKED,
3368     (void *) SCAN_POSTPONES, 0, sysctl_timer, "Q", "");
3369 
3370 STATIC int
3371 sysctl_usrstack
3372 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
3373 {
3374 	return sysctl_io_number(req, (int)req->p->user_stack, sizeof(int), NULL, NULL);
3375 }
3376 
3377 SYSCTL_PROC(_kern, KERN_USRSTACK32, usrstack,
3378     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
3379     0, 0, sysctl_usrstack, "I", "");
3380 
3381 STATIC int
3382 sysctl_usrstack64
3383 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
3384 {
3385 	return sysctl_io_number(req, req->p->user_stack, sizeof(req->p->user_stack), NULL, NULL);
3386 }
3387 
3388 SYSCTL_PROC(_kern, KERN_USRSTACK64, usrstack64,
3389     CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_LOCKED,
3390     0, 0, sysctl_usrstack64, "Q", "");
3391 
3392 
3393 #if EXCLAVES_COREDUMP
3394 
3395 /* secure kernel coredump support. */
3396 extern unsigned int sc_dump_mode;
3397 SYSCTL_UINT(_kern, OID_AUTO, secure_coredump, CTLFLAG_RD, &sc_dump_mode, 0, "secure_coredump");
3398 
3399 #endif /* EXCLAVES_COREDUMP */
3400 
3401 #if CONFIG_COREDUMP || CONFIG_UCOREDUMP
3402 
3403 SYSCTL_STRING(_kern, KERN_COREFILE, corefile,
3404     CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
3405     corefilename, sizeof(corefilename), "");
3406 
3407 SYSCTL_STRING(_kern, OID_AUTO, drivercorefile,
3408     CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
3409     drivercorefilename, sizeof(drivercorefilename), "");
3410 
3411 STATIC int
3412 sysctl_coredump
3413 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
3414 {
3415 #ifdef SECURE_KERNEL
3416 	(void)req;
3417 	return ENOTSUP;
3418 #else
3419 	int new_value, changed;
3420 	int error = sysctl_io_number(req, do_coredump, sizeof(int), &new_value, &changed);
3421 	if (changed) {
3422 		if ((new_value == 0) || (new_value == 1)) {
3423 			do_coredump = new_value;
3424 		} else {
3425 			error = EINVAL;
3426 		}
3427 	}
3428 	return error;
3429 #endif
3430 }
3431 
3432 SYSCTL_PROC(_kern, KERN_COREDUMP, coredump,
3433     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
3434     0, 0, sysctl_coredump, "I", "");
3435 
3436 STATIC int
3437 sysctl_suid_coredump
3438 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
3439 {
3440 #ifdef SECURE_KERNEL
3441 	(void)req;
3442 	return ENOTSUP;
3443 #else
3444 	int new_value, changed;
3445 	int error = sysctl_io_number(req, sugid_coredump, sizeof(int), &new_value, &changed);
3446 	if (changed) {
3447 		if ((new_value == 0) || (new_value == 1)) {
3448 			sugid_coredump = new_value;
3449 		} else {
3450 			error = EINVAL;
3451 		}
3452 	}
3453 	return error;
3454 #endif
3455 }
3456 
3457 SYSCTL_PROC(_kern, KERN_SUGID_COREDUMP, sugid_coredump,
3458     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
3459     0, 0, sysctl_suid_coredump, "I", "");
3460 
3461 #if CONFIG_UCOREDUMP
3462 
3463 STATIC int
3464 sysctl_ucoredump
3465 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
3466 {
3467 #ifdef SECURE_KERNEL
3468 	(void)req;
3469 	return ENOTSUP;
3470 #else
3471 	int new_value, changed;
3472 	int error = sysctl_io_number(req, do_ucoredump, sizeof(int), &new_value, &changed);
3473 	if (changed) {
3474 		if (new_value == 0 || new_value == 1) {
3475 			do_ucoredump = new_value;
3476 		} else {
3477 			error = EINVAL;
3478 		}
3479 	}
3480 	return error;
3481 #endif
3482 }
3483 
3484 SYSCTL_PROC(_kern, OID_AUTO, ucoredump,
3485     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
3486     0, 0, sysctl_ucoredump, "I", "");
3487 #endif /* CONFIG_UCOREDUMP */
3488 #endif /* CONFIG_COREDUMP || CONFIG_UCOREDUMP */
3489 
3490 #if CONFIG_KDP_INTERACTIVE_DEBUGGING
3491 
3492 extern const char* kdp_corefile_path;
3493 STATIC int
3494 sysctl_kdp_corefile(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
3495 {
3496 	return SYSCTL_OUT(req, kdp_corefile_path, strlen(kdp_corefile_path) + 1);
3497 }
3498 
3499 /* this needs to be a proc rather than a string since kdp_corefile_path is not a compile-time constant */
3500 SYSCTL_PROC(_kern, OID_AUTO, kdp_corefile,
3501     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_LOCKED,
3502     0, 0, sysctl_kdp_corefile, "A", "");
3503 
3504 #endif /* CONFIG_KDP_INTERACTIVE_DEBUGGING */
3505 
3506 STATIC int
3507 sysctl_delayterm
3508 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
3509 {
3510 	struct proc *p = req->p;
3511 	int new_value, changed;
3512 	int error = sysctl_io_number(req, (req->p->p_lflag & P_LDELAYTERM)? 1: 0, sizeof(int), &new_value, &changed);
3513 	if (changed) {
3514 		proc_lock(p);
3515 		if (new_value) {
3516 			req->p->p_lflag |=  P_LDELAYTERM;
3517 		} else {
3518 			req->p->p_lflag &=  ~P_LDELAYTERM;
3519 		}
3520 		proc_unlock(p);
3521 	}
3522 	return error;
3523 }
3524 
3525 SYSCTL_PROC(_kern, KERN_PROCDELAYTERM, delayterm,
3526     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
3527     0, 0, sysctl_delayterm, "I", "");
3528 
3529 
3530 STATIC int
3531 sysctl_rage_vnode
3532 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
3533 {
3534 	struct proc *p = req->p;
3535 	struct  uthread *ut;
3536 	int new_value, old_value, changed;
3537 	int error;
3538 
3539 	ut = current_uthread();
3540 
3541 	if (ut->uu_flag & UT_RAGE_VNODES) {
3542 		old_value = KERN_RAGE_THREAD;
3543 	} else if (p->p_lflag & P_LRAGE_VNODES) {
3544 		old_value = KERN_RAGE_PROC;
3545 	} else {
3546 		old_value = 0;
3547 	}
3548 
3549 	error = sysctl_io_number(req, old_value, sizeof(int), &new_value, &changed);
3550 
3551 	if ((error == 0) && (changed != 0)) {
3552 		switch (new_value) {
3553 		case KERN_RAGE_PROC:
3554 			proc_lock(p);
3555 			p->p_lflag |= P_LRAGE_VNODES;
3556 			proc_unlock(p);
3557 			break;
3558 		case KERN_UNRAGE_PROC:
3559 			proc_lock(p);
3560 			p->p_lflag &= ~P_LRAGE_VNODES;
3561 			proc_unlock(p);
3562 			break;
3563 
3564 		case KERN_RAGE_THREAD:
3565 			ut->uu_flag |= UT_RAGE_VNODES;
3566 			break;
3567 		case KERN_UNRAGE_THREAD:
3568 			ut = current_uthread();
3569 			ut->uu_flag &= ~UT_RAGE_VNODES;
3570 			break;
3571 		}
3572 	}
3573 	return error;
3574 }
3575 
3576 SYSCTL_PROC(_kern, KERN_RAGEVNODE, rage_vnode,
3577     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED,
3578     0, 0, sysctl_rage_vnode, "I", "");
3579 
3580 /* XXX until filecoordinationd fixes a bit of inverted logic. */
3581 STATIC int
3582 sysctl_vfsnspace
3583 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
3584 {
3585 	int old_value = 0, new_value, changed;
3586 
3587 	return sysctl_io_number(req, old_value, sizeof(int), &new_value,
3588 	           &changed);
3589 }
3590 
3591 SYSCTL_PROC(_kern, OID_AUTO, vfsnspace,
3592     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED,
3593     0, 0, sysctl_vfsnspace, "I", "");
3594 
3595 /* XXX move this interface into libproc and remove this sysctl */
3596 STATIC int
3597 sysctl_setthread_cpupercent
3598 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
3599 {
3600 	int new_value, old_value;
3601 	int error = 0;
3602 	kern_return_t kret = KERN_SUCCESS;
3603 	uint8_t percent = 0;
3604 	int ms_refill = 0;
3605 
3606 	if (!req->newptr) {
3607 		return 0;
3608 	}
3609 
3610 	old_value = 0;
3611 
3612 	if ((error = sysctl_io_number(req, old_value, sizeof(old_value), &new_value, NULL)) != 0) {
3613 		return error;
3614 	}
3615 
3616 	percent = new_value & 0xff;                     /* low 8 bytes for perent */
3617 	ms_refill = (new_value >> 8) & 0xffffff;        /* upper 24bytes represent ms refill value */
3618 	if (percent > 100) {
3619 		return EINVAL;
3620 	}
3621 
3622 	/*
3623 	 * If the caller is specifying a percentage of 0, this will unset the CPU limit, if present.
3624 	 */
3625 	kret = percent == 0 ?
3626 	    thread_set_cpulimit(THREAD_CPULIMIT_DISABLE, 0, 0) :
3627 	    thread_set_cpulimit(THREAD_CPULIMIT_BLOCK, percent, ms_refill * (int)NSEC_PER_MSEC);
3628 
3629 	if (kret != 0) {
3630 		return EIO;
3631 	}
3632 
3633 	return 0;
3634 }
3635 
3636 SYSCTL_PROC(_kern, OID_AUTO, setthread_cpupercent,
3637     CTLTYPE_INT | CTLFLAG_WR | CTLFLAG_ANYBODY,
3638     0, 0, sysctl_setthread_cpupercent, "I", "set thread cpu percentage limit");
3639 
3640 
3641 STATIC int
3642 sysctl_kern_check_openevt
3643 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
3644 {
3645 	struct proc *p = req->p;
3646 	int new_value, old_value, changed;
3647 	int error;
3648 
3649 	if (p->p_flag & P_CHECKOPENEVT) {
3650 		old_value = KERN_OPENEVT_PROC;
3651 	} else {
3652 		old_value = 0;
3653 	}
3654 
3655 	error = sysctl_io_number(req, old_value, sizeof(int), &new_value, &changed);
3656 
3657 	if ((error == 0) && (changed != 0)) {
3658 		switch (new_value) {
3659 		case KERN_OPENEVT_PROC:
3660 			OSBitOrAtomic(P_CHECKOPENEVT, &p->p_flag);
3661 			break;
3662 
3663 		case KERN_UNOPENEVT_PROC:
3664 			OSBitAndAtomic(~((uint32_t)P_CHECKOPENEVT), &p->p_flag);
3665 			break;
3666 
3667 		default:
3668 			error = EINVAL;
3669 		}
3670 	}
3671 	return error;
3672 }
3673 
3674 SYSCTL_PROC(_kern, KERN_CHECKOPENEVT, check_openevt, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED,
3675     0, 0, sysctl_kern_check_openevt, "I", "set the per-process check-open-evt flag");
3676 
3677 
3678 #if DEVELOPMENT || DEBUG
3679 STATIC int
3680 sysctl_nx
3681 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
3682 {
3683 #ifdef SECURE_KERNEL
3684 	(void)req;
3685 	return ENOTSUP;
3686 #else
3687 	int new_value, changed;
3688 	int error;
3689 
3690 	error = sysctl_io_number(req, nx_enabled, sizeof(nx_enabled), &new_value, &changed);
3691 	if (error) {
3692 		return error;
3693 	}
3694 
3695 	if (changed) {
3696 #if defined(__x86_64__)
3697 		/*
3698 		 * Only allow setting if NX is supported on the chip
3699 		 */
3700 		if (!(cpuid_extfeatures() & CPUID_EXTFEATURE_XD)) {
3701 			return ENOTSUP;
3702 		}
3703 #endif
3704 		nx_enabled = new_value;
3705 	}
3706 	return error;
3707 #endif /* SECURE_KERNEL */
3708 }
3709 #endif
3710 
3711 #if DEVELOPMENT || DEBUG
3712 SYSCTL_PROC(_kern, KERN_NX_PROTECTION, nx,
3713     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
3714     0, 0, sysctl_nx, "I", "");
3715 #endif
3716 
3717 STATIC int
3718 sysctl_loadavg
3719 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
3720 {
3721 	if (proc_is64bit(req->p)) {
3722 		struct user64_loadavg loadinfo64 = {};
3723 		fill_loadavg64(&averunnable, &loadinfo64);
3724 		return sysctl_io_opaque(req, &loadinfo64, sizeof(loadinfo64), NULL);
3725 	} else {
3726 		struct user32_loadavg loadinfo32 = {};
3727 		fill_loadavg32(&averunnable, &loadinfo32);
3728 		return sysctl_io_opaque(req, &loadinfo32, sizeof(loadinfo32), NULL);
3729 	}
3730 }
3731 
3732 SYSCTL_PROC(_vm, VM_LOADAVG, loadavg,
3733     CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED,
3734     0, 0, sysctl_loadavg, "S,loadavg", "");
3735 
3736 /*
3737  * Note:	Thread safe; vm_map_lock protects in  vm_toggle_entry_reuse()
3738  */
3739 STATIC int
3740 sysctl_vm_toggle_address_reuse(__unused struct sysctl_oid *oidp, __unused void *arg1,
3741     __unused int arg2, struct sysctl_req *req)
3742 {
3743 	int old_value = 0, new_value = 0, error = 0;
3744 
3745 	if (vm_toggle_entry_reuse( VM_TOGGLE_GETVALUE, &old_value )) {
3746 		return error;
3747 	}
3748 	error = sysctl_io_number(req, old_value, sizeof(int), &new_value, NULL);
3749 	if (!error) {
3750 		return vm_toggle_entry_reuse(new_value, NULL);
3751 	}
3752 	return error;
3753 }
3754 
3755 SYSCTL_PROC(_debug, OID_AUTO, toggle_address_reuse, CTLFLAG_ANYBODY | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0, sysctl_vm_toggle_address_reuse, "I", "");
3756 
3757 #ifdef CONFIG_XNUPOST
3758 
3759 extern uint32_t xnupost_get_estimated_testdata_size(void);
3760 extern int xnupost_reset_all_tests(void);
3761 
3762 STATIC int
3763 sysctl_handle_xnupost_get_tests SYSCTL_HANDLER_ARGS
3764 {
3765 	/* fixup unused arguments warnings */
3766 	__unused int _oa2                  = arg2;
3767 	__unused void * _oa1               = arg1;
3768 	__unused struct sysctl_oid * _oidp = oidp;
3769 
3770 	int error          = 0;
3771 	user_addr_t oldp   = 0;
3772 	user_addr_t newp   = 0;
3773 	uint32_t usedbytes = 0;
3774 
3775 	oldp = req->oldptr;
3776 	newp = req->newptr;
3777 
3778 	if (newp) {
3779 		return ENOTSUP;
3780 	}
3781 
3782 	if ((void *)oldp == NULL) {
3783 		/* return estimated size for second call where info can be placed */
3784 		req->oldidx = xnupost_get_estimated_testdata_size();
3785 	} else {
3786 		error       = xnupost_export_testdata((void *)oldp, req->oldlen, &usedbytes);
3787 		req->oldidx = usedbytes;
3788 	}
3789 
3790 	return error;
3791 }
3792 
3793 SYSCTL_PROC(_debug,
3794     OID_AUTO,
3795     xnupost_get_tests,
3796     CTLFLAG_MASKED | CTLFLAG_ANYBODY | CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_LOCKED,
3797     0,
3798     0,
3799     sysctl_handle_xnupost_get_tests,
3800     "-",
3801     "read xnupost test data in kernel");
3802 
3803 #if CONFIG_EXT_PANICLOG
3804 /*
3805  * Extensible panic log test hooks
3806  */
3807 static int
3808 sysctl_debug_ext_paniclog_test_hook SYSCTL_HANDLER_ARGS
3809 {
3810 #pragma unused(arg1, arg2)
3811 	int rval = 0;
3812 	uint32_t test_option = 0;
3813 
3814 	rval = sysctl_handle_int(oidp, &test_option, 0, req);
3815 
3816 	if (rval == 0 && req->newptr) {
3817 		rval = ext_paniclog_test_hook(test_option);
3818 	}
3819 
3820 	return rval;
3821 }
3822 
3823 SYSCTL_PROC(_debug, OID_AUTO, ext_paniclog_test_hook,
3824     CTLTYPE_INT | CTLFLAG_RW,
3825     0, 0,
3826     sysctl_debug_ext_paniclog_test_hook, "A", "ext paniclog test hook");
3827 
3828 #endif
3829 
3830 STATIC int
3831 sysctl_debug_xnupost_ctl SYSCTL_HANDLER_ARGS
3832 {
3833 	/* fixup unused arguments warnings */
3834 	__unused int _oa2                  = arg2;
3835 	__unused void * _oa1               = arg1;
3836 	__unused struct sysctl_oid * _oidp = oidp;
3837 
3838 #define ARRCOUNT 4
3839 	/*
3840 	 * INPUT: ACTION,  PARAM1, PARAM2, PARAM3
3841 	 * OUTPUT: RESULTCODE, ADDITIONAL DATA
3842 	 */
3843 	int32_t outval[ARRCOUNT] = {0};
3844 	int32_t input[ARRCOUNT]  = {0};
3845 	int32_t out_size         = sizeof(outval);
3846 	int32_t in_size          = sizeof(input);
3847 	int error                = 0;
3848 
3849 	/* if this is NULL call to find out size, send out size info */
3850 	if (!req->newptr) {
3851 		goto out;
3852 	}
3853 
3854 	/* pull in provided value from userspace */
3855 	error = SYSCTL_IN(req, &input[0], in_size);
3856 	if (error) {
3857 		return error;
3858 	}
3859 
3860 	if (input[0] == XTCTL_RESET_TESTDATA) {
3861 		outval[0] = xnupost_reset_all_tests();
3862 		goto out;
3863 	}
3864 
3865 out:
3866 	error = SYSCTL_OUT(req, &outval[0], out_size);
3867 	return error;
3868 }
3869 
3870 SYSCTL_PROC(_debug,
3871     OID_AUTO,
3872     xnupost_testctl,
3873     CTLFLAG_MASKED | CTLFLAG_ANYBODY | CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_LOCKED,
3874     0,
3875     0,
3876     sysctl_debug_xnupost_ctl,
3877     "I",
3878     "xnupost control for kernel testing");
3879 
3880 extern void test_oslog_handleOSLogCtl(int32_t * in, int32_t * out, int32_t arraycount);
3881 
3882 STATIC int
3883 sysctl_debug_test_oslog_ctl(__unused struct sysctl_oid * oidp, __unused void * arg1, __unused int arg2, struct sysctl_req * req)
3884 {
3885 #define ARRCOUNT 4
3886 	int32_t outval[ARRCOUNT] = {0};
3887 	int32_t input[ARRCOUNT]  = {0};
3888 	int32_t size_outval      = sizeof(outval);
3889 	int32_t size_inval       = sizeof(input);
3890 	int32_t error;
3891 
3892 	/* if this is NULL call to find out size, send out size info */
3893 	if (!req->newptr) {
3894 		error = SYSCTL_OUT(req, &outval[0], size_outval);
3895 		return error;
3896 	}
3897 
3898 	/* pull in provided value from userspace */
3899 	error = SYSCTL_IN(req, &input[0], size_inval);
3900 	if (error) {
3901 		return error;
3902 	}
3903 
3904 	test_oslog_handleOSLogCtl(input, outval, ARRCOUNT);
3905 
3906 	error = SYSCTL_OUT(req, &outval[0], size_outval);
3907 
3908 	return error;
3909 }
3910 
3911 SYSCTL_PROC(_debug,
3912     OID_AUTO,
3913     test_OSLogCtl,
3914     CTLFLAG_MASKED | CTLFLAG_ANYBODY | CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_LOCKED,
3915     0,
3916     0,
3917     sysctl_debug_test_oslog_ctl,
3918     "I",
3919     "testing oslog in kernel");
3920 
3921 #include <mach/task.h>
3922 #include <mach/semaphore.h>
3923 
3924 static LCK_GRP_DECLARE(sysctl_debug_test_stackshot_owner_grp, "test-stackshot-owner-grp");
3925 static LCK_MTX_DECLARE(sysctl_debug_test_stackshot_owner_init_mtx,
3926     &sysctl_debug_test_stackshot_owner_grp);
3927 
3928 /* This is a sysctl for testing collection of owner info on a lock in kernel space. A multi-threaded
3929  * test from userland sets this sysctl in such a way that a thread blocks in kernel mode, and a
3930  * stackshot is taken to see if the owner of the lock can be identified.
3931  *
3932  * We can't return to userland with a kernel lock held, so be sure to unlock before we leave.
3933  * the semaphores allow us to artificially create cases where the lock is being held and the
3934  * thread is hanging / taking a long time to do something. */
3935 
3936 volatile char      sysctl_debug_test_stackshot_mtx_inited = 0;
3937 semaphore_t        sysctl_debug_test_stackshot_mutex_sem;
3938 lck_mtx_t          sysctl_debug_test_stackshot_owner_lck;
3939 
3940 #define SYSCTL_DEBUG_MTX_ACQUIRE_WAIT   1
3941 #define SYSCTL_DEBUG_MTX_ACQUIRE_NOWAIT 2
3942 #define SYSCTL_DEBUG_MTX_SIGNAL         3
3943 #define SYSCTL_DEBUG_MTX_TEARDOWN       4
3944 
3945 STATIC int
3946 sysctl_debug_test_stackshot_mutex_owner(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
3947 {
3948 	long long option = -1;
3949 	/* if the user tries to read the sysctl, we tell them what the address of the lock is (to test against stackshot's output) */
3950 	long long mtx_unslid_addr = (long long)VM_KERNEL_UNSLIDE_OR_PERM(&sysctl_debug_test_stackshot_owner_lck);
3951 	int error = sysctl_io_number(req, mtx_unslid_addr, sizeof(long long), (void*)&option, NULL);
3952 
3953 	lck_mtx_lock(&sysctl_debug_test_stackshot_owner_init_mtx);
3954 	if (!sysctl_debug_test_stackshot_mtx_inited) {
3955 		lck_mtx_init(&sysctl_debug_test_stackshot_owner_lck,
3956 		    &sysctl_debug_test_stackshot_owner_grp,
3957 		    LCK_ATTR_NULL);
3958 		semaphore_create(kernel_task,
3959 		    &sysctl_debug_test_stackshot_mutex_sem,
3960 		    SYNC_POLICY_FIFO, 0);
3961 		sysctl_debug_test_stackshot_mtx_inited = 1;
3962 	}
3963 	lck_mtx_unlock(&sysctl_debug_test_stackshot_owner_init_mtx);
3964 
3965 	if (!error) {
3966 		switch (option) {
3967 		case SYSCTL_DEBUG_MTX_ACQUIRE_NOWAIT:
3968 			lck_mtx_lock(&sysctl_debug_test_stackshot_owner_lck);
3969 			lck_mtx_unlock(&sysctl_debug_test_stackshot_owner_lck);
3970 			break;
3971 		case SYSCTL_DEBUG_MTX_ACQUIRE_WAIT:
3972 			lck_mtx_lock(&sysctl_debug_test_stackshot_owner_lck);
3973 			semaphore_wait(sysctl_debug_test_stackshot_mutex_sem);
3974 			lck_mtx_unlock(&sysctl_debug_test_stackshot_owner_lck);
3975 			break;
3976 		case SYSCTL_DEBUG_MTX_SIGNAL:
3977 			semaphore_signal(sysctl_debug_test_stackshot_mutex_sem);
3978 			break;
3979 		case SYSCTL_DEBUG_MTX_TEARDOWN:
3980 			lck_mtx_lock(&sysctl_debug_test_stackshot_owner_init_mtx);
3981 
3982 			lck_mtx_destroy(&sysctl_debug_test_stackshot_owner_lck,
3983 			    &sysctl_debug_test_stackshot_owner_grp);
3984 			semaphore_destroy(kernel_task,
3985 			    sysctl_debug_test_stackshot_mutex_sem);
3986 			sysctl_debug_test_stackshot_mtx_inited = 0;
3987 
3988 			lck_mtx_unlock(&sysctl_debug_test_stackshot_owner_init_mtx);
3989 			break;
3990 		case -1:         /* user just wanted to read the value, so do nothing */
3991 			break;
3992 		default:
3993 			error = EINVAL;
3994 			break;
3995 		}
3996 	}
3997 	return error;
3998 }
3999 
4000 /* we can't return to userland with a kernel rwlock held, so be sure to unlock before we leave.
4001  * the semaphores allow us to artificially create cases where the lock is being held and the
4002  * thread is hanging / taking a long time to do something. */
4003 
4004 SYSCTL_PROC(_debug,
4005     OID_AUTO,
4006     test_MutexOwnerCtl,
4007     CTLFLAG_MASKED | CTLFLAG_ANYBODY | CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED,
4008     0,
4009     0,
4010     sysctl_debug_test_stackshot_mutex_owner,
4011     "-",
4012     "Testing mutex owner in kernel");
4013 
4014 volatile char sysctl_debug_test_stackshot_rwlck_inited = 0;
4015 lck_rw_t      sysctl_debug_test_stackshot_owner_rwlck;
4016 semaphore_t   sysctl_debug_test_stackshot_rwlck_sem;
4017 
4018 #define SYSCTL_DEBUG_KRWLCK_RACQUIRE_NOWAIT 1
4019 #define SYSCTL_DEBUG_KRWLCK_RACQUIRE_WAIT   2
4020 #define SYSCTL_DEBUG_KRWLCK_WACQUIRE_NOWAIT 3
4021 #define SYSCTL_DEBUG_KRWLCK_WACQUIRE_WAIT   4
4022 #define SYSCTL_DEBUG_KRWLCK_SIGNAL          5
4023 #define SYSCTL_DEBUG_KRWLCK_TEARDOWN        6
4024 
4025 STATIC int
4026 sysctl_debug_test_stackshot_rwlck_owner(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
4027 {
4028 	long long option = -1;
4029 	/* if the user tries to read the sysctl, we tell them what the address of the lock is
4030 	 * (to test against stackshot's output) */
4031 	long long rwlck_unslid_addr = (long long)VM_KERNEL_UNSLIDE_OR_PERM(&sysctl_debug_test_stackshot_owner_rwlck);
4032 	int error = sysctl_io_number(req, rwlck_unslid_addr, sizeof(long long), (void*)&option, NULL);
4033 
4034 	lck_mtx_lock(&sysctl_debug_test_stackshot_owner_init_mtx);
4035 	if (!sysctl_debug_test_stackshot_rwlck_inited) {
4036 		lck_rw_init(&sysctl_debug_test_stackshot_owner_rwlck,
4037 		    &sysctl_debug_test_stackshot_owner_grp,
4038 		    LCK_ATTR_NULL);
4039 		semaphore_create(kernel_task,
4040 		    &sysctl_debug_test_stackshot_rwlck_sem,
4041 		    SYNC_POLICY_FIFO,
4042 		    0);
4043 		sysctl_debug_test_stackshot_rwlck_inited = 1;
4044 	}
4045 	lck_mtx_unlock(&sysctl_debug_test_stackshot_owner_init_mtx);
4046 
4047 	if (!error) {
4048 		switch (option) {
4049 		case SYSCTL_DEBUG_KRWLCK_RACQUIRE_NOWAIT:
4050 			lck_rw_lock(&sysctl_debug_test_stackshot_owner_rwlck, LCK_RW_TYPE_SHARED);
4051 			lck_rw_unlock(&sysctl_debug_test_stackshot_owner_rwlck, LCK_RW_TYPE_SHARED);
4052 			break;
4053 		case SYSCTL_DEBUG_KRWLCK_RACQUIRE_WAIT:
4054 			lck_rw_lock(&sysctl_debug_test_stackshot_owner_rwlck, LCK_RW_TYPE_SHARED);
4055 			semaphore_wait(sysctl_debug_test_stackshot_rwlck_sem);
4056 			lck_rw_unlock(&sysctl_debug_test_stackshot_owner_rwlck, LCK_RW_TYPE_SHARED);
4057 			break;
4058 		case SYSCTL_DEBUG_KRWLCK_WACQUIRE_NOWAIT:
4059 			lck_rw_lock(&sysctl_debug_test_stackshot_owner_rwlck, LCK_RW_TYPE_EXCLUSIVE);
4060 			lck_rw_unlock(&sysctl_debug_test_stackshot_owner_rwlck, LCK_RW_TYPE_EXCLUSIVE);
4061 			break;
4062 		case SYSCTL_DEBUG_KRWLCK_WACQUIRE_WAIT:
4063 			lck_rw_lock(&sysctl_debug_test_stackshot_owner_rwlck, LCK_RW_TYPE_EXCLUSIVE);
4064 			semaphore_wait(sysctl_debug_test_stackshot_rwlck_sem);
4065 			lck_rw_unlock(&sysctl_debug_test_stackshot_owner_rwlck, LCK_RW_TYPE_EXCLUSIVE);
4066 			break;
4067 		case SYSCTL_DEBUG_KRWLCK_SIGNAL:
4068 			semaphore_signal(sysctl_debug_test_stackshot_rwlck_sem);
4069 			break;
4070 		case SYSCTL_DEBUG_KRWLCK_TEARDOWN:
4071 			lck_mtx_lock(&sysctl_debug_test_stackshot_owner_init_mtx);
4072 
4073 			lck_rw_destroy(&sysctl_debug_test_stackshot_owner_rwlck,
4074 			    &sysctl_debug_test_stackshot_owner_grp);
4075 			semaphore_destroy(kernel_task,
4076 			    sysctl_debug_test_stackshot_rwlck_sem);
4077 			sysctl_debug_test_stackshot_rwlck_inited = 0;
4078 
4079 			lck_mtx_unlock(&sysctl_debug_test_stackshot_owner_init_mtx);
4080 			break;
4081 		case -1:         /* user just wanted to read the value, so do nothing */
4082 			break;
4083 		default:
4084 			error = EINVAL;
4085 			break;
4086 		}
4087 	}
4088 	return error;
4089 }
4090 
4091 
4092 SYSCTL_PROC(_debug,
4093     OID_AUTO,
4094     test_RWLockOwnerCtl,
4095     CTLFLAG_MASKED | CTLFLAG_ANYBODY | CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED,
4096     0,
4097     0,
4098     sysctl_debug_test_stackshot_rwlck_owner,
4099     "-",
4100     "Testing rwlock owner in kernel");
4101 #endif /* !CONFIG_XNUPOST */
4102 
4103 STATIC int
4104 sysctl_swapusage
4105 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
4106 {
4107 	int                     error;
4108 	uint64_t                swap_total;
4109 	uint64_t                swap_avail;
4110 	vm_size_t               swap_pagesize;
4111 	boolean_t               swap_encrypted;
4112 	struct xsw_usage        xsu = {};
4113 
4114 	error = macx_swapinfo(&swap_total,
4115 	    &swap_avail,
4116 	    &swap_pagesize,
4117 	    &swap_encrypted);
4118 	if (error) {
4119 		return error;
4120 	}
4121 
4122 	xsu.xsu_total = swap_total;
4123 	xsu.xsu_avail = swap_avail;
4124 	xsu.xsu_used = swap_total - swap_avail;
4125 	xsu.xsu_pagesize = (u_int32_t)MIN(swap_pagesize, UINT32_MAX);
4126 	xsu.xsu_encrypted = swap_encrypted;
4127 	return sysctl_io_opaque(req, &xsu, sizeof(xsu), NULL);
4128 }
4129 
4130 
4131 
4132 SYSCTL_PROC(_vm, VM_SWAPUSAGE, swapusage,
4133     CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED,
4134     0, 0, sysctl_swapusage, "S,xsw_usage", "");
4135 
4136 extern int vm_swap_enabled;
4137 SYSCTL_INT(_vm, OID_AUTO, swap_enabled, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_swap_enabled, 0, "");
4138 
4139 #if DEVELOPMENT || DEBUG
4140 extern int vm_num_swap_files_config;
4141 extern int vm_num_swap_files;
4142 extern lck_mtx_t vm_swap_data_lock;
4143 #define VM_MAX_SWAP_FILE_NUM            100
4144 
4145 static int
4146 sysctl_vm_config_num_swap_files SYSCTL_HANDLER_ARGS
4147 {
4148 #pragma unused(arg1, arg2)
4149 	int error = 0, val = vm_num_swap_files_config;
4150 
4151 	error = sysctl_handle_int(oidp, &val, 0, req);
4152 	if (error || !req->newptr) {
4153 		goto out;
4154 	}
4155 
4156 	if (!VM_CONFIG_SWAP_IS_ACTIVE && !VM_CONFIG_FREEZER_SWAP_IS_ACTIVE) {
4157 		printf("Swap is disabled\n");
4158 		error = EINVAL;
4159 		goto out;
4160 	}
4161 
4162 	lck_mtx_lock(&vm_swap_data_lock);
4163 
4164 	if (val < vm_num_swap_files) {
4165 		printf("Cannot configure fewer swap files than already exist.\n");
4166 		error = EINVAL;
4167 		lck_mtx_unlock(&vm_swap_data_lock);
4168 		goto out;
4169 	}
4170 
4171 	if (val > VM_MAX_SWAP_FILE_NUM) {
4172 		printf("Capping number of swap files to upper bound.\n");
4173 		val = VM_MAX_SWAP_FILE_NUM;
4174 	}
4175 
4176 	vm_num_swap_files_config = val;
4177 	lck_mtx_unlock(&vm_swap_data_lock);
4178 out:
4179 
4180 	return 0;
4181 }
4182 
4183 SYSCTL_PROC(_debug, OID_AUTO, num_swap_files_configured, CTLFLAG_ANYBODY | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0, sysctl_vm_config_num_swap_files, "I", "");
4184 #endif /* DEVELOPMENT || DEBUG */
4185 
4186 /* this kernel does NOT implement shared_region_make_private_np() */
4187 SYSCTL_INT(_kern, KERN_SHREG_PRIVATIZABLE, shreg_private,
4188     CTLFLAG_RD | CTLFLAG_LOCKED,
4189     (int *)NULL, 0, "");
4190 
4191 STATIC int
4192 fetch_process_cputype(
4193 	proc_t cur_proc,
4194 	int *name,
4195 	u_int namelen,
4196 	cpu_type_t *cputype)
4197 {
4198 	proc_t p = PROC_NULL;
4199 	int refheld = 0;
4200 	cpu_type_t ret = 0;
4201 	int error = 0;
4202 
4203 	if (namelen == 0) {
4204 		p = cur_proc;
4205 	} else if (namelen == 1) {
4206 		p = proc_find(name[0]);
4207 		if (p == NULL) {
4208 			return EINVAL;
4209 		}
4210 		refheld = 1;
4211 	} else {
4212 		error = EINVAL;
4213 		goto out;
4214 	}
4215 
4216 	ret = cpu_type() & ~CPU_ARCH_MASK;
4217 	if (IS_64BIT_PROCESS(p)) {
4218 		ret |= CPU_ARCH_ABI64;
4219 	}
4220 
4221 	*cputype = ret;
4222 
4223 	if (refheld != 0) {
4224 		proc_rele(p);
4225 	}
4226 out:
4227 	return error;
4228 }
4229 
4230 #if CONFIG_ROSETTA
4231 STATIC int
4232 sysctl_sysctl_translated(
4233 	__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, __unused struct sysctl_req *req)
4234 {
4235 	int res = 0;
4236 	if (proc_is_translated(req->p)) {
4237 		res = 1;
4238 	}
4239 	return SYSCTL_OUT(req, &res, sizeof(res));
4240 }
4241 SYSCTL_PROC(_sysctl, OID_AUTO, proc_translated, CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0, sysctl_sysctl_translated, "I", "proc_translated");
4242 #endif /* CONFIG_ROSETTA */
4243 
4244 STATIC int
4245 sysctl_sysctl_native(__unused struct sysctl_oid *oidp, void *arg1, int arg2,
4246     struct sysctl_req *req)
4247 {
4248 	int error;
4249 	cpu_type_t proc_cputype = 0;
4250 	if ((error = fetch_process_cputype(req->p, (int *)arg1, arg2, &proc_cputype)) != 0) {
4251 		return error;
4252 	}
4253 	int res = 1;
4254 	if ((proc_cputype & ~CPU_ARCH_MASK) != (cpu_type() & ~CPU_ARCH_MASK)) {
4255 		res = 0;
4256 	}
4257 	return SYSCTL_OUT(req, &res, sizeof(res));
4258 }
4259 SYSCTL_PROC(_sysctl, OID_AUTO, proc_native, CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0, sysctl_sysctl_native, "I", "proc_native");
4260 
4261 STATIC int
4262 sysctl_sysctl_cputype(__unused struct sysctl_oid *oidp, void *arg1, int arg2,
4263     struct sysctl_req *req)
4264 {
4265 	int error;
4266 	cpu_type_t proc_cputype = 0;
4267 	if ((error = fetch_process_cputype(req->p, (int *)arg1, arg2, &proc_cputype)) != 0) {
4268 		return error;
4269 	}
4270 	return SYSCTL_OUT(req, &proc_cputype, sizeof(proc_cputype));
4271 }
4272 SYSCTL_PROC(_sysctl, OID_AUTO, proc_cputype, CTLTYPE_NODE | CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0, sysctl_sysctl_cputype, "I", "proc_cputype");
4273 
4274 STATIC int
4275 sysctl_safeboot
4276 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
4277 {
4278 	return sysctl_io_number(req, boothowto & RB_SAFEBOOT ? 1 : 0, sizeof(int), NULL, NULL);
4279 }
4280 
4281 SYSCTL_PROC(_kern, KERN_SAFEBOOT, safeboot,
4282     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
4283     0, 0, sysctl_safeboot, "I", "");
4284 
4285 STATIC int
4286 sysctl_singleuser
4287 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
4288 {
4289 	return sysctl_io_number(req, boothowto & RB_SINGLE ? 1 : 0, sizeof(int), NULL, NULL);
4290 }
4291 
4292 SYSCTL_PROC(_kern, OID_AUTO, singleuser,
4293     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
4294     0, 0, sysctl_singleuser, "I", "");
4295 
4296 STATIC int
4297 sysctl_minimalboot
4298 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
4299 {
4300 	return sysctl_io_number(req, minimalboot, sizeof(int), NULL, NULL);
4301 }
4302 
4303 SYSCTL_PROC(_kern, OID_AUTO, minimalboot,
4304     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
4305     0, 0, sysctl_minimalboot, "I", "");
4306 
4307 /*
4308  * Controls for debugging affinity sets - see osfmk/kern/affinity.c
4309  */
4310 extern boolean_t        affinity_sets_enabled;
4311 extern int              affinity_sets_mapping;
4312 
4313 SYSCTL_INT(_kern, OID_AUTO, affinity_sets_enabled,
4314     CTLFLAG_RW | CTLFLAG_LOCKED, (int *) &affinity_sets_enabled, 0, "hinting enabled");
4315 SYSCTL_INT(_kern, OID_AUTO, affinity_sets_mapping,
4316     CTLFLAG_RW | CTLFLAG_LOCKED, &affinity_sets_mapping, 0, "mapping policy");
4317 
4318 /*
4319  * Boolean indicating if KASLR is active.
4320  */
4321 STATIC int
4322 sysctl_slide
4323 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
4324 {
4325 	uint32_t        slide;
4326 
4327 	slide = vm_kernel_slide ? 1 : 0;
4328 
4329 	return sysctl_io_number( req, slide, sizeof(int), NULL, NULL);
4330 }
4331 
4332 SYSCTL_PROC(_kern, OID_AUTO, slide,
4333     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
4334     0, 0, sysctl_slide, "I", "");
4335 
4336 #if DEBUG || DEVELOPMENT
4337 #if defined(__arm64__)
4338 extern vm_offset_t segTEXTEXECB;
4339 
4340 static int
4341 sysctl_kernel_text_exec_base_slide SYSCTL_HANDLER_ARGS
4342 {
4343 #pragma unused(arg1, arg2, oidp)
4344 	unsigned long slide = 0;
4345 	kc_format_t kc_format;
4346 
4347 	PE_get_primary_kc_format(&kc_format);
4348 
4349 	if (kc_format == KCFormatFileset) {
4350 		void *kch = PE_get_kc_header(KCKindPrimary);
4351 		slide = (unsigned long)segTEXTEXECB - (unsigned long)kch + vm_kernel_slide;
4352 	}
4353 	return SYSCTL_OUT(req, &slide, sizeof(slide));
4354 }
4355 
4356 SYSCTL_QUAD(_kern, OID_AUTO, kernel_slide, CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED, &vm_kernel_slide, "");
4357 SYSCTL_QUAD(_kern, OID_AUTO, kernel_text_exec_base, CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED, &segTEXTEXECB, "");
4358 SYSCTL_PROC(_kern, OID_AUTO, kernel_text_exec_base_slide, CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0, sysctl_kernel_text_exec_base_slide, "Q", "");
4359 #endif /* defined(__arm64__) */
4360 
4361 /* User address of the PFZ */
4362 extern user32_addr_t commpage_text32_location;
4363 extern user64_addr_t commpage_text64_location;
4364 
4365 STATIC int
4366 sysctl_pfz_start SYSCTL_HANDLER_ARGS
4367 {
4368 #pragma unused(oidp, arg1, arg2)
4369 
4370 #ifdef __LP64__
4371 	return sysctl_io_number(req, commpage_text64_location, sizeof(user64_addr_t), NULL, NULL);
4372 #else
4373 	return sysctl_io_number(req, commpage_text32_location, sizeof(user32_addr_t), NULL, NULL);
4374 #endif
4375 }
4376 
4377 SYSCTL_PROC(_kern, OID_AUTO, pfz,
4378     CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_LOCKED | CTLFLAG_MASKED,
4379     0, 0, sysctl_pfz_start, "I", "");
4380 #endif
4381 
4382 
4383 /*
4384  * Limit on total memory users can wire.
4385  *
4386  * vm_global_user_wire_limit - system wide limit on wired memory from all processes combined.
4387  *
4388  * vm_per_task_user_wire_limit - per address space limit on wired memory.  This puts a cap on the process's rlimit value.
4389  *
4390  * These values are initialized to reasonable defaults at boot time based on the available physical memory in
4391  * kmem_init().
4392  *
4393  * All values are in bytes.
4394  */
4395 
4396 vm_map_size_t   vm_global_user_wire_limit;
4397 vm_map_size_t   vm_per_task_user_wire_limit;
4398 extern uint64_t max_mem_actual, max_mem;
4399 
4400 uint64_t        vm_add_wire_count_over_global_limit;
4401 uint64_t        vm_add_wire_count_over_user_limit;
4402 /*
4403  * We used to have a global in the kernel called vm_global_no_user_wire_limit which was the inverse
4404  * of vm_global_user_wire_limit. But maintaining both of those is silly, and vm_global_user_wire_limit is the
4405  * real limit.
4406  * This function is for backwards compatibility with userspace
4407  * since we exposed the old global via a sysctl.
4408  */
4409 STATIC int
4410 sysctl_global_no_user_wire_amount(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
4411 {
4412 	vm_map_size_t old_value;
4413 	vm_map_size_t new_value;
4414 	int changed;
4415 	int error;
4416 	uint64_t config_memsize = max_mem;
4417 #if defined(XNU_TARGET_OS_OSX)
4418 	config_memsize = max_mem_actual;
4419 #endif /* defined(XNU_TARGET_OS_OSX) */
4420 
4421 	old_value = (vm_map_size_t)(config_memsize - vm_global_user_wire_limit);
4422 	error = sysctl_io_number(req, old_value, sizeof(vm_map_size_t), &new_value, &changed);
4423 	if (changed) {
4424 		if ((uint64_t)new_value > config_memsize) {
4425 			error = EINVAL;
4426 		} else {
4427 			vm_global_user_wire_limit = (vm_map_size_t)(config_memsize - new_value);
4428 		}
4429 	}
4430 	return error;
4431 }
4432 /*
4433  * There needs to be a more automatic/elegant way to do this
4434  */
4435 SYSCTL_QUAD(_vm, OID_AUTO, global_user_wire_limit, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_global_user_wire_limit, "");
4436 SYSCTL_QUAD(_vm, OID_AUTO, user_wire_limit, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_per_task_user_wire_limit, "");
4437 SYSCTL_PROC(_vm, OID_AUTO, global_no_user_wire_amount, CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0, &sysctl_global_no_user_wire_amount, "Q", "");
4438 
4439 /*
4440  * Relaxed atomic RW of a 64bit value via sysctl.
4441  */
4442 STATIC int
4443 sysctl_r_64bit_atomic(uint64_t *ptr, struct sysctl_req *req)
4444 {
4445 	uint64_t old_value;
4446 	uint64_t new_value;
4447 	int error;
4448 
4449 	old_value = os_atomic_load_wide(ptr, relaxed);
4450 	error = sysctl_io_number(req, old_value, sizeof(vm_map_size_t), &new_value, NULL);
4451 	return error;
4452 }
4453 STATIC int
4454 sysctl_add_wire_count_over_global_limit(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
4455 {
4456 	return sysctl_r_64bit_atomic(&vm_add_wire_count_over_global_limit, req);
4457 }
4458 STATIC int
4459 sysctl_add_wire_count_over_user_limit(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
4460 {
4461 	return sysctl_r_64bit_atomic(&vm_add_wire_count_over_user_limit, req);
4462 }
4463 
4464 SYSCTL_PROC(_vm, OID_AUTO, add_wire_count_over_global_limit, CTLTYPE_QUAD | CTLFLAG_RD |  CTLFLAG_LOCKED, 0, 0, &sysctl_add_wire_count_over_global_limit, "Q", "");
4465 SYSCTL_PROC(_vm, OID_AUTO, add_wire_count_over_user_limit, CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0, &sysctl_add_wire_count_over_user_limit, "Q", "");
4466 
4467 #if DEVELOPMENT || DEBUG
4468 /* These sysctls are used to test the wired limit. */
4469 SYSCTL_INT(_vm, OID_AUTO, page_wire_count, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_wire_count, 0,
4470     "The number of physical pages which are pinned and cannot be evicted");
4471 #if XNU_VM_HAS_LOPAGE
4472 SYSCTL_INT(_vm, OID_AUTO, lopage_free_count, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_lopage_free_count, 0, "");
4473 #endif
4474 SYSCTL_INT(_vm, OID_AUTO, page_stolen_count, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_stolen_count, 0, "");
4475 SYSCTL_UINT(_vm, OID_AUTO, page_swapped_count, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_swapped_count, 0,
4476     "The number of virtual pages whose contents are currently compressed and swapped to disk");
4477 
4478 /*
4479  * Setting the per task variable exclude_physfootprint_ledger to 1 will allow the calling task to exclude memory entries that are
4480  * tagged by VM_LEDGER_TAG_DEFAULT and flagged by VM_LEDGER_FLAG_EXCLUDE_FOOTPRINT_DEBUG from its phys_footprint ledger.
4481  */
4482 
4483 STATIC int
4484 sysctl_rw_task_no_footprint_for_debug(struct sysctl_oid *oidp __unused, void *arg1 __unused, int arg2 __unused, struct sysctl_req *req)
4485 {
4486 	int error;
4487 	int value;
4488 	proc_t p = current_proc();
4489 
4490 	if (req->newptr) {
4491 		// Write request
4492 		error = SYSCTL_IN(req, &value, sizeof(value));
4493 		if (!error) {
4494 			if (value == 1) {
4495 				task_set_no_footprint_for_debug(proc_task(p), TRUE);
4496 			} else if (value == 0) {
4497 				task_set_no_footprint_for_debug(proc_task(p), FALSE);
4498 			} else {
4499 				error = EINVAL;
4500 			}
4501 		}
4502 	} else {
4503 		// Read request
4504 		value = task_get_no_footprint_for_debug(proc_task(p));
4505 		error = SYSCTL_OUT(req, &value, sizeof(value));
4506 	}
4507 	return error;
4508 }
4509 
4510 SYSCTL_PROC(_vm, OID_AUTO, task_no_footprint_for_debug,
4511     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
4512     0, 0, &sysctl_rw_task_no_footprint_for_debug, "I", "Allow debug memory to be excluded from this task's memory footprint (debug only)");
4513 
4514 #endif /* DEVELOPMENT || DEBUG */
4515 
4516 
4517 extern int vm_map_copy_overwrite_aligned_src_not_internal;
4518 extern int vm_map_copy_overwrite_aligned_src_not_symmetric;
4519 extern int vm_map_copy_overwrite_aligned_src_large;
4520 SYSCTL_INT(_vm, OID_AUTO, vm_copy_src_not_internal, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_copy_overwrite_aligned_src_not_internal, 0, "");
4521 SYSCTL_INT(_vm, OID_AUTO, vm_copy_src_not_symmetric, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_copy_overwrite_aligned_src_not_symmetric, 0, "");
4522 SYSCTL_INT(_vm, OID_AUTO, vm_copy_src_large, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_map_copy_overwrite_aligned_src_large, 0, "");
4523 
4524 
4525 extern uint32_t vm_page_external_count;
4526 
4527 SYSCTL_INT(_vm, OID_AUTO, vm_page_external_count, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_external_count, 0, "");
4528 
4529 SYSCTL_INT(_vm, OID_AUTO, vm_page_filecache_min, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_pageout_state.vm_page_filecache_min, 0, "");
4530 SYSCTL_INT(_vm, OID_AUTO, vm_page_xpmapped_min, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_pageout_state.vm_page_xpmapped_min, 0, "");
4531 
4532 #if DEVELOPMENT || DEBUG
4533 SYSCTL_INT(_vm, OID_AUTO, vm_page_filecache_min_divisor, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_pageout_state.vm_page_filecache_min_divisor, 0, "");
4534 SYSCTL_INT(_vm, OID_AUTO, vm_page_xpmapped_min_divisor, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_pageout_state.vm_page_xpmapped_min_divisor, 0, "");
4535 extern boolean_t vps_yield_for_pgqlockwaiters;
4536 SYSCTL_INT(_vm, OID_AUTO, vm_pageoutscan_yields_for_pageQlockwaiters, CTLFLAG_RW | CTLFLAG_LOCKED, &vps_yield_for_pgqlockwaiters, 0, "");
4537 #endif
4538 
4539 extern int      vm_compressor_mode;
4540 extern int      vm_compressor_is_active;
4541 extern int      vm_compressor_available;
4542 extern uint32_t c_seg_bufsize;
4543 extern uint32_t c_seg_allocsize;
4544 extern int      c_seg_fixed_array_len;
4545 extern uint32_t c_segments_limit;
4546 extern uint32_t c_segment_pages_compressed_limit;
4547 extern uint64_t compressor_pool_size;
4548 extern uint32_t compressor_pool_multiplier;
4549 extern uint32_t vm_ripe_target_age;
4550 extern uint32_t swapout_target_age;
4551 extern _Atomic uint64_t compressor_bytes_used;
4552 extern _Atomic uint64_t c_segment_input_bytes;
4553 extern _Atomic uint64_t c_segment_compressed_bytes;
4554 extern uint32_t c_segment_pages_compressed;
4555 extern uint32_t compressor_eval_period_in_msecs;
4556 extern uint32_t compressor_sample_min_in_msecs;
4557 extern uint32_t compressor_sample_max_in_msecs;
4558 extern uint32_t compressor_thrashing_threshold_per_10msecs;
4559 extern uint32_t compressor_thrashing_min_per_10msecs;
4560 extern uint32_t vm_compressor_time_thread;
4561 extern uint32_t c_segment_svp_in_hash;
4562 extern uint32_t c_segment_svp_hash_succeeded;
4563 extern uint32_t c_segment_svp_hash_failed;
4564 
4565 #if DEVELOPMENT || DEBUG
4566 extern uint32_t vm_compressor_minorcompact_threshold_divisor;
4567 extern uint32_t vm_compressor_majorcompact_threshold_divisor;
4568 extern uint32_t vm_compressor_unthrottle_threshold_divisor;
4569 extern uint32_t vm_compressor_catchup_threshold_divisor;
4570 
4571 extern uint32_t vm_compressor_minorcompact_threshold_divisor_overridden;
4572 extern uint32_t vm_compressor_majorcompact_threshold_divisor_overridden;
4573 extern uint32_t vm_compressor_unthrottle_threshold_divisor_overridden;
4574 extern uint32_t vm_compressor_catchup_threshold_divisor_overridden;
4575 
4576 extern vmct_stats_t vmct_stats;
4577 
4578 
4579 STATIC int
4580 sysctl_minorcompact_threshold_divisor(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
4581 {
4582 	int new_value, changed;
4583 	int error = sysctl_io_number(req, vm_compressor_minorcompact_threshold_divisor, sizeof(int), &new_value, &changed);
4584 
4585 	if (changed) {
4586 		vm_compressor_minorcompact_threshold_divisor = new_value;
4587 		vm_compressor_minorcompact_threshold_divisor_overridden = 1;
4588 	}
4589 	return error;
4590 }
4591 
4592 SYSCTL_PROC(_vm, OID_AUTO, compressor_minorcompact_threshold_divisor,
4593     CTLTYPE_INT | CTLFLAG_LOCKED | CTLFLAG_RW,
4594     0, 0, sysctl_minorcompact_threshold_divisor, "I", "");
4595 
4596 
4597 STATIC int
4598 sysctl_majorcompact_threshold_divisor(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
4599 {
4600 	int new_value, changed;
4601 	int error = sysctl_io_number(req, vm_compressor_majorcompact_threshold_divisor, sizeof(int), &new_value, &changed);
4602 
4603 	if (changed) {
4604 		vm_compressor_majorcompact_threshold_divisor = new_value;
4605 		vm_compressor_majorcompact_threshold_divisor_overridden = 1;
4606 	}
4607 	return error;
4608 }
4609 
4610 SYSCTL_PROC(_vm, OID_AUTO, compressor_majorcompact_threshold_divisor,
4611     CTLTYPE_INT | CTLFLAG_LOCKED | CTLFLAG_RW,
4612     0, 0, sysctl_majorcompact_threshold_divisor, "I", "");
4613 
4614 
4615 STATIC int
4616 sysctl_unthrottle_threshold_divisor(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
4617 {
4618 	int new_value, changed;
4619 	int error = sysctl_io_number(req, vm_compressor_unthrottle_threshold_divisor, sizeof(int), &new_value, &changed);
4620 
4621 	if (changed) {
4622 		vm_compressor_unthrottle_threshold_divisor = new_value;
4623 		vm_compressor_unthrottle_threshold_divisor_overridden = 1;
4624 	}
4625 	return error;
4626 }
4627 
4628 SYSCTL_PROC(_vm, OID_AUTO, compressor_unthrottle_threshold_divisor,
4629     CTLTYPE_INT | CTLFLAG_LOCKED | CTLFLAG_RW,
4630     0, 0, sysctl_unthrottle_threshold_divisor, "I", "");
4631 
4632 
4633 STATIC int
4634 sysctl_catchup_threshold_divisor(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
4635 {
4636 	int new_value, changed;
4637 	int error = sysctl_io_number(req, vm_compressor_catchup_threshold_divisor, sizeof(int), &new_value, &changed);
4638 
4639 	if (changed) {
4640 		vm_compressor_catchup_threshold_divisor = new_value;
4641 		vm_compressor_catchup_threshold_divisor_overridden = 1;
4642 	}
4643 	return error;
4644 }
4645 
4646 SYSCTL_PROC(_vm, OID_AUTO, compressor_catchup_threshold_divisor,
4647     CTLTYPE_INT | CTLFLAG_LOCKED | CTLFLAG_RW,
4648     0, 0, sysctl_catchup_threshold_divisor, "I", "");
4649 #endif
4650 
4651 
4652 SYSCTL_QUAD(_vm, OID_AUTO, compressor_input_bytes, CTLFLAG_RD | CTLFLAG_LOCKED, ((uint64_t *)&c_segment_input_bytes), "");
4653 SYSCTL_QUAD(_vm, OID_AUTO, compressor_compressed_bytes, CTLFLAG_RD | CTLFLAG_LOCKED, ((uint64_t *)&c_segment_compressed_bytes), "");
4654 SYSCTL_QUAD(_vm, OID_AUTO, compressor_bytes_used, CTLFLAG_RD | CTLFLAG_LOCKED, ((uint64_t *)&compressor_bytes_used), "");
4655 
4656 SYSCTL_INT(_vm, OID_AUTO, compressor_swapout_target_age, CTLFLAG_RD | CTLFLAG_LOCKED, &swapout_target_age, 0, "");
4657 SYSCTL_INT(_vm, OID_AUTO, compressor_available, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_compressor_available, 0, "");
4658 SYSCTL_INT(_vm, OID_AUTO, compressor_segment_buffer_size, CTLFLAG_RD | CTLFLAG_LOCKED, &c_seg_bufsize, 0, "");
4659 SYSCTL_QUAD(_vm, OID_AUTO, compressor_pool_size, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_pool_size, "");
4660 SYSCTL_UINT(_vm, OID_AUTO, compressor_pool_multiplier, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_pool_multiplier, 0, "");
4661 SYSCTL_INT(_vm, OID_AUTO, compressor_segment_slots_fixed_array_len, CTLFLAG_RD | CTLFLAG_LOCKED, &c_seg_fixed_array_len, 0, "");
4662 SYSCTL_UINT(_vm, OID_AUTO, compressor_segment_pages_compressed_limit, CTLFLAG_RD | CTLFLAG_LOCKED, &c_segment_pages_compressed_limit, 0, "");
4663 SYSCTL_UINT(_vm, OID_AUTO, compressor_segment_alloc_size, CTLFLAG_RD | CTLFLAG_LOCKED, &c_seg_allocsize, 0, "");
4664 SYSCTL_UINT(_vm, OID_AUTO, compressor_segment_pages_compressed, CTLFLAG_RD | CTLFLAG_LOCKED, &c_segment_pages_compressed, 0, "");
4665 SYSCTL_UINT(_vm, OID_AUTO, compressor_segment_svp_in_hash, CTLFLAG_RD | CTLFLAG_LOCKED, &c_segment_svp_in_hash, 0, "");
4666 SYSCTL_UINT(_vm, OID_AUTO, compressor_segment_svp_hash_succeeded, CTLFLAG_RD | CTLFLAG_LOCKED, &c_segment_svp_hash_succeeded, 0, "");
4667 SYSCTL_UINT(_vm, OID_AUTO, compressor_segment_svp_hash_failed, CTLFLAG_RD | CTLFLAG_LOCKED, &c_segment_svp_hash_failed, 0, "");
4668 
4669 #if CONFIG_TRACK_UNMODIFIED_ANON_PAGES
4670 extern uint64_t compressor_ro_uncompressed;
4671 extern uint64_t compressor_ro_uncompressed_total_returned;
4672 extern uint64_t compressor_ro_uncompressed_skip_returned;
4673 extern uint64_t compressor_ro_uncompressed_get;
4674 extern uint64_t compressor_ro_uncompressed_put;
4675 extern uint64_t compressor_ro_uncompressed_swap_usage;
4676 
4677 SYSCTL_QUAD(_vm, OID_AUTO, compressor_ro_uncompressed_total_returned, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_ro_uncompressed_total_returned, "");
4678 SYSCTL_QUAD(_vm, OID_AUTO, compressor_ro_uncompressed_writes_saved, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_ro_uncompressed_skip_returned, "");
4679 SYSCTL_QUAD(_vm, OID_AUTO, compressor_ro_uncompressed_candidates, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_ro_uncompressed, "");
4680 SYSCTL_QUAD(_vm, OID_AUTO, compressor_ro_uncompressed_rereads, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_ro_uncompressed_get, "");
4681 SYSCTL_QUAD(_vm, OID_AUTO, compressor_ro_uncompressed_swap_pages_on_disk, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_ro_uncompressed_swap_usage, "");
4682 #endif /* CONFIG_TRACK_UNMODIFIED_ANON_PAGES */
4683 
4684 extern int min_csegs_per_major_compaction;
4685 SYSCTL_INT(_vm, OID_AUTO, compressor_min_csegs_per_major_compaction, CTLFLAG_RW | CTLFLAG_LOCKED, &min_csegs_per_major_compaction, 0, "");
4686 
4687 SYSCTL_INT(_vm, OID_AUTO, vm_ripe_target_age_in_secs, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_ripe_target_age, 0, "");
4688 
4689 SYSCTL_INT(_vm, OID_AUTO, compressor_eval_period_in_msecs, CTLFLAG_RW | CTLFLAG_LOCKED, &compressor_eval_period_in_msecs, 0, "");
4690 SYSCTL_INT(_vm, OID_AUTO, compressor_sample_min_in_msecs, CTLFLAG_RW | CTLFLAG_LOCKED, &compressor_sample_min_in_msecs, 0, "");
4691 SYSCTL_INT(_vm, OID_AUTO, compressor_sample_max_in_msecs, CTLFLAG_RW | CTLFLAG_LOCKED, &compressor_sample_max_in_msecs, 0, "");
4692 SYSCTL_INT(_vm, OID_AUTO, compressor_thrashing_threshold_per_10msecs, CTLFLAG_RW | CTLFLAG_LOCKED, &compressor_thrashing_threshold_per_10msecs, 0, "");
4693 SYSCTL_INT(_vm, OID_AUTO, compressor_thrashing_min_per_10msecs, CTLFLAG_RW | CTLFLAG_LOCKED, &compressor_thrashing_min_per_10msecs, 0, "");
4694 
4695 SYSCTL_QUAD(_vm, OID_AUTO, compressor_swapouts_under_30s, CTLFLAG_RD | CTLFLAG_LOCKED, &vmcs_stats.unripe_under_30s, "");
4696 SYSCTL_QUAD(_vm, OID_AUTO, compressor_swapouts_under_60s, CTLFLAG_RD | CTLFLAG_LOCKED, &vmcs_stats.unripe_under_60s, "");
4697 SYSCTL_QUAD(_vm, OID_AUTO, compressor_swapouts_under_300s, CTLFLAG_RD | CTLFLAG_LOCKED, &vmcs_stats.unripe_under_300s, "");
4698 SYSCTL_QUAD(_vm, OID_AUTO, compressor_swapper_reclaim_swapins, CTLFLAG_RD | CTLFLAG_LOCKED, &vmcs_stats.reclaim_swapins, "");
4699 SYSCTL_QUAD(_vm, OID_AUTO, compressor_swapper_defrag_swapins, CTLFLAG_RD | CTLFLAG_LOCKED, &vmcs_stats.defrag_swapins, "");
4700 SYSCTL_QUAD(_vm, OID_AUTO, compressor_swapper_swapout_threshold_exceeded, CTLFLAG_RD | CTLFLAG_LOCKED, &vmcs_stats.compressor_swap_threshold_exceeded, "");
4701 SYSCTL_QUAD(_vm, OID_AUTO, compressor_swapper_swapout_fileq_throttled, CTLFLAG_RD | CTLFLAG_LOCKED, &vmcs_stats.external_q_throttled, "");
4702 SYSCTL_QUAD(_vm, OID_AUTO, compressor_swapper_swapout_free_count_low, CTLFLAG_RD | CTLFLAG_LOCKED, &vmcs_stats.free_count_below_reserve, "");
4703 SYSCTL_QUAD(_vm, OID_AUTO, compressor_swapper_swapout_thrashing_detected, CTLFLAG_RD | CTLFLAG_LOCKED, &vmcs_stats.thrashing_detected, "");
4704 SYSCTL_QUAD(_vm, OID_AUTO, compressor_swapper_swapout_fragmentation_detected, CTLFLAG_RD | CTLFLAG_LOCKED, &vmcs_stats.fragmentation_detected, "");
4705 
4706 SYSCTL_STRING(_vm, OID_AUTO, swapfileprefix, CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED, swapfilename, sizeof(swapfilename) - SWAPFILENAME_INDEX_LEN, "");
4707 
4708 SYSCTL_INT(_vm, OID_AUTO, compressor_timing_enabled, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_compressor_time_thread, 0, "");
4709 
4710 #if DEVELOPMENT || DEBUG
4711 SYSCTL_QUAD(_vm, OID_AUTO, compressor_thread_runtime0, CTLFLAG_RD | CTLFLAG_LOCKED, &vmct_stats.vmct_runtimes[0], "");
4712 SYSCTL_QUAD(_vm, OID_AUTO, compressor_thread_runtime1, CTLFLAG_RD | CTLFLAG_LOCKED, &vmct_stats.vmct_runtimes[1], "");
4713 
4714 SYSCTL_QUAD(_vm, OID_AUTO, compressor_threads_total_execution_time, CTLFLAG_RD | CTLFLAG_LOCKED, &vmct_stats.vmct_cthreads_total, "");
4715 
4716 SYSCTL_QUAD(_vm, OID_AUTO, compressor_thread_pages0, CTLFLAG_RD | CTLFLAG_LOCKED, &vmct_stats.vmct_pages[0], "");
4717 SYSCTL_QUAD(_vm, OID_AUTO, compressor_thread_pages1, CTLFLAG_RD | CTLFLAG_LOCKED, &vmct_stats.vmct_pages[1], "");
4718 
4719 SYSCTL_QUAD(_vm, OID_AUTO, compressor_thread_iterations0, CTLFLAG_RD | CTLFLAG_LOCKED, &vmct_stats.vmct_iterations[0], "");
4720 SYSCTL_QUAD(_vm, OID_AUTO, compressor_thread_iterations1, CTLFLAG_RD | CTLFLAG_LOCKED, &vmct_stats.vmct_iterations[1], "");
4721 
4722 SYSCTL_INT(_vm, OID_AUTO, compressor_thread_minpages0, CTLFLAG_RD | CTLFLAG_LOCKED, &vmct_stats.vmct_minpages[0], 0, "");
4723 SYSCTL_INT(_vm, OID_AUTO, compressor_thread_minpages1, CTLFLAG_RD | CTLFLAG_LOCKED, &vmct_stats.vmct_minpages[1], 0, "");
4724 
4725 SYSCTL_INT(_vm, OID_AUTO, compressor_thread_maxpages0, CTLFLAG_RD | CTLFLAG_LOCKED, &vmct_stats.vmct_maxpages[0], 0, "");
4726 SYSCTL_INT(_vm, OID_AUTO, compressor_thread_maxpages1, CTLFLAG_RD | CTLFLAG_LOCKED, &vmct_stats.vmct_maxpages[1], 0, "");
4727 
4728 int vm_compressor_injected_error_count;
4729 
4730 SYSCTL_INT(_vm, OID_AUTO, compressor_injected_error_count, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_compressor_injected_error_count, 0, "");
4731 
4732 static int
4733 sysctl_compressor_inject_error(__unused struct sysctl_oid *oidp,
4734     __unused void *arg1, __unused int arg2, struct sysctl_req *req)
4735 {
4736 	int result;
4737 	vm_address_t va = 0;
4738 	int changed;
4739 
4740 	result = sysctl_io_number(req, va, sizeof(va), &va, &changed);
4741 	if (result == 0 && changed) {
4742 		result = vm_map_inject_error(current_map(), va);
4743 		if (result == 0) {
4744 			/*
4745 			 * Count the number of errors injected successfully to detect
4746 			 * situations where corruption was caused by improper use of this
4747 			 * sysctl.
4748 			 */
4749 			os_atomic_inc(&vm_compressor_injected_error_count, relaxed);
4750 		}
4751 	}
4752 	return result;
4753 }
4754 
4755 SYSCTL_PROC(_vm, OID_AUTO, compressor_inject_error, CTLTYPE_QUAD | CTLFLAG_LOCKED | CTLFLAG_RW,
4756     0, 0, sysctl_compressor_inject_error, "Q", "flips a bit in a compressed page for the current task");
4757 
4758 /*
4759  * Opt a process in/out of self donation mode.
4760  */
4761 static int
4762 sysctl_vm_pid_toggle_selfdonate_pages SYSCTL_HANDLER_ARGS
4763 {
4764 #pragma unused(arg1, arg2)
4765 	int error, pid = 0;
4766 	proc_t p;
4767 
4768 	error = sysctl_handle_int(oidp, &pid, 0, req);
4769 	if (error || !req->newptr) {
4770 		return error;
4771 	}
4772 
4773 	p = proc_find(pid);
4774 	if (p != NULL) {
4775 		(void) vm_toggle_task_selfdonate_pages(proc_task(p));
4776 		proc_rele(p);
4777 		return error;
4778 	} else {
4779 		printf("sysctl_vm_pid_selfdonate_pages: Invalid process\n");
4780 	}
4781 
4782 	return EINVAL;
4783 }
4784 SYSCTL_PROC(_vm, OID_AUTO, pid_toggle_selfdonate_pages, CTLTYPE_INT | CTLFLAG_WR | CTLFLAG_LOCKED | CTLFLAG_MASKED,
4785     0, 0, &sysctl_vm_pid_toggle_selfdonate_pages, "I", "");
4786 #endif /* DEVELOPMENT || DEBUG */
4787 extern uint32_t vm_page_donate_mode;
4788 extern uint32_t vm_page_donate_target_high, vm_page_donate_target_low;
4789 SYSCTL_INT(_vm, OID_AUTO, vm_page_donate_mode, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_page_donate_mode, 0, "");
4790 SYSCTL_INT(_vm, OID_AUTO, vm_page_donate_target_high, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_page_donate_target_high, 0, "");
4791 SYSCTL_INT(_vm, OID_AUTO, vm_page_donate_target_low, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_page_donate_target_low, 0, "");
4792 
4793 SYSCTL_QUAD(_vm, OID_AUTO, lz4_compressions, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.lz4_compressions, "");
4794 SYSCTL_QUAD(_vm, OID_AUTO, lz4_compression_failures, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.lz4_compression_failures, "");
4795 SYSCTL_QUAD(_vm, OID_AUTO, lz4_compressed_bytes, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.lz4_compressed_bytes, "");
4796 SYSCTL_QUAD(_vm, OID_AUTO, lz4_wk_compression_delta, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.lz4_wk_compression_delta, "");
4797 SYSCTL_QUAD(_vm, OID_AUTO, lz4_wk_compression_negative_delta, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.lz4_wk_compression_negative_delta, "");
4798 
4799 SYSCTL_QUAD(_vm, OID_AUTO, lz4_decompressions, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.lz4_decompressions, "");
4800 SYSCTL_QUAD(_vm, OID_AUTO, lz4_decompressed_bytes, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.lz4_decompressed_bytes, "");
4801 
4802 SYSCTL_QUAD(_vm, OID_AUTO, uc_decompressions, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.uc_decompressions, "");
4803 
4804 SYSCTL_QUAD(_vm, OID_AUTO, wk_compressions, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.wk_compressions, "");
4805 
4806 SYSCTL_QUAD(_vm, OID_AUTO, wk_catime, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.wk_cabstime, "");
4807 
4808 SYSCTL_QUAD(_vm, OID_AUTO, wkh_catime, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.wkh_cabstime, "");
4809 SYSCTL_QUAD(_vm, OID_AUTO, wkh_compressions, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.wkh_compressions, "");
4810 
4811 SYSCTL_QUAD(_vm, OID_AUTO, wks_catime, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.wks_cabstime, "");
4812 SYSCTL_QUAD(_vm, OID_AUTO, wks_compressions, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.wks_compressions, "");
4813 
4814 SYSCTL_QUAD(_vm, OID_AUTO, wk_compressions_exclusive, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.wk_compressions_exclusive, "");
4815 SYSCTL_QUAD(_vm, OID_AUTO, wk_sv_compressions, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.wk_sv_compressions, "");
4816 SYSCTL_QUAD(_vm, OID_AUTO, wk_mzv_compressions, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.wk_mzv_compressions, "");
4817 SYSCTL_QUAD(_vm, OID_AUTO, wk_compression_failures, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.wk_compression_failures, "");
4818 SYSCTL_QUAD(_vm, OID_AUTO, wk_compressed_bytes_exclusive, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.wk_compressed_bytes_exclusive, "");
4819 SYSCTL_QUAD(_vm, OID_AUTO, wk_compressed_bytes_total, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.wk_compressed_bytes_total, "");
4820 
4821 SYSCTL_QUAD(_vm, OID_AUTO, wks_compressed_bytes, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.wks_compressed_bytes, "");
4822 SYSCTL_QUAD(_vm, OID_AUTO, wks_compression_failures, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.wks_compression_failures, "");
4823 SYSCTL_QUAD(_vm, OID_AUTO, wks_sv_compressions, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.wks_sv_compressions, "");
4824 
4825 
4826 SYSCTL_QUAD(_vm, OID_AUTO, wk_decompressions, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.wk_decompressions, "");
4827 
4828 SYSCTL_QUAD(_vm, OID_AUTO, wk_datime, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.wk_dabstime, "");
4829 
4830 SYSCTL_QUAD(_vm, OID_AUTO, wkh_datime, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.wkh_dabstime, "");
4831 SYSCTL_QUAD(_vm, OID_AUTO, wkh_decompressions, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.wkh_decompressions, "");
4832 
4833 SYSCTL_QUAD(_vm, OID_AUTO, wks_datime, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.wks_dabstime, "");
4834 SYSCTL_QUAD(_vm, OID_AUTO, wks_decompressions, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.wks_decompressions, "");
4835 
4836 SYSCTL_QUAD(_vm, OID_AUTO, wk_decompressed_bytes, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.wk_decompressed_bytes, "");
4837 SYSCTL_QUAD(_vm, OID_AUTO, wk_sv_decompressions, CTLFLAG_RD | CTLFLAG_LOCKED, &compressor_stats.wk_sv_decompressions, "");
4838 
4839 SYSCTL_INT(_vm, OID_AUTO, lz4_threshold, CTLFLAG_RW | CTLFLAG_LOCKED, &vmctune.lz4_threshold, 0, "");
4840 SYSCTL_INT(_vm, OID_AUTO, wkdm_reeval_threshold, CTLFLAG_RW | CTLFLAG_LOCKED, &vmctune.wkdm_reeval_threshold, 0, "");
4841 SYSCTL_INT(_vm, OID_AUTO, lz4_max_failure_skips, CTLFLAG_RW | CTLFLAG_LOCKED, &vmctune.lz4_max_failure_skips, 0, "");
4842 SYSCTL_INT(_vm, OID_AUTO, lz4_max_failure_run_length, CTLFLAG_RW | CTLFLAG_LOCKED, &vmctune.lz4_max_failure_run_length, 0, "");
4843 SYSCTL_INT(_vm, OID_AUTO, lz4_max_preselects, CTLFLAG_RW | CTLFLAG_LOCKED, &vmctune.lz4_max_preselects, 0, "");
4844 SYSCTL_INT(_vm, OID_AUTO, lz4_run_preselection_threshold, CTLFLAG_RW | CTLFLAG_LOCKED, &vmctune.lz4_run_preselection_threshold, 0, "");
4845 SYSCTL_INT(_vm, OID_AUTO, lz4_run_continue_bytes, CTLFLAG_RW | CTLFLAG_LOCKED, &vmctune.lz4_run_continue_bytes, 0, "");
4846 SYSCTL_INT(_vm, OID_AUTO, lz4_profitable_bytes, CTLFLAG_RW | CTLFLAG_LOCKED, &vmctune.lz4_profitable_bytes, 0, "");
4847 #if DEVELOPMENT || DEBUG
4848 extern int vm_compressor_current_codec;
4849 extern int vm_compressor_test_seg_wp;
4850 extern boolean_t vm_compressor_force_sw_wkdm;
4851 SYSCTL_INT(_vm, OID_AUTO, compressor_codec, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_compressor_current_codec, 0, "");
4852 SYSCTL_INT(_vm, OID_AUTO, compressor_test_wp, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_compressor_test_seg_wp, 0, "");
4853 
4854 SYSCTL_INT(_vm, OID_AUTO, wksw_force, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_compressor_force_sw_wkdm, 0, "");
4855 extern int precompy, wkswhw;
4856 
4857 SYSCTL_INT(_vm, OID_AUTO, precompy, CTLFLAG_RW | CTLFLAG_LOCKED, &precompy, 0, "");
4858 SYSCTL_INT(_vm, OID_AUTO, wkswhw, CTLFLAG_RW | CTLFLAG_LOCKED, &wkswhw, 0, "");
4859 extern unsigned int vm_ktrace_enabled;
4860 SYSCTL_INT(_vm, OID_AUTO, vm_ktrace, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_ktrace_enabled, 0, "");
4861 #endif /* DEVELOPMENT || DEBUG */
4862 
4863 #if CONFIG_PHANTOM_CACHE
4864 extern uint32_t phantom_cache_thrashing_threshold;
4865 extern uint32_t phantom_cache_eval_period_in_msecs;
4866 extern uint32_t phantom_cache_thrashing_threshold_ssd;
4867 
4868 
4869 SYSCTL_INT(_vm, OID_AUTO, phantom_cache_eval_period_in_msecs, CTLFLAG_RW | CTLFLAG_LOCKED, &phantom_cache_eval_period_in_msecs, 0, "");
4870 SYSCTL_INT(_vm, OID_AUTO, phantom_cache_thrashing_threshold, CTLFLAG_RW | CTLFLAG_LOCKED, &phantom_cache_thrashing_threshold, 0, "");
4871 SYSCTL_INT(_vm, OID_AUTO, phantom_cache_thrashing_threshold_ssd, CTLFLAG_RW | CTLFLAG_LOCKED, &phantom_cache_thrashing_threshold_ssd, 0, "");
4872 #endif
4873 
4874 #if    defined(__LP64__)
4875 extern uint32_t vm_page_background_count;
4876 extern uint32_t vm_page_background_target;
4877 extern uint32_t vm_page_background_internal_count;
4878 extern uint32_t vm_page_background_external_count;
4879 extern uint32_t vm_page_background_mode;
4880 extern uint32_t vm_page_background_exclude_external;
4881 extern uint64_t vm_page_background_promoted_count;
4882 extern uint64_t vm_pageout_rejected_bq_internal;
4883 extern uint64_t vm_pageout_rejected_bq_external;
4884 
4885 SYSCTL_INT(_vm, OID_AUTO, vm_page_background_mode, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_page_background_mode, 0, "");
4886 SYSCTL_INT(_vm, OID_AUTO, vm_page_background_exclude_external, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_page_background_exclude_external, 0, "");
4887 SYSCTL_INT(_vm, OID_AUTO, vm_page_background_target, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_page_background_target, 0, "");
4888 SYSCTL_INT(_vm, OID_AUTO, vm_page_background_count, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_background_count, 0, "");
4889 SYSCTL_INT(_vm, OID_AUTO, vm_page_background_internal_count, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_background_internal_count, 0, "");
4890 SYSCTL_INT(_vm, OID_AUTO, vm_page_background_external_count, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_background_external_count, 0, "");
4891 
4892 SYSCTL_QUAD(_vm, OID_AUTO, vm_page_background_promoted_count, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_background_promoted_count, "");
4893 SYSCTL_QUAD(_vm, OID_AUTO, vm_pageout_considered_bq_internal, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_pageout_vminfo.vm_pageout_considered_bq_internal, "");
4894 SYSCTL_QUAD(_vm, OID_AUTO, vm_pageout_considered_bq_external, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_pageout_vminfo.vm_pageout_considered_bq_external, "");
4895 SYSCTL_QUAD(_vm, OID_AUTO, vm_pageout_rejected_bq_internal, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_pageout_rejected_bq_internal, "");
4896 SYSCTL_QUAD(_vm, OID_AUTO, vm_pageout_rejected_bq_external, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_pageout_rejected_bq_external, "");
4897 
4898 #endif /* __LP64__ */
4899 
4900 extern boolean_t vm_darkwake_mode;
4901 
4902 STATIC int
4903 sysctl_toggle_darkwake_mode(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
4904 {
4905 	int new_value, changed;
4906 	int error = sysctl_io_number(req, vm_darkwake_mode, sizeof(int), &new_value, &changed);
4907 
4908 	if (!error && changed) {
4909 		if (new_value != 0 && new_value != 1) {
4910 			printf("Error: Invalid value passed to darkwake sysctl. Acceptable: 0 or 1.\n");
4911 			error = EINVAL;
4912 		} else {
4913 			vm_update_darkwake_mode((boolean_t) new_value);
4914 		}
4915 	}
4916 
4917 	return error;
4918 }
4919 
4920 SYSCTL_PROC(_vm, OID_AUTO, darkwake_mode,
4921     CTLTYPE_INT | CTLFLAG_LOCKED | CTLFLAG_RW,
4922     0, 0, sysctl_toggle_darkwake_mode, "I", "");
4923 
4924 #if (DEVELOPMENT || DEBUG)
4925 
4926 SYSCTL_UINT(_vm, OID_AUTO, vm_page_creation_throttled_hard,
4927     CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
4928     &vm_page_creation_throttled_hard, 0, "");
4929 
4930 SYSCTL_UINT(_vm, OID_AUTO, vm_page_creation_throttled_soft,
4931     CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
4932     &vm_page_creation_throttled_soft, 0, "");
4933 
4934 extern uint32_t vm_pageout_memorystatus_fb_factor_nr;
4935 extern uint32_t vm_pageout_memorystatus_fb_factor_dr;
4936 SYSCTL_INT(_vm, OID_AUTO, vm_pageout_memorystatus_fb_factor_nr, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_pageout_memorystatus_fb_factor_nr, 0, "");
4937 SYSCTL_INT(_vm, OID_AUTO, vm_pageout_memorystatus_fb_factor_dr, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_pageout_memorystatus_fb_factor_dr, 0, "");
4938 
4939 extern uint32_t vm_grab_anon_nops;
4940 
4941 SYSCTL_INT(_vm, OID_AUTO, vm_grab_anon_overrides, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_pageout_debug.vm_grab_anon_overrides, 0, "");
4942 SYSCTL_INT(_vm, OID_AUTO, vm_grab_anon_nops, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_pageout_debug.vm_grab_anon_nops, 0, "");
4943 SYSCTL_INT(_vm, OID_AUTO, vm_pageout_yield_for_free_pages, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_pageout_debug.vm_pageout_yield_for_free_pages, 0, "");
4944 
4945 
4946 extern int vm_page_delayed_work_ctx_needed;
4947 SYSCTL_INT(_vm, OID_AUTO, vm_page_needed_delayed_work_ctx, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_delayed_work_ctx_needed, 0, "");
4948 
4949 
4950 /* log message counters for persistence mode */
4951 SCALABLE_COUNTER_DECLARE(oslog_p_total_msgcount);
4952 SCALABLE_COUNTER_DECLARE(oslog_p_metadata_saved_msgcount);
4953 SCALABLE_COUNTER_DECLARE(oslog_p_metadata_dropped_msgcount);
4954 SCALABLE_COUNTER_DECLARE(oslog_p_signpost_saved_msgcount);
4955 SCALABLE_COUNTER_DECLARE(oslog_p_signpost_dropped_msgcount);
4956 SCALABLE_COUNTER_DECLARE(oslog_p_error_count);
4957 SCALABLE_COUNTER_DECLARE(oslog_p_error_count);
4958 SCALABLE_COUNTER_DECLARE(oslog_p_saved_msgcount);
4959 SCALABLE_COUNTER_DECLARE(oslog_p_dropped_msgcount);
4960 SCALABLE_COUNTER_DECLARE(oslog_p_boot_dropped_msgcount);
4961 SCALABLE_COUNTER_DECLARE(oslog_p_coprocessor_total_msgcount);
4962 SCALABLE_COUNTER_DECLARE(oslog_p_coprocessor_dropped_msgcount);
4963 SCALABLE_COUNTER_DECLARE(oslog_p_unresolved_kc_msgcount);
4964 SCALABLE_COUNTER_DECLARE(oslog_p_fmt_invalid_msgcount);
4965 SCALABLE_COUNTER_DECLARE(oslog_p_fmt_max_args_msgcount);
4966 SCALABLE_COUNTER_DECLARE(oslog_p_truncated_msgcount);
4967 
4968 SCALABLE_COUNTER_DECLARE(oslog_subsystem_count);
4969 SCALABLE_COUNTER_DECLARE(oslog_subsystem_found);
4970 SCALABLE_COUNTER_DECLARE(oslog_subsystem_dropped);
4971 
4972 SCALABLE_COUNTER_DECLARE(log_queue_cnt_received);
4973 SCALABLE_COUNTER_DECLARE(log_queue_cnt_rejected_fh);
4974 SCALABLE_COUNTER_DECLARE(log_queue_cnt_sent);
4975 SCALABLE_COUNTER_DECLARE(log_queue_cnt_dropped_nomem);
4976 SCALABLE_COUNTER_DECLARE(log_queue_cnt_queued);
4977 SCALABLE_COUNTER_DECLARE(log_queue_cnt_dropped_off);
4978 SCALABLE_COUNTER_DECLARE(log_queue_cnt_mem_active);
4979 SCALABLE_COUNTER_DECLARE(log_queue_cnt_mem_allocated);
4980 SCALABLE_COUNTER_DECLARE(log_queue_cnt_mem_released);
4981 SCALABLE_COUNTER_DECLARE(log_queue_cnt_mem_failed);
4982 
4983 /* log message counters for streaming mode */
4984 SCALABLE_COUNTER_DECLARE(oslog_s_total_msgcount);
4985 SCALABLE_COUNTER_DECLARE(oslog_s_metadata_msgcount);
4986 SCALABLE_COUNTER_DECLARE(oslog_s_error_count);
4987 SCALABLE_COUNTER_DECLARE(oslog_s_streamed_msgcount);
4988 SCALABLE_COUNTER_DECLARE(oslog_s_dropped_msgcount);
4989 
4990 /* log message counters for msgbuf logging */
4991 SCALABLE_COUNTER_DECLARE(oslog_msgbuf_msgcount);
4992 SCALABLE_COUNTER_DECLARE(oslog_msgbuf_dropped_msgcount);
4993 extern uint32_t oslog_msgbuf_dropped_charcount;
4994 
4995 #if CONFIG_EXCLAVES
4996 /* log message counters for exclaves logging */
4997 SCALABLE_COUNTER_DECLARE(oslog_e_log_count);
4998 SCALABLE_COUNTER_DECLARE(oslog_e_log_dropped_count);
4999 SCALABLE_COUNTER_DECLARE(oslog_e_metadata_count);
5000 SCALABLE_COUNTER_DECLARE(oslog_e_metadata_dropped_count);
5001 SCALABLE_COUNTER_DECLARE(oslog_e_signpost_count);
5002 SCALABLE_COUNTER_DECLARE(oslog_e_signpost_dropped_count);
5003 SCALABLE_COUNTER_DECLARE(oslog_e_replay_failure_count);
5004 SCALABLE_COUNTER_DECLARE(oslog_e_query_count);
5005 SCALABLE_COUNTER_DECLARE(oslog_e_query_error_count);
5006 SCALABLE_COUNTER_DECLARE(oslog_e_trace_mode_set_count);
5007 SCALABLE_COUNTER_DECLARE(oslog_e_trace_mode_error_count);
5008 #endif // CONFIG_EXCLAVES
5009 
5010 SYSCTL_SCALABLE_COUNTER(_debug, oslog_p_total_msgcount, oslog_p_total_msgcount, "");
5011 SYSCTL_SCALABLE_COUNTER(_debug, oslog_p_metadata_saved_msgcount, oslog_p_metadata_saved_msgcount, "");
5012 SYSCTL_SCALABLE_COUNTER(_debug, oslog_p_metadata_dropped_msgcount, oslog_p_metadata_dropped_msgcount, "");
5013 SYSCTL_SCALABLE_COUNTER(_debug, oslog_p_signpost_saved_msgcount, oslog_p_signpost_saved_msgcount, "");
5014 SYSCTL_SCALABLE_COUNTER(_debug, oslog_p_signpost_dropped_msgcount, oslog_p_signpost_dropped_msgcount, "");
5015 SYSCTL_SCALABLE_COUNTER(_debug, oslog_p_error_count, oslog_p_error_count, "");
5016 SYSCTL_SCALABLE_COUNTER(_debug, oslog_p_saved_msgcount, oslog_p_saved_msgcount, "");
5017 SYSCTL_SCALABLE_COUNTER(_debug, oslog_p_dropped_msgcount, oslog_p_dropped_msgcount, "");
5018 SYSCTL_SCALABLE_COUNTER(_debug, oslog_p_boot_dropped_msgcount, oslog_p_boot_dropped_msgcount, "");
5019 SYSCTL_SCALABLE_COUNTER(_debug, oslog_p_coprocessor_total_msgcount, oslog_p_coprocessor_total_msgcount, "");
5020 SYSCTL_SCALABLE_COUNTER(_debug, oslog_p_coprocessor_dropped_msgcount, oslog_p_coprocessor_dropped_msgcount, "");
5021 SYSCTL_SCALABLE_COUNTER(_debug, oslog_p_unresolved_kc_msgcount, oslog_p_unresolved_kc_msgcount, "");
5022 
5023 SYSCTL_SCALABLE_COUNTER(_debug, oslog_p_fmt_invalid_msgcount, oslog_p_fmt_invalid_msgcount, "");
5024 SYSCTL_SCALABLE_COUNTER(_debug, oslog_p_fmt_max_args_msgcount, oslog_p_fmt_max_args_msgcount, "");
5025 SYSCTL_SCALABLE_COUNTER(_debug, oslog_p_truncated_msgcount, oslog_p_truncated_msgcount, "");
5026 
5027 SYSCTL_SCALABLE_COUNTER(_debug, oslog_s_total_msgcount, oslog_s_total_msgcount, "Number of logs sent to streaming");
5028 SYSCTL_SCALABLE_COUNTER(_debug, oslog_s_metadata_msgcount, oslog_s_metadata_msgcount, "Number of metadata sent to streaming");
5029 SYSCTL_SCALABLE_COUNTER(_debug, oslog_s_error_count, oslog_s_error_count, "Number of invalid stream logs");
5030 SYSCTL_SCALABLE_COUNTER(_debug, oslog_s_streamed_msgcount, oslog_s_streamed_msgcount, "Number of streamed logs");
5031 SYSCTL_SCALABLE_COUNTER(_debug, oslog_s_dropped_msgcount, oslog_s_dropped_msgcount, "Number of logs dropped from stream");
5032 
5033 SYSCTL_SCALABLE_COUNTER(_debug, oslog_msgbuf_msgcount, oslog_msgbuf_msgcount, "Number of dmesg log messages");
5034 SYSCTL_SCALABLE_COUNTER(_debug, oslog_msgbuf_dropped_msgcount, oslog_msgbuf_dropped_msgcount, "Number of dropped dmesg log messages");
5035 SYSCTL_UINT(_debug, OID_AUTO, oslog_msgbuf_dropped_charcount, CTLFLAG_ANYBODY | CTLFLAG_RD | CTLFLAG_LOCKED, &oslog_msgbuf_dropped_charcount, 0, "Number of dropped dmesg log chars");
5036 
5037 SYSCTL_SCALABLE_COUNTER(_debug, log_queue_cnt_received, log_queue_cnt_received, "Number of received logs");
5038 SYSCTL_SCALABLE_COUNTER(_debug, log_queue_cnt_rejected_fh, log_queue_cnt_rejected_fh, "Number of logs initially rejected by FH");
5039 SYSCTL_SCALABLE_COUNTER(_debug, log_queue_cnt_sent, log_queue_cnt_sent, "Number of logs successfully saved in FH");
5040 SYSCTL_SCALABLE_COUNTER(_debug, log_queue_cnt_dropped_nomem, log_queue_cnt_dropped_nomem, "Number of logs dropped due to lack of queue memory");
5041 SYSCTL_SCALABLE_COUNTER(_debug, log_queue_cnt_queued, log_queue_cnt_queued, "Current number of logs stored in log queues");
5042 SYSCTL_SCALABLE_COUNTER(_debug, log_queue_cnt_dropped_off, log_queue_cnt_dropped_off, "Number of logs dropped due to disabled log queues");
5043 SYSCTL_SCALABLE_COUNTER(_debug, log_queue_cnt_mem_allocated, log_queue_cnt_mem_allocated, "Number of memory allocations");
5044 SYSCTL_SCALABLE_COUNTER(_debug, log_queue_cnt_mem_released, log_queue_cnt_mem_released, "Number of memory releases");
5045 SYSCTL_SCALABLE_COUNTER(_debug, log_queue_cnt_mem_failed, log_queue_cnt_mem_failed, "Number of failed memory allocations");
5046 
5047 SYSCTL_SCALABLE_COUNTER(_debug, oslog_subsystem_count, oslog_subsystem_count, "Number of registered log subsystems");
5048 SYSCTL_SCALABLE_COUNTER(_debug, oslog_subsystem_found, oslog_subsystem_found, "Number of sucessful log subsystem lookups");
5049 SYSCTL_SCALABLE_COUNTER(_debug, oslog_subsystem_dropped, oslog_subsystem_dropped, "Number of dropped log subsystem registrations");
5050 
5051 #if CONFIG_EXCLAVES
5052 SYSCTL_SCALABLE_COUNTER(_debug, oslog_e_metadata_count, oslog_e_metadata_count,
5053     "Number of metadata messages retrieved from the exclaves log server");
5054 SYSCTL_SCALABLE_COUNTER(_debug, oslog_e_metadata_dropped_count, oslog_e_metadata_dropped_count,
5055     "Number of dropped metadata messages retrieved from the exclaves log server");
5056 SYSCTL_SCALABLE_COUNTER(_debug, oslog_e_log_count, oslog_e_log_count,
5057     "Number of logs retrieved from the exclaves log server");
5058 SYSCTL_SCALABLE_COUNTER(_debug, oslog_e_log_dropped_count, oslog_e_log_dropped_count,
5059     "Number of dropeed logs retrieved from the exclaves log server");
5060 SYSCTL_SCALABLE_COUNTER(_debug, oslog_e_signpost_count, oslog_e_signpost_count,
5061     "Number of signposts retrieved from the exclaves log server");
5062 SYSCTL_SCALABLE_COUNTER(_debug, oslog_e_signpost_dropped_count, oslog_e_signpost_dropped_count,
5063     "Number of dropped signposts retrieved from the exclaves log server");
5064 SYSCTL_SCALABLE_COUNTER(_debug, oslog_e_replay_failure_count, oslog_e_replay_failure_count,
5065     "Number of dropped messages that couldn't be replayed and failed generically");
5066 SYSCTL_SCALABLE_COUNTER(_debug, oslog_e_query_count, oslog_e_query_count,
5067     "Number of sucessful queries to the exclaves log server");
5068 SYSCTL_SCALABLE_COUNTER(_debug, oslog_e_query_error_count, oslog_e_query_error_count,
5069     "Number of failed queries to the exclaves log server");
5070 SYSCTL_SCALABLE_COUNTER(_debug, oslog_e_trace_mode_set_count, oslog_e_trace_mode_set_count,
5071     "Number of exclaves trace mode updates");
5072 SYSCTL_SCALABLE_COUNTER(_debug, oslog_e_trace_mode_error_count, oslog_e_trace_mode_error_count,
5073     "Number of failed exclaves trace mode updates");
5074 #endif // CONFIG_EXCLAVES
5075 
5076 #endif /* DEVELOPMENT || DEBUG */
5077 
5078 /*
5079  * Enable tracing of voucher contents
5080  */
5081 extern uint32_t ipc_voucher_trace_contents;
5082 
5083 SYSCTL_INT(_kern, OID_AUTO, ipc_voucher_trace_contents,
5084     CTLFLAG_RW | CTLFLAG_LOCKED, &ipc_voucher_trace_contents, 0, "Enable tracing voucher contents");
5085 
5086 /*
5087  * Kernel stack size and depth
5088  */
5089 SYSCTL_INT(_kern, OID_AUTO, stack_size,
5090     CTLFLAG_RD | CTLFLAG_LOCKED, (int *) &kernel_stack_size, 0, "Kernel stack size");
5091 SYSCTL_INT(_kern, OID_AUTO, stack_depth_max,
5092     CTLFLAG_RD | CTLFLAG_LOCKED, (int *) &kernel_stack_depth_max, 0, "Max kernel stack depth at interrupt or context switch");
5093 
5094 extern unsigned int kern_feature_overrides;
5095 SYSCTL_INT(_kern, OID_AUTO, kern_feature_overrides,
5096     CTLFLAG_RD | CTLFLAG_LOCKED, &kern_feature_overrides, 0, "Kernel feature override mask");
5097 
5098 /*
5099  * enable back trace for port allocations
5100  */
5101 extern int ipc_portbt;
5102 
5103 SYSCTL_INT(_kern, OID_AUTO, ipc_portbt,
5104     CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
5105     &ipc_portbt, 0, "");
5106 
5107 /*
5108  * Scheduler sysctls
5109  */
5110 
5111 SYSCTL_STRING(_kern, OID_AUTO, sched,
5112     CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
5113     sched_string, sizeof(sched_string),
5114     "Timeshare scheduler implementation");
5115 
5116 static int
5117 sysctl_cpu_quiescent_counter_interval SYSCTL_HANDLER_ARGS
5118 {
5119 #pragma unused(arg1, arg2)
5120 
5121 	uint32_t local_min_interval_us = smr_cpu_checkin_get_min_interval_us();
5122 
5123 	int error = sysctl_handle_int(oidp, &local_min_interval_us, 0, req);
5124 	if (error || !req->newptr) {
5125 		return error;
5126 	}
5127 
5128 	smr_cpu_checkin_set_min_interval_us(local_min_interval_us);
5129 
5130 	return 0;
5131 }
5132 
5133 SYSCTL_PROC(_kern, OID_AUTO, cpu_checkin_interval,
5134     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
5135     0, 0,
5136     sysctl_cpu_quiescent_counter_interval, "I",
5137     "Quiescent CPU checkin interval (microseconds)");
5138 
5139 /*
5140  * Allow the precise user/kernel time sysctl to be set, but don't allow it to
5141  * affect anything.  Some tools expect to be able to set this, even though
5142  * runtime configuration is no longer supported.
5143  */
5144 
5145 static int
5146 sysctl_precise_user_kernel_time SYSCTL_HANDLER_ARGS
5147 {
5148 #if PRECISE_USER_KERNEL_TIME
5149 	int dummy_set = 1;
5150 #else /* PRECISE_USER_KERNEL_TIME */
5151 	int dummy_set = 0;
5152 #endif /* !PRECISE_USER_KERNEL_TIME */
5153 	return sysctl_handle_int(oidp, &dummy_set, 0, req);
5154 }
5155 
5156 SYSCTL_PROC(_kern, OID_AUTO, precise_user_kernel_time,
5157     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
5158     0, 0, sysctl_precise_user_kernel_time, "I",
5159     "Precise accounting of kernel vs. user time (deprecated)");
5160 
5161 #if CONFIG_PERVASIVE_ENERGY && HAS_CPU_DPE_COUNTER
5162 __security_const_late static int pervasive_energy = 1;
5163 #else /* CONFIG_PERVASIVE_ENERGY && HAS_CPU_DPE_COUNTER */
5164 __security_const_late static int pervasive_energy = 0;
5165 #endif /* !CONFIG_PERVASIVE_ENERGY || !HAS_CPU_DPE_COUNTER */
5166 
5167 SYSCTL_INT(_kern, OID_AUTO, pervasive_energy,
5168     CTLFLAG_KERN | CTLFLAG_RD | CTLFLAG_LOCKED, &pervasive_energy, 0, "");
5169 
5170 /* Parameters related to timer coalescing tuning, to be replaced
5171  * with a dedicated systemcall in the future.
5172  */
5173 /* Enable processing pending timers in the context of any other interrupt
5174  * Coalescing tuning parameters for various thread/task attributes */
5175 STATIC int
5176 sysctl_timer_user_us_kernel_abstime SYSCTL_HANDLER_ARGS
5177 {
5178 #pragma unused(oidp)
5179 	int size = arg2;        /* subcommand*/
5180 	int error;
5181 	int changed = 0;
5182 	uint64_t old_value_ns;
5183 	uint64_t new_value_ns;
5184 	uint64_t value_abstime;
5185 	if (size == sizeof(uint32_t)) {
5186 		value_abstime = *((uint32_t *)arg1);
5187 	} else if (size == sizeof(uint64_t)) {
5188 		value_abstime = *((uint64_t *)arg1);
5189 	} else {
5190 		return ENOTSUP;
5191 	}
5192 
5193 	absolutetime_to_nanoseconds(value_abstime, &old_value_ns);
5194 	error = sysctl_io_number(req, old_value_ns, sizeof(old_value_ns), &new_value_ns, &changed);
5195 	if ((error) || (!changed)) {
5196 		return error;
5197 	}
5198 
5199 	nanoseconds_to_absolutetime(new_value_ns, &value_abstime);
5200 	if (size == sizeof(uint32_t)) {
5201 		*((uint32_t *)arg1) = (uint32_t)value_abstime;
5202 	} else {
5203 		*((uint64_t *)arg1) = value_abstime;
5204 	}
5205 	return error;
5206 }
5207 
5208 SYSCTL_INT(_kern, OID_AUTO, timer_coalesce_bg_scale,
5209     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
5210     &tcoal_prio_params.timer_coalesce_bg_shift, 0, "");
5211 SYSCTL_PROC(_kern, OID_AUTO, timer_resort_threshold_ns,
5212     CTLTYPE_QUAD | CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
5213     &tcoal_prio_params.timer_resort_threshold_abstime,
5214     sizeof(tcoal_prio_params.timer_resort_threshold_abstime),
5215     sysctl_timer_user_us_kernel_abstime,
5216     "Q", "");
5217 SYSCTL_PROC(_kern, OID_AUTO, timer_coalesce_bg_ns_max,
5218     CTLTYPE_QUAD | CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
5219     &tcoal_prio_params.timer_coalesce_bg_abstime_max,
5220     sizeof(tcoal_prio_params.timer_coalesce_bg_abstime_max),
5221     sysctl_timer_user_us_kernel_abstime,
5222     "Q", "");
5223 
5224 SYSCTL_INT(_kern, OID_AUTO, timer_coalesce_kt_scale,
5225     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
5226     &tcoal_prio_params.timer_coalesce_kt_shift, 0, "");
5227 
5228 SYSCTL_PROC(_kern, OID_AUTO, timer_coalesce_kt_ns_max,
5229     CTLTYPE_QUAD | CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
5230     &tcoal_prio_params.timer_coalesce_kt_abstime_max,
5231     sizeof(tcoal_prio_params.timer_coalesce_kt_abstime_max),
5232     sysctl_timer_user_us_kernel_abstime,
5233     "Q", "");
5234 
5235 SYSCTL_INT(_kern, OID_AUTO, timer_coalesce_fp_scale,
5236     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
5237     &tcoal_prio_params.timer_coalesce_fp_shift, 0, "");
5238 
5239 SYSCTL_PROC(_kern, OID_AUTO, timer_coalesce_fp_ns_max,
5240     CTLTYPE_QUAD | CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
5241     &tcoal_prio_params.timer_coalesce_fp_abstime_max,
5242     sizeof(tcoal_prio_params.timer_coalesce_fp_abstime_max),
5243     sysctl_timer_user_us_kernel_abstime,
5244     "Q", "");
5245 
5246 SYSCTL_INT(_kern, OID_AUTO, timer_coalesce_ts_scale,
5247     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
5248     &tcoal_prio_params.timer_coalesce_ts_shift, 0, "");
5249 
5250 SYSCTL_PROC(_kern, OID_AUTO, timer_coalesce_ts_ns_max,
5251     CTLTYPE_QUAD | CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
5252     &tcoal_prio_params.timer_coalesce_ts_abstime_max,
5253     sizeof(tcoal_prio_params.timer_coalesce_ts_abstime_max),
5254     sysctl_timer_user_us_kernel_abstime,
5255     "Q", "");
5256 
5257 SYSCTL_INT(_kern, OID_AUTO, timer_coalesce_tier0_scale,
5258     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
5259     &tcoal_prio_params.latency_qos_scale[0], 0, "");
5260 
5261 SYSCTL_PROC(_kern, OID_AUTO, timer_coalesce_tier0_ns_max,
5262     CTLTYPE_QUAD | CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
5263     &tcoal_prio_params.latency_qos_abstime_max[0],
5264     sizeof(tcoal_prio_params.latency_qos_abstime_max[0]),
5265     sysctl_timer_user_us_kernel_abstime,
5266     "Q", "");
5267 
5268 SYSCTL_INT(_kern, OID_AUTO, timer_coalesce_tier1_scale,
5269     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
5270     &tcoal_prio_params.latency_qos_scale[1], 0, "");
5271 
5272 SYSCTL_PROC(_kern, OID_AUTO, timer_coalesce_tier1_ns_max,
5273     CTLTYPE_QUAD | CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
5274     &tcoal_prio_params.latency_qos_abstime_max[1],
5275     sizeof(tcoal_prio_params.latency_qos_abstime_max[1]),
5276     sysctl_timer_user_us_kernel_abstime,
5277     "Q", "");
5278 
5279 SYSCTL_INT(_kern, OID_AUTO, timer_coalesce_tier2_scale,
5280     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
5281     &tcoal_prio_params.latency_qos_scale[2], 0, "");
5282 
5283 SYSCTL_PROC(_kern, OID_AUTO, timer_coalesce_tier2_ns_max,
5284     CTLTYPE_QUAD | CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
5285     &tcoal_prio_params.latency_qos_abstime_max[2],
5286     sizeof(tcoal_prio_params.latency_qos_abstime_max[2]),
5287     sysctl_timer_user_us_kernel_abstime,
5288     "Q", "");
5289 
5290 SYSCTL_INT(_kern, OID_AUTO, timer_coalesce_tier3_scale,
5291     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
5292     &tcoal_prio_params.latency_qos_scale[3], 0, "");
5293 
5294 SYSCTL_PROC(_kern, OID_AUTO, timer_coalesce_tier3_ns_max,
5295     CTLTYPE_QUAD | CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
5296     &tcoal_prio_params.latency_qos_abstime_max[3],
5297     sizeof(tcoal_prio_params.latency_qos_abstime_max[3]),
5298     sysctl_timer_user_us_kernel_abstime,
5299     "Q", "");
5300 
5301 SYSCTL_INT(_kern, OID_AUTO, timer_coalesce_tier4_scale,
5302     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
5303     &tcoal_prio_params.latency_qos_scale[4], 0, "");
5304 
5305 SYSCTL_PROC(_kern, OID_AUTO, timer_coalesce_tier4_ns_max,
5306     CTLTYPE_QUAD | CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
5307     &tcoal_prio_params.latency_qos_abstime_max[4],
5308     sizeof(tcoal_prio_params.latency_qos_abstime_max[4]),
5309     sysctl_timer_user_us_kernel_abstime,
5310     "Q", "");
5311 
5312 SYSCTL_INT(_kern, OID_AUTO, timer_coalesce_tier5_scale,
5313     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
5314     &tcoal_prio_params.latency_qos_scale[5], 0, "");
5315 
5316 SYSCTL_PROC(_kern, OID_AUTO, timer_coalesce_tier5_ns_max,
5317     CTLTYPE_QUAD | CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
5318     &tcoal_prio_params.latency_qos_abstime_max[5],
5319     sizeof(tcoal_prio_params.latency_qos_abstime_max[5]),
5320     sysctl_timer_user_us_kernel_abstime,
5321     "Q", "");
5322 
5323 /* Communicate the "user idle level" heuristic to the timer layer, and
5324  * potentially other layers in the future.
5325  */
5326 
5327 static int
5328 timer_user_idle_level(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
5329 {
5330 	int new_value = 0, old_value = 0, changed = 0, error;
5331 
5332 	old_value = timer_get_user_idle_level();
5333 
5334 	error = sysctl_io_number(req, old_value, sizeof(int), &new_value, &changed);
5335 
5336 	if (error == 0 && changed) {
5337 		if (timer_set_user_idle_level(new_value) != KERN_SUCCESS) {
5338 			error = ERANGE;
5339 		}
5340 	}
5341 
5342 	return error;
5343 }
5344 
5345 SYSCTL_PROC(_machdep, OID_AUTO, user_idle_level,
5346     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
5347     0, 0,
5348     timer_user_idle_level, "I", "User idle level heuristic, 0-128");
5349 
5350 #if DEVELOPMENT || DEBUG
5351 /*
5352  * Basic console mode for games; used for development purposes only.
5353  * Final implementation for this feature (with possible removal of
5354  * sysctl) tracked via rdar://101215873.
5355  */
5356 static int console_mode = 0;
5357 SYSCTL_INT(_kern, OID_AUTO, console_mode,
5358     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED | CTLFLAG_MASKED,
5359     &console_mode, 0, "Game Console Mode");
5360 #endif /* DEVELOPMENT || DEBUG */
5361 
5362 
5363 #if HYPERVISOR
5364 SYSCTL_INT(_kern, OID_AUTO, hv_support,
5365     CTLFLAG_KERN | CTLFLAG_RD | CTLFLAG_LOCKED,
5366     &hv_support_available, 0, "");
5367 
5368 SYSCTL_INT(_kern, OID_AUTO, hv_disable,
5369     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
5370     &hv_disable, 0, "");
5371 
5372 #endif /* HYPERVISOR */
5373 
5374 #if DEVELOPMENT || DEBUG
5375 extern uint64_t driverkit_checkin_timed_out;
5376 SYSCTL_QUAD(_kern, OID_AUTO, driverkit_checkin_timed_out,
5377     CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
5378     &driverkit_checkin_timed_out, "timestamp of dext checkin timeout");
5379 #endif
5380 
5381 #if CONFIG_DARKBOOT
5382 STATIC int
5383 sysctl_darkboot SYSCTL_HANDLER_ARGS
5384 {
5385 	int err = 0, value = 0;
5386 #pragma unused(oidp, arg1, arg2, err, value, req)
5387 
5388 	/*
5389 	 * Handle the sysctl request.
5390 	 *
5391 	 * If this is a read, the function will set the value to the current darkboot value. Otherwise,
5392 	 * we'll get the request identifier into "value" and then we can honor it.
5393 	 */
5394 	if ((err = sysctl_io_number(req, darkboot, sizeof(int), &value, NULL)) != 0) {
5395 		goto exit;
5396 	}
5397 
5398 	/* writing requested, let's process the request */
5399 	if (req->newptr) {
5400 		/* writing is protected by an entitlement */
5401 		if (priv_check_cred(kauth_cred_get(), PRIV_DARKBOOT, 0) != 0) {
5402 			err = EPERM;
5403 			goto exit;
5404 		}
5405 
5406 		switch (value) {
5407 		case MEMORY_MAINTENANCE_DARK_BOOT_UNSET:
5408 			/*
5409 			 * If the darkboot sysctl is unset, the NVRAM variable
5410 			 * must be unset too. If that's not the case, it means
5411 			 * someone is doing something crazy and not supported.
5412 			 */
5413 			if (darkboot != 0) {
5414 				int ret = PERemoveNVRAMProperty(MEMORY_MAINTENANCE_DARK_BOOT_NVRAM_NAME);
5415 				if (ret) {
5416 					darkboot = 0;
5417 				} else {
5418 					err = EINVAL;
5419 				}
5420 			}
5421 			break;
5422 		case MEMORY_MAINTENANCE_DARK_BOOT_SET:
5423 			darkboot = 1;
5424 			break;
5425 		case MEMORY_MAINTENANCE_DARK_BOOT_SET_PERSISTENT: {
5426 			/*
5427 			 * Set the NVRAM and update 'darkboot' in case
5428 			 * of success. Otherwise, do not update
5429 			 * 'darkboot' and report the failure.
5430 			 */
5431 			if (PEWriteNVRAMBooleanProperty(MEMORY_MAINTENANCE_DARK_BOOT_NVRAM_NAME, TRUE)) {
5432 				darkboot = 1;
5433 			} else {
5434 				err = EINVAL;
5435 			}
5436 
5437 			break;
5438 		}
5439 		default:
5440 			err = EINVAL;
5441 		}
5442 	}
5443 
5444 exit:
5445 	return err;
5446 }
5447 
5448 SYSCTL_PROC(_kern, OID_AUTO, darkboot,
5449     CTLFLAG_KERN | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
5450     0, 0, sysctl_darkboot, "I", "");
5451 #endif /* CONFIG_DARKBOOT */
5452 
5453 #if DEVELOPMENT || DEBUG
5454 #include <sys/sysent.h>
5455 /* This should result in a fatal exception, verifying that "sysent" is
5456  * write-protected.
5457  */
5458 static int
5459 kern_sysent_write(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
5460 {
5461 	uint64_t new_value = 0, old_value = 0;
5462 	int changed = 0, error;
5463 
5464 	error = sysctl_io_number(req, old_value, sizeof(uint64_t), &new_value, &changed);
5465 	if ((error == 0) && changed) {
5466 		volatile uint32_t *wraddr = __DECONST(uint32_t *, &sysent[0]);
5467 		*wraddr = 0;
5468 		printf("sysent[0] write succeeded\n");
5469 	}
5470 	return error;
5471 }
5472 
5473 SYSCTL_PROC(_kern, OID_AUTO, sysent_const_check,
5474     CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED,
5475     0, 0,
5476     kern_sysent_write, "I", "Attempt sysent[0] write");
5477 
5478 #endif
5479 
5480 #if DEVELOPMENT || DEBUG
5481 SYSCTL_COMPAT_INT(_kern, OID_AUTO, development, CTLFLAG_RD | CTLFLAG_MASKED | CTLFLAG_KERN, NULL, 1, "");
5482 #else
5483 SYSCTL_COMPAT_INT(_kern, OID_AUTO, development, CTLFLAG_RD | CTLFLAG_MASKED, NULL, 0, "");
5484 #endif
5485 
5486 SYSCTL_INT(_kern, OID_AUTO, serverperfmode, CTLFLAG_RD, &serverperfmode, 0, "");
5487 
5488 #if DEVELOPMENT || DEBUG
5489 
5490 decl_lck_spin_data(, spinlock_panic_test_lock);
5491 
5492 __attribute__((noreturn))
5493 static void
5494 spinlock_panic_test_acquire_spinlock(void * arg __unused, wait_result_t wres __unused)
5495 {
5496 	lck_spin_lock(&spinlock_panic_test_lock);
5497 	while (1) {
5498 		;
5499 	}
5500 }
5501 
5502 static int
5503 sysctl_spinlock_panic_test SYSCTL_HANDLER_ARGS
5504 {
5505 #pragma unused(oidp, arg1, arg2)
5506 	if (req->newlen == 0) {
5507 		return EINVAL;
5508 	}
5509 
5510 	thread_t panic_spinlock_thread;
5511 	/* Initialize panic spinlock */
5512 	lck_grp_t * panic_spinlock_grp;
5513 	lck_grp_attr_t * panic_spinlock_grp_attr;
5514 	lck_attr_t * panic_spinlock_attr;
5515 
5516 	panic_spinlock_grp_attr = lck_grp_attr_alloc_init();
5517 	panic_spinlock_grp = lck_grp_alloc_init("panic_spinlock", panic_spinlock_grp_attr);
5518 	panic_spinlock_attr = lck_attr_alloc_init();
5519 
5520 	lck_spin_init(&spinlock_panic_test_lock, panic_spinlock_grp, panic_spinlock_attr);
5521 
5522 
5523 	/* Create thread to acquire spinlock */
5524 	if (kernel_thread_start(spinlock_panic_test_acquire_spinlock, NULL, &panic_spinlock_thread) != KERN_SUCCESS) {
5525 		return EBUSY;
5526 	}
5527 
5528 	/* Try to acquire spinlock -- should panic eventually */
5529 	lck_spin_lock(&spinlock_panic_test_lock);
5530 	while (1) {
5531 		;
5532 	}
5533 }
5534 
5535 __attribute__((noreturn))
5536 static void
5537 simultaneous_panic_worker
5538 (void * arg, wait_result_t wres __unused)
5539 {
5540 	atomic_int *start_panic = (atomic_int *)arg;
5541 
5542 	while (!atomic_load(start_panic)) {
5543 		;
5544 	}
5545 	panic("SIMULTANEOUS PANIC TEST: INITIATING PANIC FROM CPU %d", cpu_number());
5546 	__builtin_unreachable();
5547 }
5548 
5549 static int
5550 sysctl_simultaneous_panic_test SYSCTL_HANDLER_ARGS
5551 {
5552 #pragma unused(oidp, arg1, arg2)
5553 	if (req->newlen == 0) {
5554 		return EINVAL;
5555 	}
5556 
5557 	int i = 0, threads_to_create = 2 * processor_count;
5558 	atomic_int start_panic = 0;
5559 	unsigned int threads_created = 0;
5560 	thread_t new_panic_thread;
5561 
5562 	for (i = threads_to_create; i > 0; i--) {
5563 		if (kernel_thread_start(simultaneous_panic_worker, (void *) &start_panic, &new_panic_thread) == KERN_SUCCESS) {
5564 			threads_created++;
5565 		}
5566 	}
5567 
5568 	/* FAIL if we couldn't create at least processor_count threads */
5569 	if (threads_created < processor_count) {
5570 		panic("SIMULTANEOUS PANIC TEST: FAILED TO CREATE ENOUGH THREADS, ONLY CREATED %d (of %d)",
5571 		    threads_created, threads_to_create);
5572 	}
5573 
5574 	atomic_exchange(&start_panic, 1);
5575 	while (1) {
5576 		;
5577 	}
5578 }
5579 
5580 extern unsigned int panic_test_failure_mode;
5581 SYSCTL_INT(_debug, OID_AUTO, xnu_panic_failure_mode, CTLFLAG_RW | CTLFLAG_LOCKED | CTLFLAG_KERN, &panic_test_failure_mode, 0, "panic/debugger test failure mode");
5582 
5583 extern unsigned int panic_test_action_count;
5584 SYSCTL_INT(_debug, OID_AUTO, xnu_panic_action_count, CTLFLAG_RW | CTLFLAG_LOCKED | CTLFLAG_KERN, &panic_test_action_count, 0, "panic/debugger test action count");
5585 
5586 extern unsigned int panic_test_case;
5587 SYSCTL_INT(_debug, OID_AUTO, xnu_panic_test_case, CTLFLAG_RW | CTLFLAG_LOCKED | CTLFLAG_KERN, &panic_test_case, 0, "panic/debugger testcase");
5588 
5589 SYSCTL_PROC(_debug, OID_AUTO, xnu_spinlock_panic_test, CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_MASKED, 0, 0, sysctl_spinlock_panic_test, "A", "spinlock panic test");
5590 SYSCTL_PROC(_debug, OID_AUTO, xnu_simultaneous_panic_test, CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_MASKED, 0, 0, sysctl_simultaneous_panic_test, "A", "simultaneous panic test");
5591 
5592 #if HAS_UPSI_FAILURE_INJECTION
5593 extern uint64_t xnu_upsi_injection_stage;
5594 SYSCTL_QUAD(_debug, OID_AUTO, xnu_upsi_injection_stage, CTLFLAG_RW | CTLFLAG_LOCKED | CTLFLAG_KERN, &xnu_upsi_injection_stage, "UPSI failure injection stage");
5595 
5596 extern uint64_t xnu_upsi_injection_action;
5597 SYSCTL_QUAD(_debug, OID_AUTO, xnu_upsi_injection_action, CTLFLAG_RW | CTLFLAG_LOCKED | CTLFLAG_KERN, &xnu_upsi_injection_action, "UPSI failure injection action");
5598 #endif /* HAS_UPSI_FAILURE_INJECTION */
5599 
5600 extern int exc_resource_threads_enabled;
5601 SYSCTL_INT(_kern, OID_AUTO, exc_resource_threads_enabled, CTLFLAG_RW | CTLFLAG_LOCKED, &exc_resource_threads_enabled, 0, "exc_resource thread limit enabled");
5602 
5603 extern unsigned int verbose_panic_flow_logging;
5604 SYSCTL_INT(_debug, OID_AUTO, verbose_panic_flow_logging, CTLFLAG_RW | CTLFLAG_LOCKED | CTLFLAG_KERN, &verbose_panic_flow_logging, 0, "verbose logging during panic");
5605 
5606 #endif /* DEVELOPMENT || DEBUG */
5607 
5608 #if BUILT_LTO
5609 static int _built_lto = 1;
5610 #else // BUILT_LTO
5611 static int _built_lto = 0;
5612 #endif // !BUILT_LTO
5613 
5614 SYSCTL_INT(_kern, OID_AUTO, link_time_optimized, CTLFLAG_RD | CTLFLAG_LOCKED | CTLFLAG_KERN, &_built_lto, 0, "Whether the kernel was built with Link Time Optimization enabled");
5615 
5616 #if CONFIG_THREAD_GROUPS
5617 #if DEVELOPMENT || DEBUG
5618 
5619 static int
5620 sysctl_get_thread_group_id SYSCTL_HANDLER_ARGS
5621 {
5622 #pragma unused(arg1, arg2, oidp)
5623 	uint64_t thread_group_id = thread_group_get_id(thread_group_get(current_thread()));
5624 	return SYSCTL_OUT(req, &thread_group_id, sizeof(thread_group_id));
5625 }
5626 
5627 SYSCTL_PROC(_kern, OID_AUTO, thread_group_id, CTLFLAG_RD | CTLFLAG_LOCKED | CTLTYPE_QUAD,
5628     0, 0, &sysctl_get_thread_group_id, "I", "thread group id of the thread");
5629 
5630 extern kern_return_t sysctl_clutch_thread_group_cpu_time_for_thread(thread_t thread, int sched_bucket, uint64_t *cpu_stats);
5631 
5632 static int
5633 sysctl_get_clutch_bucket_group_cpu_stats SYSCTL_HANDLER_ARGS
5634 {
5635 	int error;
5636 	kern_return_t kr;
5637 	int sched_bucket = -1;
5638 	error = SYSCTL_IN(req, &sched_bucket, sizeof(sched_bucket));
5639 	if (error) {
5640 		return error;
5641 	}
5642 	uint64_t cpu_stats[2];
5643 	kr = sysctl_clutch_thread_group_cpu_time_for_thread(current_thread(), sched_bucket, cpu_stats);
5644 	error = mach_to_bsd_errno(kr);
5645 	if (error) {
5646 		return error;
5647 	}
5648 	return SYSCTL_OUT(req, cpu_stats, sizeof(cpu_stats));
5649 }
5650 
5651 SYSCTL_PROC(_kern, OID_AUTO, clutch_bucket_group_cpu_stats, CTLFLAG_RW | CTLFLAG_LOCKED | CTLTYPE_OPAQUE,
5652     0, 0, &sysctl_get_clutch_bucket_group_cpu_stats, "I",
5653     "CPU used and blocked time for the current thread group at a specified scheduling bucket");
5654 
5655 STATIC int
5656 sysctl_thread_group_count(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
5657 {
5658 	int value = thread_group_count();
5659 	return sysctl_io_number(req, value, sizeof(value), NULL, NULL);
5660 }
5661 
5662 SYSCTL_PROC(_kern, OID_AUTO, thread_group_count, CTLFLAG_RD | CTLFLAG_LOCKED | CTLFLAG_KERN,
5663     0, 0, &sysctl_thread_group_count, "I", "count of thread groups");
5664 
5665 #endif /* DEVELOPMENT || DEBUG */
5666 const uint32_t thread_groups_supported = 1;
5667 #else /* CONFIG_THREAD_GROUPS */
5668 const uint32_t thread_groups_supported = 0;
5669 #endif /* CONFIG_THREAD_GROUPS */
5670 
5671 STATIC int
5672 sysctl_thread_groups_supported(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
5673 {
5674 	int value = thread_groups_supported;
5675 	return sysctl_io_number(req, value, sizeof(value), NULL, NULL);
5676 }
5677 
5678 SYSCTL_PROC(_kern, OID_AUTO, thread_groups_supported, CTLFLAG_RD | CTLFLAG_LOCKED | CTLFLAG_KERN,
5679     0, 0, &sysctl_thread_groups_supported, "I", "thread groups supported");
5680 
5681 static int
5682 sysctl_grade_cputype SYSCTL_HANDLER_ARGS
5683 {
5684 #pragma unused(arg1, arg2, oidp)
5685 	int error = 0;
5686 	int type_tuple[2] = {};
5687 	int return_value = 0;
5688 
5689 	error = SYSCTL_IN(req, &type_tuple, sizeof(type_tuple));
5690 
5691 	if (error) {
5692 		return error;
5693 	}
5694 
5695 	return_value = grade_binary(type_tuple[0], type_tuple[1] & ~CPU_SUBTYPE_MASK, type_tuple[1] & CPU_SUBTYPE_MASK, FALSE);
5696 
5697 	error = SYSCTL_OUT(req, &return_value, sizeof(return_value));
5698 
5699 	if (error) {
5700 		return error;
5701 	}
5702 
5703 	return error;
5704 }
5705 
5706 SYSCTL_PROC(_kern, OID_AUTO, grade_cputype,
5707     CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED | CTLTYPE_OPAQUE,
5708     0, 0, &sysctl_grade_cputype, "S",
5709     "grade value of cpu_type_t+cpu_sub_type_t");
5710 
5711 
5712 #if DEVELOPMENT || DEBUG
5713 STATIC int
5714 sysctl_binary_grade_override(  __unused struct sysctl_oid *oidp, __unused void *arg1,
5715     __unused int arg2, struct sysctl_req *req)
5716 {
5717 	int error;
5718 	user_addr_t oldp = 0, newp = 0;
5719 	size_t *oldlenp = NULL;
5720 	size_t newlen = 0;
5721 
5722 	oldp = req->oldptr;
5723 	oldlenp = &(req->oldlen);
5724 	newp = req->newptr;
5725 	newlen = req->newlen;
5726 
5727 	/* We want the current length, and maybe the string itself */
5728 	if (oldlenp) {
5729 		char existing_overrides[256] = { 0 };
5730 
5731 		size_t currlen = bingrade_get_override_string(existing_overrides, sizeof(existing_overrides));
5732 
5733 		if (oldp && currlen > 0) {
5734 			if (*oldlenp < currlen) {
5735 				return ENOMEM;
5736 			}
5737 			/* NOTE - we do not copy the NULL terminator */
5738 			error = copyout(existing_overrides, oldp, currlen);
5739 			if (error) {
5740 				return error;
5741 			}
5742 		}
5743 		/* return length of overrides minus the NULL terminator (just like strlen)  */
5744 		req->oldidx = currlen;
5745 	}
5746 
5747 	/* We want to set the override string to something */
5748 	if (newp) {
5749 		char *tmp_override = (char *)kalloc_data(newlen + 1, Z_WAITOK | Z_ZERO);
5750 		if (!tmp_override) {
5751 			return ENOMEM;
5752 		}
5753 
5754 		error = copyin(newp, tmp_override, newlen);
5755 		if (error) {
5756 			kfree_data(tmp_override, newlen + 1);
5757 			return error;
5758 		}
5759 
5760 		tmp_override[newlen] = 0;       /* Terminate string */
5761 
5762 		/* Set the binary grading overrides */
5763 		if (binary_grade_overrides_update(tmp_override) == 0) {
5764 			/* Nothing got set. */
5765 			kfree_data(tmp_override, newlen + 1);
5766 			return EINVAL;
5767 		}
5768 
5769 		kfree_data(tmp_override, newlen + 1);
5770 	}
5771 
5772 	return 0;
5773 }
5774 
5775 
5776 SYSCTL_PROC(_kern, OID_AUTO, grade_override,
5777     CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_LOCKED,
5778     0, 0, &sysctl_binary_grade_override, "A",
5779     "");
5780 #endif /* DEVELOPMENT || DEBUG */
5781 
5782 extern boolean_t allow_direct_handoff;
5783 SYSCTL_INT(_kern, OID_AUTO, direct_handoff,
5784     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
5785     &allow_direct_handoff, 0, "Enable direct handoff for realtime threads");
5786 
5787 #if DEVELOPMENT || DEBUG
5788 
5789 SYSCTL_QUAD(_kern, OID_AUTO, phys_carveout_pa, CTLFLAG_RD | CTLFLAG_LOCKED | CTLFLAG_KERN,
5790     &phys_carveout_pa,
5791     "base physical address of the phys_carveout_mb boot-arg region");
5792 SYSCTL_QUAD(_kern, OID_AUTO, phys_carveout_va, CTLFLAG_RD | CTLFLAG_LOCKED | CTLFLAG_KERN,
5793     &phys_carveout,
5794     "base virtual address of the phys_carveout_mb boot-arg region");
5795 SYSCTL_QUAD(_kern, OID_AUTO, phys_carveout_size, CTLFLAG_RD | CTLFLAG_LOCKED | CTLFLAG_KERN,
5796     &phys_carveout_size,
5797     "size in bytes of the phys_carveout_mb boot-arg region");
5798 
5799 
5800 
5801 static int
5802 cseg_wedge_thread SYSCTL_HANDLER_ARGS
5803 {
5804 #pragma unused(arg1, arg2)
5805 
5806 	int error, val = 0;
5807 	error = sysctl_handle_int(oidp, &val, 0, req);
5808 	if (error || val == 0) {
5809 		return error;
5810 	}
5811 
5812 	do_cseg_wedge_thread();
5813 	return 0;
5814 }
5815 SYSCTL_PROC(_kern, OID_AUTO, cseg_wedge_thread, CTLFLAG_RW | CTLFLAG_LOCKED | CTLFLAG_MASKED, 0, 0, cseg_wedge_thread, "I", "wedge c_seg thread");
5816 
5817 static int
5818 cseg_unwedge_thread SYSCTL_HANDLER_ARGS
5819 {
5820 #pragma unused(arg1, arg2)
5821 
5822 	int error, val = 0;
5823 	error = sysctl_handle_int(oidp, &val, 0, req);
5824 	if (error || val == 0) {
5825 		return error;
5826 	}
5827 
5828 	do_cseg_unwedge_thread();
5829 	return 0;
5830 }
5831 SYSCTL_PROC(_kern, OID_AUTO, cseg_unwedge_thread, CTLFLAG_RW | CTLFLAG_LOCKED | CTLFLAG_MASKED, 0, 0, cseg_unwedge_thread, "I", "unstuck c_seg thread");
5832 
5833 static atomic_int wedge_thread_should_wake = 0;
5834 
5835 static int
5836 unwedge_thread SYSCTL_HANDLER_ARGS
5837 {
5838 #pragma unused(arg1, arg2)
5839 	int error, val = 0;
5840 	error = sysctl_handle_int(oidp, &val, 0, req);
5841 	if (error || val == 0) {
5842 		return error;
5843 	}
5844 
5845 	atomic_store(&wedge_thread_should_wake, 1);
5846 	return 0;
5847 }
5848 
5849 SYSCTL_PROC(_kern, OID_AUTO, unwedge_thread, CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED, 0, 0, unwedge_thread, "I", "unwedge the thread wedged by kern.wedge_thread");
5850 
5851 static int
5852 wedge_thread SYSCTL_HANDLER_ARGS
5853 {
5854 #pragma unused(arg1, arg2)
5855 
5856 	int error, val = 0;
5857 	error = sysctl_handle_int(oidp, &val, 0, req);
5858 	if (error || val == 0) {
5859 		return error;
5860 	}
5861 
5862 	uint64_t interval = 1;
5863 	nanoseconds_to_absolutetime(1000 * 1000 * 50, &interval);
5864 
5865 	atomic_store(&wedge_thread_should_wake, 0);
5866 	while (!atomic_load(&wedge_thread_should_wake)) {
5867 		tsleep1(NULL, 0, "wedge_thread", mach_absolute_time() + interval, NULL);
5868 	}
5869 
5870 	return 0;
5871 }
5872 
5873 SYSCTL_PROC(_kern, OID_AUTO, wedge_thread,
5874     CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED, 0, 0, wedge_thread, "I",
5875     "wedge this thread so it cannot be cleaned up");
5876 
5877 static int
5878 sysctl_total_corpses_count SYSCTL_HANDLER_ARGS
5879 {
5880 #pragma unused(oidp, arg1, arg2)
5881 	extern unsigned long total_corpses_count(void);
5882 
5883 	unsigned long corpse_count_long = total_corpses_count();
5884 	unsigned int corpse_count = (unsigned int)MIN(corpse_count_long, UINT_MAX);
5885 	return sysctl_io_opaque(req, &corpse_count, sizeof(corpse_count), NULL);
5886 }
5887 
5888 SYSCTL_PROC(_kern, OID_AUTO, total_corpses_count,
5889     CTLFLAG_RD | CTLFLAG_ANYBODY | CTLFLAG_LOCKED, 0, 0,
5890     sysctl_total_corpses_count, "I", "total corpses on the system");
5891 
5892 static int
5893 sysctl_turnstile_test_prim_lock SYSCTL_HANDLER_ARGS;
5894 static int
5895 sysctl_turnstile_test_prim_unlock SYSCTL_HANDLER_ARGS;
5896 int
5897 tstile_test_prim_lock(boolean_t use_hashtable);
5898 int
5899 tstile_test_prim_unlock(boolean_t use_hashtable);
5900 
5901 static int
5902 sysctl_turnstile_test_prim_lock SYSCTL_HANDLER_ARGS
5903 {
5904 #pragma unused(arg1, arg2)
5905 	int error, val = 0;
5906 	error = sysctl_handle_int(oidp, &val, 0, req);
5907 	if (error || val == 0) {
5908 		return error;
5909 	}
5910 	switch (val) {
5911 	case SYSCTL_TURNSTILE_TEST_USER_DEFAULT:
5912 	case SYSCTL_TURNSTILE_TEST_USER_HASHTABLE:
5913 	case SYSCTL_TURNSTILE_TEST_KERNEL_DEFAULT:
5914 	case SYSCTL_TURNSTILE_TEST_KERNEL_HASHTABLE:
5915 		return tstile_test_prim_lock(val);
5916 	default:
5917 		return error;
5918 	}
5919 }
5920 
5921 static int
5922 sysctl_turnstile_test_prim_unlock SYSCTL_HANDLER_ARGS
5923 {
5924 #pragma unused(arg1, arg2)
5925 	int error, val = 0;
5926 	error = sysctl_handle_int(oidp, &val, 0, req);
5927 	if (error || val == 0) {
5928 		return error;
5929 	}
5930 	switch (val) {
5931 	case SYSCTL_TURNSTILE_TEST_USER_DEFAULT:
5932 	case SYSCTL_TURNSTILE_TEST_USER_HASHTABLE:
5933 	case SYSCTL_TURNSTILE_TEST_KERNEL_DEFAULT:
5934 	case SYSCTL_TURNSTILE_TEST_KERNEL_HASHTABLE:
5935 		return tstile_test_prim_unlock(val);
5936 	default:
5937 		return error;
5938 	}
5939 }
5940 
5941 SYSCTL_PROC(_kern, OID_AUTO, turnstiles_test_lock, CTLFLAG_WR | CTLFLAG_ANYBODY | CTLFLAG_KERN | CTLFLAG_LOCKED,
5942     0, 0, sysctl_turnstile_test_prim_lock, "I", "turnstiles test lock");
5943 
5944 SYSCTL_PROC(_kern, OID_AUTO, turnstiles_test_unlock, CTLFLAG_WR | CTLFLAG_ANYBODY | CTLFLAG_KERN | CTLFLAG_LOCKED,
5945     0, 0, sysctl_turnstile_test_prim_unlock, "I", "turnstiles test unlock");
5946 
5947 int
5948 turnstile_get_boost_stats_sysctl(void *req);
5949 int
5950 turnstile_get_unboost_stats_sysctl(void *req);
5951 static int
5952 sysctl_turnstile_boost_stats SYSCTL_HANDLER_ARGS;
5953 static int
5954 sysctl_turnstile_unboost_stats SYSCTL_HANDLER_ARGS;
5955 extern uint64_t thread_block_on_turnstile_count;
5956 extern uint64_t thread_block_on_regular_waitq_count;
5957 
5958 static int
5959 sysctl_turnstile_boost_stats SYSCTL_HANDLER_ARGS
5960 {
5961 #pragma unused(arg1, arg2, oidp)
5962 	return turnstile_get_boost_stats_sysctl(req);
5963 }
5964 
5965 static int
5966 sysctl_turnstile_unboost_stats SYSCTL_HANDLER_ARGS
5967 {
5968 #pragma unused(arg1, arg2, oidp)
5969 	return turnstile_get_unboost_stats_sysctl(req);
5970 }
5971 
5972 SYSCTL_PROC(_kern, OID_AUTO, turnstile_boost_stats, CTLFLAG_RD | CTLFLAG_ANYBODY | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLTYPE_STRUCT,
5973     0, 0, sysctl_turnstile_boost_stats, "S", "turnstiles boost stats");
5974 SYSCTL_PROC(_kern, OID_AUTO, turnstile_unboost_stats, CTLFLAG_RD | CTLFLAG_ANYBODY | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLTYPE_STRUCT,
5975     0, 0, sysctl_turnstile_unboost_stats, "S", "turnstiles unboost stats");
5976 SYSCTL_QUAD(_kern, OID_AUTO, thread_block_count_on_turnstile,
5977     CTLFLAG_RD | CTLFLAG_ANYBODY | CTLFLAG_KERN | CTLFLAG_LOCKED,
5978     &thread_block_on_turnstile_count, "thread blocked on turnstile count");
5979 SYSCTL_QUAD(_kern, OID_AUTO, thread_block_count_on_reg_waitq,
5980     CTLFLAG_RD | CTLFLAG_ANYBODY | CTLFLAG_KERN | CTLFLAG_LOCKED,
5981     &thread_block_on_regular_waitq_count, "thread blocked on regular waitq count");
5982 
5983 #if CONFIG_PV_TICKET
5984 
5985 extern int ticket_lock_spins;
5986 SYSCTL_INT(_kern, OID_AUTO, ticket_lock_spins,
5987     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
5988     &ticket_lock_spins, 0, "loops before hypercall");
5989 
5990 #if (DEBUG || DEVELOPMENT)
5991 
5992 /* PV ticket lock stats */
5993 
5994 SYSCTL_SCALABLE_COUNTER(_kern, ticket_lock_kicks, ticket_kick_count,
5995     "ticket lock kicks");
5996 SYSCTL_SCALABLE_COUNTER(_kern, ticket_lock_waits, ticket_wait_count,
5997     "ticket lock waits");
5998 SYSCTL_SCALABLE_COUNTER(_kern, ticket_lock_already, ticket_already_count,
5999     "ticket lock already unlocked");
6000 SYSCTL_SCALABLE_COUNTER(_kern, ticket_lock_just_unlock, ticket_just_unlock,
6001     "ticket unlock without kick");
6002 SYSCTL_SCALABLE_COUNTER(_kern, ticket_lock_wflag_cleared, ticket_wflag_cleared,
6003     "ticket lock wait flag cleared");
6004 SYSCTL_SCALABLE_COUNTER(_kern, ticket_lock_wflag_still, ticket_wflag_still,
6005     "ticket lock wait flag not cleared");
6006 SYSCTL_SCALABLE_COUNTER(_kern, ticket_lock_spin_count, ticket_spin_count,
6007     "ticket lock spin count");
6008 
6009 /* sysctl kern.hcall_probe=n -- does hypercall #n exist? */
6010 
6011 static int
6012 sysctl_hcall_probe SYSCTL_HANDLER_ARGS
6013 {
6014 	char instr[20];
6015 
6016 	if (!req->newptr) {
6017 		return 0;
6018 	}
6019 	if (req->newlen >= sizeof(instr)) {
6020 		return EOVERFLOW;
6021 	}
6022 
6023 	int error = SYSCTL_IN(req, instr, req->newlen);
6024 	if (error) {
6025 		return error;
6026 	}
6027 	instr[req->newlen] = '\0';
6028 
6029 	int hcall = 0;
6030 	error = sscanf(instr, "%d", &hcall);
6031 	if (error != 1 || hcall < 0) {
6032 		return EINVAL;
6033 	}
6034 	uprintf("%savailable\n",
6035 	    hvg_is_hcall_available((hvg_hcall_code_t)hcall) ? "" : "not ");
6036 	return 0;
6037 }
6038 
6039 SYSCTL_PROC(_kern, OID_AUTO, hcall_probe,
6040     CTLTYPE_STRING | CTLFLAG_WR | CTLFLAG_LOCKED | CTLFLAG_MASKED,
6041     0, 0, sysctl_hcall_probe, "A", "probe hypercall by id");
6042 
6043 #endif /* (DEBUG || DEVELOPMENT) */
6044 #endif /* CONFIG_PV_TICKET */
6045 
6046 #if defined(__x86_64__)
6047 extern uint64_t MutexSpin;
6048 
6049 SYSCTL_QUAD(_kern, OID_AUTO, mutex_spin_abs, CTLFLAG_RW, &MutexSpin,
6050     "Spin time in abs for acquiring a kernel mutex");
6051 #else
6052 extern machine_timeout_t MutexSpin;
6053 
6054 SYSCTL_QUAD(_kern, OID_AUTO, mutex_spin_abs, CTLFLAG_RW, &MutexSpin,
6055     "Spin time in abs for acquiring a kernel mutex");
6056 #endif
6057 
6058 extern uint64_t low_MutexSpin;
6059 extern int64_t high_MutexSpin;
6060 extern unsigned int real_ncpus;
6061 
6062 SYSCTL_QUAD(_kern, OID_AUTO, low_mutex_spin_abs, CTLFLAG_RW, &low_MutexSpin,
6063     "Low spin threshold in abs for acquiring a kernel mutex");
6064 
6065 static int
6066 sysctl_high_mutex_spin_ns SYSCTL_HANDLER_ARGS
6067 {
6068 #pragma unused(oidp, arg1, arg2)
6069 	int error;
6070 	int64_t val = 0;
6071 	int64_t res;
6072 
6073 	/* Check if the user is writing to high_MutexSpin, or just reading it */
6074 	if (req->newptr) {
6075 		error = SYSCTL_IN(req, &val, sizeof(val));
6076 		if (error || (val < 0 && val != -1)) {
6077 			return error;
6078 		}
6079 		high_MutexSpin = val;
6080 	}
6081 
6082 	if (high_MutexSpin >= 0) {
6083 		res = high_MutexSpin;
6084 	} else {
6085 		res = low_MutexSpin * real_ncpus;
6086 	}
6087 	return SYSCTL_OUT(req, &res, sizeof(res));
6088 }
6089 SYSCTL_PROC(_kern, OID_AUTO, high_mutex_spin_abs, CTLFLAG_RW | CTLTYPE_QUAD, 0, 0, sysctl_high_mutex_spin_ns, "I",
6090     "High spin threshold in abs for acquiring a kernel mutex");
6091 
6092 #if defined (__x86_64__)
6093 
6094 semaphore_t sysctl_test_panic_with_thread_sem;
6095 
6096 #pragma clang diagnostic push
6097 #pragma clang diagnostic ignored "-Winfinite-recursion" /* rdar://38801963 */
6098 __attribute__((noreturn))
6099 static void
6100 panic_thread_test_child_spin(void * arg, wait_result_t wres)
6101 {
6102 	static int panic_thread_recurse_count = 5;
6103 
6104 	if (panic_thread_recurse_count > 0) {
6105 		panic_thread_recurse_count--;
6106 		panic_thread_test_child_spin(arg, wres);
6107 	}
6108 
6109 	semaphore_signal(sysctl_test_panic_with_thread_sem);
6110 	while (1) {
6111 		;
6112 	}
6113 }
6114 #pragma clang diagnostic pop
6115 
6116 static void
6117 panic_thread_test_child_park(void * arg __unused, wait_result_t wres __unused)
6118 {
6119 	int event;
6120 
6121 	assert_wait(&event, THREAD_UNINT);
6122 	semaphore_signal(sysctl_test_panic_with_thread_sem);
6123 	thread_block(panic_thread_test_child_park);
6124 }
6125 
6126 static int
6127 sysctl_test_panic_with_thread SYSCTL_HANDLER_ARGS
6128 {
6129 #pragma unused(arg1, arg2)
6130 	int rval = 0;
6131 	char str[16] = { '\0' };
6132 	thread_t child_thread = THREAD_NULL;
6133 
6134 	rval = sysctl_handle_string(oidp, str, sizeof(str), req);
6135 	if (rval != 0 || !req->newptr) {
6136 		return EINVAL;
6137 	}
6138 
6139 	semaphore_create(kernel_task, &sysctl_test_panic_with_thread_sem, SYNC_POLICY_FIFO, 0);
6140 
6141 	/* Create thread to spin or park in continuation */
6142 	if (strncmp("spin", str, strlen("spin")) == 0) {
6143 		if (kernel_thread_start(panic_thread_test_child_spin, NULL, &child_thread) != KERN_SUCCESS) {
6144 			semaphore_destroy(kernel_task, sysctl_test_panic_with_thread_sem);
6145 			return EBUSY;
6146 		}
6147 	} else if (strncmp("continuation", str, strlen("continuation")) == 0) {
6148 		if (kernel_thread_start(panic_thread_test_child_park, NULL, &child_thread) != KERN_SUCCESS) {
6149 			semaphore_destroy(kernel_task, sysctl_test_panic_with_thread_sem);
6150 			return EBUSY;
6151 		}
6152 	} else {
6153 		semaphore_destroy(kernel_task, sysctl_test_panic_with_thread_sem);
6154 		return EINVAL;
6155 	}
6156 
6157 	semaphore_wait(sysctl_test_panic_with_thread_sem);
6158 
6159 	panic_with_thread_context(0, NULL, 0, child_thread, "testing panic_with_thread_context for thread %p", child_thread);
6160 
6161 	/* Not reached */
6162 	return EINVAL;
6163 }
6164 
6165 SYSCTL_PROC(_kern, OID_AUTO, test_panic_with_thread,
6166     CTLFLAG_MASKED | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLFLAG_WR | CTLTYPE_STRING,
6167     0, 0, sysctl_test_panic_with_thread, "A", "test panic flow for backtracing a different thread");
6168 #endif /* defined (__x86_64__) */
6169 
6170 static int
6171 sysctl_generate_file_permissions_guard_exception SYSCTL_HANDLER_ARGS
6172 {
6173 #pragma unused(arg1, arg2)
6174 	int error, val = 0;
6175 	error = sysctl_handle_int(oidp, &val, 0, req);
6176 	if (error || val == 0) {
6177 		return error;
6178 	}
6179 	generate_file_permissions_guard_exception(0, val);
6180 	return 0;
6181 }
6182 
6183 SYSCTL_PROC(_kern, OID_AUTO, file_perm_guard_exception, CTLFLAG_WR | CTLFLAG_ANYBODY | CTLFLAG_KERN | CTLFLAG_LOCKED,
6184     0, 0, sysctl_generate_file_permissions_guard_exception, "I", "Test File Permission Guard exception");
6185 
6186 #endif /* DEVELOPMENT || DEBUG */
6187 
6188 extern const int copysize_limit_panic;
6189 static int
6190 sysctl_get_owned_vmobjects SYSCTL_HANDLER_ARGS
6191 {
6192 #pragma unused(oidp, arg1, arg2)
6193 
6194 	/* validate */
6195 	if (req->newlen != sizeof(mach_port_name_t) || req->newptr == USER_ADDR_NULL ||
6196     req->oldidx != 0 || req->newidx != 0 || req->p == NULL ||
6197     (req->oldlen == 0 && req->oldptr != USER_ADDR_NULL)) {
6198 		return EINVAL;
6199 	}
6200 
6201 	int error;
6202 	mach_port_name_t task_port_name;
6203 	task_t task;
6204 	size_t buffer_size = (req->oldptr != USER_ADDR_NULL) ? req->oldlen : 0;
6205 	vmobject_list_output_t buffer = NULL;
6206 	size_t output_size;
6207 	size_t entries;
6208 	bool free_buffer = false;
6209 
6210 	/* we have a "newptr" (for write) we get a task port name from the caller. */
6211 	error = SYSCTL_IN(req, &task_port_name, sizeof(mach_port_name_t));
6212 
6213 	if (error != 0) {
6214 		goto sysctl_get_vmobject_list_exit;
6215 	}
6216 
6217 	task = port_name_to_task_read(task_port_name);
6218 	if (task == TASK_NULL) {
6219 		error = ESRCH;
6220 		goto sysctl_get_vmobject_list_exit;
6221 	}
6222 
6223 	bool corpse = task_is_a_corpse(task);
6224 
6225 	/* get the current size */
6226 	size_t max_size;
6227 	task_get_owned_vmobjects(task, 0, NULL, &max_size, &entries);
6228 
6229 	if (buffer_size && (buffer_size < sizeof(*buffer) + sizeof(vm_object_query_data_t))) {
6230 		error = ENOMEM;
6231 		goto sysctl_get_vmobject_list_deallocate_and_exit;
6232 	}
6233 
6234 	if (corpse == false) {
6235 		/* copy the vmobjects and vmobject data out of the task */
6236 		if (buffer_size == 0) {
6237 			output_size = max_size;
6238 		} else {
6239 			buffer_size = (buffer_size > max_size) ? max_size : buffer_size;
6240 			buffer = (struct _vmobject_list_output_ *)kalloc_data(buffer_size, Z_WAITOK);
6241 
6242 			if (!buffer) {
6243 				error = ENOMEM;
6244 				goto sysctl_get_vmobject_list_deallocate_and_exit;
6245 			}
6246 			free_buffer = true;
6247 
6248 			task_get_owned_vmobjects(task, buffer_size, buffer, &output_size, &entries);
6249 		}
6250 	} else {
6251 		vmobject_list_output_t list;
6252 
6253 		task_get_corpse_vmobject_list(task, &list, &max_size);
6254 		assert(buffer == NULL);
6255 
6256 		/* copy corpse_vmobject_list to output buffer to avoid double copy */
6257 		if (buffer_size) {
6258 			size_t temp_size;
6259 
6260 			temp_size = buffer_size > max_size ? max_size : buffer_size;
6261 			output_size = temp_size - sizeof(*buffer);
6262 			/* whole multiple of vm_object_query_data_t */
6263 			output_size = (output_size / sizeof(vm_object_query_data_t)) * sizeof(vm_object_query_data_t) + sizeof(*buffer);
6264 			buffer = list;
6265 		} else {
6266 			output_size = max_size;
6267 		}
6268 	}
6269 
6270 	/* req->oldptr should be USER_ADDR_NULL if buffer == NULL and return the current size */
6271 	/* otherwise copy buffer to oldptr and return the bytes copied */
6272 	size_t num_copied, chunk_size;
6273 	for (num_copied = 0, chunk_size = 0;
6274 	    num_copied < output_size;
6275 	    num_copied += chunk_size) {
6276 		chunk_size = MIN(output_size - num_copied, copysize_limit_panic);
6277 		error = SYSCTL_OUT(req, (char *)buffer + num_copied, chunk_size);
6278 		if (error) {
6279 			break;
6280 		}
6281 	}
6282 
6283 sysctl_get_vmobject_list_deallocate_and_exit:
6284 	task_deallocate(task);
6285 
6286 sysctl_get_vmobject_list_exit:
6287 	if (free_buffer) {
6288 		kfree_data(buffer, buffer_size);
6289 	}
6290 
6291 	return error;
6292 }
6293 
6294 SYSCTL_PROC(_vm, OID_AUTO, get_owned_vmobjects,
6295     CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_WR | CTLFLAG_MASKED | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
6296     0, 0, sysctl_get_owned_vmobjects, "A", "get owned vmobjects in task");
6297 
6298 extern uint64_t num_static_scalable_counters;
6299 SYSCTL_QUAD(_kern, OID_AUTO, num_static_scalable_counters, CTLFLAG_RD | CTLFLAG_LOCKED, &num_static_scalable_counters, "");
6300 
6301 #if SCHED_HYGIENE_DEBUG
6302 TUNABLE_DT(bool, sched_hygiene_nonspec_tb, "machine-timeouts", "nonspec-tb", "sched-hygiene-nonspec-tb", false, TUNABLE_DT_NONE);
6303 static SECURITY_READ_ONLY_LATE(int) sched_hygiene_debug_available = 1;
6304 #else
6305 static SECURITY_READ_ONLY_LATE(int) sched_hygiene_debug_available = 0;
6306 #endif /* SCHED_HYGIENE_DEBUG */
6307 
6308 SYSCTL_INT(_debug, OID_AUTO, sched_hygiene_debug_available,
6309     CTLFLAG_KERN | CTLFLAG_RD | CTLFLAG_LOCKED,
6310     &sched_hygiene_debug_available, 0, "");
6311 
6312 uuid_string_t trial_treatment_id;
6313 uuid_string_t trial_experiment_id;
6314 int trial_deployment_id = -1;
6315 
6316 SYSCTL_STRING(_kern, OID_AUTO, trial_treatment_id, CTLFLAG_RW | CTLFLAG_LOCKED | CTLFLAG_ANYBODY | CTLFLAG_LEGACY_EXPERIMENT, trial_treatment_id, sizeof(trial_treatment_id), "");
6317 SYSCTL_STRING(_kern, OID_AUTO, trial_experiment_id, CTLFLAG_RW | CTLFLAG_LOCKED | CTLFLAG_ANYBODY | CTLFLAG_LEGACY_EXPERIMENT, trial_experiment_id, sizeof(trial_experiment_id), "");
6318 SYSCTL_INT(_kern, OID_AUTO, trial_deployment_id, CTLFLAG_RW | CTLFLAG_LOCKED | CTLFLAG_ANYBODY | CTLFLAG_LEGACY_EXPERIMENT, &trial_deployment_id, 0, "");
6319 
6320 #if (DEVELOPMENT || DEBUG)
6321 /* For unit testing setting factors & limits. */
6322 unsigned int testing_experiment_factor;
6323 EXPERIMENT_FACTOR_LEGACY_UINT(_kern, testing_experiment_factor, &testing_experiment_factor, 5, 10, "");
6324 
6325 static int32_t experiment_factor_test;
6326 EXPERIMENT_FACTOR_INT(test, &experiment_factor_test, 0, 32, "test factor");
6327 
6328 #if MACH_ASSERT && __arm64__
6329 /* rdar://149041040 */
6330 extern unsigned int panic_on_jit_guard;
6331 EXPERIMENT_FACTOR_UINT(jitguard, &panic_on_jit_guard, 0, 7, "Panic on JIT guard failure");
6332 #endif /* MACH_ASSERT && __arm64__ */
6333 
6334 extern int exception_log_max_pid;
6335 SYSCTL_INT(_debug, OID_AUTO, exception_log_max_pid, CTLFLAG_RW | CTLFLAG_LOCKED, &exception_log_max_pid, 0, "Log exceptions for all processes up to this pid");
6336 #endif /* (DEVELOPMENT || DEBUG) */
6337 
6338 #if DEVELOPMENT || DEBUG
6339 static int
6340 unlink_kernelcore_sysctl SYSCTL_HANDLER_ARGS
6341 {
6342 	if (!req->newptr) {
6343 		return EINVAL;
6344 	}
6345 	void IOBSDLowSpaceUnlinkKernelCore(void);
6346 	IOBSDLowSpaceUnlinkKernelCore();
6347 	return 0;
6348 }
6349 
6350 SYSCTL_PROC(_kern, OID_AUTO, unlink_kernelcore,
6351     CTLTYPE_INT | CTLFLAG_WR | CTLFLAG_LOCKED | CTLFLAG_MASKED, 0, 0,
6352     unlink_kernelcore_sysctl, "-", "unlink the kernelcore file");
6353 #endif /* DEVELOPMENT || DEBUG */
6354 
6355 #if CONFIG_IOTRACE
6356 #pragma clang diagnostic push
6357 #pragma clang diagnostic ignored "-Wcast-qual"
6358 SYSCTL_INT(_debug, OID_AUTO, MMIOtrace,
6359     CTLFLAG_KERN | CTLFLAG_RW | CTLFLAG_LOCKED,
6360     (int *)&mmiotrace_enabled, 0, "");
6361 #pragma clang diagnostic pop
6362 #endif /* CONFIG_IOTRACE */
6363 
6364 static int
6365 sysctl_page_protection_type SYSCTL_HANDLER_ARGS
6366 {
6367 #pragma unused(oidp, arg1, arg2)
6368 	int value = ml_page_protection_type();
6369 	return SYSCTL_OUT(req, &value, sizeof(value));
6370 }
6371 
6372 SYSCTL_PROC(_kern, OID_AUTO, page_protection_type,
6373     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
6374     0, 0, sysctl_page_protection_type, "I", "Type of page protection that the system supports");
6375 
6376 #if CONFIG_SPTM && HAS_SPTM_SYSCTL
6377 extern bool disarm_protected_io;
6378 static int sysctl_sptm_disarm_protected_io SYSCTL_HANDLER_ARGS
6379 {
6380 	int error = 0;
6381 
6382 	uint64_t old_disarm_protected_io = (uint64_t) disarm_protected_io;
6383 	error = SYSCTL_OUT(req, &old_disarm_protected_io, sizeof(old_disarm_protected_io));
6384 
6385 	if (error) {
6386 		return error;
6387 	}
6388 
6389 	uint64_t new_disarm_protected_io = old_disarm_protected_io;
6390 	if (req->newptr) {
6391 		error = SYSCTL_IN(req, &new_disarm_protected_io, sizeof(new_disarm_protected_io));
6392 		if (!disarm_protected_io && new_disarm_protected_io) {
6393 			sptm_sysctl(SPTM_SYSCTL_DISARM_PROTECTED_IO, SPTM_SYSCTL_SET, 1);
6394 			os_atomic_thread_fence(release);
6395 			disarm_protected_io = true;
6396 		}
6397 	}
6398 
6399 	return error;
6400 }
6401 SYSCTL_PROC(_kern, OID_AUTO, sptm_disarm_protected_io, CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0, sysctl_sptm_disarm_protected_io, "Q", "");
6402 
6403 /**
6404  * Usage of kern.sptm_sysctl_poke
6405  *
6406  * This sysctl provides a convenient way to trigger the "getter" handler of a
6407  * specified SPTM sysctl. With this sysctl, you can trigger arbitrary SPTM
6408  * code without modifying xnu source code. All you need to do is define a
6409  * new SPTM sysctl and implement its "getter". After that, you can write
6410  * the SPTM sysctl number to this sysctl to trigger it.
6411  */
6412 static int sysctl_sptm_sysctl_poke SYSCTL_HANDLER_ARGS
6413 {
6414 	int error = 0;
6415 
6416 	/* Always read-as-zero. */
6417 	const uint64_t out = 0;
6418 	error = SYSCTL_OUT(req, &out, sizeof(out));
6419 
6420 	if (error) {
6421 		return error;
6422 	}
6423 
6424 	uint64_t selector;
6425 	if (req->newptr) {
6426 		error = SYSCTL_IN(req, &selector, sizeof(selector));
6427 		sptm_sysctl(selector, SPTM_SYSCTL_GET, 0);
6428 	}
6429 
6430 	return error;
6431 }
6432 SYSCTL_PROC(_kern, OID_AUTO, sptm_sysctl_poke, CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0, sysctl_sptm_sysctl_poke, "Q", "");
6433 #endif /* CONFIG_SPTM && HAS_SPTM_SYSCTL */
6434 
6435 #if CONFIG_SPTM && (DEVELOPMENT || DEBUG)
6436 /**
6437  * Sysctls to get SPTM allowed I/O ranges, pmap I/O ranges and I/O ranges by index.
6438  * Used by SEAR/LASER tools.
6439  */
6440 static int
6441 sysctl_sptm_allowed_io_ranges SYSCTL_HANDLER_ARGS
6442 {
6443 #pragma unused(oidp, arg1, arg2)
6444 	sptm_io_range_t io_range = { 0 };
6445 	unsigned int index = 0;
6446 
6447 	int error = SYSCTL_IN(req, &index, sizeof(index));
6448 	if (error) {
6449 		return error;
6450 	}
6451 
6452 	libsptm_error_t ret = sptm_get_info(INFO_SPTM_ALLOWED_IO_RANGES, index, &io_range);
6453 	if (__improbable(ret != LIBSPTM_SUCCESS)) {
6454 		return EINVAL;
6455 	}
6456 
6457 	return SYSCTL_OUT(req, &io_range, sizeof(io_range));
6458 }
6459 SYSCTL_PROC(_kern, OID_AUTO, sptm_allowed_io_ranges, CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_LOCKED,
6460     0, 0, sysctl_sptm_allowed_io_ranges, "S,sptm_io_range_t", "SPTM allowed I/O ranges by index");
6461 
6462 static int
6463 sysctl_sptm_allowed_io_ranges_count SYSCTL_HANDLER_ARGS
6464 {
6465 #pragma unused(oidp, arg1, arg2)
6466 	unsigned int count = 0;
6467 
6468 	libsptm_error_t ret = sptm_get_info(INFO_SPTM_ALLOWED_IO_RANGES_COUNT, 0, &count);
6469 	if (__improbable(ret != LIBSPTM_SUCCESS)) {
6470 		return EINVAL;
6471 	}
6472 
6473 	return SYSCTL_OUT(req, &count, sizeof(count));
6474 }
6475 SYSCTL_PROC(_kern, OID_AUTO, sptm_allowed_io_ranges_count, CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
6476     0, 0, sysctl_sptm_allowed_io_ranges_count, "I", "SPTM allowed I/O ranges count");
6477 
6478 static int
6479 sysctl_sptm_pmap_io_ranges SYSCTL_HANDLER_ARGS
6480 {
6481 #pragma unused(oidp, arg1, arg2)
6482 	sptm_io_range_t io_range = { 0 };
6483 	unsigned int index = 0;
6484 
6485 	int error = SYSCTL_IN(req, &index, sizeof(index));
6486 	if (error) {
6487 		return error;
6488 	}
6489 
6490 	libsptm_error_t ret = sptm_get_info(INFO_SPTM_PMAP_IO_RANGES, index, &io_range);
6491 	if (__improbable(ret != LIBSPTM_SUCCESS)) {
6492 		return EINVAL;
6493 	}
6494 
6495 	return SYSCTL_OUT(req, &io_range, sizeof(io_range));
6496 }
6497 SYSCTL_PROC(_kern, OID_AUTO, sptm_pmap_io_ranges, CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_LOCKED,
6498     0, 0, sysctl_sptm_pmap_io_ranges, "S,sptm_io_range_t", "SPTM pmap I/O ranges by index");
6499 
6500 static int
6501 sysctl_sptm_pmap_io_ranges_count SYSCTL_HANDLER_ARGS
6502 {
6503 #pragma unused(oidp, arg1, arg2)
6504 	unsigned int count = 0;
6505 
6506 	libsptm_error_t ret = sptm_get_info(INFO_SPTM_PMAP_IO_RANGES_COUNT, 0, &count);
6507 	if (__improbable(ret != LIBSPTM_SUCCESS)) {
6508 		return EINVAL;
6509 	}
6510 
6511 	return SYSCTL_OUT(req, &count, sizeof(count));
6512 }
6513 SYSCTL_PROC(_kern, OID_AUTO, sptm_pmap_io_ranges_count, CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
6514     0, 0, sysctl_sptm_pmap_io_ranges_count, "I", "SPTM pmap I/O ranges count");
6515 
6516 /* Establish the `kern.sptm` sysctl namespace. */
6517 SYSCTL_NODE(_kern, OID_AUTO, sptm, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "SPTM (Secure Page Table Monitor)");
6518 
6519 /* Establish the `kern.sptm.event_counters` sysctl namespace. */
6520 SYSCTL_NODE(_kern_sptm, OID_AUTO, event_counters, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "SPTM event counters");
6521 
6522 /**
6523  * The single sysctl handler function shared by all of the SPTM event counter sysctls.
6524  *
6525  * @param arg2 The `sptm_info_t` enum value corresponding to the SPTM event counter.
6526  *             This value is bound at sysctl registration time.
6527  */
6528 static int
6529 sysctl_handle_sptm_event_counter SYSCTL_HANDLER_ARGS
6530 {
6531 #pragma unused(oidp, arg1)
6532 	/* Overall count across all CPUs. */
6533 	uint64_t total_count = 0;
6534 
6535 	/* Loop over all CPUs and accumulate counts. */
6536 	const int ncpus = ml_early_cpu_max_number() + 1;
6537 	for (int cpu = 0; cpu < ncpus; cpu++) {
6538 		/* Get count for this CPU. */
6539 		uint64_t count = 0;
6540 		libsptm_error_t ret = sptm_get_info((sptm_info_t)arg2, cpu, &count);
6541 		if (__improbable(ret != LIBSPTM_SUCCESS)) {
6542 			return EINVAL;
6543 		}
6544 
6545 		/* Accumulate the count. */
6546 		total_count += count;
6547 	}
6548 
6549 	return SYSCTL_OUT(req, &total_count, sizeof(total_count));
6550 }
6551 
6552 #define GENERATE_SPTM_EVNT_CNTR_SYSCTL_REGISTRATION(event_counter, description) \
6553 	SYSCTL_PROC(_kern_sptm_event_counters, OID_AUTO, event_counter, \
6554 	        CTLTYPE_QUAD | CTLFLAG_RD | CTLFLAG_LOCKED | CTLFLAG_KERN, \
6555 	        NULL, SPTM_EVENT_COUNTER_TO_ENUM(event_counter), \
6556 	        sysctl_handle_sptm_event_counter, "Q", description);
6557 
6558 /* Generate sysctl accessors for every SPTM event counter. */
6559 FOREACH_SPTM_EVENT_COUNTER(GENERATE_SPTM_EVNT_CNTR_SYSCTL_REGISTRATION)
6560 
6561 static int
6562 sysctl_sptm_io_ranges SYSCTL_HANDLER_ARGS
6563 {
6564 #pragma unused(oidp, arg1, arg2)
6565 	sptm_io_range_t io_range = { 0 };
6566 	unsigned int index = 0;
6567 
6568 	int error = SYSCTL_IN(req, &index, sizeof(index));
6569 	if (error) {
6570 		return error;
6571 	}
6572 
6573 	libsptm_error_t ret = sptm_get_info(INFO_SPTM_IO_RANGES, index, &io_range);
6574 	if (__improbable(ret != LIBSPTM_SUCCESS)) {
6575 		return EINVAL;
6576 	}
6577 
6578 	return SYSCTL_OUT(req, &io_range, sizeof(io_range));
6579 }
6580 SYSCTL_PROC(_kern, OID_AUTO, sptm_io_ranges, CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_LOCKED,
6581     0, 0, sysctl_sptm_io_ranges, "S,sptm_io_range_t", "SPTM I/O ranges by index");
6582 
6583 static int
6584 sysctl_sptm_io_ranges_count SYSCTL_HANDLER_ARGS
6585 {
6586 #pragma unused(oidp, arg1, arg2)
6587 	unsigned int count = 0;
6588 
6589 	libsptm_error_t ret = sptm_get_info(INFO_SPTM_IO_RANGES_COUNT, 0, &count);
6590 	if (__improbable(ret != LIBSPTM_SUCCESS)) {
6591 		return EINVAL;
6592 	}
6593 
6594 	return SYSCTL_OUT(req, &count, sizeof(count));
6595 }
6596 SYSCTL_PROC(_kern, OID_AUTO, sptm_io_ranges_count, CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
6597     0, 0, sysctl_sptm_io_ranges_count, "I", "SPTM I/O ranges count");
6598 #endif /* CONFIG_SPTM && (DEVELOPMENT || DEBUG) */
6599 
6600 #if __ARM64_PMAP_SUBPAGE_L1__ && CONFIG_SPTM
6601 extern bool surt_ready;
6602 static int
6603 sysctl_surt_ready SYSCTL_HANDLER_ARGS
6604 {
6605 #pragma unused(oidp, arg1, arg2)
6606 	unsigned int surt_ready_uint = (unsigned int)surt_ready;
6607 	return SYSCTL_OUT(req, &surt_ready_uint, sizeof(surt_ready_uint));
6608 }
6609 SYSCTL_PROC(_kern, OID_AUTO, surt_ready, CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
6610     0, 0, sysctl_surt_ready, "I", "SURT system readiness");
6611 #endif /* __ARM64_PMAP_SUBPAGE_L1__ && CONFIG_SPTM */
6612 
6613 #if __arm64__ && (DEBUG || DEVELOPMENT)
6614 extern unsigned int pmap_wcrt_on_non_dram_count_get(void);
6615 static int
6616 sysctl_pmap_wcrt_on_non_dram_count SYSCTL_HANDLER_ARGS
6617 {
6618 #pragma unused(oidp, arg1, arg2)
6619 	unsigned int count = pmap_wcrt_on_non_dram_count_get();
6620 
6621 	return SYSCTL_OUT(req, &count, sizeof(count));
6622 }
6623 SYSCTL_PROC(_kern, OID_AUTO, pmap_wcrt_on_non_dram_count, CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
6624     0, 0, sysctl_pmap_wcrt_on_non_dram_count, "I", "pmap WC/RT mapping request on non-DRAM count");
6625 #endif /* __arm64__ && (DEBUG || DEVELOPMENT) */
6626 
6627 TUNABLE_DT(int, gpu_pmem_selector, "defaults", "kern.gpu_pmem_selector", "gpu-pmem-selector", 0, TUNABLE_DT_NONE);
6628 
6629 #if CONFIG_EXCLAVES
6630 
6631 static int
6632 sysctl_task_conclave SYSCTL_HANDLER_ARGS
6633 {
6634 	extern const char *exclaves_resource_name(void *);
6635 
6636 #pragma unused(arg2)
6637 	void *conclave = task_get_conclave(current_task());
6638 	if (conclave != NULL) {
6639 		const char *name = exclaves_resource_name(conclave);
6640 		assert3u(strlen(name), >, 0);
6641 
6642 		/*
6643 		 * This is a RO operation already and the string is never
6644 		 * written to.
6645 		 */
6646 #pragma clang diagnostic push
6647 #pragma clang diagnostic ignored "-Wcast-qual"
6648 		return sysctl_handle_string(oidp, (char *)name, 0, req);
6649 #pragma clang diagnostic pop
6650 	}
6651 	return sysctl_handle_string(oidp, arg1, MAXCONCLAVENAME, req);
6652 }
6653 
6654 SYSCTL_PROC(_kern, OID_AUTO, task_conclave,
6655     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
6656     "", 0, sysctl_task_conclave, "A", "Conclave string for the task");
6657 
6658 
6659 void task_set_conclave_untaintable(task_t task);
6660 
6661 static int
6662 sysctl_task_conclave_untaintable SYSCTL_HANDLER_ARGS
6663 {
6664 #pragma unused(arg1, arg2)
6665 	int error, val = 0;
6666 	error = sysctl_handle_int(oidp, &val, 0, req);
6667 	if (error || val == 0) {
6668 		return error;
6669 	}
6670 
6671 	task_set_conclave_untaintable(current_task());
6672 	return 0;
6673 }
6674 
6675 SYSCTL_PROC(_kern, OID_AUTO, task_conclave_untaintable,
6676     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
6677     "", 0, sysctl_task_conclave_untaintable, "A", "Task could not be tainted by talking to conclaves");
6678 
6679 extern exclaves_requirement_t exclaves_relaxed_requirements;
6680 SYSCTL_QUAD(_kern, OID_AUTO, exclaves_relaxed_requirements,
6681     CTLFLAG_KERN | CTLFLAG_RD | CTLFLAG_LOCKED,
6682     &exclaves_relaxed_requirements, "Exclaves requirements which have been relaxed");
6683 
6684 #endif /* CONFIG_EXCLAVES */
6685 
6686 #if (DEVELOPMENT || DEBUG)
6687 SYSCTL_INT(_kern, OID_AUTO, gpu_pmem_selector,
6688     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED | CTLFLAG_KERN,
6689     &gpu_pmem_selector, 0, "GPU wire down limit selector");
6690 #else /* !(DEVELOPMENT || DEBUG) */
6691 SYSCTL_INT(_kern, OID_AUTO, gpu_pmem_selector,
6692     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED | CTLFLAG_KERN | CTLFLAG_MASKED,
6693     &gpu_pmem_selector, 0, "GPU wire down limit selector");
6694 #endif /* (DEVELOPMENT || DEBUG) */
6695 
6696 static int
6697 sysctl_exclaves_status SYSCTL_HANDLER_ARGS
6698 {
6699 	int value = exclaves_get_status();
6700 	return sysctl_io_number(req, value, sizeof(value), NULL, NULL);
6701 }
6702 
6703 SYSCTL_PROC(_kern, OID_AUTO, exclaves_status,
6704     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
6705     0, 0, sysctl_exclaves_status, "I", "Running status of Exclaves");
6706 
6707 
6708 static int
6709 sysctl_exclaves_boot_stage SYSCTL_HANDLER_ARGS
6710 {
6711 	int value = exclaves_get_boot_stage();
6712 	return sysctl_io_number(req, value, sizeof(value), NULL, NULL);
6713 }
6714 
6715 SYSCTL_PROC(_kern, OID_AUTO, exclaves_boot_stage,
6716     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
6717     0, 0, sysctl_exclaves_boot_stage, "I", "Boot stage of Exclaves");
6718 
6719 #if CONFIG_EXCLAVES && (DEVELOPMENT || DEBUG)
6720 extern unsigned int exclaves_debug;
6721 SYSCTL_UINT(_kern, OID_AUTO, exclaves_debug, CTLFLAG_RW | CTLFLAG_LOCKED,
6722     &exclaves_debug, 0, "Exclaves debug flags");
6723 
6724 static int
6725 sysctl_exclaves_inspection_status SYSCTL_HANDLER_ARGS
6726 {
6727 #pragma unused(oidp, arg1, arg2)
6728 	int value = (int)exclaves_inspection_is_initialized();
6729 	return sysctl_io_number(req, value, sizeof(value), NULL, NULL);
6730 }
6731 SYSCTL_PROC(_kern, OID_AUTO, exclaves_inspection_status,
6732     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_LOCKED,
6733     0, 0, sysctl_exclaves_inspection_status, "I", "Exclaves debug inspection status");
6734 #endif /* CONFIG_EXCLAVES && (DEVELOPMENT || DEBUG) */
6735 
6736 #if (DEBUG || DEVELOPMENT)
6737 extern uint32_t disable_vm_sanitize_telemetry;
6738 SYSCTL_UINT(_debug, OID_AUTO, disable_vm_sanitize_telemetry, CTLFLAG_RW | CTLFLAG_LOCKED /*| CTLFLAG_MASKED*/, &disable_vm_sanitize_telemetry, 0, "disable VM API sanitization telemetry");
6739 #endif
6740 
6741 #define kReadUserspaceRebootInfoEntitlement "com.apple.private.kernel.userspacereboot-info-read-only"
6742 static int
6743 _sysctl_userspacereboot_info(struct sysctl_req *req, void *ptr, size_t ptr_size)
6744 {
6745 	if (req->newptr != 0) {
6746 		/* initproc is the only process that can write to these sysctls */
6747 		if (proc_getpid(req->p) != 1) {
6748 			return EPERM;
6749 		}
6750 		return SYSCTL_IN(req, ptr, ptr_size);
6751 	} else {
6752 		/* A read entitlement is required to read these sysctls */
6753 		if (!IOCurrentTaskHasEntitlement(kReadUserspaceRebootInfoEntitlement)) {
6754 			return EPERM;
6755 		}
6756 		return SYSCTL_OUT(req, ptr, ptr_size);
6757 	}
6758 }
6759 
6760 static int
6761 sysctl_userspacereboottime(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
6762 {
6763 	return _sysctl_userspacereboot_info(req, &userspacereboottime, sizeof(userspacereboottime));
6764 }
6765 
6766 static int
6767 sysctl_userspacerebootpurpose(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
6768 {
6769 	return _sysctl_userspacereboot_info(req, &userspacerebootpurpose, sizeof(userspacerebootpurpose));
6770 }
6771 
6772 SYSCTL_PROC(_kern, OID_AUTO, userspacereboottime, CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0, sysctl_userspacereboottime, "Q", "");
6773 SYSCTL_PROC(_kern, OID_AUTO, userspacerebootpurpose, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0, sysctl_userspacerebootpurpose, "I", "");
6774 
6775 #if XNU_TARGET_OS_IOS
6776 
6777 static LCK_GRP_DECLARE(erm_config_lock_grp, "ERM sysctl");
6778 static LCK_RW_DECLARE(erm_config_lock, &erm_config_lock_grp);
6779 #define ERM_CONFIG_SYSCTL_WRITE_ENTITLEMENT "com.apple.private.security-research-device.extended-research-mode"
6780 #define ERM_CONFIG_SYSCTL_MAX_SIZE PAGE_SIZE
6781 
6782 // This sysctl handler is only registered when Extended Research Mode (ERM) is active.
6783 static int
6784 sysctl_user_extended_research_mode_config_handler(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
6785 {
6786 	// Pointer for the dynamically allocated buffer
6787 	static void *extended_research_mode_config_data = NULL;
6788 
6789 	// Current size of the valid data stored in the buffer
6790 	static size_t extended_research_mode_config_current_size = 0;
6791 
6792 	// Handle Read request (user wants to read the current config, before it is overwritten)
6793 	if (req->oldptr != USER_ADDR_NULL) {
6794 		int error = 0;
6795 
6796 		lck_rw_lock_shared(&erm_config_lock);
6797 
6798 		if (req->oldlen < extended_research_mode_config_current_size) {
6799 			error = ENOMEM;
6800 		} else {
6801 			if (extended_research_mode_config_current_size > 0) {
6802 				error = copyout(extended_research_mode_config_data,
6803 				    req->oldptr,
6804 				    extended_research_mode_config_current_size);
6805 			}
6806 		}
6807 		// In all cases, report the total size of the currently stored config back to the user,
6808 		req->oldlen = extended_research_mode_config_current_size;
6809 		req->oldidx = req->oldlen;
6810 
6811 		lck_rw_unlock_shared(&erm_config_lock);
6812 
6813 		if (error != 0) {
6814 			return error;
6815 		}
6816 	} else {
6817 		// User just want to know the current buffer size.
6818 		// All accesses to extended_research_mode_config* variables are expected
6819 		// to be done under erm_config_lock.
6820 		lck_rw_lock_shared(&erm_config_lock);
6821 		req->oldidx = extended_research_mode_config_current_size;
6822 		lck_rw_unlock_shared(&erm_config_lock);
6823 	}
6824 
6825 
6826 	// Handle Write request (new data provided by user)
6827 	if (req->newptr != USER_ADDR_NULL) {
6828 		if (!IOTaskHasEntitlement(proc_task(req->p), ERM_CONFIG_SYSCTL_WRITE_ENTITLEMENT)) {
6829 			return EPERM;
6830 		}
6831 
6832 		size_t requested_len = req->newlen;
6833 
6834 		if (requested_len > ERM_CONFIG_SYSCTL_MAX_SIZE) {
6835 			// We ensure the config provided by user-space is not too big
6836 			return EINVAL;
6837 		}
6838 
6839 		// Allocate a new buffer for the incoming data
6840 		void *new_buffer = (void *)kalloc_data(requested_len, Z_WAITOK | Z_ZERO);
6841 
6842 		if (new_buffer == NULL) {
6843 			return ENOMEM; // Allocation failed
6844 		}
6845 
6846 		// Copy data from user space into the newly allocated buffer
6847 		int error = copyin(req->newptr, new_buffer, requested_len);
6848 
6849 		if (error == 0) {
6850 			// Success: Replace the old buffer with the new one
6851 			lck_rw_lock_exclusive(&erm_config_lock);
6852 
6853 			// Backup old buffer info for freeing it in a second step
6854 			void *old_buffer_to_free = extended_research_mode_config_data;
6855 			size_t old_buffer_size = extended_research_mode_config_current_size;
6856 
6857 			// Point to the new buffer and update size
6858 			extended_research_mode_config_data = new_buffer;
6859 			extended_research_mode_config_current_size = requested_len;
6860 			lck_rw_unlock_exclusive(&erm_config_lock);
6861 			new_buffer = NULL;  // transferred to the static pointer
6862 
6863 			// Previous buffer is not referenced anymore, good to be deleted.
6864 			kfree_data(old_buffer_to_free, old_buffer_size);
6865 		} else {
6866 			// Copyin failed, free the buffer we just allocated and keep the old data and size intact
6867 			kfree_data(new_buffer, requested_len);
6868 			return error;
6869 		}
6870 	}
6871 
6872 	return 0;
6873 }
6874 
6875 // We don't register this sysctl handler automatically , but rather only register it only if the extended
6876 // research mode is active.
6877 SYSCTL_PROC(_user,                // Parent node structure (_kern)
6878     OID_AUTO,                     // Automatically assign OID
6879     extended_research_mode_config,         // Name of the node
6880     CTLFLAG_NOAUTO |              // We will register this sysctl on our own
6881     CTLTYPE_OPAQUE |              // Type: Opaque binary data
6882     CTLFLAG_WR |                  // Allow both read and write
6883     CTLFLAG_ANYBODY |                             // No user filtering
6884     CTLFLAG_LOCKED,               // The handler manages its own locking.
6885     NULL,                         // arg1 (not used)
6886     0,                            // arg2 (not used)
6887     &sysctl_user_extended_research_mode_config_handler,
6888     "-",                          // don't print the content (as it is a blob)
6889     "Configuration blob for Extended Research Mode");
6890 
6891 // This function is defined in kern_codesigning.c but don't worth include the whole .h just for it.
6892 bool extended_research_mode_state(void);
6893 
6894 // Only register the research_mode_config sysctl if Extended Research Mode is active
6895 __startup_func
6896 static void
6897 extended_research_mode_config_sysctl_startup(void)
6898 {
6899 	if (__improbable(extended_research_mode_state())) {
6900 		// Register the sysctl handler
6901 		sysctl_register_oid_early(&sysctl__user_extended_research_mode_config);
6902 	}
6903 }
6904 STARTUP(SYSCTL, STARTUP_RANK_MIDDLE, extended_research_mode_config_sysctl_startup);
6905 #endif /* XNU_TARGET_OS_IOS */
6906 
6907 #if DEBUG || DEVELOPMENT
6908 SCALABLE_COUNTER_DEFINE(mach_eventlink_handoff_success_count);
6909 SYSCTL_SCALABLE_COUNTER(_kern, mach_eventlink_handoff_success_count,
6910     mach_eventlink_handoff_success_count, "Number of successful handoffs");
6911 #endif /* DEBUG || DEVELOPMENT*/
6912