]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/kern_kpc.c
xnu-2782.20.48.tar.gz
[apple/xnu.git] / bsd / kern / kern_kpc.c
index 321fa1b5add70fc7bba1e5c97fd4636ff4c70314..dde93bbce390077794e0f4d2ea94670375ae4e15 100644 (file)
@@ -27,6 +27,7 @@
  */
 
 #include <kern/debug.h>
+#include <kern/kalloc.h>
 #include <sys/param.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
@@ -37,6 +38,7 @@
 #include <kern/kpc.h>
 
 #include <pexpert/pexpert.h>
+#include <kperf/kperf.h>
 
 /* Various sysctl requests */
 #define REQ_CLASSES              (1)
@@ -50,8 +52,7 @@
 #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)
 
 /* Type-munging casts */
 typedef int (*getint_t)(void);
@@ -61,6 +62,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;
@@ -69,8 +71,9 @@ 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);
+extern void kpc_common_init(void);
+extern void kpc_thread_init(void); /* osfmk/kern/kpc_thread.c */
 
 void
 kpc_init(void)
@@ -81,6 +84,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 +103,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 +139,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 +162,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 )
        {
@@ -254,7 +280,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 +335,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 +413,24 @@ kpc_sysctl SYSCTL_HANDLER_ARGS
        if( !kpc_initted )
                panic("kpc_init not called");
 
+       // 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.
+               ret = kperf_access_check();
+               if (ret) {
+                       return ret;
+               }
+               break;
+       }
+
        lck_mtx_lock(&sysctl_buffer_lock);
 
        /* which request */
@@ -451,6 +495,11 @@ 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;          
+
        default:
                ret = ENOENT;
                break;
@@ -495,6 +544,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 +585,5 @@ SYSCTL_PROC(_kpc, OID_AUTO, actionid,
             (void*)REQ_ACTIONID, 
             sizeof(uint32_t), kpc_sysctl, 
             "QU", "Set counter actionids");
+
+