2 * Copyright (c) 2013 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 #include <kern/assert.h>
31 #include <kern/locks.h>
32 #include <kern/task.h>
33 #include <kern/thread.h>
35 #include <libkern/libkern.h>
36 #include <mach/mach_time.h>
37 #include <pexpert/pexpert.h>
39 #include <sys/proc_info.h>
40 #include <sys/sysproto.h>
42 #include <sys/kdebug.h>
46 * This file provides the syscall-based configuration facility
47 * for Selective Forced Idle (SFI). Input arguments have basic checking
48 * applied here, although more specific semantic checking is done in
49 * osfmk/kern/sfi.c. All copyin()/copyout() operations are performed
50 * in this source file.
56 #define dprintf(...) printf(__VA_ARGS__)
58 #define dprintf(...) do { } while(0)
61 static int proc_apply_sfi_managed(proc_t p
, void * arg
);
63 int sfi_ctl(struct proc
*p __unused
, struct sfi_ctl_args
*uap
, int32_t *retval __unused
)
65 uint32_t operation
= uap
->operation
;
67 kern_return_t kret
= KERN_SUCCESS
;
68 uint64_t out_time
= 0;
71 case SFI_CTL_OPERATION_SFI_SET_WINDOW
:
72 if (uap
->out_time
!= USER_ADDR_NULL
) {
75 if (uap
->sfi_class
!= SFI_CLASS_UNSPECIFIED
) {
79 error
= priv_check_cred(kauth_cred_get(), PRIV_SELECTIVE_FORCED_IDLE
, 0);
81 dprintf("%s failed privilege check for sfi_ctl: %d\n", p
->p_comm
, error
);
84 dprintf("%s succeeded privilege check for sfi_ctl\n", p
->p_comm
);
88 /* actually a cancel */
89 kret
= sfi_window_cancel();
91 kret
= sfi_set_window(uap
->time
);
99 case SFI_CTL_OPERATION_SFI_GET_WINDOW
:
100 if (uap
->time
!= 0) {
103 if (uap
->sfi_class
!= SFI_CLASS_UNSPECIFIED
) {
107 kret
= sfi_get_window(&out_time
);
108 if (kret
== KERN_SUCCESS
) {
109 error
= copyout(&out_time
, uap
->out_time
, sizeof(out_time
));
115 case SFI_CTL_OPERATION_SET_CLASS_OFFTIME
:
116 if (uap
->out_time
!= USER_ADDR_NULL
) {
120 error
= priv_check_cred(kauth_cred_get(), PRIV_SELECTIVE_FORCED_IDLE
, 0);
122 dprintf("%s failed privilege check for sfi_ctl: %d\n", p
->p_comm
, error
);
125 dprintf("%s succeeded privilege check for sfi_ctl\n", p
->p_comm
);
128 if (uap
->time
== 0) {
129 /* actually a cancel */
130 kret
= sfi_class_offtime_cancel(uap
->sfi_class
);
132 kret
= sfi_set_class_offtime(uap
->sfi_class
, uap
->time
);
140 case SFI_CTL_OPERATION_GET_CLASS_OFFTIME
:
141 if (uap
->time
!= 0) {
145 kret
= sfi_get_class_offtime(uap
->sfi_class
, &out_time
);
146 if (kret
== KERN_SUCCESS
) {
147 error
= copyout(&out_time
, uap
->out_time
, sizeof(out_time
));
161 static int proc_apply_sfi_managed(proc_t p
, void * arg
)
163 uint32_t flags
= *(uint32_t *)arg
;
164 pid_t pid
= p
->p_pid
;
165 boolean_t managed_enabled
= (flags
== SFI_PROCESS_SET_MANAGED
)? TRUE
: FALSE
;
167 if (pid
== 0) { /* ignore setting on kernproc */
168 return PROC_RETURNED
;
171 if (managed_enabled
) {
172 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SFI
, SFI_PID_SET_MANAGED
) | DBG_FUNC_NONE
, pid
, 0, 0, 0, 0);
174 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SFI
, SFI_PID_CLEAR_MANAGED
) | DBG_FUNC_NONE
, pid
, 0, 0, 0, 0);
177 proc_set_task_policy(p
->task
, THREAD_NULL
,
178 TASK_POLICY_ATTRIBUTE
, TASK_POLICY_SFI_MANAGED
,
179 managed_enabled
? TASK_POLICY_ENABLE
: TASK_POLICY_DISABLE
);
180 return PROC_RETURNED
;
183 int sfi_pidctl(struct proc
*p __unused
, struct sfi_pidctl_args
*uap
, int32_t *retval __unused
)
185 uint32_t operation
= uap
->operation
;
186 pid_t pid
= uap
->pid
;
188 uint32_t out_flags
= 0;
189 boolean_t managed_enabled
;
193 case SFI_PIDCTL_OPERATION_PID_SET_FLAGS
:
194 if (uap
->out_sfi_flags
!= USER_ADDR_NULL
195 || !(uap
->sfi_flags
& SFI_PROCESS_SET_MANAGED_MASK
)
196 || uap
->sfi_flags
== SFI_PROCESS_SET_MANAGED_MASK
) {
200 error
= priv_check_cred(kauth_cred_get(), PRIV_SELECTIVE_FORCED_IDLE
, 0);
202 dprintf("%s failed privilege check for sfi_pidctl: %d\n", p
->p_comm
, error
);
205 dprintf("%s succeeded privilege check for sfi_pidctl\n", p
->p_comm
);
209 /* only allow SFI_PROCESS_SET_UNMANAGED for pid 0 */
210 if (uap
->sfi_flags
!= SFI_PROCESS_SET_UNMANAGED
) {
214 proc_iterate(PROC_ALLPROCLIST
, proc_apply_sfi_managed
, (void *)&uap
->sfi_flags
, NULL
, NULL
);
218 targetp
= proc_find(pid
);
224 proc_apply_sfi_managed(targetp
, (void *)&uap
->sfi_flags
);
229 case SFI_PIDCTL_OPERATION_PID_GET_FLAGS
:
230 if (uap
->sfi_flags
!= 0) {
237 targetp
= proc_find(pid
);
243 managed_enabled
= proc_get_task_policy(targetp
->task
, THREAD_NULL
, TASK_POLICY_ATTRIBUTE
, TASK_POLICY_SFI_MANAGED
);
247 out_flags
= managed_enabled
? SFI_PROCESS_SET_MANAGED
: SFI_PROCESS_SET_UNMANAGED
;
249 error
= copyout(&out_flags
, uap
->out_sfi_flags
, sizeof(out_flags
));