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, ©_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