]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_kpc.c
xnu-2782.40.9.tar.gz
[apple/xnu.git] / bsd / kern / kern_kpc.c
1 /*
2 * Copyright (c) 2012 Apple 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 #include <kern/debug.h>
30 #include <kern/kalloc.h>
31 #include <sys/param.h>
32 #include <sys/mman.h>
33 #include <sys/stat.h>
34 #include <sys/sysctl.h>
35 #include <libkern/libkern.h>
36 #include <kern/assert.h>
37
38 #include <kern/kpc.h>
39
40 #include <pexpert/pexpert.h>
41 #include <kperf/kperf.h>
42
43 /* Various sysctl requests */
44 #define REQ_CLASSES (1)
45 #define REQ_COUNTING (2)
46 #define REQ_THREAD_COUNTING (3)
47 #define REQ_CONFIG_COUNT (4)
48 #define REQ_COUNTER_COUNT (5)
49 #define REQ_THREAD_COUNTERS (6)
50 #define REQ_COUNTERS (7)
51 #define REQ_SHADOW_COUNTERS (8)
52 #define REQ_CONFIG (9)
53 #define REQ_PERIOD (10)
54 #define REQ_ACTIONID (11)
55 #define REQ_SW_INC (14)
56
57 /* Type-munging casts */
58 typedef int (*getint_t)(void);
59 typedef int (*setint_t)(int);
60
61 /* safety */
62 static int kpc_initted = 0;
63
64 /* locking and buffer for large data requests */
65 #define SYSCTL_BUFFER_SIZE (33 * sizeof(uint64_t))
66 static lck_grp_attr_t *sysctl_buffer_lckgrp_attr = NULL;
67 static lck_grp_t *sysctl_buffer_lckgrp = NULL;
68 static lck_mtx_t sysctl_buffer_lock;
69 static void *sysctl_buffer = NULL;
70
71 typedef int (*setget_func_t)(int);
72
73 /* init our stuff */
74 extern void kpc_arch_init(void);
75 extern void kpc_common_init(void);
76 extern void kpc_thread_init(void); /* osfmk/kern/kpc_thread.c */
77
78 void
79 kpc_init(void)
80 {
81 sysctl_buffer_lckgrp_attr = lck_grp_attr_alloc_init();
82 sysctl_buffer_lckgrp = lck_grp_alloc_init("kpc",
83 sysctl_buffer_lckgrp_attr);
84 lck_mtx_init(&sysctl_buffer_lock, sysctl_buffer_lckgrp, LCK_ATTR_NULL);
85
86 kpc_arch_init();
87 kpc_common_init();
88 kpc_thread_init();
89
90 kpc_initted = 1;
91 }
92
93 /* abstract sysctl handlers */
94 static int
95 sysctl_get_int( struct sysctl_oid *oidp, struct sysctl_req *req,
96 uint32_t value )
97 {
98 int error = 0;
99
100 /* copy out the old value */
101 error = sysctl_handle_int(oidp, &value, 0, req);
102
103 return error;
104 }
105
106 static int
107 sysctl_set_int( struct sysctl_req *req, int (*set_func)(int))
108 {
109 int error = 0;
110 int value = 0;
111
112 error = SYSCTL_IN( req, &value, sizeof(value) );
113 if( error )
114 return error;
115
116 error = set_func( value );
117
118 return error;
119 }
120
121 static int
122 sysctl_getset_int( struct sysctl_oid *oidp, struct sysctl_req *req,
123 int (*get_func)(void), int (*set_func)(int) )
124 {
125 int error = 0;
126 uint32_t value = 0;
127
128 /* get the old value and process it */
129 value = get_func();
130
131 /* copy out the old value, get the new value */
132 error = sysctl_handle_int(oidp, &value, 0, req);
133 if (error || !req->newptr)
134 return (error);
135
136 /* if that worked, and we're writing... */
137 error = set_func( value );
138
139 return error;
140 }
141
142
143 static int
144 sysctl_setget_int( struct sysctl_req *req,
145 int (*setget_func)(int) )
146 {
147 int error = 0;
148 int value = 0;
149
150 error = SYSCTL_IN( req, &value, sizeof(value) );
151 if( error )
152 return error;
153
154 value = setget_func(value);
155
156 error = SYSCTL_OUT( req, &value, sizeof(value) );
157
158 return error;
159 }
160
161 static int
162 kpc_sysctl_acquire_buffer(void)
163 {
164 if( sysctl_buffer == NULL )
165 {
166 sysctl_buffer = kalloc(SYSCTL_BUFFER_SIZE);
167 if( sysctl_buffer )
168 {
169 bzero( sysctl_buffer, SYSCTL_BUFFER_SIZE );
170 }
171 }
172
173 if( !sysctl_buffer )
174 {
175 return ENOMEM;
176 }
177
178 return 0;
179 }
180
181 static int
182 sysctl_kpc_get_counters(uint32_t counters,
183 uint32_t *size, void *buf)
184 {
185 uint64_t *ctr_buf = (uint64_t*)buf;
186 int curcpu;
187 uint32_t count;
188
189 count = kpc_get_cpu_counters(counters & KPC_ALL_CPUS,
190 counters,
191 &curcpu, &ctr_buf[1]);
192 if (!count)
193 return EINVAL;
194
195 ctr_buf[0] = curcpu;
196
197 *size = (count+1) * sizeof(uint64_t);
198
199 return 0;
200 }
201
202 static int
203 sysctl_kpc_get_shadow_counters(uint32_t counters,
204 uint32_t *size, void *buf)
205 {
206 uint64_t *ctr_buf = (uint64_t*)buf;
207 int curcpu;
208 uint32_t count;
209
210 count = kpc_get_shadow_counters(counters & KPC_ALL_CPUS,
211 counters,
212 &curcpu, &ctr_buf[1]);
213
214 if (!count)
215 return EINVAL;
216
217 ctr_buf[0] = curcpu;
218
219 *size = (count+1) * sizeof(uint64_t);
220
221 return 0;
222 }
223
224 static int
225 sysctl_kpc_get_thread_counters(uint32_t tid,
226 uint32_t *size, void *buf)
227 {
228 uint32_t count = *size / sizeof(uint64_t);
229 int r;
230
231 if( tid != 0 )
232 return EINVAL;
233
234 r = kpc_get_curthread_counters(&count, buf);
235 if( !r )
236 *size = count * sizeof(uint64_t);
237
238 return r;
239 }
240
241 static int
242 sysctl_kpc_get_config(uint32_t classes, void* buf)
243 {
244 return kpc_get_config( classes, buf );
245 }
246
247 static int
248 sysctl_kpc_set_config(uint32_t classes, void* buf)
249 {
250 return kpc_set_config( classes, buf);
251 }
252
253 static int
254 sysctl_kpc_get_period(uint32_t classes, void* buf)
255 {
256 return kpc_get_period( classes, buf );
257 }
258
259 static int
260 sysctl_kpc_set_period(uint32_t classes, void* buf)
261 {
262 return kpc_set_period( classes, buf);
263 }
264
265 static int
266 sysctl_kpc_get_actionid(uint32_t classes, void* buf)
267 {
268 return kpc_get_actionid( classes, buf );
269 }
270
271 static int
272 sysctl_kpc_set_actionid(uint32_t classes, void* buf)
273 {
274 return kpc_set_actionid( classes, buf);
275 }
276
277
278 static int
279 sysctl_get_bigarray( struct sysctl_req *req,
280 int (*get_fn)(uint32_t, uint32_t*, void*) )
281 {
282 int error = 0;
283 uint32_t bufsize = SYSCTL_BUFFER_SIZE;
284 uint32_t arg = 0;
285
286 /* get the argument */
287 error = SYSCTL_IN( req, &arg, sizeof(arg) );
288 if(error)
289 {
290 printf( "kpc: no arg?\n" );
291 return error;
292 }
293
294 /* get the wired buffer */
295 error = kpc_sysctl_acquire_buffer();
296 if (error)
297 return error;
298
299 /* atomically get the array into the wired buffer. We have a double
300 * copy, but this is better than page faulting / interrupting during
301 * a copy.
302 */
303 error = get_fn( arg, &bufsize, sysctl_buffer );
304
305 /* do the copy out */
306 if( !error )
307 error = SYSCTL_OUT( req, sysctl_buffer, bufsize );
308
309 return error;
310 }
311
312 /* given a config word, how many bytes does it take? */
313 static int
314 sysctl_config_size( uint32_t config )
315 {
316 return kpc_get_config_count(config) * sizeof(kpc_config_t);
317 }
318
319 static int
320 sysctl_counter_size( uint32_t classes )
321 {
322 return kpc_get_counter_count(classes) * sizeof(uint64_t);
323 }
324
325 static int
326 sysctl_actionid_size( uint32_t classes )
327 {
328 return kpc_get_counter_count(classes) * sizeof(int32_t);
329 }
330
331 static int
332 sysctl_getset_bigarray( struct sysctl_req *req,
333 int (*size_fn)(uint32_t arg),
334 int (*get_fn)(uint32_t, void*),
335 int (*set_fn)(uint32_t, void*) )
336 {
337 int error = 0;
338 uint32_t bufsize = SYSCTL_BUFFER_SIZE;
339 uint32_t regsize = 0;
340 uint64_t arg;
341
342 /* get the config word */
343 error = SYSCTL_IN( req, &arg, sizeof(arg) );
344 if(error)
345 {
346 printf( "kpc: no arg?\n" );
347 return error;
348 }
349
350 /* Work out size of registers */
351 regsize = size_fn((uint32_t)arg);
352
353 /* Ignore NULL requests */
354 if(regsize == 0)
355 return EINVAL;
356
357 /* ensure not too big */
358 if( regsize > bufsize )
359 return EINVAL;
360
361 /* get the wired buffer */
362 error = kpc_sysctl_acquire_buffer();
363 if (error)
364 return error;
365
366 // if writing...
367 if(req->newptr)
368 {
369 // copy in the rest in -- sysctl remembers we did one already
370 error = SYSCTL_IN( req, sysctl_buffer,
371 regsize );
372
373 // if SYSCTL_IN fails it means we are only doing a read
374 if(!error) {
375 // set it
376 error = set_fn( (uint32_t)arg, sysctl_buffer );
377 if( error )
378 goto fail;
379 }
380 }
381
382 // if reading
383 if(req->oldptr)
384 {
385 // read it
386 error = get_fn( (uint32_t)arg, sysctl_buffer );
387 if( error )
388 goto fail;
389
390 // copy out the full set
391 error = SYSCTL_OUT( req, sysctl_buffer, regsize );
392 }
393
394 fail:
395 return error;
396 }
397
398
399
400 /*
401 * #define SYSCTL_HANDLER_ARGS (struct sysctl_oid *oidp, \
402 * void *arg1, int arg2, \
403 * struct sysctl_req *req )
404 */
405 static int
406 kpc_sysctl SYSCTL_HANDLER_ARGS
407 {
408 int ret;
409
410 // __unused struct sysctl_oid *unused_oidp = oidp;
411 (void)arg2;
412
413 if( !kpc_initted )
414 panic("kpc_init not called");
415
416 // Most sysctls require an access check, but a few are public.
417 switch( (uintptr_t) arg1 ) {
418 case REQ_CLASSES:
419 case REQ_CONFIG_COUNT:
420 case REQ_COUNTER_COUNT:
421 // These read-only sysctls are public.
422 break;
423
424 default:
425 // Require kperf access to read or write anything else.
426 // This is either root or the blessed pid.
427 ret = kperf_access_check();
428 if (ret) {
429 return ret;
430 }
431 break;
432 }
433
434 lck_mtx_lock(&sysctl_buffer_lock);
435
436 /* which request */
437 switch( (uintptr_t) arg1 )
438 {
439 case REQ_CLASSES:
440 ret = sysctl_get_int( oidp, req,
441 kpc_get_classes() );
442 break;
443 case REQ_COUNTING:
444 ret = sysctl_getset_int( oidp, req,
445 (getint_t)kpc_get_running,
446 (setint_t)kpc_set_running );
447 break;
448 case REQ_THREAD_COUNTING:
449 ret = sysctl_getset_int( oidp, req,
450 (getint_t)kpc_get_thread_counting,
451 (setint_t)kpc_set_thread_counting );
452 break;
453
454 case REQ_CONFIG_COUNT:
455 ret = sysctl_setget_int( req,
456 (setget_func_t)kpc_get_config_count );
457 break;
458
459 case REQ_COUNTER_COUNT:
460 ret = sysctl_setget_int( req,
461 (setget_func_t)kpc_get_counter_count );
462 break;
463
464
465 case REQ_THREAD_COUNTERS:
466 ret = sysctl_get_bigarray( req, sysctl_kpc_get_thread_counters );
467 break;
468
469 case REQ_COUNTERS:
470 ret = sysctl_get_bigarray( req, sysctl_kpc_get_counters );
471 break;
472
473 case REQ_SHADOW_COUNTERS:
474 ret = sysctl_get_bigarray( req, sysctl_kpc_get_shadow_counters );
475 break;
476
477 case REQ_CONFIG:
478 ret = sysctl_getset_bigarray( req,
479 sysctl_config_size,
480 sysctl_kpc_get_config,
481 sysctl_kpc_set_config );
482 break;
483
484 case REQ_PERIOD:
485 ret = sysctl_getset_bigarray( req,
486 sysctl_counter_size,
487 sysctl_kpc_get_period,
488 sysctl_kpc_set_period );
489 break;
490
491 case REQ_ACTIONID:
492 ret = sysctl_getset_bigarray( req,
493 sysctl_actionid_size,
494 sysctl_kpc_get_actionid,
495 sysctl_kpc_set_actionid );
496 break;
497
498
499 case REQ_SW_INC:
500 ret = sysctl_set_int( req, (setget_func_t)kpc_set_sw_inc );
501 break;
502
503 default:
504 ret = ENOENT;
505 break;
506 }
507
508 lck_mtx_unlock(&sysctl_buffer_lock);
509
510 return ret;
511 }
512
513
514 /*** sysctl definitions ***/
515
516 /* root kperf node */
517 SYSCTL_NODE(, OID_AUTO, kpc, CTLFLAG_RW|CTLFLAG_LOCKED, 0,
518 "kpc");
519
520 /* values */
521 SYSCTL_PROC(_kpc, OID_AUTO, classes,
522 CTLTYPE_INT|CTLFLAG_RD|CTLFLAG_ANYBODY,
523 (void*)REQ_CLASSES,
524 sizeof(int), kpc_sysctl, "I", "Available classes");
525
526 SYSCTL_PROC(_kpc, OID_AUTO, counting,
527 CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
528 (void*)REQ_COUNTING,
529 sizeof(int), kpc_sysctl, "I", "PMCs counting");
530
531 SYSCTL_PROC(_kpc, OID_AUTO, thread_counting,
532 CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
533 (void*)REQ_THREAD_COUNTING,
534 sizeof(int), kpc_sysctl, "I", "Thread accumulation");
535
536 /* faux values */
537 SYSCTL_PROC(_kpc, OID_AUTO, config_count,
538 CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
539 (void*)REQ_CONFIG_COUNT,
540 sizeof(int), kpc_sysctl, "S", "Config count");
541
542 SYSCTL_PROC(_kpc, OID_AUTO, counter_count,
543 CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
544 (void*)REQ_COUNTER_COUNT,
545 sizeof(int), kpc_sysctl, "S", "Counter count");
546
547 SYSCTL_PROC(_kpc, OID_AUTO, sw_inc,
548 CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
549 (void*)REQ_SW_INC,
550 sizeof(int), kpc_sysctl, "S", "Software increment");
551
552 /* arrays */
553 SYSCTL_PROC(_kpc, OID_AUTO, thread_counters,
554 CTLFLAG_RD|CTLFLAG_WR|CTLFLAG_ANYBODY,
555 (void*)REQ_THREAD_COUNTERS,
556 sizeof(uint64_t), kpc_sysctl,
557 "QU", "Current thread counters");
558
559 SYSCTL_PROC(_kpc, OID_AUTO, counters,
560 CTLFLAG_RD|CTLFLAG_WR|CTLFLAG_ANYBODY,
561 (void*)REQ_COUNTERS,
562 sizeof(uint64_t), kpc_sysctl,
563 "QU", "Current counters");
564
565 SYSCTL_PROC(_kpc, OID_AUTO, shadow_counters,
566 CTLFLAG_RD|CTLFLAG_WR|CTLFLAG_ANYBODY,
567 (void*)REQ_SHADOW_COUNTERS,
568 sizeof(uint64_t), kpc_sysctl,
569 "QU", "Current shadow counters");
570
571 SYSCTL_PROC(_kpc, OID_AUTO, config,
572 CTLFLAG_RD|CTLFLAG_WR|CTLFLAG_ANYBODY,
573 (void*)REQ_CONFIG,
574 sizeof(uint64_t), kpc_sysctl,
575 "QU", "Set counter configs");
576
577 SYSCTL_PROC(_kpc, OID_AUTO, period,
578 CTLFLAG_RD|CTLFLAG_WR|CTLFLAG_ANYBODY,
579 (void*)REQ_PERIOD,
580 sizeof(uint64_t), kpc_sysctl,
581 "QU", "Set counter periods");
582
583 SYSCTL_PROC(_kpc, OID_AUTO, actionid,
584 CTLFLAG_RD|CTLFLAG_WR|CTLFLAG_ANYBODY,
585 (void*)REQ_ACTIONID,
586 sizeof(uint32_t), kpc_sysctl,
587 "QU", "Set counter actionids");
588
589