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)
67 #define REQ_KDBG_CSWITCH (15)
68 #define REQ_CSWITCH_ACTION (16)
69 #define REQ_SIGNPOST_ACTION (17)
71 /* simple state variables */
72 int kperf_debug_level
= 0;
74 static lck_grp_attr_t
*kperf_cfg_lckgrp_attr
= NULL
;
75 static lck_grp_t
*kperf_cfg_lckgrp
= NULL
;
76 static lck_mtx_t kperf_cfg_lock
;
77 static boolean_t kperf_cfg_initted
= FALSE
;
79 void kdbg_swap_global_state_pid(pid_t old_pid
, pid_t new_pid
); /* bsd/kern/kdebug.c */
81 /***************************
85 ***************************/
90 kperf_cfg_lckgrp_attr
= lck_grp_attr_alloc_init();
91 kperf_cfg_lckgrp
= lck_grp_alloc_init("kperf cfg",
92 kperf_cfg_lckgrp_attr
);
93 lck_mtx_init(&kperf_cfg_lock
, kperf_cfg_lckgrp
, LCK_ATTR_NULL
);
95 kperf_cfg_initted
= TRUE
;
98 /***************************
102 ***************************/
105 sysctl_timer_period( __unused
struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
108 uint64_t inputs
[2], retval
;
109 unsigned timer
, set
= 0;
111 /* get 2x 64-bit words */
112 error
= SYSCTL_IN( req
, inputs
, 2*sizeof(inputs
[0]) );
117 timer
= (unsigned) inputs
[0];
118 if( inputs
[1] != ~0ULL )
123 error
= kperf_timer_set_period( timer
, inputs
[1] );
128 error
= kperf_timer_get_period(timer
, &retval
);
135 error
= SYSCTL_OUT( req
, inputs
, 2*sizeof(inputs
[0]) );
141 sysctl_timer_action( __unused
struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
146 unsigned timer
, set
= 0;
148 /* get 2x 64-bit words */
149 error
= SYSCTL_IN( req
, inputs
, 2*sizeof(inputs
[0]) );
154 timer
= (unsigned) inputs
[0];
155 if( inputs
[1] != ~0ULL )
160 error
= kperf_timer_set_action( timer
, inputs
[1] );
165 error
= kperf_timer_get_action(timer
, &retval
);
172 error
= SYSCTL_OUT( req
, inputs
, 2*sizeof(inputs
[0]) );
178 sysctl_action_samplers( __unused
struct sysctl_oid
*oidp
,
179 struct sysctl_req
*req
)
184 unsigned actionid
, set
= 0;
186 /* get 3x 64-bit words */
187 error
= SYSCTL_IN( req
, inputs
, 3*sizeof(inputs
[0]) );
192 set
= (unsigned) inputs
[0];
193 actionid
= (unsigned) inputs
[1];
197 error
= kperf_action_set_samplers( actionid
, inputs
[2] );
202 error
= kperf_action_get_samplers(actionid
, &retval
);
209 error
= SYSCTL_OUT( req
, inputs
, 3*sizeof(inputs
[0]) );
215 sysctl_action_userdata( __unused
struct sysctl_oid
*oidp
,
216 struct sysctl_req
*req
)
221 unsigned actionid
, set
= 0;
223 /* get 3x 64-bit words */
224 error
= SYSCTL_IN( req
, inputs
, 3*sizeof(inputs
[0]) );
229 set
= (unsigned) inputs
[0];
230 actionid
= (unsigned) inputs
[1];
234 error
= kperf_action_set_userdata( actionid
, inputs
[2] );
239 error
= kperf_action_get_userdata(actionid
, &retval
);
246 error
= SYSCTL_OUT( req
, inputs
, 3*sizeof(inputs
[0]) );
252 sysctl_action_filter( __unused
struct sysctl_oid
*oidp
,
253 struct sysctl_req
*req
, int is_task_t
)
258 unsigned actionid
, set
= 0;
259 mach_port_name_t portname
;
262 /* get 3x 64-bit words */
263 error
= SYSCTL_IN( req
, inputs
, 3*sizeof(inputs
[0]) );
268 set
= (unsigned) inputs
[0];
269 actionid
= (unsigned) inputs
[1];
275 portname
= (mach_port_name_t
) inputs
[2];
276 pid
= kperf_port_to_pid(portname
);
279 pid
= (int) inputs
[2];
281 error
= kperf_action_set_filter( actionid
, pid
);
286 error
= kperf_action_get_filter(actionid
, &retval
);
293 error
= SYSCTL_OUT( req
, inputs
, 3*sizeof(inputs
[0]) );
299 sysctl_sampling( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
304 /* get the old value and process it */
305 value
= kperf_sampling_status();
307 /* copy out the old value, get the new value */
308 error
= sysctl_handle_int(oidp
, &value
, 0, req
);
309 if (error
|| !req
->newptr
)
312 /* if that worked, and we're writing... */
314 error
= kperf_sampling_enable();
316 error
= kperf_sampling_disable();
322 sysctl_action_count( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
327 /* get the old value and process it */
328 value
= kperf_action_get_count();
330 /* copy out the old value, get the new value */
331 error
= sysctl_handle_int(oidp
, &value
, 0, req
);
332 if (error
|| !req
->newptr
)
335 /* if that worked, and we're writing... */
336 return kperf_action_set_count(value
);
340 sysctl_timer_count( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
345 /* get the old value and process it */
346 value
= kperf_timer_get_count();
348 /* copy out the old value, get the new value */
349 error
= sysctl_handle_int(oidp
, &value
, 0, req
);
350 if (error
|| !req
->newptr
)
353 /* if that worked, and we're writing... */
354 return kperf_timer_set_count(value
);
358 sysctl_timer_pet( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
363 /* get the old value and process it */
364 value
= kperf_timer_get_petid();
366 /* copy out the old value, get the new value */
367 error
= sysctl_handle_int(oidp
, &value
, 0, req
);
368 if (error
|| !req
->newptr
)
371 /* if that worked, and we're writing... */
372 return kperf_timer_set_petid(value
);
376 sysctl_bless( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
381 /* get the old value and process it */
384 /* copy out the old value, get the new value */
385 error
= sysctl_handle_int(oidp
, &value
, 0, req
);
386 if (error
|| !req
->newptr
)
389 /* if that worked, and we're writing... */
390 error
= kperf_bless_pid(value
);
396 sysctl_bless_preempt( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
401 /* get the old value and process it */
402 value
= blessed_preempt
;
404 /* copy out the old value, get the new value */
405 error
= sysctl_handle_int(oidp
, &value
, 0, req
);
406 if (error
|| !req
->newptr
)
409 /* if that worked, and we're writing... */
410 blessed_preempt
= value
? TRUE
: FALSE
;
417 sysctl_kdbg_callstacks( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
422 /* get the old value and process it */
423 value
= kperf_kdbg_get_stacks();
425 /* copy out the old value, get the new value */
426 error
= sysctl_handle_int(oidp
, &value
, 0, req
);
427 if (error
|| !req
->newptr
)
430 /* if that worked, and we're writing... */
431 error
= kperf_kdbg_set_stacks(value
);
437 sysctl_pet_idle_rate( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
442 /* get the old value and process it */
443 value
= kperf_get_pet_idle_rate();
445 /* copy out the old value, get the new value */
446 error
= sysctl_handle_int(oidp
, &value
, 0, req
);
447 if (error
|| !req
->newptr
)
450 /* if that worked, and we're writing... */
451 kperf_set_pet_idle_rate(value
);
457 sysctl_kdbg_cswitch( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
459 int value
= kperf_kdbg_cswitch_get();
460 int error
= sysctl_handle_int(oidp
, &value
, 0, req
);
462 if (error
|| !req
->newptr
) {
466 return kperf_kdbg_cswitch_set(value
);
470 sysctl_cswitch_action( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
472 int value
= kperf_cswitch_action_get();
473 int error
= sysctl_handle_int(oidp
, &value
, 0, req
);
475 if (error
|| !req
->newptr
) {
479 return kperf_cswitch_action_set(value
);
483 sysctl_signpost_action( struct sysctl_oid
*oidp
, struct sysctl_req
*req
)
485 int value
= kperf_signpost_action_get();
486 int error
= sysctl_handle_int(oidp
, &value
, 0, req
);
488 if (error
|| !req
->newptr
) {
492 return kperf_signpost_action_set(value
);
496 * #define SYSCTL_HANDLER_ARGS (struct sysctl_oid *oidp, \
497 * void *arg1, int arg2, \
498 * struct sysctl_req *req )
501 kperf_sysctl SYSCTL_HANDLER_ARGS
505 // __unused struct sysctl_oid *unused_oidp = oidp;
508 if ( !kperf_cfg_initted
)
509 panic("kperf_bootstrap not called");
511 ret
= kperf_access_check();
516 lck_mtx_lock(&kperf_cfg_lock
);
519 switch( (uintptr_t) arg1
)
521 case REQ_ACTION_COUNT
:
522 ret
= sysctl_action_count( oidp
, req
);
524 case REQ_ACTION_SAMPLERS
:
525 ret
= sysctl_action_samplers( oidp
, req
);
527 case REQ_ACTION_USERDATA
:
528 ret
= sysctl_action_userdata( oidp
, req
);
530 case REQ_TIMER_COUNT
:
531 ret
= sysctl_timer_count( oidp
, req
);
533 case REQ_TIMER_PERIOD
:
534 ret
= sysctl_timer_period( oidp
, req
);
537 ret
= sysctl_timer_pet( oidp
, req
);
539 case REQ_TIMER_ACTION
:
540 ret
= sysctl_timer_action( oidp
, req
);
543 ret
= sysctl_sampling( oidp
, req
);
545 case REQ_KDBG_CALLSTACKS
:
546 ret
= sysctl_kdbg_callstacks( oidp
, req
);
548 case REQ_KDBG_CSWITCH
:
549 ret
= sysctl_kdbg_cswitch( oidp
, req
);
551 case REQ_ACTION_FILTER_BY_TASK
:
552 ret
= sysctl_action_filter( oidp
, req
, 1 );
554 case REQ_ACTION_FILTER_BY_PID
:
555 ret
= sysctl_action_filter( oidp
, req
, 0 );
557 case REQ_PET_IDLE_RATE
:
558 ret
= sysctl_pet_idle_rate( oidp
, req
);
560 case REQ_BLESS_PREEMPT
:
561 ret
= sysctl_bless_preempt( oidp
, req
);
563 case REQ_CSWITCH_ACTION
:
564 ret
= sysctl_cswitch_action( oidp
, req
);
566 case REQ_SIGNPOST_ACTION
:
567 ret
= sysctl_signpost_action( oidp
, req
);
574 lck_mtx_unlock(&kperf_cfg_lock
);
580 kperf_sysctl_bless_handler SYSCTL_HANDLER_ARGS
583 // __unused struct sysctl_oid *unused_oidp = oidp;
586 if ( !kperf_cfg_initted
)
587 panic("kperf_bootstrap not called");
589 lck_mtx_lock(&kperf_cfg_lock
);
592 if ( (uintptr_t) arg1
== REQ_BLESS
)
593 ret
= sysctl_bless( oidp
, req
);
597 lck_mtx_unlock(&kperf_cfg_lock
);
602 /***************************
606 ***************************/
608 /* Validate whether the current process has priviledges to access
609 * kperf (and by extension, trace). Returns 0 if access is granted.
612 kperf_access_check(void)
614 proc_t p
= current_proc();
617 boolean_t pid_gone
= FALSE
;
619 /* check if the pid that held the lock is gone */
620 blessed_p
= proc_find(blessed_pid
);
622 if ( blessed_p
!= NULL
)
623 proc_rele(blessed_p
);
627 if ( blessed_pid
== -1 || pid_gone
) {
629 ret
= suser(kauth_cred_get(), &p
->p_acflag
);
634 /* check against blessed pid */
635 if( p
->p_pid
!= blessed_pid
)
638 /* access granted. */
642 /* specify a pid as being able to access kperf/trace, depiste not
646 kperf_bless_pid(pid_t newpid
)
652 current_pid
= p
->p_pid
;
654 /* are we allowed to preempt? */
655 if ( (newpid
!= -1) && (blessed_pid
!= -1) &&
656 (blessed_pid
!= current_pid
) && !blessed_preempt
) {
657 /* check if the pid that held the lock is gone */
658 p
= proc_find(blessed_pid
);
666 /* validate new pid */
667 if ( newpid
!= -1 ) {
668 p
= proc_find(newpid
);
676 /* take trace facility as well */
677 kdbg_swap_global_state_pid(blessed_pid
, newpid
);
679 blessed_pid
= newpid
;
680 blessed_preempt
= FALSE
;
685 /***************************
689 ***************************/
691 /* root kperf node */
692 SYSCTL_NODE(, OID_AUTO
, kperf
, CTLFLAG_RW
|CTLFLAG_LOCKED
, 0,
695 /* action sub-section */
696 SYSCTL_NODE(_kperf
, OID_AUTO
, action
, CTLFLAG_RW
|CTLFLAG_LOCKED
, 0,
699 SYSCTL_PROC(_kperf_action
, OID_AUTO
, count
,
700 CTLTYPE_INT
|CTLFLAG_RW
|CTLFLAG_ANYBODY
,
701 (void*)REQ_ACTION_COUNT
,
702 sizeof(int), kperf_sysctl
, "I", "Number of actions");
704 SYSCTL_PROC(_kperf_action
, OID_AUTO
, samplers
,
705 CTLFLAG_RW
|CTLFLAG_ANYBODY
,
706 (void*)REQ_ACTION_SAMPLERS
,
707 3*sizeof(uint64_t), kperf_sysctl
, "UQ",
708 "What to sample what a trigger fires an action");
710 SYSCTL_PROC(_kperf_action
, OID_AUTO
, userdata
,
711 CTLFLAG_RW
|CTLFLAG_ANYBODY
,
712 (void*)REQ_ACTION_USERDATA
,
713 3*sizeof(uint64_t), kperf_sysctl
, "UQ",
714 "User data to attribute to action");
716 SYSCTL_PROC(_kperf_action
, OID_AUTO
, filter_by_task
,
717 CTLFLAG_RW
|CTLFLAG_ANYBODY
,
718 (void*)REQ_ACTION_FILTER_BY_TASK
,
719 3*sizeof(uint64_t), kperf_sysctl
, "UQ",
720 "Apply a task filter to the action");
722 SYSCTL_PROC(_kperf_action
, OID_AUTO
, filter_by_pid
,
723 CTLFLAG_RW
|CTLFLAG_ANYBODY
,
724 (void*)REQ_ACTION_FILTER_BY_PID
,
725 3*sizeof(uint64_t), kperf_sysctl
, "UQ",
726 "Apply a pid filter to the action");
728 /* timer sub-section */
729 SYSCTL_NODE(_kperf
, OID_AUTO
, timer
, CTLFLAG_RW
|CTLFLAG_LOCKED
, 0,
732 SYSCTL_PROC(_kperf_timer
, OID_AUTO
, count
,
733 CTLTYPE_INT
|CTLFLAG_RW
|CTLFLAG_ANYBODY
,
734 (void*)REQ_TIMER_COUNT
,
735 sizeof(int), kperf_sysctl
, "I", "Number of time triggers");
737 SYSCTL_PROC(_kperf_timer
, OID_AUTO
, period
,
738 CTLFLAG_RW
|CTLFLAG_ANYBODY
,
739 (void*)REQ_TIMER_PERIOD
,
740 2*sizeof(uint64_t), kperf_sysctl
, "UQ", "Timer number and period");
742 SYSCTL_PROC(_kperf_timer
, OID_AUTO
, action
,
743 CTLFLAG_RW
|CTLFLAG_ANYBODY
,
744 (void*)REQ_TIMER_ACTION
,
745 2*sizeof(uint64_t), kperf_sysctl
, "UQ", "Timer number and actionid");
747 SYSCTL_PROC(_kperf_timer
, OID_AUTO
, pet_timer
,
748 CTLTYPE_INT
|CTLFLAG_RW
|CTLFLAG_ANYBODY
,
749 (void*)REQ_TIMER_PET
,
750 sizeof(int), kperf_sysctl
, "I", "Which timer ID does PET");
753 SYSCTL_PROC(_kperf
, OID_AUTO
, sampling
,
754 CTLTYPE_INT
|CTLFLAG_RW
|CTLFLAG_ANYBODY
,
756 sizeof(int), kperf_sysctl
, "I", "Sampling running");
758 SYSCTL_PROC(_kperf
, OID_AUTO
, blessed_pid
,
759 CTLTYPE_INT
|CTLFLAG_RW
, /* must be root */
761 sizeof(int), kperf_sysctl_bless_handler
, "I", "Blessed pid");
763 SYSCTL_PROC(_kperf
, OID_AUTO
, blessed_preempt
,
764 CTLTYPE_INT
|CTLFLAG_RW
|CTLFLAG_ANYBODY
,
765 (void*)REQ_BLESS_PREEMPT
,
766 sizeof(int), kperf_sysctl
, "I", "Blessed preemption");
768 SYSCTL_PROC(_kperf
, OID_AUTO
, kdbg_callstacks
,
769 CTLTYPE_INT
|CTLFLAG_RW
|CTLFLAG_ANYBODY
,
770 (void*)REQ_KDBG_CALLSTACKS
,
771 sizeof(int), kperf_sysctl
, "I", "Generate kdbg callstacks");
773 SYSCTL_PROC(_kperf
, OID_AUTO
, kdbg_cswitch
,
774 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_ANYBODY
,
775 (void *)REQ_KDBG_CSWITCH
,
776 sizeof(int), kperf_sysctl
, "I", "Generate context switch info");
778 SYSCTL_PROC(_kperf
, OID_AUTO
, pet_idle_rate
,
779 CTLTYPE_INT
|CTLFLAG_RW
|CTLFLAG_ANYBODY
,
780 (void*)REQ_PET_IDLE_RATE
,
781 sizeof(int), kperf_sysctl
, "I", "Rate at which unscheduled threads are forced to be sampled in PET mode");
783 SYSCTL_PROC(_kperf
, OID_AUTO
, cswitch_action
,
784 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_ANYBODY
,
785 (void*)REQ_CSWITCH_ACTION
,
786 sizeof(int), kperf_sysctl
, "I", "ID of action to trigger on context-switch");
788 SYSCTL_PROC(_kperf
, OID_AUTO
, signpost_action
,
789 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_ANYBODY
,
790 (void*)REQ_SIGNPOST_ACTION
,
791 sizeof(int), kperf_sysctl
, "I", "ID of action to trigger on signposts");
794 SYSCTL_INT(_kperf
, OID_AUTO
, debug_level
, CTLFLAG_RW
,
795 &kperf_debug_level
, 0, "debug level");