]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kperf/kperfbsd.c
149b07093f530d5858e78077df9c104c311fb3c2
[apple/xnu.git] / osfmk / kperf / kperfbsd.c
1 /*
2 * Copyright (c) 2011 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 /* sysctl interface for paramters from user-land */
30
31 #include <sys/param.h>
32 #include <sys/mman.h>
33 #include <sys/stat.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>
39
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>
46
47
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;
51
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)
60 #define REQ_BLESS (8)
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
68 /* simple state variables */
69 int kperf_debug_level = 0;
70
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;
75
76 /***************************
77 *
78 * lock init
79 *
80 ***************************/
81
82 void
83 kperf_bootstrap(void)
84 {
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);
89
90 kperf_cfg_initted = TRUE;
91 }
92
93 /***************************
94 *
95 * sysctl handlers
96 *
97 ***************************/
98
99 static int
100 sysctl_timer_period( __unused struct sysctl_oid *oidp, struct sysctl_req *req )
101 {
102 int error = 0;
103 uint64_t inputs[2], retval;
104 unsigned timer, set = 0;
105
106 /* get 2x 64-bit words */
107 error = SYSCTL_IN( req, inputs, 2*sizeof(inputs[0]) );
108 if(error)
109 return (error);
110
111 /* setup inputs */
112 timer = (unsigned) inputs[0];
113 if( inputs[1] != ~0ULL )
114 set = 1;
115
116 if( set )
117 {
118 error = kperf_timer_set_period( timer, inputs[1] );
119 if( error )
120 return error;
121 }
122
123 error = kperf_timer_get_period(timer, &retval);
124 if(error)
125 return (error);
126
127 inputs[1] = retval;
128
129 if( error == 0 )
130 error = SYSCTL_OUT( req, inputs, 2*sizeof(inputs[0]) );
131
132 return error;
133 }
134
135 static int
136 sysctl_timer_action( __unused struct sysctl_oid *oidp, struct sysctl_req *req )
137 {
138 int error = 0;
139 uint64_t inputs[2];
140 uint32_t retval;
141 unsigned timer, set = 0;
142
143 /* get 2x 64-bit words */
144 error = SYSCTL_IN( req, inputs, 2*sizeof(inputs[0]) );
145 if(error)
146 return (error);
147
148 /* setup inputs */
149 timer = (unsigned) inputs[0];
150 if( inputs[1] != ~0ULL )
151 set = 1;
152
153 if( set )
154 {
155 error = kperf_timer_set_action( timer, inputs[1] );
156 if( error )
157 return error;
158 }
159
160 error = kperf_timer_get_action(timer, &retval);
161 if(error)
162 return (error);
163
164 inputs[1] = retval;
165
166 if( error == 0 )
167 error = SYSCTL_OUT( req, inputs, 2*sizeof(inputs[0]) );
168
169 return error;
170 }
171
172 static int
173 sysctl_action_samplers( __unused struct sysctl_oid *oidp,
174 struct sysctl_req *req )
175 {
176 int error = 0;
177 uint64_t inputs[3];
178 uint32_t retval;
179 unsigned actionid, set = 0;
180
181 /* get 3x 64-bit words */
182 error = SYSCTL_IN( req, inputs, 3*sizeof(inputs[0]) );
183 if(error)
184 return (error);
185
186 /* setup inputs */
187 set = (unsigned) inputs[0];
188 actionid = (unsigned) inputs[1];
189
190 if( set )
191 {
192 error = kperf_action_set_samplers( actionid, inputs[2] );
193 if( error )
194 return error;
195 }
196
197 error = kperf_action_get_samplers(actionid, &retval);
198 if(error)
199 return (error);
200
201 inputs[2] = retval;
202
203 if( error == 0 )
204 error = SYSCTL_OUT( req, inputs, 3*sizeof(inputs[0]) );
205
206 return error;
207 }
208
209 static int
210 sysctl_action_userdata( __unused struct sysctl_oid *oidp,
211 struct sysctl_req *req )
212 {
213 int error = 0;
214 uint64_t inputs[3];
215 uint32_t retval;
216 unsigned actionid, set = 0;
217
218 /* get 3x 64-bit words */
219 error = SYSCTL_IN( req, inputs, 3*sizeof(inputs[0]) );
220 if(error)
221 return (error);
222
223 /* setup inputs */
224 set = (unsigned) inputs[0];
225 actionid = (unsigned) inputs[1];
226
227 if( set )
228 {
229 error = kperf_action_set_userdata( actionid, inputs[2] );
230 if( error )
231 return error;
232 }
233
234 error = kperf_action_get_userdata(actionid, &retval);
235 if(error)
236 return (error);
237
238 inputs[2] = retval;
239
240 if( error == 0 )
241 error = SYSCTL_OUT( req, inputs, 3*sizeof(inputs[0]) );
242
243 return error;
244 }
245
246 static int
247 sysctl_action_filter( __unused struct sysctl_oid *oidp,
248 struct sysctl_req *req, int is_task_t )
249 {
250 int error = 0;
251 uint64_t inputs[3];
252 int retval;
253 unsigned actionid, set = 0;
254 mach_port_name_t portname;
255 int pid;
256
257 /* get 3x 64-bit words */
258 error = SYSCTL_IN( req, inputs, 3*sizeof(inputs[0]) );
259 if(error)
260 return (error);
261
262 /* setup inputs */
263 set = (unsigned) inputs[0];
264 actionid = (unsigned) inputs[1];
265
266 if( set )
267 {
268 if( is_task_t )
269 {
270 portname = (mach_port_name_t) inputs[2];
271 pid = kperf_port_to_pid(portname);
272 }
273 else
274 pid = (int) inputs[2];
275
276 error = kperf_action_set_filter( actionid, pid );
277 if( error )
278 return error;
279 }
280
281 error = kperf_action_get_filter(actionid, &retval);
282 if(error)
283 return (error);
284
285 inputs[2] = retval;
286
287 if( error == 0 )
288 error = SYSCTL_OUT( req, inputs, 3*sizeof(inputs[0]) );
289
290 return error;
291 }
292
293 static int
294 sysctl_sampling( struct sysctl_oid *oidp, struct sysctl_req *req )
295 {
296 int error = 0;
297 uint32_t value = 0;
298
299 /* get the old value and process it */
300 value = kperf_sampling_status();
301
302 /* copy out the old value, get the new value */
303 error = sysctl_handle_int(oidp, &value, 0, req);
304 if (error || !req->newptr)
305 return (error);
306
307 /* if that worked, and we're writing... */
308 if( value )
309 error = kperf_sampling_enable();
310 else
311 error = kperf_sampling_disable();
312
313 return error;
314 }
315
316 static int
317 sysctl_action_count( struct sysctl_oid *oidp, struct sysctl_req *req )
318 {
319 int error = 0;
320 uint32_t value = 0;
321
322 /* get the old value and process it */
323 value = kperf_action_get_count();
324
325 /* copy out the old value, get the new value */
326 error = sysctl_handle_int(oidp, &value, 0, req);
327 if (error || !req->newptr)
328 return (error);
329
330 /* if that worked, and we're writing... */
331 return kperf_action_set_count(value);
332 }
333
334 static int
335 sysctl_timer_count( struct sysctl_oid *oidp, struct sysctl_req *req )
336 {
337 int error = 0;
338 uint32_t value = 0;
339
340 /* get the old value and process it */
341 value = kperf_timer_get_count();
342
343 /* copy out the old value, get the new value */
344 error = sysctl_handle_int(oidp, &value, 0, req);
345 if (error || !req->newptr)
346 return (error);
347
348 /* if that worked, and we're writing... */
349 return kperf_timer_set_count(value);
350 }
351
352 static int
353 sysctl_timer_pet( struct sysctl_oid *oidp, struct sysctl_req *req )
354 {
355 int error = 0;
356 uint32_t value = 0;
357
358 /* get the old value and process it */
359 value = kperf_timer_get_petid();
360
361 /* copy out the old value, get the new value */
362 error = sysctl_handle_int(oidp, &value, 0, req);
363 if (error || !req->newptr)
364 return (error);
365
366 /* if that worked, and we're writing... */
367 return kperf_timer_set_petid(value);
368 }
369
370 static int
371 sysctl_bless( struct sysctl_oid *oidp, struct sysctl_req *req )
372 {
373 int error = 0;
374 int value = 0;
375
376 /* get the old value and process it */
377 value = blessed_pid;
378
379 /* copy out the old value, get the new value */
380 error = sysctl_handle_int(oidp, &value, 0, req);
381 if (error || !req->newptr)
382 return (error);
383
384 /* if that worked, and we're writing... */
385 error = kperf_bless_pid(value);
386
387 return error;
388 }
389
390 static int
391 sysctl_bless_preempt( struct sysctl_oid *oidp, struct sysctl_req *req )
392 {
393 int error = 0;
394 int value = 0;
395
396 /* get the old value and process it */
397 value = blessed_preempt;
398
399 /* copy out the old value, get the new value */
400 error = sysctl_handle_int(oidp, &value, 0, req);
401 if (error || !req->newptr)
402 return (error);
403
404 /* if that worked, and we're writing... */
405 blessed_preempt = value ? TRUE : FALSE;
406
407 return 0;
408 }
409
410
411 static int
412 sysctl_kdbg_callstacks( struct sysctl_oid *oidp, struct sysctl_req *req )
413 {
414 int error = 0;
415 int value = 0;
416
417 /* get the old value and process it */
418 value = kperf_kdbg_get_stacks();
419
420 /* copy out the old value, get the new value */
421 error = sysctl_handle_int(oidp, &value, 0, req);
422 if (error || !req->newptr)
423 return (error);
424
425 /* if that worked, and we're writing... */
426 error = kperf_kdbg_set_stacks(value);
427
428 return error;
429 }
430
431 static int
432 sysctl_pet_idle_rate( struct sysctl_oid *oidp, struct sysctl_req *req )
433 {
434 int error = 0;
435 int value = 0;
436
437 /* get the old value and process it */
438 value = kperf_get_pet_idle_rate();
439
440 /* copy out the old value, get the new value */
441 error = sysctl_handle_int(oidp, &value, 0, req);
442 if (error || !req->newptr)
443 return (error);
444
445 /* if that worked, and we're writing... */
446 kperf_set_pet_idle_rate(value);
447
448 return error;
449 }
450
451 /*
452 * #define SYSCTL_HANDLER_ARGS (struct sysctl_oid *oidp, \
453 * void *arg1, int arg2, \
454 * struct sysctl_req *req )
455 */
456 static int
457 kperf_sysctl SYSCTL_HANDLER_ARGS
458 {
459 int ret;
460
461 // __unused struct sysctl_oid *unused_oidp = oidp;
462 (void)arg2;
463
464 if ( !kperf_cfg_initted )
465 panic("kperf_bootstrap not called");
466
467 ret = kperf_access_check();
468 if (ret) {
469 return ret;
470 }
471
472 lck_mtx_lock(&kperf_cfg_lock);
473
474 /* which request */
475 switch( (uintptr_t) arg1 )
476 {
477 case REQ_ACTION_COUNT:
478 ret = sysctl_action_count( oidp, req );
479 break;
480 case REQ_ACTION_SAMPLERS:
481 ret = sysctl_action_samplers( oidp, req );
482 break;
483 case REQ_ACTION_USERDATA:
484 ret = sysctl_action_userdata( oidp, req );
485 break;
486 case REQ_TIMER_COUNT:
487 ret = sysctl_timer_count( oidp, req );
488 break;
489 case REQ_TIMER_PERIOD:
490 ret = sysctl_timer_period( oidp, req );
491 break;
492 case REQ_TIMER_PET:
493 ret = sysctl_timer_pet( oidp, req );
494 break;
495 case REQ_TIMER_ACTION:
496 ret = sysctl_timer_action( oidp, req );
497 break;
498 case REQ_SAMPLING:
499 ret = sysctl_sampling( oidp, req );
500 break;
501 case REQ_KDBG_CALLSTACKS:
502 ret = sysctl_kdbg_callstacks( oidp, req );
503 break;
504 case REQ_ACTION_FILTER_BY_TASK:
505 ret = sysctl_action_filter( oidp, req, 1 );
506 break;
507 case REQ_ACTION_FILTER_BY_PID:
508 ret = sysctl_action_filter( oidp, req, 0 );
509 break;
510 case REQ_PET_IDLE_RATE:
511 ret = sysctl_pet_idle_rate( oidp, req );
512 break;
513 case REQ_BLESS_PREEMPT:
514 ret = sysctl_bless_preempt( oidp, req );
515 break;
516 default:
517 ret = ENOENT;
518 break;
519 }
520
521 lck_mtx_unlock(&kperf_cfg_lock);
522
523 return ret;
524 }
525
526 static int
527 kperf_sysctl_bless_handler SYSCTL_HANDLER_ARGS
528 {
529 int ret;
530 // __unused struct sysctl_oid *unused_oidp = oidp;
531 (void)arg2;
532
533 if ( !kperf_cfg_initted )
534 panic("kperf_bootstrap not called");
535
536 lck_mtx_lock(&kperf_cfg_lock);
537
538 /* which request */
539 if ( (uintptr_t) arg1 == REQ_BLESS )
540 ret = sysctl_bless( oidp, req );
541 else
542 ret = ENOENT;
543
544 lck_mtx_unlock(&kperf_cfg_lock);
545
546 return ret;
547 }
548
549
550 /***************************
551 *
552 * Access control
553 *
554 ***************************/
555
556 /* Validate whether the current process has priviledges to access
557 * kperf (and by extension, trace). Returns 0 if access is granted.
558 */
559 int
560 kperf_access_check(void)
561 {
562 proc_t p = current_proc();
563 proc_t blessed_p;
564 int ret = 0;
565 boolean_t pid_gone = FALSE;
566
567 /* check if the pid that held the lock is gone */
568 blessed_p = proc_find(blessed_pid);
569
570 if ( blessed_p != NULL )
571 proc_rele(blessed_p);
572 else
573 pid_gone = TRUE;
574
575 if ( blessed_pid == -1 || pid_gone ) {
576 /* check for root */
577 ret = suser(kauth_cred_get(), &p->p_acflag);
578 if( !ret )
579 return ret;
580 }
581
582 /* check against blessed pid */
583 if( p->p_pid != blessed_pid )
584 return EACCES;
585
586 /* access granted. */
587 return 0;
588 }
589
590 /* specify a pid as being able to access kperf/trace, depiste not
591 * being root
592 */
593 int
594 kperf_bless_pid(pid_t newpid)
595 {
596 proc_t p = NULL;
597 pid_t current_pid;
598
599 p = current_proc();
600 current_pid = p->p_pid;
601
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);
607
608 if ( p != NULL ) {
609 proc_rele(p);
610 return EACCES;
611 }
612 }
613
614 /* validate new pid */
615 if ( newpid != -1 ) {
616 p = proc_find(newpid);
617
618 if ( p == NULL )
619 return EINVAL;
620
621 proc_rele(p);
622 }
623
624 blessed_pid = newpid;
625 blessed_preempt = FALSE;
626
627 return 0;
628 }
629
630 /***************************
631 *
632 * sysctl hooks
633 *
634 ***************************/
635
636 /* root kperf node */
637 SYSCTL_NODE(, OID_AUTO, kperf, CTLFLAG_RW|CTLFLAG_LOCKED, 0,
638 "kperf");
639
640 /* action sub-section */
641 SYSCTL_NODE(_kperf, OID_AUTO, action, CTLFLAG_RW|CTLFLAG_LOCKED, 0,
642 "action");
643
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");
648
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");
654
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");
660
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");
666
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");
672
673 /* timer sub-section */
674 SYSCTL_NODE(_kperf, OID_AUTO, timer, CTLFLAG_RW|CTLFLAG_LOCKED, 0,
675 "timer");
676
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");
681
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");
686
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");
691
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");
696
697 /* misc */
698 SYSCTL_PROC(_kperf, OID_AUTO, sampling,
699 CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
700 (void*)REQ_SAMPLING,
701 sizeof(int), kperf_sysctl, "I", "Sampling running");
702
703 SYSCTL_PROC(_kperf, OID_AUTO, blessed_pid,
704 CTLTYPE_INT|CTLFLAG_RW, /* must be root */
705 (void*)REQ_BLESS,
706 sizeof(int), kperf_sysctl_bless_handler, "I", "Blessed pid");
707
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");
712
713
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");
718
719 SYSCTL_INT(_kperf, OID_AUTO, kdbg_cswitch,
720 CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
721 &kperf_cswitch_hook, 0, "Generate context switch info");
722
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");
727
728 /* debug */
729 SYSCTL_INT(_kperf, OID_AUTO, debug_level, CTLFLAG_RW,
730 &kperf_debug_level, 0, "debug level");
731