2 * Copyright (c) 2011 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 /* sysctl interface for paramters from user-land */
31 #include <sys/param.h>
34 #include <sys/sysctl.h>
35 #include <sys/kauth.h>
36 #include <libkern/libkern.h>
37 #include <kern/debug.h>
38 #include <pexpert/pexpert.h>
40 #include <kperf/context.h>
41 #include <kperf/action.h>
42 #include <kperf/timetrigger.h>
43 #include <kperf/pet.h>
44 #include <kperf/kperfbsd.h>
45 #include <kperf/kperf.h>
48 /* a pid which is allowed to control kperf without requiring root access */
49 static pid_t blessed_pid
= -1;
50 static boolean_t blessed_preempt
= FALSE
;
52 /* IDs for dispatch from SYSCTL macros */
53 #define REQ_SAMPLING (1)
54 #define REQ_ACTION_COUNT (2)
55 #define REQ_ACTION_SAMPLERS (3)
56 #define REQ_TIMER_COUNT (4)
57 #define REQ_TIMER_PERIOD (5)
58 #define REQ_TIMER_PET (6)
59 #define REQ_TIMER_ACTION (7)
61 #define REQ_ACTION_USERDATA (9)
62 #define REQ_ACTION_FILTER_BY_TASK (10)
63 #define REQ_ACTION_FILTER_BY_PID (11)
64 #define REQ_KDBG_CALLSTACKS (12)
65 #define REQ_PET_IDLE_RATE (13)
66 #define REQ_BLESS_PREEMPT (14)
68 /* simple state variables */
69 int kperf_debug_level
= 0;
71 static lck_grp_attr_t
*kperf_cfg_lckgrp_attr
= NULL
;
72 static lck_grp_t
*kperf_cfg_lckgrp
= NULL
;
73 static lck_mtx_t kperf_cfg_lock
;
74 static boolean_t kperf_cfg_initted
= FALSE
;
76 void kdbg_swap_global_state_pid(pid_t old_pid
, pid_t new_pid
); /* bsd/kern/kdebug.c */
78 /***************************
82 ***************************/
87 kperf_cfg_lckgrp_attr
= lck_grp_attr_alloc_init();
88 kperf_cfg_lckgrp
= lck_grp_alloc_init("kperf cfg",
89 kperf_cfg_lckgrp_attr
);
90 lck_mtx_init(&kperf_cfg_lock
, kperf_cfg_lckgrp
, LCK_ATTR_NULL
);
92 kperf_cfg_initted
= TRUE
;
95 /***************************
99 ***************************/
102 sysctl_timer_period( __unused
struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
105 uint64_t inputs
[2], retval
;
106 unsigned timer
, set
= 0;
108 /* get 2x 64-bit words */
109 error
= SYSCTL_IN( req
, inputs
, 2*sizeof(inputs
[0]) );
114 timer
= (unsigned) inputs
[0];
115 if( inputs
[1] != ~0ULL )
120 error
= kperf_timer_set_period( timer
, inputs
[1] );
125 error
= kperf_timer_get_period(timer
, &retval
);
132 error
= SYSCTL_OUT( req
, inputs
, 2*sizeof(inputs
[0]) );
138 sysctl_timer_action( __unused
struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
143 unsigned timer
, set
= 0;
145 /* get 2x 64-bit words */
146 error
= SYSCTL_IN( req
, inputs
, 2*sizeof(inputs
[0]) );
151 timer
= (unsigned) inputs
[0];
152 if( inputs
[1] != ~0ULL )
157 error
= kperf_timer_set_action( timer
, inputs
[1] );
162 error
= kperf_timer_get_action(timer
, &retval
);
169 error
= SYSCTL_OUT( req
, inputs
, 2*sizeof(inputs
[0]) );
175 sysctl_action_samplers( __unused
struct sysctl_oid
*oidp
,
176 struct sysctl_req
*req
)
181 unsigned actionid
, set
= 0;
183 /* get 3x 64-bit words */
184 error
= SYSCTL_IN( req
, inputs
, 3*sizeof(inputs
[0]) );
189 set
= (unsigned) inputs
[0];
190 actionid
= (unsigned) inputs
[1];
194 error
= kperf_action_set_samplers( actionid
, inputs
[2] );
199 error
= kperf_action_get_samplers(actionid
, &retval
);
206 error
= SYSCTL_OUT( req
, inputs
, 3*sizeof(inputs
[0]) );
212 sysctl_action_userdata( __unused
struct sysctl_oid
*oidp
,
213 struct sysctl_req
*req
)
218 unsigned actionid
, set
= 0;
220 /* get 3x 64-bit words */
221 error
= SYSCTL_IN( req
, inputs
, 3*sizeof(inputs
[0]) );
226 set
= (unsigned) inputs
[0];
227 actionid
= (unsigned) inputs
[1];
231 error
= kperf_action_set_userdata( actionid
, inputs
[2] );
236 error
= kperf_action_get_userdata(actionid
, &retval
);
243 error
= SYSCTL_OUT( req
, inputs
, 3*sizeof(inputs
[0]) );
249 sysctl_action_filter( __unused
struct sysctl_oid
*oidp
,
250 struct sysctl_req
*req
, int is_task_t
)
255 unsigned actionid
, set
= 0;
256 mach_port_name_t portname
;
259 /* get 3x 64-bit words */
260 error
= SYSCTL_IN( req
, inputs
, 3*sizeof(inputs
[0]) );
265 set
= (unsigned) inputs
[0];
266 actionid
= (unsigned) inputs
[1];
272 portname
= (mach_port_name_t
) inputs
[2];
273 pid
= kperf_port_to_pid(portname
);
276 pid
= (int) inputs
[2];
278 error
= kperf_action_set_filter( actionid
, pid
);
283 error
= kperf_action_get_filter(actionid
, &retval
);
290 error
= SYSCTL_OUT( req
, inputs
, 3*sizeof(inputs
[0]) );
296 sysctl_sampling( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
301 /* get the old value and process it */
302 value
= kperf_sampling_status();
304 /* copy out the old value, get the new value */
305 error
= sysctl_handle_int(oidp
, &value
, 0, req
);
306 if (error
|| !req
->newptr
)
309 /* if that worked, and we're writing... */
311 error
= kperf_sampling_enable();
313 error
= kperf_sampling_disable();
319 sysctl_action_count( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
324 /* get the old value and process it */
325 value
= kperf_action_get_count();
327 /* copy out the old value, get the new value */
328 error
= sysctl_handle_int(oidp
, &value
, 0, req
);
329 if (error
|| !req
->newptr
)
332 /* if that worked, and we're writing... */
333 return kperf_action_set_count(value
);
337 sysctl_timer_count( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
342 /* get the old value and process it */
343 value
= kperf_timer_get_count();
345 /* copy out the old value, get the new value */
346 error
= sysctl_handle_int(oidp
, &value
, 0, req
);
347 if (error
|| !req
->newptr
)
350 /* if that worked, and we're writing... */
351 return kperf_timer_set_count(value
);
355 sysctl_timer_pet( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
360 /* get the old value and process it */
361 value
= kperf_timer_get_petid();
363 /* copy out the old value, get the new value */
364 error
= sysctl_handle_int(oidp
, &value
, 0, req
);
365 if (error
|| !req
->newptr
)
368 /* if that worked, and we're writing... */
369 return kperf_timer_set_petid(value
);
373 sysctl_bless( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
378 /* get the old value and process it */
381 /* copy out the old value, get the new value */
382 error
= sysctl_handle_int(oidp
, &value
, 0, req
);
383 if (error
|| !req
->newptr
)
386 /* if that worked, and we're writing... */
387 error
= kperf_bless_pid(value
);
393 sysctl_bless_preempt( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
398 /* get the old value and process it */
399 value
= blessed_preempt
;
401 /* copy out the old value, get the new value */
402 error
= sysctl_handle_int(oidp
, &value
, 0, req
);
403 if (error
|| !req
->newptr
)
406 /* if that worked, and we're writing... */
407 blessed_preempt
= value
? TRUE
: FALSE
;
414 sysctl_kdbg_callstacks( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
419 /* get the old value and process it */
420 value
= kperf_kdbg_get_stacks();
422 /* copy out the old value, get the new value */
423 error
= sysctl_handle_int(oidp
, &value
, 0, req
);
424 if (error
|| !req
->newptr
)
427 /* if that worked, and we're writing... */
428 error
= kperf_kdbg_set_stacks(value
);
434 sysctl_pet_idle_rate( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
439 /* get the old value and process it */
440 value
= kperf_get_pet_idle_rate();
442 /* copy out the old value, get the new value */
443 error
= sysctl_handle_int(oidp
, &value
, 0, req
);
444 if (error
|| !req
->newptr
)
447 /* if that worked, and we're writing... */
448 kperf_set_pet_idle_rate(value
);
454 * #define SYSCTL_HANDLER_ARGS (struct sysctl_oid *oidp, \
455 * void *arg1, int arg2, \
456 * struct sysctl_req *req )
459 kperf_sysctl SYSCTL_HANDLER_ARGS
463 // __unused struct sysctl_oid *unused_oidp = oidp;
466 if ( !kperf_cfg_initted
)
467 panic("kperf_bootstrap not called");
469 ret
= kperf_access_check();
474 lck_mtx_lock(&kperf_cfg_lock
);
477 switch( (uintptr_t) arg1
)
479 case REQ_ACTION_COUNT
:
480 ret
= sysctl_action_count( oidp
, req
);
482 case REQ_ACTION_SAMPLERS
:
483 ret
= sysctl_action_samplers( oidp
, req
);
485 case REQ_ACTION_USERDATA
:
486 ret
= sysctl_action_userdata( oidp
, req
);
488 case REQ_TIMER_COUNT
:
489 ret
= sysctl_timer_count( oidp
, req
);
491 case REQ_TIMER_PERIOD
:
492 ret
= sysctl_timer_period( oidp
, req
);
495 ret
= sysctl_timer_pet( oidp
, req
);
497 case REQ_TIMER_ACTION
:
498 ret
= sysctl_timer_action( oidp
, req
);
501 ret
= sysctl_sampling( oidp
, req
);
503 case REQ_KDBG_CALLSTACKS
:
504 ret
= sysctl_kdbg_callstacks( oidp
, req
);
506 case REQ_ACTION_FILTER_BY_TASK
:
507 ret
= sysctl_action_filter( oidp
, req
, 1 );
509 case REQ_ACTION_FILTER_BY_PID
:
510 ret
= sysctl_action_filter( oidp
, req
, 0 );
512 case REQ_PET_IDLE_RATE
:
513 ret
= sysctl_pet_idle_rate( oidp
, req
);
515 case REQ_BLESS_PREEMPT
:
516 ret
= sysctl_bless_preempt( oidp
, req
);
523 lck_mtx_unlock(&kperf_cfg_lock
);
529 kperf_sysctl_bless_handler SYSCTL_HANDLER_ARGS
532 // __unused struct sysctl_oid *unused_oidp = oidp;
535 if ( !kperf_cfg_initted
)
536 panic("kperf_bootstrap not called");
538 lck_mtx_lock(&kperf_cfg_lock
);
541 if ( (uintptr_t) arg1
== REQ_BLESS
)
542 ret
= sysctl_bless( oidp
, req
);
546 lck_mtx_unlock(&kperf_cfg_lock
);
552 /***************************
556 ***************************/
558 /* Validate whether the current process has priviledges to access
559 * kperf (and by extension, trace). Returns 0 if access is granted.
562 kperf_access_check(void)
564 proc_t p
= current_proc();
567 boolean_t pid_gone
= FALSE
;
569 /* check if the pid that held the lock is gone */
570 blessed_p
= proc_find(blessed_pid
);
572 if ( blessed_p
!= NULL
)
573 proc_rele(blessed_p
);
577 if ( blessed_pid
== -1 || pid_gone
) {
579 ret
= suser(kauth_cred_get(), &p
->p_acflag
);
584 /* check against blessed pid */
585 if( p
->p_pid
!= blessed_pid
)
588 /* access granted. */
592 /* specify a pid as being able to access kperf/trace, depiste not
596 kperf_bless_pid(pid_t newpid
)
602 current_pid
= p
->p_pid
;
604 /* are we allowed to preempt? */
605 if ( (newpid
!= -1) && (blessed_pid
!= -1) &&
606 (blessed_pid
!= current_pid
) && !blessed_preempt
) {
607 /* check if the pid that held the lock is gone */
608 p
= proc_find(blessed_pid
);
616 /* validate new pid */
617 if ( newpid
!= -1 ) {
618 p
= proc_find(newpid
);
626 /* take trace facility as well */
627 kdbg_swap_global_state_pid(blessed_pid
, newpid
);
629 blessed_pid
= newpid
;
630 blessed_preempt
= FALSE
;
635 /***************************
639 ***************************/
641 /* root kperf node */
642 SYSCTL_NODE(, OID_AUTO
, kperf
, CTLFLAG_RW
|CTLFLAG_LOCKED
, 0,
645 /* action sub-section */
646 SYSCTL_NODE(_kperf
, OID_AUTO
, action
, CTLFLAG_RW
|CTLFLAG_LOCKED
, 0,
649 SYSCTL_PROC(_kperf_action
, OID_AUTO
, count
,
650 CTLTYPE_INT
|CTLFLAG_RW
|CTLFLAG_ANYBODY
,
651 (void*)REQ_ACTION_COUNT
,
652 sizeof(int), kperf_sysctl
, "I", "Number of actions");
654 SYSCTL_PROC(_kperf_action
, OID_AUTO
, samplers
,
655 CTLFLAG_RW
|CTLFLAG_ANYBODY
,
656 (void*)REQ_ACTION_SAMPLERS
,
657 3*sizeof(uint64_t), kperf_sysctl
, "UQ",
658 "What to sample what a trigger fires an action");
660 SYSCTL_PROC(_kperf_action
, OID_AUTO
, userdata
,
661 CTLFLAG_RW
|CTLFLAG_ANYBODY
,
662 (void*)REQ_ACTION_USERDATA
,
663 3*sizeof(uint64_t), kperf_sysctl
, "UQ",
664 "User data to attribute to action");
666 SYSCTL_PROC(_kperf_action
, OID_AUTO
, filter_by_task
,
667 CTLFLAG_RW
|CTLFLAG_ANYBODY
,
668 (void*)REQ_ACTION_FILTER_BY_TASK
,
669 3*sizeof(uint64_t), kperf_sysctl
, "UQ",
670 "Apply a task filter to the action");
672 SYSCTL_PROC(_kperf_action
, OID_AUTO
, filter_by_pid
,
673 CTLFLAG_RW
|CTLFLAG_ANYBODY
,
674 (void*)REQ_ACTION_FILTER_BY_PID
,
675 3*sizeof(uint64_t), kperf_sysctl
, "UQ",
676 "Apply a pid filter to the action");
678 /* timer sub-section */
679 SYSCTL_NODE(_kperf
, OID_AUTO
, timer
, CTLFLAG_RW
|CTLFLAG_LOCKED
, 0,
682 SYSCTL_PROC(_kperf_timer
, OID_AUTO
, count
,
683 CTLTYPE_INT
|CTLFLAG_RW
|CTLFLAG_ANYBODY
,
684 (void*)REQ_TIMER_COUNT
,
685 sizeof(int), kperf_sysctl
, "I", "Number of time triggers");
687 SYSCTL_PROC(_kperf_timer
, OID_AUTO
, period
,
688 CTLFLAG_RW
|CTLFLAG_ANYBODY
,
689 (void*)REQ_TIMER_PERIOD
,
690 2*sizeof(uint64_t), kperf_sysctl
, "UQ", "Timer number and period");
692 SYSCTL_PROC(_kperf_timer
, OID_AUTO
, action
,
693 CTLFLAG_RW
|CTLFLAG_ANYBODY
,
694 (void*)REQ_TIMER_ACTION
,
695 2*sizeof(uint64_t), kperf_sysctl
, "UQ", "Timer number and actionid");
697 SYSCTL_PROC(_kperf_timer
, OID_AUTO
, pet_timer
,
698 CTLTYPE_INT
|CTLFLAG_RW
|CTLFLAG_ANYBODY
,
699 (void*)REQ_TIMER_PET
,
700 sizeof(int), kperf_sysctl
, "I", "Which timer ID does PET");
703 SYSCTL_PROC(_kperf
, OID_AUTO
, sampling
,
704 CTLTYPE_INT
|CTLFLAG_RW
|CTLFLAG_ANYBODY
,
706 sizeof(int), kperf_sysctl
, "I", "Sampling running");
708 SYSCTL_PROC(_kperf
, OID_AUTO
, blessed_pid
,
709 CTLTYPE_INT
|CTLFLAG_RW
, /* must be root */
711 sizeof(int), kperf_sysctl_bless_handler
, "I", "Blessed pid");
713 SYSCTL_PROC(_kperf
, OID_AUTO
, blessed_preempt
,
714 CTLTYPE_INT
|CTLFLAG_RW
|CTLFLAG_ANYBODY
,
715 (void*)REQ_BLESS_PREEMPT
,
716 sizeof(int), kperf_sysctl
, "I", "Blessed preemption");
719 SYSCTL_PROC(_kperf
, OID_AUTO
, kdbg_callstacks
,
720 CTLTYPE_INT
|CTLFLAG_RW
|CTLFLAG_ANYBODY
,
721 (void*)REQ_KDBG_CALLSTACKS
,
722 sizeof(int), kperf_sysctl
, "I", "Generate kdbg callstacks");
724 SYSCTL_INT(_kperf
, OID_AUTO
, kdbg_cswitch
,
725 CTLTYPE_INT
|CTLFLAG_RW
|CTLFLAG_ANYBODY
,
726 &kperf_cswitch_hook
, 0, "Generate context switch info");
728 SYSCTL_PROC(_kperf
, OID_AUTO
, pet_idle_rate
,
729 CTLTYPE_INT
|CTLFLAG_RW
|CTLFLAG_ANYBODY
,
730 (void*)REQ_PET_IDLE_RATE
,
731 sizeof(int), kperf_sysctl
, "I", "Rate at which unscheduled threads are forced to be sampled in PET mode");
734 SYSCTL_INT(_kperf
, OID_AUTO
, debug_level
, CTLFLAG_RW
,
735 &kperf_debug_level
, 0, "debug level");