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