2  * Copyright (c) 2012 Apple Inc. All rights reserved. 
   4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 
   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. 
  15  * Please obtain a copy of the License at 
  16  * http://www.opensource.apple.com/apsl/ and read it before using this file. 
  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. 
  26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 
  29 #include <kern/debug.h> 
  30 #include <kern/kalloc.h> 
  31 #include <sys/param.h> 
  34 #include <sys/sysctl.h> 
  35 #include <libkern/libkern.h> 
  36 #include <kern/assert.h> 
  39 #include <sys/ktrace.h> 
  41 #include <pexpert/pexpert.h> 
  42 #include <kperf/kperf.h> 
  44 /* Various sysctl requests */ 
  45 #define REQ_CLASSES              (1) 
  46 #define REQ_COUNTING             (2) 
  47 #define REQ_THREAD_COUNTING      (3) 
  48 #define REQ_CONFIG_COUNT         (4) 
  49 #define REQ_COUNTER_COUNT        (5) 
  50 #define REQ_THREAD_COUNTERS      (6) 
  51 #define REQ_COUNTERS             (7) 
  52 #define REQ_SHADOW_COUNTERS      (8) 
  53 #define REQ_CONFIG               (9) 
  54 #define REQ_PERIOD              (10) 
  55 #define REQ_ACTIONID            (11) 
  56 #define REQ_SW_INC              (14) 
  57 #define REQ_PMU_VERSION         (15) 
  59 /* Type-munging casts */ 
  60 typedef int (*getint_t
)(void); 
  61 typedef int (*setint_t
)(int); 
  63 static int kpc_initted 
= 0; 
  65 static lck_grp_attr_t 
*sysctl_lckgrp_attr 
= NULL
; 
  66 static lck_grp_t 
*sysctl_lckgrp 
= NULL
; 
  67 static lck_mtx_t sysctl_lock
; 
  70  * Another element is needed to hold the CPU number when getting counter values. 
  72 #define KPC_MAX_BUF_LEN (KPC_MAX_COUNTERS_COPIED + 1) 
  74 typedef int (*setget_func_t
)(int); 
  79         sysctl_lckgrp_attr 
= lck_grp_attr_alloc_init(); 
  80         sysctl_lckgrp 
= lck_grp_alloc_init("kpc", sysctl_lckgrp_attr
); 
  81         lck_mtx_init(&sysctl_lock
, sysctl_lckgrp
, LCK_ATTR_NULL
); 
  91 kpc_get_bigarray(uint32_t *size_out
) 
  93         static uint64_t *bigarray 
= NULL
; 
  95         LCK_MTX_ASSERT(&sysctl_lock
, LCK_MTX_ASSERT_OWNED
); 
  97         uint32_t size 
= kpc_get_counterbuf_size() + sizeof(uint64_t); 
 105          * Another element is needed to hold the CPU number when getting counter 
 108         bigarray 
= kalloc_tag(size
, VM_KERN_MEMORY_DIAG
); 
 109         assert(bigarray 
!= NULL
); 
 113 /* abstract sysctl handlers */ 
 115 sysctl_get_int( struct sysctl_oid 
*oidp
, struct sysctl_req 
*req
, 
 120         /* copy out the old value */ 
 121         error 
= sysctl_handle_int(oidp
, &value
, 0, req
); 
 127 sysctl_set_int( struct sysctl_req 
*req
, int (*set_func
)(int)) 
 132         error 
= SYSCTL_IN( req
, &value
, sizeof(value
)); 
 137         error 
= set_func( value 
); 
 143 sysctl_getset_int( struct sysctl_oid 
*oidp
, struct sysctl_req 
*req
, 
 144     int (*get_func
)(void), int (*set_func
)(int)) 
 149         /* get the old value and process it */ 
 152         /* copy out the old value, get the new value */ 
 153         error 
= sysctl_handle_int(oidp
, &value
, 0, req
); 
 154         if (error 
|| !req
->newptr
) { 
 158         /* if that worked, and we're writing... */ 
 159         error 
= set_func( value 
); 
 166 sysctl_setget_int( struct sysctl_req 
*req
, 
 167     int (*setget_func
)(int)) 
 172         error 
= SYSCTL_IN( req
, &value
, sizeof(value
)); 
 177         value 
= setget_func(value
); 
 179         error 
= SYSCTL_OUT( req
, &value
, sizeof(value
)); 
 185 sysctl_kpc_get_counters(uint32_t counters
, 
 186     uint32_t *size
, void *buf
) 
 188         uint64_t *ctr_buf 
= (uint64_t*)buf
; 
 192         count 
= kpc_get_cpu_counters(counters 
& KPC_ALL_CPUS
, 
 194             &curcpu
, &ctr_buf
[1]); 
 201         *size 
= (count 
+ 1) * sizeof(uint64_t); 
 207 sysctl_kpc_get_shadow_counters(uint32_t counters
, 
 208     uint32_t *size
, void *buf
) 
 210         uint64_t *ctr_buf 
= (uint64_t*)buf
; 
 214         count 
= kpc_get_shadow_counters(counters 
& KPC_ALL_CPUS
, 
 216             &curcpu
, &ctr_buf
[1]); 
 224         *size 
= (count 
+ 1) * sizeof(uint64_t); 
 230 sysctl_kpc_get_thread_counters(uint32_t tid
, 
 231     uint32_t *size
, void *buf
) 
 233         uint32_t count 
= *size 
/ sizeof(uint64_t); 
 240         r 
= kpc_get_curthread_counters(&count
, buf
); 
 242                 *size 
= count 
* sizeof(uint64_t); 
 249 sysctl_kpc_get_config(uint32_t classes
, void* buf
) 
 251         return kpc_get_config( classes
, buf 
); 
 255 sysctl_kpc_set_config(uint32_t classes
, void* buf
) 
 257         /* userspace cannot reconfigure the power class */ 
 258         if (classes 
& KPC_CLASS_POWER_MASK
) { 
 261         return kpc_set_config( classes
, buf
); 
 265 sysctl_kpc_get_period(uint32_t classes
, void* buf
) 
 267         return kpc_get_period( classes
, buf 
); 
 271 sysctl_kpc_set_period(uint32_t classes
, void* buf
) 
 273         /* userspace cannot reconfigure the power class */ 
 274         if (classes 
& KPC_CLASS_POWER_MASK
) { 
 277         return kpc_set_period( classes
, buf
); 
 281 sysctl_kpc_get_actionid(uint32_t classes
, void* buf
) 
 283         return kpc_get_actionid( classes
, buf 
); 
 287 sysctl_kpc_set_actionid(uint32_t classes
, void* buf
) 
 289         return kpc_set_actionid( classes
, buf
); 
 294 sysctl_get_bigarray(struct sysctl_req 
*req
, 
 295     int (*get_fn
)(uint32_t, uint32_t*, void*)) 
 297         uint32_t bufsize 
= 0; 
 298         uint64_t *buf 
= kpc_get_bigarray(&bufsize
); 
 301         /* get the argument */ 
 302         int error 
= SYSCTL_IN(req
, &arg
, sizeof(arg
)); 
 307         error 
= get_fn(arg
, &bufsize
, buf
); 
 309                 error 
= SYSCTL_OUT(req
, buf
, bufsize
); 
 315 /* given a config word, how many bytes does it take? */ 
 317 sysctl_config_size( uint32_t config 
) 
 319         return kpc_get_config_count(config
) * sizeof(kpc_config_t
); 
 323 sysctl_counter_size( uint32_t classes 
) 
 325         return kpc_get_counter_count(classes
) * sizeof(uint64_t); 
 329 sysctl_actionid_size( uint32_t classes 
) 
 331         return kpc_get_counter_count(classes
) * sizeof(int32_t); 
 335 sysctl_getset_bigarray(struct sysctl_req 
*req
, int (*size_fn
)(uint32_t arg
), 
 336     int (*get_fn
)(uint32_t, void*), int (*set_fn
)(uint32_t, void*)) 
 341         uint32_t bufsize 
= 0; 
 342         uint64_t *buf 
= kpc_get_bigarray(&bufsize
); 
 344         /* get the config word */ 
 345         error 
= SYSCTL_IN(req
, &arg
, sizeof(arg
)); 
 350         /* Determine the size of registers to modify. */ 
 351         uint32_t regsize 
= size_fn((uint32_t)arg
); 
 352         if (regsize 
== 0 || regsize 
> bufsize
) { 
 358                 /* copy the rest -- SYSCTL_IN knows the copyin should be shifted */ 
 359                 error 
= SYSCTL_IN(req
, buf
, regsize
); 
 361                 /* SYSCTL_IN failure means only need to read */ 
 363                         error 
= set_fn((uint32_t)arg
, buf
); 
 372                 error 
= get_fn((uint32_t)arg
, buf
); 
 377                 error 
= SYSCTL_OUT(req
, buf
, regsize
); 
 384 kpc_sysctl SYSCTL_HANDLER_ARGS
 
 388         // __unused struct sysctl_oid *unused_oidp = oidp; 
 392                 panic("kpc_init not called"); 
 395         if (!kpc_supported
) { 
 401         // Most sysctls require an access check, but a few are public. 
 402         switch ((uintptr_t) arg1
) { 
 404         case REQ_CONFIG_COUNT
: 
 405         case REQ_COUNTER_COUNT
: 
 406                 // These read-only sysctls are public. 
 410                 // Require kperf access to read or write anything else. 
 411                 // This is either root or the blessed pid. 
 412                 if ((ret 
= ktrace_read_check())) { 
 421         lck_mtx_lock(&sysctl_lock
); 
 424         switch ((uintptr_t) arg1
) { 
 426                 ret 
= sysctl_get_int( oidp
, req
, 
 430                 ret 
= sysctl_getset_int( oidp
, req
, 
 431                     (getint_t
)kpc_get_running
, 
 432                     (setint_t
)kpc_set_running 
); 
 434         case REQ_THREAD_COUNTING
: 
 435                 ret 
= sysctl_getset_int( oidp
, req
, 
 436                     (getint_t
)kpc_get_thread_counting
, 
 437                     (setint_t
)kpc_set_thread_counting 
); 
 440         case REQ_CONFIG_COUNT
: 
 441                 ret 
= sysctl_setget_int( req
, 
 442                     (setget_func_t
)kpc_get_config_count 
); 
 445         case REQ_COUNTER_COUNT
: 
 446                 ret 
= sysctl_setget_int( req
, 
 447                     (setget_func_t
)kpc_get_counter_count 
); 
 451         case REQ_THREAD_COUNTERS
: 
 452                 ret 
= sysctl_get_bigarray( req
, sysctl_kpc_get_thread_counters 
); 
 456                 ret 
= sysctl_get_bigarray( req
, sysctl_kpc_get_counters 
); 
 459         case REQ_SHADOW_COUNTERS
: 
 460                 ret 
= sysctl_get_bigarray( req
, sysctl_kpc_get_shadow_counters 
); 
 464                 ret 
= sysctl_getset_bigarray( req
, 
 466                     sysctl_kpc_get_config
, 
 467                     sysctl_kpc_set_config 
); 
 471                 ret 
= sysctl_getset_bigarray( req
, 
 473                     sysctl_kpc_get_period
, 
 474                     sysctl_kpc_set_period 
); 
 478                 ret 
= sysctl_getset_bigarray( req
, 
 479                     sysctl_actionid_size
, 
 480                     sysctl_kpc_get_actionid
, 
 481                     sysctl_kpc_set_actionid 
); 
 486                 ret 
= sysctl_set_int( req
, (setget_func_t
)kpc_set_sw_inc 
); 
 489         case REQ_PMU_VERSION
: 
 490                 ret 
= sysctl_get_int(oidp
, req
, kpc_get_pmu_version()); 
 498         lck_mtx_unlock(&sysctl_lock
); 
 504 /***  sysctl definitions  ***/ 
 506 /* root kperf node */ 
 507 SYSCTL_NODE(, OID_AUTO
, kpc
, CTLFLAG_RW 
| CTLFLAG_LOCKED
, 0, 
 511 SYSCTL_PROC(_kpc
, OID_AUTO
, classes
, 
 512     CTLTYPE_INT 
| CTLFLAG_RD 
| CTLFLAG_ANYBODY 
| CTLFLAG_MASKED 
| CTLFLAG_LOCKED
, 
 514     sizeof(int), kpc_sysctl
, "I", "Available classes"); 
 516 SYSCTL_PROC(_kpc
, OID_AUTO
, counting
, 
 517     CTLTYPE_INT 
| CTLFLAG_RW 
| CTLFLAG_ANYBODY 
| CTLFLAG_MASKED 
| CTLFLAG_LOCKED
, 
 519     sizeof(int), kpc_sysctl
, "I", "PMCs counting"); 
 521 SYSCTL_PROC(_kpc
, OID_AUTO
, thread_counting
, 
 522     CTLTYPE_INT 
| CTLFLAG_RW 
| CTLFLAG_ANYBODY 
| CTLFLAG_MASKED 
| CTLFLAG_LOCKED
, 
 523     (void*)REQ_THREAD_COUNTING
, 
 524     sizeof(int), kpc_sysctl
, "I", "Thread accumulation"); 
 526 SYSCTL_PROC(_kpc
, OID_AUTO
, pmu_version
, 
 527     CTLTYPE_INT 
| CTLFLAG_RD 
| CTLFLAG_ANYBODY 
| CTLFLAG_MASKED 
| CTLFLAG_LOCKED
, 
 528     (void *)REQ_PMU_VERSION
, 
 529     sizeof(int), kpc_sysctl
, "I", "PMU version for hardware"); 
 532 SYSCTL_PROC(_kpc
, OID_AUTO
, config_count
, 
 533     CTLTYPE_INT 
| CTLFLAG_RW 
| CTLFLAG_ANYBODY 
| CTLFLAG_MASKED 
| CTLFLAG_LOCKED
, 
 534     (void*)REQ_CONFIG_COUNT
, 
 535     sizeof(int), kpc_sysctl
, "S", "Config count"); 
 537 SYSCTL_PROC(_kpc
, OID_AUTO
, counter_count
, 
 538     CTLTYPE_INT 
| CTLFLAG_RW 
| CTLFLAG_ANYBODY 
| CTLFLAG_MASKED 
| CTLFLAG_LOCKED
, 
 539     (void*)REQ_COUNTER_COUNT
, 
 540     sizeof(int), kpc_sysctl
, "S", "Counter count"); 
 542 SYSCTL_PROC(_kpc
, OID_AUTO
, sw_inc
, 
 543     CTLTYPE_INT 
| CTLFLAG_RW 
| CTLFLAG_ANYBODY 
| CTLFLAG_MASKED 
| CTLFLAG_LOCKED
, 
 545     sizeof(int), kpc_sysctl
, "S", "Software increment"); 
 548 SYSCTL_PROC(_kpc
, OID_AUTO
, thread_counters
, 
 549     CTLFLAG_RD 
| CTLFLAG_WR 
| CTLFLAG_ANYBODY 
| CTLFLAG_MASKED 
| CTLFLAG_LOCKED
, 
 550     (void*)REQ_THREAD_COUNTERS
, 
 551     sizeof(uint64_t), kpc_sysctl
, 
 552     "QU", "Current thread counters"); 
 554 SYSCTL_PROC(_kpc
, OID_AUTO
, counters
, 
 555     CTLFLAG_RD 
| CTLFLAG_WR 
| CTLFLAG_ANYBODY 
| CTLFLAG_MASKED 
| CTLFLAG_LOCKED
, 
 557     sizeof(uint64_t), kpc_sysctl
, 
 558     "QU", "Current counters"); 
 560 SYSCTL_PROC(_kpc
, OID_AUTO
, shadow_counters
, 
 561     CTLFLAG_RD 
| CTLFLAG_WR 
| CTLFLAG_ANYBODY 
| CTLFLAG_MASKED 
| CTLFLAG_LOCKED
, 
 562     (void*)REQ_SHADOW_COUNTERS
, 
 563     sizeof(uint64_t), kpc_sysctl
, 
 564     "QU", "Current shadow counters"); 
 566 SYSCTL_PROC(_kpc
, OID_AUTO
, config
, 
 567     CTLFLAG_RD 
| CTLFLAG_WR 
| CTLFLAG_ANYBODY 
| CTLFLAG_MASKED 
| CTLFLAG_LOCKED
, 
 569     sizeof(uint64_t), kpc_sysctl
, 
 570     "QU", "Set counter configs"); 
 572 SYSCTL_PROC(_kpc
, OID_AUTO
, period
, 
 573     CTLFLAG_RD 
| CTLFLAG_WR 
| CTLFLAG_ANYBODY 
| CTLFLAG_MASKED 
| CTLFLAG_LOCKED
, 
 575     sizeof(uint64_t), kpc_sysctl
, 
 576     "QU", "Set counter periods"); 
 578 SYSCTL_PROC(_kpc
, OID_AUTO
, actionid
, 
 579     CTLFLAG_RD 
| CTLFLAG_WR 
| CTLFLAG_ANYBODY 
| CTLFLAG_MASKED 
| CTLFLAG_LOCKED
, 
 581     sizeof(uint32_t), kpc_sysctl
, 
 582     "QU", "Set counter actionids");