X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/39236c6e673c41db228275375ab7fdb0f837b292..d190cdc3f5544636abb56dc1874be391d3e1b148:/bsd/kern/kern_kpc.c?ds=sidebyside diff --git a/bsd/kern/kern_kpc.c b/bsd/kern/kern_kpc.c index 321fa1b5a..38bc2abbd 100644 --- a/bsd/kern/kern_kpc.c +++ b/bsd/kern/kern_kpc.c @@ -27,6 +27,7 @@ */ #include +#include #include #include #include @@ -35,8 +36,10 @@ #include #include +#include #include +#include /* Various sysctl requests */ #define REQ_CLASSES (1) @@ -50,8 +53,8 @@ #define REQ_CONFIG (9) #define REQ_PERIOD (10) #define REQ_ACTIONID (11) -#define REQ_FORCE_ALL_CTRS (12) -#define REQ_DISABLE_WHITELIST (13) +#define REQ_SW_INC (14) +#define REQ_PMU_VERSION (15) /* Type-munging casts */ typedef int (*getint_t)(void); @@ -61,6 +64,7 @@ typedef int (*setint_t)(int); static int kpc_initted = 0; /* locking and buffer for large data requests */ +#define SYSCTL_BUFFER_SIZE (33 * sizeof(uint64_t)) static lck_grp_attr_t *sysctl_buffer_lckgrp_attr = NULL; static lck_grp_t *sysctl_buffer_lckgrp = NULL; static lck_mtx_t sysctl_buffer_lock; @@ -68,10 +72,6 @@ static void *sysctl_buffer = NULL; typedef int (*setget_func_t)(int); -/* init our stuff */ -extern void kpc_thread_init(void); /* osfmk/kern/kpc_thread.c */ -extern void kpc_arch_init(void); - void kpc_init(void) { @@ -81,6 +81,7 @@ kpc_init(void) lck_mtx_init(&sysctl_buffer_lock, sysctl_buffer_lckgrp, LCK_ATTR_NULL); kpc_arch_init(); + kpc_common_init(); kpc_thread_init(); kpc_initted = 1; @@ -99,6 +100,21 @@ sysctl_get_int( struct sysctl_oid *oidp, struct sysctl_req *req, return error; } +static int +sysctl_set_int( struct sysctl_req *req, int (*set_func)(int)) +{ + int error = 0; + int value = 0; + + error = SYSCTL_IN( req, &value, sizeof(value) ); + if( error ) + return error; + + error = set_func( value ); + + return error; +} + static int sysctl_getset_int( struct sysctl_oid *oidp, struct sysctl_req *req, int (*get_func)(void), int (*set_func)(int) ) @@ -120,6 +136,7 @@ sysctl_getset_int( struct sysctl_oid *oidp, struct sysctl_req *req, return error; } + static int sysctl_setget_int( struct sysctl_req *req, int (*setget_func)(int) ) @@ -142,7 +159,13 @@ static int kpc_sysctl_acquire_buffer(void) { if( sysctl_buffer == NULL ) - sysctl_buffer = kpc_counterbuf_alloc(); + { + sysctl_buffer = kalloc(SYSCTL_BUFFER_SIZE); + if( sysctl_buffer ) + { + bzero( sysctl_buffer, SYSCTL_BUFFER_SIZE ); + } + } if( !sysctl_buffer ) { @@ -221,6 +244,9 @@ sysctl_kpc_get_config(uint32_t classes, void* buf) static int sysctl_kpc_set_config(uint32_t classes, void* buf) { + /* userspace cannot reconfigure the power class */ + if (classes & KPC_CLASS_POWER_MASK) + return (EPERM); return kpc_set_config( classes, buf); } @@ -233,6 +259,9 @@ sysctl_kpc_get_period(uint32_t classes, void* buf) static int sysctl_kpc_set_period(uint32_t classes, void* buf) { + /* userspace cannot reconfigure the power class */ + if (classes & KPC_CLASS_POWER_MASK) + return (EPERM); return kpc_set_period( classes, buf); } @@ -254,7 +283,7 @@ sysctl_get_bigarray( struct sysctl_req *req, int (*get_fn)(uint32_t, uint32_t*, void*) ) { int error = 0; - uint32_t bufsize = KPC_MAX_COUNTERS * sizeof(uint64_t); /* XXX? */ + uint32_t bufsize = SYSCTL_BUFFER_SIZE; uint32_t arg = 0; /* get the argument */ @@ -309,7 +338,7 @@ sysctl_getset_bigarray( struct sysctl_req *req, int (*set_fn)(uint32_t, void*) ) { int error = 0; - uint32_t bufsize = KPC_MAX_COUNTERS * sizeof(uint64_t); /* XXX? */ + uint32_t bufsize = SYSCTL_BUFFER_SIZE; uint32_t regsize = 0; uint64_t arg; @@ -387,6 +416,28 @@ kpc_sysctl SYSCTL_HANDLER_ARGS if( !kpc_initted ) panic("kpc_init not called"); + lck_mtx_lock(ktrace_lock); + + // Most sysctls require an access check, but a few are public. + switch( (uintptr_t) arg1 ) { + case REQ_CLASSES: + case REQ_CONFIG_COUNT: + case REQ_COUNTER_COUNT: + // These read-only sysctls are public. + break; + + default: + // Require kperf access to read or write anything else. + // This is either root or the blessed pid. + if ((ret = ktrace_read_check())) { + lck_mtx_unlock(ktrace_lock); + return ret; + } + break; + } + + lck_mtx_unlock(ktrace_lock); + lck_mtx_lock(&sysctl_buffer_lock); /* which request */ @@ -451,6 +502,15 @@ kpc_sysctl SYSCTL_HANDLER_ARGS sysctl_kpc_set_actionid ); break; + + case REQ_SW_INC: + ret = sysctl_set_int( req, (setget_func_t)kpc_set_sw_inc ); + break; + + case REQ_PMU_VERSION: + ret = sysctl_get_int(oidp, req, kpc_get_pmu_version()); + break; + default: ret = ENOENT; break; @@ -484,6 +544,11 @@ SYSCTL_PROC(_kpc, OID_AUTO, thread_counting, (void*)REQ_THREAD_COUNTING, sizeof(int), kpc_sysctl, "I", "Thread accumulation"); +SYSCTL_PROC(_kpc, OID_AUTO, pmu_version, + CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_ANYBODY, + (void *)REQ_PMU_VERSION, + sizeof(int), kpc_sysctl, "I", "PMU version for hardware"); + /* faux values */ SYSCTL_PROC(_kpc, OID_AUTO, config_count, CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, @@ -495,6 +560,11 @@ SYSCTL_PROC(_kpc, OID_AUTO, counter_count, (void*)REQ_COUNTER_COUNT, sizeof(int), kpc_sysctl, "S", "Counter count"); +SYSCTL_PROC(_kpc, OID_AUTO, sw_inc, + CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, + (void*)REQ_SW_INC, + sizeof(int), kpc_sysctl, "S", "Software increment"); + /* arrays */ SYSCTL_PROC(_kpc, OID_AUTO, thread_counters, CTLFLAG_RD|CTLFLAG_WR|CTLFLAG_ANYBODY, @@ -531,3 +601,5 @@ SYSCTL_PROC(_kpc, OID_AUTO, actionid, (void*)REQ_ACTIONID, sizeof(uint32_t), kpc_sysctl, "QU", "Set counter actionids"); + +