1/*
2 * Copyright (c) 2011 Apple Computer, 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/*  sysctl interface for paramters from user-land */
30
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
37#include <kperf/context.h>
38#include <kperf/action.h>
39#include <kperf/timetrigger.h>
40#include <kperf/pet.h>
41#include <kperf/filter.h>
42#include <kperf/kperfbsd.h>
43#include <kperf/kperf.h>
44
45#define REQ_SAMPLING        (1)
46#define REQ_ACTION_COUNT    (2)
47#define REQ_ACTION_SAMPLERS (3)
48#define REQ_TIMER_COUNT     (4)
49#define REQ_TIMER_PERIOD    (5)
50#define REQ_TIMER_PET       (6)
51
52
53static int
54sysctl_timer_period( __unused struct sysctl_oid *oidp, struct sysctl_req *req )
55{
56    int error = 0;
57    uint64_t inputs[2], retval;
58    unsigned timer, set = 0;
59
60    /* get 2x 64-bit words */
61    error = SYSCTL_IN( req, inputs, 2*sizeof(inputs[0]) );
62    if(error)
63    {
64	    printf( "error in\n" );
65	    return (error);
66    }
67
68    /* setup inputs */
69    timer = (unsigned) inputs[0];
70    if( inputs[1] != ~0ULL )
71	    set = 1;
72
73    printf( "%s timer: %u, inp[0] %llu\n", set ? "set" : "get",
74            timer, inputs[0] );
75
76    if( set )
77    {
78	    printf( "timer set period\n" );
79	    error = kperf_timer_set_period( timer, inputs[1] );
80	    if( error )
81		    return error;
82    }
83
84    error = kperf_timer_get_period(timer, &retval);
85    if(error)
86    {
87	    printf( "error get period\n" );
88	    return (error);
89    }
90
91    inputs[1] = retval;
92
93    if( error == 0 )
94    {
95	    error = SYSCTL_OUT( req, inputs, 2*sizeof(inputs[0]) );
96	    if( error )
97		    printf( "error out\n" );
98    }
99
100    return error;
101}
102
103static int
104sysctl_action_samplers( __unused struct sysctl_oid *oidp,
105                        struct sysctl_req *req )
106{
107    int error = 0;
108    uint64_t inputs[3];
109    uint32_t retval;
110    unsigned actionid, set = 0;
111
112    /* get 3x 64-bit words */
113    error = SYSCTL_IN( req, inputs, 3*sizeof(inputs[0]) );
114    if(error)
115    {
116	    printf( "error in\n" );
117	    return (error);
118    }
119
120    /* setup inputs */
121    set = (unsigned) inputs[0];
122    actionid = (unsigned) inputs[1];
123
124    if( set )
125    {
126	    error = kperf_action_set_samplers( actionid, inputs[2] );
127	    if( error )
128		    return error;
129    }
130
131    printf("set %d actionid %u samplers val %u\n",
132           set, actionid, (unsigned) inputs[2] );
133
134    error = kperf_action_get_samplers(actionid, &retval);
135    if(error)
136    {
137	    printf( "error get samplers\n" );
138	    return (error);
139    }
140
141    inputs[2] = retval;
142
143    if( error == 0 )
144    {
145	    error = SYSCTL_OUT( req, inputs, 3*sizeof(inputs[0]) );
146	    if( error )
147		    printf( "error out\n" );
148    }
149
150    return error;
151}
152
153static int
154sysctl_sampling( struct sysctl_oid *oidp, struct sysctl_req *req )
155{
156    int error = 0;
157    uint32_t value = 0;
158
159    /* get the old value and process it */
160    value = kperf_sampling_status();
161
162    /* copy out the old value, get the new value */
163    error = sysctl_handle_int(oidp, &value, 0, req);
164    if (error || !req->newptr)
165	    return (error);
166
167    printf( "setting sampling to %d\n", value );
168
169    /* if that worked, and we're writing... */
170    if( value )
171	    error = kperf_sampling_enable();
172    else
173	    error = kperf_sampling_disable();
174
175    return error;
176}
177
178static int
179sysctl_action_count( struct sysctl_oid *oidp, struct sysctl_req *req )
180{
181    int error = 0;
182    uint32_t value = 0;
183
184    /* get the old value and process it */
185    value = kperf_action_get_count();
186
187    /* copy out the old value, get the new value */
188    error = sysctl_handle_int(oidp, &value, 0, req);
189    if (error || !req->newptr)
190	    return (error);
191
192    printf( "setting action count to %d\n", value );
193
194    /* if that worked, and we're writing... */
195    return kperf_action_set_count(value);
196}
197
198static int
199sysctl_timer_count( struct sysctl_oid *oidp, struct sysctl_req *req )
200{
201    int error = 0;
202    uint32_t value = 0;
203
204    /* get the old value and process it */
205    value = kperf_timer_get_count();
206
207    /* copy out the old value, get the new value */
208    error = sysctl_handle_int(oidp, &value, 0, req);
209    if (error || !req->newptr)
210	    return (error);
211
212    printf( "setting timer count to %d\n", value );
213
214    /* if that worked, and we're writing... */
215    return kperf_timer_set_count(value);
216}
217
218static int
219sysctl_timer_pet( struct sysctl_oid *oidp, struct sysctl_req *req )
220{
221    int error = 0;
222    uint32_t value = 0;
223
224    /* get the old value and process it */
225    value = kperf_timer_get_petid();
226
227    /* copy out the old value, get the new value */
228    error = sysctl_handle_int(oidp, &value, 0, req);
229    if (error || !req->newptr)
230	    return (error);
231
232    printf( "setting timer petid to %d\n", value );
233
234    /* if that worked, and we're writing... */
235    return kperf_timer_set_petid(value);
236}
237
238/*
239 * #define SYSCTL_HANDLER_ARGS (struct sysctl_oid *oidp,         \
240 *                                void *arg1, int arg2,                 \
241 *                              struct sysctl_req *req )
242 */
243static int
244kperf_sysctl SYSCTL_HANDLER_ARGS
245{
246	// __unused struct sysctl_oid *unused_oidp = oidp;
247	(void)arg2;
248
249	/* which request */
250	switch( (uintptr_t) arg1 )
251	{
252	case REQ_ACTION_COUNT:
253		return sysctl_action_count( oidp, req );
254	case REQ_ACTION_SAMPLERS:
255		return sysctl_action_samplers( oidp, req );
256	case REQ_TIMER_COUNT:
257		return sysctl_timer_count( oidp, req );
258	case REQ_TIMER_PERIOD:
259		return sysctl_timer_period( oidp, req );
260	case REQ_TIMER_PET:
261		return sysctl_timer_pet( oidp, req );
262	case REQ_SAMPLING:
263		return sysctl_sampling( oidp, req );
264
265#if 0
266	case REQ_TIMER:
267		return sysctl_timer_period( req );
268	case REQ_PET:
269		return sysctl_pet_period( req );
270#endif
271	default:
272		return ENOENT;
273	}
274}
275
276/* root kperf node */
277SYSCTL_NODE(, OID_AUTO, kperf, CTLFLAG_RW|CTLFLAG_LOCKED, 0,
278            "kperf");
279
280/* action sub-section */
281SYSCTL_NODE(_kperf, OID_AUTO, action, CTLFLAG_RW|CTLFLAG_LOCKED, 0,
282            "action");
283
284SYSCTL_PROC(_kperf_action, OID_AUTO, count,
285            CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
286            (void*)REQ_ACTION_COUNT,
287            sizeof(int), kperf_sysctl, "I", "Number of actions");
288
289SYSCTL_PROC(_kperf_action, OID_AUTO, samplers,
290            CTLFLAG_RW|CTLFLAG_ANYBODY,
291            (void*)REQ_ACTION_SAMPLERS,
292            3*sizeof(uint64_t), kperf_sysctl, "UQ",
293            "What to sample what a trigger fires an action");
294
295/* timer sub-section */
296SYSCTL_NODE(_kperf, OID_AUTO, timer, CTLFLAG_RW|CTLFLAG_LOCKED, 0,
297            "timer");
298
299SYSCTL_PROC(_kperf_timer, OID_AUTO, count,
300            CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
301            (void*)REQ_TIMER_COUNT,
302            sizeof(int), kperf_sysctl, "I", "Number of time triggers");
303
304SYSCTL_PROC(_kperf_timer, OID_AUTO, period,
305            CTLFLAG_RW|CTLFLAG_ANYBODY,
306            (void*)REQ_TIMER_PERIOD,
307            2*sizeof(uint64_t), kperf_sysctl, "UQ", "Timer number and period");
308
309SYSCTL_PROC(_kperf_timer, OID_AUTO, pet_timer,
310            CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
311            (void*)REQ_TIMER_PET,
312            sizeof(int), kperf_sysctl, "I", "Which timer ID does PET");
313
314/* misc */
315SYSCTL_PROC(_kperf, OID_AUTO, sampling,
316            CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
317            (void*)REQ_SAMPLING,
318            sizeof(int), kperf_sysctl, "I", "Sampling running");
319
320int legacy_mode = 1;
321SYSCTL_INT(_kperf, OID_AUTO, legacy_mode, CTLFLAG_RW, &legacy_mode, 0, "legacy_mode");
322
323#if 0
324SYSCTL_PROC(_kperf, OID_AUTO, timer_period,
325            CTLFLAG_RW, (void*)REQ_TIMER,
326            sizeof(uint64_t), kperf_sysctl, "QU", "nanoseconds");
327
328SYSCTL_PROC(_kperf, OID_AUTO, pet_period,
329            CTLFLAG_RW, (void*)REQ_PET,
330            sizeof(uint64_t), kperf_sysctl, "QU", "nanoseconds");
331
332/* FIXME: do real stuff */
333SYSCTL_INT(_kperf, OID_AUTO, filter_pid0,
334           CTLFLAG_RW, &pid_list[0], 0, "");
335SYSCTL_INT(_kperf, OID_AUTO, filter_pid1,
336           CTLFLAG_RW, &pid_list[1], 0, "");
337SYSCTL_INT(_kperf, OID_AUTO, filter_pid2,
338           CTLFLAG_RW, &pid_list[2], 0, "");
339SYSCTL_INT(_kperf, OID_AUTO, filter_pid3,
340           CTLFLAG_RW, &pid_list[3], 0, "");
341
342#endif
343