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 /***************************
80 ***************************/
85 kperf_cfg_lckgrp_attr
= lck_grp_attr_alloc_init();
86 kperf_cfg_lckgrp
= lck_grp_alloc_init("kperf cfg",
87 kperf_cfg_lckgrp_attr
);
88 lck_mtx_init(&kperf_cfg_lock
, kperf_cfg_lckgrp
, LCK_ATTR_NULL
);
90 kperf_cfg_initted
= TRUE
;
93 /***************************
97 ***************************/
100 sysctl_timer_period( __unused
struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
103 uint64_t inputs
[2], retval
;
104 unsigned timer
, set
= 0;
106 /* get 2x 64-bit words */
107 error
= SYSCTL_IN( req
, inputs
, 2*sizeof(inputs
[0]) );
112 timer
= (unsigned) inputs
[0];
113 if( inputs
[1] != ~0ULL )
118 error
= kperf_timer_set_period( timer
, inputs
[1] );
123 error
= kperf_timer_get_period(timer
, &retval
);
130 error
= SYSCTL_OUT( req
, inputs
, 2*sizeof(inputs
[0]) );
136 sysctl_timer_action( __unused
struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
141 unsigned timer
, set
= 0;
143 /* get 2x 64-bit words */
144 error
= SYSCTL_IN( req
, inputs
, 2*sizeof(inputs
[0]) );
149 timer
= (unsigned) inputs
[0];
150 if( inputs
[1] != ~0ULL )
155 error
= kperf_timer_set_action( timer
, inputs
[1] );
160 error
= kperf_timer_get_action(timer
, &retval
);
167 error
= SYSCTL_OUT( req
, inputs
, 2*sizeof(inputs
[0]) );
173 sysctl_action_samplers( __unused
struct sysctl_oid
*oidp
,
174 struct sysctl_req
*req
)
179 unsigned actionid
, set
= 0;
181 /* get 3x 64-bit words */
182 error
= SYSCTL_IN( req
, inputs
, 3*sizeof(inputs
[0]) );
187 set
= (unsigned) inputs
[0];
188 actionid
= (unsigned) inputs
[1];
192 error
= kperf_action_set_samplers( actionid
, inputs
[2] );
197 error
= kperf_action_get_samplers(actionid
, &retval
);
204 error
= SYSCTL_OUT( req
, inputs
, 3*sizeof(inputs
[0]) );
210 sysctl_action_userdata( __unused
struct sysctl_oid
*oidp
,
211 struct sysctl_req
*req
)
216 unsigned actionid
, set
= 0;
218 /* get 3x 64-bit words */
219 error
= SYSCTL_IN( req
, inputs
, 3*sizeof(inputs
[0]) );
224 set
= (unsigned) inputs
[0];
225 actionid
= (unsigned) inputs
[1];
229 error
= kperf_action_set_userdata( actionid
, inputs
[2] );
234 error
= kperf_action_get_userdata(actionid
, &retval
);
241 error
= SYSCTL_OUT( req
, inputs
, 3*sizeof(inputs
[0]) );
247 sysctl_action_filter( __unused
struct sysctl_oid
*oidp
,
248 struct sysctl_req
*req
, int is_task_t
)
253 unsigned actionid
, set
= 0;
254 mach_port_name_t portname
;
257 /* get 3x 64-bit words */
258 error
= SYSCTL_IN( req
, inputs
, 3*sizeof(inputs
[0]) );
263 set
= (unsigned) inputs
[0];
264 actionid
= (unsigned) inputs
[1];
270 portname
= (mach_port_name_t
) inputs
[2];
271 pid
= kperf_port_to_pid(portname
);
274 pid
= (int) inputs
[2];
276 error
= kperf_action_set_filter( actionid
, pid
);
281 error
= kperf_action_get_filter(actionid
, &retval
);
288 error
= SYSCTL_OUT( req
, inputs
, 3*sizeof(inputs
[0]) );
294 sysctl_sampling( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
299 /* get the old value and process it */
300 value
= kperf_sampling_status();
302 /* copy out the old value, get the new value */
303 error
= sysctl_handle_int(oidp
, &value
, 0, req
);
304 if (error
|| !req
->newptr
)
307 /* if that worked, and we're writing... */
309 error
= kperf_sampling_enable();
311 error
= kperf_sampling_disable();
317 sysctl_action_count( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
322 /* get the old value and process it */
323 value
= kperf_action_get_count();
325 /* copy out the old value, get the new value */
326 error
= sysctl_handle_int(oidp
, &value
, 0, req
);
327 if (error
|| !req
->newptr
)
330 /* if that worked, and we're writing... */
331 return kperf_action_set_count(value
);
335 sysctl_timer_count( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
340 /* get the old value and process it */
341 value
= kperf_timer_get_count();
343 /* copy out the old value, get the new value */
344 error
= sysctl_handle_int(oidp
, &value
, 0, req
);
345 if (error
|| !req
->newptr
)
348 /* if that worked, and we're writing... */
349 return kperf_timer_set_count(value
);
353 sysctl_timer_pet( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
358 /* get the old value and process it */
359 value
= kperf_timer_get_petid();
361 /* copy out the old value, get the new value */
362 error
= sysctl_handle_int(oidp
, &value
, 0, req
);
363 if (error
|| !req
->newptr
)
366 /* if that worked, and we're writing... */
367 return kperf_timer_set_petid(value
);
371 sysctl_bless( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
376 /* get the old value and process it */
379 /* copy out the old value, get the new value */
380 error
= sysctl_handle_int(oidp
, &value
, 0, req
);
381 if (error
|| !req
->newptr
)
384 /* if that worked, and we're writing... */
385 error
= kperf_bless_pid(value
);
391 sysctl_bless_preempt( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
396 /* get the old value and process it */
397 value
= blessed_preempt
;
399 /* copy out the old value, get the new value */
400 error
= sysctl_handle_int(oidp
, &value
, 0, req
);
401 if (error
|| !req
->newptr
)
404 /* if that worked, and we're writing... */
405 blessed_preempt
= value
? TRUE
: FALSE
;
412 sysctl_kdbg_callstacks( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
417 /* get the old value and process it */
418 value
= kperf_kdbg_get_stacks();
420 /* copy out the old value, get the new value */
421 error
= sysctl_handle_int(oidp
, &value
, 0, req
);
422 if (error
|| !req
->newptr
)
425 /* if that worked, and we're writing... */
426 error
= kperf_kdbg_set_stacks(value
);
432 sysctl_pet_idle_rate( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
437 /* get the old value and process it */
438 value
= kperf_get_pet_idle_rate();
440 /* copy out the old value, get the new value */
441 error
= sysctl_handle_int(oidp
, &value
, 0, req
);
442 if (error
|| !req
->newptr
)
445 /* if that worked, and we're writing... */
446 kperf_set_pet_idle_rate(value
);
452 * #define SYSCTL_HANDLER_ARGS (struct sysctl_oid *oidp, \
453 * void *arg1, int arg2, \
454 * struct sysctl_req *req )
457 kperf_sysctl SYSCTL_HANDLER_ARGS
461 // __unused struct sysctl_oid *unused_oidp = oidp;
464 if ( !kperf_cfg_initted
)
465 panic("kperf_bootstrap not called");
467 ret
= kperf_access_check();
472 lck_mtx_lock(&kperf_cfg_lock
);
475 switch( (uintptr_t) arg1
)
477 case REQ_ACTION_COUNT
:
478 ret
= sysctl_action_count( oidp
, req
);
480 case REQ_ACTION_SAMPLERS
:
481 ret
= sysctl_action_samplers( oidp
, req
);
483 case REQ_ACTION_USERDATA
:
484 ret
= sysctl_action_userdata( oidp
, req
);
486 case REQ_TIMER_COUNT
:
487 ret
= sysctl_timer_count( oidp
, req
);
489 case REQ_TIMER_PERIOD
:
490 ret
= sysctl_timer_period( oidp
, req
);
493 ret
= sysctl_timer_pet( oidp
, req
);
495 case REQ_TIMER_ACTION
:
496 ret
= sysctl_timer_action( oidp
, req
);
499 ret
= sysctl_sampling( oidp
, req
);
501 case REQ_KDBG_CALLSTACKS
:
502 ret
= sysctl_kdbg_callstacks( oidp
, req
);
504 case REQ_ACTION_FILTER_BY_TASK
:
505 ret
= sysctl_action_filter( oidp
, req
, 1 );
507 case REQ_ACTION_FILTER_BY_PID
:
508 ret
= sysctl_action_filter( oidp
, req
, 0 );
510 case REQ_PET_IDLE_RATE
:
511 ret
= sysctl_pet_idle_rate( oidp
, req
);
513 case REQ_BLESS_PREEMPT
:
514 ret
= sysctl_bless_preempt( oidp
, req
);
521 lck_mtx_unlock(&kperf_cfg_lock
);
527 kperf_sysctl_bless_handler SYSCTL_HANDLER_ARGS
530 // __unused struct sysctl_oid *unused_oidp = oidp;
533 if ( !kperf_cfg_initted
)
534 panic("kperf_bootstrap not called");
536 lck_mtx_lock(&kperf_cfg_lock
);
539 if ( (uintptr_t) arg1
== REQ_BLESS
)
540 ret
= sysctl_bless( oidp
, req
);
544 lck_mtx_unlock(&kperf_cfg_lock
);
550 /***************************
554 ***************************/
556 /* Validate whether the current process has priviledges to access
557 * kperf (and by extension, trace). Returns 0 if access is granted.
560 kperf_access_check(void)
562 proc_t p
= current_proc();
565 boolean_t pid_gone
= FALSE
;
567 /* check if the pid that held the lock is gone */
568 blessed_p
= proc_find(blessed_pid
);
570 if ( blessed_p
!= NULL
)
571 proc_rele(blessed_p
);
575 if ( blessed_pid
== -1 || pid_gone
) {
577 ret
= suser(kauth_cred_get(), &p
->p_acflag
);
582 /* check against blessed pid */
583 if( p
->p_pid
!= blessed_pid
)
586 /* access granted. */
590 /* specify a pid as being able to access kperf/trace, depiste not
594 kperf_bless_pid(pid_t newpid
)
600 current_pid
= p
->p_pid
;
602 /* are we allowed to preempt? */
603 if ( (newpid
!= -1) && (blessed_pid
!= -1) &&
604 (blessed_pid
!= current_pid
) && !blessed_preempt
) {
605 /* check if the pid that held the lock is gone */
606 p
= proc_find(blessed_pid
);
614 /* validate new pid */
615 if ( newpid
!= -1 ) {
616 p
= proc_find(newpid
);
624 blessed_pid
= newpid
;
625 blessed_preempt
= FALSE
;
630 /***************************
634 ***************************/
636 /* root kperf node */
637 SYSCTL_NODE(, OID_AUTO
, kperf
, CTLFLAG_RW
|CTLFLAG_LOCKED
, 0,
640 /* action sub-section */
641 SYSCTL_NODE(_kperf
, OID_AUTO
, action
, CTLFLAG_RW
|CTLFLAG_LOCKED
, 0,
644 SYSCTL_PROC(_kperf_action
, OID_AUTO
, count
,
645 CTLTYPE_INT
|CTLFLAG_RW
|CTLFLAG_ANYBODY
,
646 (void*)REQ_ACTION_COUNT
,
647 sizeof(int), kperf_sysctl
, "I", "Number of actions");
649 SYSCTL_PROC(_kperf_action
, OID_AUTO
, samplers
,
650 CTLFLAG_RW
|CTLFLAG_ANYBODY
,
651 (void*)REQ_ACTION_SAMPLERS
,
652 3*sizeof(uint64_t), kperf_sysctl
, "UQ",
653 "What to sample what a trigger fires an action");
655 SYSCTL_PROC(_kperf_action
, OID_AUTO
, userdata
,
656 CTLFLAG_RW
|CTLFLAG_ANYBODY
,
657 (void*)REQ_ACTION_USERDATA
,
658 3*sizeof(uint64_t), kperf_sysctl
, "UQ",
659 "User data to attribute to action");
661 SYSCTL_PROC(_kperf_action
, OID_AUTO
, filter_by_task
,
662 CTLFLAG_RW
|CTLFLAG_ANYBODY
,
663 (void*)REQ_ACTION_FILTER_BY_TASK
,
664 3*sizeof(uint64_t), kperf_sysctl
, "UQ",
665 "Apply a task filter to the action");
667 SYSCTL_PROC(_kperf_action
, OID_AUTO
, filter_by_pid
,
668 CTLFLAG_RW
|CTLFLAG_ANYBODY
,
669 (void*)REQ_ACTION_FILTER_BY_PID
,
670 3*sizeof(uint64_t), kperf_sysctl
, "UQ",
671 "Apply a pid filter to the action");
673 /* timer sub-section */
674 SYSCTL_NODE(_kperf
, OID_AUTO
, timer
, CTLFLAG_RW
|CTLFLAG_LOCKED
, 0,
677 SYSCTL_PROC(_kperf_timer
, OID_AUTO
, count
,
678 CTLTYPE_INT
|CTLFLAG_RW
|CTLFLAG_ANYBODY
,
679 (void*)REQ_TIMER_COUNT
,
680 sizeof(int), kperf_sysctl
, "I", "Number of time triggers");
682 SYSCTL_PROC(_kperf_timer
, OID_AUTO
, period
,
683 CTLFLAG_RW
|CTLFLAG_ANYBODY
,
684 (void*)REQ_TIMER_PERIOD
,
685 2*sizeof(uint64_t), kperf_sysctl
, "UQ", "Timer number and period");
687 SYSCTL_PROC(_kperf_timer
, OID_AUTO
, action
,
688 CTLFLAG_RW
|CTLFLAG_ANYBODY
,
689 (void*)REQ_TIMER_ACTION
,
690 2*sizeof(uint64_t), kperf_sysctl
, "UQ", "Timer number and actionid");
692 SYSCTL_PROC(_kperf_timer
, OID_AUTO
, pet_timer
,
693 CTLTYPE_INT
|CTLFLAG_RW
|CTLFLAG_ANYBODY
,
694 (void*)REQ_TIMER_PET
,
695 sizeof(int), kperf_sysctl
, "I", "Which timer ID does PET");
698 SYSCTL_PROC(_kperf
, OID_AUTO
, sampling
,
699 CTLTYPE_INT
|CTLFLAG_RW
|CTLFLAG_ANYBODY
,
701 sizeof(int), kperf_sysctl
, "I", "Sampling running");
703 SYSCTL_PROC(_kperf
, OID_AUTO
, blessed_pid
,
704 CTLTYPE_INT
|CTLFLAG_RW
, /* must be root */
706 sizeof(int), kperf_sysctl_bless_handler
, "I", "Blessed pid");
708 SYSCTL_PROC(_kperf
, OID_AUTO
, blessed_preempt
,
709 CTLTYPE_INT
|CTLFLAG_RW
|CTLFLAG_ANYBODY
,
710 (void*)REQ_BLESS_PREEMPT
,
711 sizeof(int), kperf_sysctl
, "I", "Blessed preemption");
714 SYSCTL_PROC(_kperf
, OID_AUTO
, kdbg_callstacks
,
715 CTLTYPE_INT
|CTLFLAG_RW
|CTLFLAG_ANYBODY
,
716 (void*)REQ_KDBG_CALLSTACKS
,
717 sizeof(int), kperf_sysctl
, "I", "Generate kdbg callstacks");
719 SYSCTL_INT(_kperf
, OID_AUTO
, kdbg_cswitch
,
720 CTLTYPE_INT
|CTLFLAG_RW
|CTLFLAG_ANYBODY
,
721 &kperf_cswitch_hook
, 0, "Generate context switch info");
723 SYSCTL_PROC(_kperf
, OID_AUTO
, pet_idle_rate
,
724 CTLTYPE_INT
|CTLFLAG_RW
|CTLFLAG_ANYBODY
,
725 (void*)REQ_PET_IDLE_RATE
,
726 sizeof(int), kperf_sysctl
, "I", "Rate at which unscheduled threads are forced to be sampled in PET mode");
729 SYSCTL_INT(_kperf
, OID_AUTO
, debug_level
, CTLFLAG_RW
,
730 &kperf_debug_level
, 0, "debug level");