]>
Commit | Line | Data |
---|---|---|
316670eb A |
1 | /* |
2 | * Copyright (c) 2011 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
39037602 | 5 | * |
316670eb A |
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. | |
39037602 | 14 | * |
316670eb A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
39037602 | 17 | * |
316670eb A |
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. | |
39037602 | 25 | * |
316670eb A |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
27 | */ | |
28 | ||
29 | /* sysctl interface for paramters from user-land */ | |
30 | ||
39037602 A |
31 | #include <kern/debug.h> |
32 | #include <libkern/libkern.h> | |
33 | #include <pexpert/pexpert.h> | |
316670eb A |
34 | #include <sys/param.h> |
35 | #include <sys/mman.h> | |
36 | #include <sys/stat.h> | |
37 | #include <sys/sysctl.h> | |
39236c6e | 38 | #include <sys/kauth.h> |
316670eb | 39 | |
316670eb | 40 | #include <kperf/action.h> |
39037602 A |
41 | #include <kperf/context.h> |
42 | #include <kperf/kdebug_trigger.h> | |
316670eb | 43 | #include <kperf/kperf.h> |
39037602 A |
44 | #include <kperf/kperfbsd.h> |
45 | #include <kperf/kperf_timer.h> | |
46 | #include <kperf/pet.h> | |
316670eb | 47 | |
39037602 | 48 | #include <sys/ktrace.h> |
39236c6e A |
49 | |
50 | /* IDs for dispatch from SYSCTL macros */ | |
39037602 A |
51 | #define REQ_SAMPLING (1) |
52 | #define REQ_ACTION_COUNT (2) | |
53 | #define REQ_ACTION_SAMPLERS (3) | |
54 | #define REQ_TIMER_COUNT (4) | |
55 | #define REQ_TIMER_PERIOD (5) | |
56 | #define REQ_TIMER_PET (6) | |
57 | #define REQ_TIMER_ACTION (7) | |
58 | #define REQ_BLESS (8) | |
59 | #define REQ_ACTION_USERDATA (9) | |
60 | #define REQ_ACTION_FILTER_BY_TASK (10) | |
61 | #define REQ_ACTION_FILTER_BY_PID (11) | |
62 | /* 12 unused */ | |
63 | #define REQ_PET_IDLE_RATE (13) | |
64 | #define REQ_BLESS_PREEMPT (14) | |
65 | #define REQ_KDBG_CSWITCH (15) | |
66 | #define REQ_RESET (16) | |
67 | /* 17 unused */ | |
68 | #define REQ_ACTION_UCALLSTACK_DEPTH (18) | |
69 | #define REQ_ACTION_KCALLSTACK_DEPTH (19) | |
70 | #define REQ_LIGHTWEIGHT_PET (20) | |
71 | #define REQ_KDEBUG_ACTION (21) | |
72 | #define REQ_KDEBUG_FILTER (22) | |
39236c6e | 73 | |
39037602 | 74 | int kperf_debug_level = 0; |
39236c6e | 75 | |
39037602 A |
76 | #if DEVELOPMENT || DEBUG |
77 | _Atomic long long kperf_pending_ipis = 0; | |
78 | #endif /* DEVELOPMENT || DEBUG */ | |
fe8ab488 | 79 | |
39037602 A |
80 | /* |
81 | * kperf has a different sysctl model than others. | |
82 | * | |
83 | * For simple queries like the number of actions, the normal sysctl style | |
84 | * of get/set works well. | |
39236c6e | 85 | * |
39037602 A |
86 | * However, when requesting information about something specific, like an |
87 | * action, user space needs to provide some contextual information. This | |
88 | * information is stored in a uint64_t array that includes the context, like | |
89 | * the action ID it is interested in. If user space is getting the value from | |
90 | * the kernel, then the get side of the sysctl is valid. If it is setting the | |
91 | * value, then the get pointers are left NULL. | |
39236c6e | 92 | * |
39037602 A |
93 | * These functions handle marshalling and unmarshalling data from sysctls. |
94 | */ | |
39236c6e | 95 | |
39037602 A |
96 | static int |
97 | kperf_sysctl_get_set_uint32(struct sysctl_req *req, | |
98 | uint32_t (*get)(void), int (*set)(uint32_t)) | |
39236c6e | 99 | { |
39037602 A |
100 | assert(req != NULL); |
101 | assert(get != NULL); | |
102 | assert(set != NULL); | |
39236c6e | 103 | |
39037602 A |
104 | uint32_t value = 0; |
105 | if (req->oldptr) { | |
106 | value = get(); | |
107 | } | |
316670eb | 108 | |
39037602 A |
109 | int error = sysctl_io_number(req, value, sizeof(value), &value, NULL); |
110 | ||
111 | if (error || !req->newptr) { | |
112 | return error; | |
113 | } | |
114 | ||
115 | return set(value); | |
116 | } | |
316670eb A |
117 | |
118 | static int | |
39037602 A |
119 | kperf_sysctl_get_set_int(struct sysctl_req *req, |
120 | int (*get)(void), int (*set)(int)) | |
316670eb | 121 | { |
39037602 A |
122 | assert(req != NULL); |
123 | assert(get != NULL); | |
124 | assert(set != NULL); | |
316670eb | 125 | |
39037602 A |
126 | int value = 0; |
127 | if (req->oldptr) { | |
128 | value = get(); | |
129 | } | |
316670eb | 130 | |
39037602 | 131 | int error = sysctl_io_number(req, value, sizeof(value), &value, NULL); |
39236c6e | 132 | |
39037602 A |
133 | if (error || !req->newptr) { |
134 | return error; | |
135 | } | |
136 | ||
137 | return set(value); | |
39236c6e A |
138 | } |
139 | ||
140 | static int | |
39037602 A |
141 | kperf_sysctl_get_set_unsigned_uint32(struct sysctl_req *req, |
142 | int (*get)(unsigned int, uint32_t *), int (*set)(unsigned int, uint32_t)) | |
39236c6e | 143 | { |
39037602 A |
144 | assert(req != NULL); |
145 | assert(get != NULL); | |
146 | assert(set != NULL); | |
147 | ||
148 | int error; | |
149 | uint64_t inputs[2]; | |
150 | if ((error = SYSCTL_IN(req, inputs, sizeof(inputs)))) { | |
151 | return error; | |
152 | } | |
153 | ||
154 | unsigned int action_id = (unsigned int)inputs[0]; | |
155 | uint32_t new_value = (uint32_t)inputs[1]; | |
316670eb | 156 | |
39037602 A |
157 | if (req->oldptr != USER_ADDR_NULL) { |
158 | uint32_t value_out = 0; | |
159 | if ((error = get(action_id, &value_out))) { | |
160 | return error; | |
161 | } | |
39236c6e | 162 | |
39037602 A |
163 | inputs[1] = value_out; |
164 | } else { | |
165 | if ((error = set(action_id, new_value))) { | |
166 | return error; | |
167 | } | |
168 | } | |
39236c6e | 169 | |
39037602 A |
170 | if (req->oldptr != USER_ADDR_NULL) { |
171 | error = SYSCTL_OUT(req, inputs, sizeof(inputs)); | |
172 | return error; | |
173 | } else { | |
174 | return 0; | |
175 | } | |
316670eb A |
176 | } |
177 | ||
39037602 A |
178 | /* |
179 | * These functions are essentially the same as the generic | |
180 | * kperf_sysctl_get_set_unsigned_uint32, except they have unique input sizes. | |
181 | */ | |
182 | ||
316670eb | 183 | static int |
39037602 | 184 | sysctl_timer_period(struct sysctl_req *req) |
316670eb | 185 | { |
39037602 | 186 | assert(req != NULL); |
316670eb | 187 | |
39037602 A |
188 | int error; |
189 | uint64_t inputs[2]; | |
190 | if ((error = SYSCTL_IN(req, inputs, sizeof(inputs)))) { | |
191 | return error; | |
192 | } | |
193 | ||
194 | unsigned int timer = (unsigned int)inputs[0]; | |
195 | uint64_t new_period = inputs[1]; | |
316670eb | 196 | |
39037602 A |
197 | if (req->oldptr != USER_ADDR_NULL) { |
198 | uint64_t period_out = 0; | |
199 | if ((error = kperf_timer_get_period(timer, &period_out))) { | |
200 | return error; | |
201 | } | |
202 | ||
203 | inputs[1] = period_out; | |
204 | } else { | |
205 | if ((error = kperf_timer_set_period(timer, new_period))) { | |
206 | return error; | |
207 | } | |
208 | } | |
39236c6e | 209 | |
39037602 | 210 | return SYSCTL_OUT(req, inputs, sizeof(inputs)); |
39236c6e A |
211 | } |
212 | ||
213 | static int | |
39037602 | 214 | sysctl_action_filter(struct sysctl_req *req, boolean_t is_task_t) |
39236c6e | 215 | { |
39037602 A |
216 | assert(req != NULL); |
217 | ||
218 | int error; | |
219 | uint64_t inputs[2]; | |
220 | if ((error = SYSCTL_IN(req, inputs, sizeof(inputs)))) { | |
221 | return error; | |
222 | } | |
223 | ||
224 | unsigned int actionid = (unsigned int)inputs[0]; | |
225 | int new_filter = (int)inputs[1]; | |
39236c6e | 226 | |
39037602 A |
227 | if (req->oldptr != USER_ADDR_NULL) { |
228 | int filter_out; | |
229 | if ((error = kperf_action_get_filter(actionid, &filter_out))) { | |
230 | return error; | |
231 | } | |
232 | ||
233 | inputs[1] = filter_out; | |
234 | } else { | |
235 | int pid = is_task_t ? kperf_port_to_pid((mach_port_name_t)new_filter) | |
236 | : new_filter; | |
39236c6e | 237 | |
39037602 A |
238 | if ((error = kperf_action_set_filter(actionid, pid))) { |
239 | return error; | |
240 | } | |
241 | } | |
39236c6e | 242 | |
39037602 | 243 | return SYSCTL_OUT(req, inputs, sizeof(inputs)); |
39236c6e A |
244 | } |
245 | ||
246 | static int | |
39037602 | 247 | sysctl_bless(struct sysctl_req *req) |
39236c6e | 248 | { |
39037602 A |
249 | int value = ktrace_get_owning_pid(); |
250 | int error = sysctl_io_number(req, value, sizeof(value), &value, NULL); | |
39236c6e | 251 | |
39037602 A |
252 | if (error || !req->newptr) { |
253 | return error; | |
254 | } | |
39236c6e | 255 | |
39037602 | 256 | return ktrace_set_owning_pid(value); |
316670eb A |
257 | } |
258 | ||
39037602 A |
259 | /* sysctl handlers that use the generic functions */ |
260 | ||
316670eb | 261 | static int |
39037602 | 262 | sysctl_action_samplers(struct sysctl_req *req) |
316670eb | 263 | { |
39037602 A |
264 | return kperf_sysctl_get_set_unsigned_uint32(req, |
265 | kperf_action_get_samplers, kperf_action_set_samplers); | |
316670eb A |
266 | } |
267 | ||
268 | static int | |
39037602 | 269 | sysctl_action_userdata(struct sysctl_req *req) |
316670eb | 270 | { |
39037602 A |
271 | return kperf_sysctl_get_set_unsigned_uint32(req, |
272 | kperf_action_get_userdata, kperf_action_set_userdata); | |
316670eb A |
273 | } |
274 | ||
275 | static int | |
39037602 | 276 | sysctl_action_ucallstack_depth(struct sysctl_req *req) |
316670eb | 277 | { |
39037602 A |
278 | return kperf_sysctl_get_set_unsigned_uint32(req, |
279 | kperf_action_get_ucallstack_depth, kperf_action_set_ucallstack_depth); | |
316670eb A |
280 | } |
281 | ||
282 | static int | |
39037602 | 283 | sysctl_action_kcallstack_depth(struct sysctl_req *req) |
316670eb | 284 | { |
39037602 A |
285 | return kperf_sysctl_get_set_unsigned_uint32(req, |
286 | kperf_action_get_kcallstack_depth, kperf_action_set_kcallstack_depth); | |
316670eb A |
287 | } |
288 | ||
39236c6e | 289 | static int |
39037602 | 290 | sysctl_kdebug_action(struct sysctl_req *req) |
39236c6e | 291 | { |
39037602 A |
292 | return kperf_sysctl_get_set_int(req, kperf_kdebug_get_action, |
293 | kperf_kdebug_set_action); | |
39236c6e A |
294 | } |
295 | ||
296 | static int | |
39037602 | 297 | sysctl_kdebug_filter(struct sysctl_req *req) |
39236c6e | 298 | { |
39037602 | 299 | assert(req != NULL); |
39236c6e | 300 | |
39037602 A |
301 | if (req->oldptr != USER_ADDR_NULL) { |
302 | struct kperf_kdebug_filter *filter = NULL; | |
303 | uint32_t n_debugids = kperf_kdebug_get_filter(&filter); | |
304 | size_t filter_size = KPERF_KDEBUG_FILTER_SIZE(n_debugids); | |
39236c6e | 305 | |
39037602 A |
306 | if (n_debugids == 0) { |
307 | return EINVAL; | |
308 | } | |
39236c6e | 309 | |
39037602 A |
310 | return SYSCTL_OUT(req, filter, filter_size); |
311 | } | |
39236c6e | 312 | |
39037602 | 313 | return kperf_kdebug_set_filter(req->newptr, (uint32_t)req->newlen); |
39236c6e A |
314 | } |
315 | ||
39236c6e | 316 | static int |
39037602 | 317 | kperf_sampling_set(uint32_t sample_start) |
39236c6e | 318 | { |
39037602 A |
319 | if (sample_start) { |
320 | return kperf_sampling_enable(); | |
321 | } else { | |
322 | return kperf_sampling_disable(); | |
323 | } | |
39236c6e A |
324 | } |
325 | ||
326 | static int | |
39037602 | 327 | sysctl_sampling(struct sysctl_req *req) |
39236c6e | 328 | { |
39037602 A |
329 | return kperf_sysctl_get_set_uint32(req, kperf_sampling_status, |
330 | kperf_sampling_set); | |
331 | } | |
39236c6e | 332 | |
39037602 A |
333 | static int |
334 | sysctl_action_count(struct sysctl_req *req) | |
335 | { | |
336 | return kperf_sysctl_get_set_uint32(req, kperf_action_get_count, | |
337 | kperf_action_set_count); | |
338 | } | |
39236c6e | 339 | |
39037602 A |
340 | static int |
341 | sysctl_timer_count(struct sysctl_req *req) | |
342 | { | |
343 | return kperf_sysctl_get_set_uint32(req, kperf_timer_get_count, | |
344 | kperf_timer_set_count); | |
39236c6e A |
345 | } |
346 | ||
3e170ce0 | 347 | static int |
39037602 | 348 | sysctl_timer_action(struct sysctl_req *req) |
3e170ce0 | 349 | { |
39037602 A |
350 | return kperf_sysctl_get_set_unsigned_uint32(req, kperf_timer_get_action, |
351 | kperf_timer_set_action); | |
352 | } | |
3e170ce0 | 353 | |
39037602 A |
354 | static int |
355 | sysctl_timer_pet(struct sysctl_req *req) | |
356 | { | |
357 | return kperf_sysctl_get_set_uint32(req, kperf_timer_get_petid, | |
358 | kperf_timer_set_petid); | |
359 | } | |
3e170ce0 | 360 | |
39037602 A |
361 | static int |
362 | sysctl_bless_preempt(struct sysctl_req *req) | |
363 | { | |
364 | return sysctl_io_number(req, ktrace_root_set_owner_allowed, | |
365 | sizeof(ktrace_root_set_owner_allowed), | |
366 | &ktrace_root_set_owner_allowed, NULL); | |
3e170ce0 A |
367 | } |
368 | ||
369 | static int | |
39037602 | 370 | sysctl_kperf_reset(struct sysctl_req *req) |
3e170ce0 | 371 | { |
39037602 | 372 | int should_reset = 0; |
3e170ce0 | 373 | |
39037602 A |
374 | int error = sysctl_io_number(req, should_reset, sizeof(should_reset), |
375 | &should_reset, NULL); | |
376 | if (error) { | |
377 | return error; | |
378 | } | |
3e170ce0 | 379 | |
39037602 A |
380 | if (should_reset) { |
381 | ktrace_reset(KTRACE_KPERF); | |
382 | } | |
383 | return 0; | |
3e170ce0 A |
384 | } |
385 | ||
386 | static int | |
39037602 | 387 | sysctl_pet_idle_rate(struct sysctl_req *req) |
3e170ce0 | 388 | { |
39037602 A |
389 | return kperf_sysctl_get_set_int(req, kperf_get_pet_idle_rate, |
390 | kperf_set_pet_idle_rate); | |
391 | } | |
3e170ce0 | 392 | |
39037602 A |
393 | static int |
394 | sysctl_lightweight_pet(struct sysctl_req *req) | |
395 | { | |
396 | return kperf_sysctl_get_set_int(req, kperf_get_lightweight_pet, | |
397 | kperf_set_lightweight_pet); | |
398 | } | |
3e170ce0 | 399 | |
39037602 A |
400 | static int |
401 | sysctl_kdbg_cswitch(struct sysctl_req *req) | |
402 | { | |
403 | return kperf_sysctl_get_set_int(req, kperf_kdbg_cswitch_get, | |
404 | kperf_kdbg_cswitch_set); | |
3e170ce0 A |
405 | } |
406 | ||
316670eb A |
407 | static int |
408 | kperf_sysctl SYSCTL_HANDLER_ARGS | |
409 | { | |
39037602 | 410 | #pragma unused(oidp, arg2) |
39236c6e | 411 | int ret; |
39037602 | 412 | uintptr_t type = (uintptr_t)arg1; |
39236c6e | 413 | |
39037602 | 414 | lck_mtx_lock(ktrace_lock); |
39236c6e | 415 | |
39037602 A |
416 | if (req->oldptr == USER_ADDR_NULL && req->newptr != USER_ADDR_NULL) { |
417 | if ((ret = ktrace_configure(KTRACE_KPERF))) { | |
418 | lck_mtx_unlock(ktrace_lock); | |
419 | return ret; | |
420 | } | |
421 | } else { | |
422 | if ((ret = ktrace_read_check())) { | |
423 | lck_mtx_unlock(ktrace_lock); | |
424 | return ret; | |
425 | } | |
39236c6e A |
426 | } |
427 | ||
316670eb | 428 | /* which request */ |
39037602 | 429 | switch (type) { |
316670eb | 430 | case REQ_ACTION_COUNT: |
39037602 | 431 | ret = sysctl_action_count(req); |
39236c6e | 432 | break; |
316670eb | 433 | case REQ_ACTION_SAMPLERS: |
39037602 | 434 | ret = sysctl_action_samplers(req); |
39236c6e A |
435 | break; |
436 | case REQ_ACTION_USERDATA: | |
39037602 | 437 | ret = sysctl_action_userdata(req); |
39236c6e | 438 | break; |
316670eb | 439 | case REQ_TIMER_COUNT: |
39037602 | 440 | ret = sysctl_timer_count(req); |
39236c6e | 441 | break; |
316670eb | 442 | case REQ_TIMER_PERIOD: |
39037602 | 443 | ret = sysctl_timer_period(req); |
39236c6e | 444 | break; |
316670eb | 445 | case REQ_TIMER_PET: |
39037602 | 446 | ret = sysctl_timer_pet(req); |
39236c6e A |
447 | break; |
448 | case REQ_TIMER_ACTION: | |
39037602 | 449 | ret = sysctl_timer_action(req); |
39236c6e | 450 | break; |
316670eb | 451 | case REQ_SAMPLING: |
39037602 | 452 | ret = sysctl_sampling(req); |
39236c6e | 453 | break; |
3e170ce0 | 454 | case REQ_KDBG_CSWITCH: |
39037602 | 455 | ret = sysctl_kdbg_cswitch(req); |
3e170ce0 | 456 | break; |
39236c6e | 457 | case REQ_ACTION_FILTER_BY_TASK: |
39037602 | 458 | ret = sysctl_action_filter(req, TRUE); |
39236c6e A |
459 | break; |
460 | case REQ_ACTION_FILTER_BY_PID: | |
39037602 A |
461 | ret = sysctl_action_filter(req, FALSE); |
462 | break; | |
463 | case REQ_KDEBUG_ACTION: | |
464 | ret = sysctl_kdebug_action(req); | |
465 | break; | |
466 | case REQ_KDEBUG_FILTER: | |
467 | ret = sysctl_kdebug_filter(req); | |
39236c6e A |
468 | break; |
469 | case REQ_PET_IDLE_RATE: | |
39037602 | 470 | ret = sysctl_pet_idle_rate(req); |
39236c6e A |
471 | break; |
472 | case REQ_BLESS_PREEMPT: | |
39037602 A |
473 | ret = sysctl_bless_preempt(req); |
474 | break; | |
475 | case REQ_RESET: | |
476 | ret = sysctl_kperf_reset(req); | |
39236c6e | 477 | break; |
39037602 A |
478 | case REQ_ACTION_UCALLSTACK_DEPTH: |
479 | ret = sysctl_action_ucallstack_depth(req); | |
3e170ce0 | 480 | break; |
39037602 A |
481 | case REQ_ACTION_KCALLSTACK_DEPTH: |
482 | ret = sysctl_action_kcallstack_depth(req); | |
3e170ce0 | 483 | break; |
39037602 A |
484 | case REQ_LIGHTWEIGHT_PET: |
485 | ret = sysctl_lightweight_pet(req); | |
486 | break; | |
316670eb | 487 | default: |
39236c6e A |
488 | ret = ENOENT; |
489 | break; | |
490 | } | |
491 | ||
39037602 | 492 | lck_mtx_unlock(ktrace_lock); |
39236c6e A |
493 | |
494 | return ret; | |
495 | } | |
496 | ||
497 | static int | |
498 | kperf_sysctl_bless_handler SYSCTL_HANDLER_ARGS | |
499 | { | |
39037602 | 500 | #pragma unused(oidp, arg2) |
39236c6e | 501 | int ret; |
39236c6e | 502 | |
39037602 A |
503 | lck_mtx_lock(ktrace_lock); |
504 | ||
505 | /* if setting a new "blessed pid" (ktrace owning pid) */ | |
506 | if (req->newptr != USER_ADDR_NULL) { | |
507 | /* | |
508 | * root can bypass the ktrace check when a flag is set (for | |
509 | * backwards compatibility) or when ownership is maintained over | |
510 | * subsystems resets (to allow the user space process that set | |
511 | * ownership to unset it). | |
512 | */ | |
513 | if (!((ktrace_root_set_owner_allowed || | |
514 | ktrace_keep_ownership_on_reset) && | |
515 | kauth_cred_issuser(kauth_cred_get()))) | |
516 | { | |
517 | if ((ret = ktrace_configure(KTRACE_KPERF))) { | |
518 | lck_mtx_unlock(ktrace_lock); | |
519 | return ret; | |
520 | } | |
521 | } | |
522 | } else { | |
523 | if ((ret = ktrace_read_check())) { | |
524 | lck_mtx_unlock(ktrace_lock); | |
39236c6e | 525 | return ret; |
39236c6e A |
526 | } |
527 | } | |
528 | ||
39037602 A |
529 | /* which request */ |
530 | if ((uintptr_t)arg1 == REQ_BLESS) { | |
531 | ret = sysctl_bless(req); | |
532 | } else { | |
533 | ret = ENOENT; | |
316670eb | 534 | } |
39236c6e | 535 | |
39037602 | 536 | lck_mtx_unlock(ktrace_lock); |
fe8ab488 | 537 | |
39037602 | 538 | return ret; |
316670eb A |
539 | } |
540 | ||
541 | /* root kperf node */ | |
39037602 A |
542 | |
543 | SYSCTL_NODE(, OID_AUTO, kperf, CTLFLAG_RW | CTLFLAG_LOCKED, 0, | |
316670eb A |
544 | "kperf"); |
545 | ||
39037602 A |
546 | /* actions */ |
547 | ||
548 | SYSCTL_NODE(_kperf, OID_AUTO, action, CTLFLAG_RW | CTLFLAG_LOCKED, 0, | |
316670eb A |
549 | "action"); |
550 | ||
551 | SYSCTL_PROC(_kperf_action, OID_AUTO, count, | |
39037602 A |
552 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED, |
553 | (void *)REQ_ACTION_COUNT, | |
316670eb A |
554 | sizeof(int), kperf_sysctl, "I", "Number of actions"); |
555 | ||
556 | SYSCTL_PROC(_kperf_action, OID_AUTO, samplers, | |
39037602 A |
557 | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED, |
558 | (void *)REQ_ACTION_SAMPLERS, | |
559 | 3 * sizeof(uint64_t), kperf_sysctl, "UQ", | |
560 | "What to sample when a trigger fires an action"); | |
316670eb | 561 | |
39236c6e | 562 | SYSCTL_PROC(_kperf_action, OID_AUTO, userdata, |
39037602 A |
563 | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED, |
564 | (void *)REQ_ACTION_USERDATA, | |
565 | 3 * sizeof(uint64_t), kperf_sysctl, "UQ", | |
39236c6e A |
566 | "User data to attribute to action"); |
567 | ||
568 | SYSCTL_PROC(_kperf_action, OID_AUTO, filter_by_task, | |
39037602 A |
569 | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED, |
570 | (void *)REQ_ACTION_FILTER_BY_TASK, | |
571 | 3 * sizeof(uint64_t), kperf_sysctl, "UQ", | |
39236c6e A |
572 | "Apply a task filter to the action"); |
573 | ||
574 | SYSCTL_PROC(_kperf_action, OID_AUTO, filter_by_pid, | |
39037602 A |
575 | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED, |
576 | (void *)REQ_ACTION_FILTER_BY_PID, | |
577 | 3 * sizeof(uint64_t), kperf_sysctl, "UQ", | |
39236c6e A |
578 | "Apply a pid filter to the action"); |
579 | ||
39037602 A |
580 | SYSCTL_PROC(_kperf_action, OID_AUTO, ucallstack_depth, |
581 | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED, | |
582 | (void *)REQ_ACTION_UCALLSTACK_DEPTH, | |
583 | sizeof(int), kperf_sysctl, "I", | |
584 | "Maximum number of frames to include in user callstacks"); | |
585 | ||
586 | SYSCTL_PROC(_kperf_action, OID_AUTO, kcallstack_depth, | |
587 | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED, | |
588 | (void *)REQ_ACTION_KCALLSTACK_DEPTH, | |
589 | sizeof(int), kperf_sysctl, "I", | |
590 | "Maximum number of frames to include in kernel callstacks"); | |
591 | ||
592 | /* timers */ | |
593 | ||
594 | SYSCTL_NODE(_kperf, OID_AUTO, timer, CTLFLAG_RW | CTLFLAG_LOCKED, 0, | |
316670eb A |
595 | "timer"); |
596 | ||
597 | SYSCTL_PROC(_kperf_timer, OID_AUTO, count, | |
39037602 A |
598 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED, |
599 | (void *)REQ_TIMER_COUNT, | |
316670eb A |
600 | sizeof(int), kperf_sysctl, "I", "Number of time triggers"); |
601 | ||
602 | SYSCTL_PROC(_kperf_timer, OID_AUTO, period, | |
39037602 A |
603 | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED, |
604 | (void *)REQ_TIMER_PERIOD, | |
605 | 2 * sizeof(uint64_t), kperf_sysctl, "UQ", | |
606 | "Timer number and period"); | |
316670eb | 607 | |
39236c6e | 608 | SYSCTL_PROC(_kperf_timer, OID_AUTO, action, |
39037602 A |
609 | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED, |
610 | (void *)REQ_TIMER_ACTION, | |
611 | 2 * sizeof(uint64_t), kperf_sysctl, "UQ", | |
612 | "Timer number and actionid"); | |
39236c6e | 613 | |
316670eb | 614 | SYSCTL_PROC(_kperf_timer, OID_AUTO, pet_timer, |
39037602 A |
615 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED, |
616 | (void *)REQ_TIMER_PET, | |
316670eb A |
617 | sizeof(int), kperf_sysctl, "I", "Which timer ID does PET"); |
618 | ||
39037602 A |
619 | /* kdebug trigger */ |
620 | ||
621 | SYSCTL_NODE(_kperf, OID_AUTO, kdebug, CTLFLAG_RW | CTLFLAG_LOCKED, 0, | |
622 | "kdebug"); | |
623 | ||
624 | SYSCTL_PROC(_kperf_kdebug, OID_AUTO, action, | |
625 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED, | |
626 | (void*)REQ_KDEBUG_ACTION, | |
627 | sizeof(int), kperf_sysctl, "I", "ID of action to trigger on kdebug events"); | |
628 | ||
629 | SYSCTL_PROC(_kperf_kdebug, OID_AUTO, filter, | |
630 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED, | |
631 | (void*)REQ_KDEBUG_FILTER, | |
632 | sizeof(int), kperf_sysctl, "P", "The filter that determines which kdebug events trigger a sample"); | |
633 | ||
316670eb | 634 | /* misc */ |
39037602 | 635 | |
316670eb | 636 | SYSCTL_PROC(_kperf, OID_AUTO, sampling, |
39037602 A |
637 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED, |
638 | (void *)REQ_SAMPLING, | |
316670eb A |
639 | sizeof(int), kperf_sysctl, "I", "Sampling running"); |
640 | ||
39037602 A |
641 | SYSCTL_PROC(_kperf, OID_AUTO, reset, |
642 | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MASKED | CTLFLAG_LOCKED, | |
643 | (void *)REQ_RESET, | |
644 | 0, kperf_sysctl, "-", "Reset kperf"); | |
645 | ||
39236c6e | 646 | SYSCTL_PROC(_kperf, OID_AUTO, blessed_pid, |
39037602 A |
647 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, /* must be root */ |
648 | (void *)REQ_BLESS, | |
39236c6e A |
649 | sizeof(int), kperf_sysctl_bless_handler, "I", "Blessed pid"); |
650 | ||
651 | SYSCTL_PROC(_kperf, OID_AUTO, blessed_preempt, | |
39037602 A |
652 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED, |
653 | (void *)REQ_BLESS_PREEMPT, | |
39236c6e A |
654 | sizeof(int), kperf_sysctl, "I", "Blessed preemption"); |
655 | ||
3e170ce0 | 656 | SYSCTL_PROC(_kperf, OID_AUTO, kdbg_cswitch, |
39037602 | 657 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED, |
3e170ce0 A |
658 | (void *)REQ_KDBG_CSWITCH, |
659 | sizeof(int), kperf_sysctl, "I", "Generate context switch info"); | |
39236c6e A |
660 | |
661 | SYSCTL_PROC(_kperf, OID_AUTO, pet_idle_rate, | |
39037602 A |
662 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED, |
663 | (void *)REQ_PET_IDLE_RATE, | |
664 | sizeof(int), kperf_sysctl, "I", | |
665 | "Rate at which unscheduled threads are forced to be sampled in " | |
666 | "PET mode"); | |
667 | ||
668 | SYSCTL_PROC(_kperf, OID_AUTO, lightweight_pet, | |
669 | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED, | |
670 | (void *)REQ_LIGHTWEIGHT_PET, | |
671 | sizeof(int), kperf_sysctl, "I", | |
672 | "Status of lightweight PET mode"); | |
3e170ce0 | 673 | |
39236c6e | 674 | /* debug */ |
39037602 | 675 | SYSCTL_INT(_kperf, OID_AUTO, debug_level, CTLFLAG_RW | CTLFLAG_LOCKED, |
39236c6e A |
676 | &kperf_debug_level, 0, "debug level"); |
677 | ||
39037602 A |
678 | #if DEVELOPMENT || DEBUG |
679 | SYSCTL_QUAD(_kperf, OID_AUTO, already_pending_ipis, | |
680 | CTLFLAG_RD | CTLFLAG_LOCKED, | |
681 | &kperf_pending_ipis, ""); | |
682 | #endif /* DEVELOPMENT || DEBUG */ |