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