2 * Copyright (c) 2013 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <sys/malloc.h>
33 #include <sys/proc_internal.h>
35 #include <sys/kauth.h>
36 #include <sys/unistd.h>
39 #include <mach/mach_types.h>
40 #include <mach/vm_param.h>
41 #include <kern/task.h>
42 #include <kern/locks.h>
43 #include <kern/assert.h>
44 #include <kern/sched_prim.h>
46 #include <sys/kern_overrides.h>
47 #include <sys/bsdtask_info.h>
48 #include <sys/kdebug.h>
49 #include <sys/sysproto.h>
50 #include <sys/msgbuf.h>
51 #include <sys/kern_memorystatus.h>
53 /* Mutex for global system override state */
54 static LCK_GRP_DECLARE(sys_override_mtx_grp
, "system_override");
55 static LCK_MTX_DECLARE(sys_override_lock
, &sys_override_mtx_grp
);
58 * Assertion counts for system properties (add new ones for each new mechanism)
60 * The assertion count management for system overrides is as follows:
62 * - All assertion counts are protected by the sys_override_lock.
64 * - Each caller of system_override() increments the assertion count for the
65 * mechanism it specified in the flags. The caller then blocks for the
66 * timeout specified in the system call.
68 * - At the end of the timeout, the caller thread wakes up and decrements the
69 * assertion count for the mechanism it originally took an assertion on.
71 * - If another caller calls the system_override() to disable the override
72 * for a mechanism, it simply disables the mechanism without changing any
73 * assertion counts. That way, the assertion counts are properly balanced.
75 * One thing to note is that a SYS_OVERRIDE_DISABLE disables the overrides
76 * for a mechanism irrespective of how many clients requested that override.
77 * That makes the implementation simpler and avoids keeping a lot of process
78 * specific state in the kernel.
81 static int64_t io_throttle_assert_cnt
;
82 static int64_t cpu_throttle_assert_cnt
;
83 static int64_t fast_jetsam_assert_cnt
;
85 /* Wait Channel for system override */
86 static uint64_t sys_override_wait
;
89 static void system_override_begin(uint64_t flags
);
90 static void system_override_end(uint64_t flags
);
91 static void system_override_abort(uint64_t flags
);
92 static void system_override_callouts(uint64_t flags
, boolean_t enable_override
);
93 static __attribute__((noinline
)) int PROCESS_OVERRIDING_SYSTEM_DEFAULTS(uint64_t timeout
);
95 /* system call implementation */
97 system_override(__unused
struct proc
*p
, struct system_override_args
* uap
, __unused
int32_t *retval
)
99 uint64_t timeout
= uap
->timeout
;
100 uint64_t flags
= uap
->flags
;
103 /* Check credentials for caller. Only entitled processes are allowed to make this call. */
104 if ((error
= priv_check_cred(kauth_cred_get(), PRIV_SYSTEM_OVERRIDE
, 0))) {
108 /* Check to see if sane flags are specified. */
109 if ((flags
& ~SYS_OVERRIDE_FLAGS_MASK
) != 0) {
114 lck_mtx_lock(&sys_override_lock
);
116 if (flags
& SYS_OVERRIDE_DISABLE
) {
117 flags
&= ~SYS_OVERRIDE_DISABLE
;
118 system_override_abort(flags
);
120 system_override_begin(flags
);
121 error
= PROCESS_OVERRIDING_SYSTEM_DEFAULTS(timeout
);
122 system_override_end(flags
);
125 lck_mtx_unlock(&sys_override_lock
);
132 * Helper routines for enabling/disabling system overrides for various mechanisms.
133 * These routines should be called with the sys_override_lock held. Each subsystem
134 * which is hooked into the override service provides two routines:
136 * - void sys_override_foo_init(void);
137 * Routine to initialize the subsystem or the data needed for the override to work.
138 * This routine is optional and if a subsystem needs it, it should be invoked from
139 * init_system_override().
141 * - void sys_override_foo(boolean_t enable_override);
142 * Routine to enable/disable the override mechanism for that subsystem. A value of
143 * true indicates that the mechanism should be overridden and the special behavior
144 * should begin. A false value indicates that the subsystem should return to default
145 * behavior. This routine is mandatory and should be invoked as part of the helper
146 * routines if the flags passed in the syscall match the subsystem. Also, this
147 * routine should preferably be idempotent.
151 system_override_callouts(uint64_t flags
, boolean_t enable_override
)
154 case SYS_OVERRIDE_IO_THROTTLE
:
155 if (enable_override
) {
156 KERNEL_DEBUG_CONSTANT(FSDBG_CODE(DBG_THROTTLE
, IO_THROTTLE_DISABLE
) | DBG_FUNC_START
,
157 current_proc()->p_pid
, 0, 0, 0, 0);
159 KERNEL_DEBUG_CONSTANT(FSDBG_CODE(DBG_THROTTLE
, IO_THROTTLE_DISABLE
) | DBG_FUNC_END
,
160 current_proc()->p_pid
, 0, 0, 0, 0);
162 sys_override_io_throttle(enable_override
);
165 case SYS_OVERRIDE_CPU_THROTTLE
:
166 if (enable_override
) {
167 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED
, MACH_CPU_THROTTLE_DISABLE
) | DBG_FUNC_START
,
168 current_proc()->p_pid
, 0, 0, 0, 0);
170 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED
, MACH_CPU_THROTTLE_DISABLE
) | DBG_FUNC_END
,
171 current_proc()->p_pid
, 0, 0, 0, 0);
173 sys_override_cpu_throttle(enable_override
);
176 case SYS_OVERRIDE_FAST_JETSAM
:
177 if (enable_override
) {
178 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_MEMSTAT
, BSD_MEMSTAT_FAST_JETSAM
) | DBG_FUNC_START
,
179 current_proc()->p_pid
, 0, 0, 0, 0);
181 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_MEMSTAT
, BSD_MEMSTAT_FAST_JETSAM
) | DBG_FUNC_END
,
182 current_proc()->p_pid
, 0, 0, 0, 0);
185 memorystatus_fast_jetsam_override(enable_override
);
186 #endif /* CONFIG_JETSAM */
190 panic("Unknown option to system_override_callouts(): %llu\n", flags
);
195 * system_override_begin(uint64_t flags)
197 * Routine to start a system override if the assertion count
198 * transitions from 0->1 for a specified mechanism.
201 system_override_begin(uint64_t flags
)
203 lck_mtx_assert(&sys_override_lock
, LCK_MTX_ASSERT_OWNED
);
205 if (flags
& SYS_OVERRIDE_IO_THROTTLE
) {
206 if (io_throttle_assert_cnt
== 0) {
207 system_override_callouts(SYS_OVERRIDE_IO_THROTTLE
, true);
209 io_throttle_assert_cnt
++;
212 if (flags
& SYS_OVERRIDE_CPU_THROTTLE
) {
213 if (cpu_throttle_assert_cnt
== 0) {
214 system_override_callouts(SYS_OVERRIDE_CPU_THROTTLE
, true);
216 cpu_throttle_assert_cnt
++;
219 if (flags
& SYS_OVERRIDE_FAST_JETSAM
) {
220 if (fast_jetsam_assert_cnt
== 0) {
221 system_override_callouts(SYS_OVERRIDE_FAST_JETSAM
, true);
223 fast_jetsam_assert_cnt
++;
228 * system_override_end(uint64_t flags)
230 * Routine to end a system override if the assertion count
231 * transitions from 1->0 for a specified mechanism.
234 system_override_end(uint64_t flags
)
236 lck_mtx_assert(&sys_override_lock
, LCK_MTX_ASSERT_OWNED
);
238 if (flags
& SYS_OVERRIDE_IO_THROTTLE
) {
239 assert(io_throttle_assert_cnt
> 0);
240 io_throttle_assert_cnt
--;
241 if (io_throttle_assert_cnt
== 0) {
242 system_override_callouts(SYS_OVERRIDE_IO_THROTTLE
, false);
246 if (flags
& SYS_OVERRIDE_CPU_THROTTLE
) {
247 assert(cpu_throttle_assert_cnt
> 0);
248 cpu_throttle_assert_cnt
--;
249 if (cpu_throttle_assert_cnt
== 0) {
250 system_override_callouts(SYS_OVERRIDE_CPU_THROTTLE
, false);
254 if (flags
& SYS_OVERRIDE_FAST_JETSAM
) {
255 assert(fast_jetsam_assert_cnt
> 0);
256 fast_jetsam_assert_cnt
--;
257 if (fast_jetsam_assert_cnt
== 0) {
258 system_override_callouts(SYS_OVERRIDE_FAST_JETSAM
, false);
264 * system_override_abort(uint64_t flags)
266 * Routine to abort a system override (if one was active)
267 * irrespective of the assertion counts and number of blocked
271 system_override_abort(uint64_t flags
)
273 lck_mtx_assert(&sys_override_lock
, LCK_MTX_ASSERT_OWNED
);
275 if ((flags
& SYS_OVERRIDE_IO_THROTTLE
) && (io_throttle_assert_cnt
> 0)) {
276 system_override_callouts(SYS_OVERRIDE_IO_THROTTLE
, false);
279 if ((flags
& SYS_OVERRIDE_CPU_THROTTLE
) && (cpu_throttle_assert_cnt
> 0)) {
280 system_override_callouts(SYS_OVERRIDE_CPU_THROTTLE
, false);
283 if ((flags
& SYS_OVERRIDE_FAST_JETSAM
) && (fast_jetsam_assert_cnt
> 0)) {
284 system_override_callouts(SYS_OVERRIDE_FAST_JETSAM
, false);
288 static __attribute__((noinline
)) int
289 PROCESS_OVERRIDING_SYSTEM_DEFAULTS(uint64_t timeout
)
292 ts
.tv_sec
= timeout
/ NSEC_PER_SEC
;
293 ts
.tv_nsec
= timeout
- ((long)ts
.tv_sec
* NSEC_PER_SEC
);
294 int error
= msleep((caddr_t
)&sys_override_wait
, &sys_override_lock
, PRIBIO
| PCATCH
, "system_override", &ts
);
295 /* msleep returns EWOULDBLOCK if timeout expires, treat that as success */
296 return (error
== EWOULDBLOCK
) ? 0 : error
;