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#include <mach/mach_types.h>
29#include <kern/thread.h>
30#include <kern/machine.h>
31#include <kern/kalloc.h>
32#include <sys/errno.h>
33
34#include <kperf/filter.h>
35#include <kperf/sample.h>
36#include <kperf/kperfbsd.h>
37#include <kperf/pet.h>
38#include <kperf/action.h>
39#include <kperf/kperf.h>
40#include <kperf/timetrigger.h>
41
42/** misc functions **/
43#include <chud/chud_xnu.h> /* XXX: should bust this out */
44
45static struct kperf_sample *intr_samplev = NULL;
46static unsigned intr_samplec = 0;
47static unsigned sampling_status = KPERF_SAMPLING_OFF;
48static unsigned kperf_initted = 0;
49
50
51extern void (*chudxnu_thread_ast_handler)(thread_t);
52
53struct kperf_sample*
54kperf_intr_sample_buffer(void)
55{
56	unsigned ncpu = chudxnu_cpu_number();
57
58	// XXX: assert?
59	if( ncpu >= intr_samplec )
60		return NULL;
61
62	return &intr_samplev[ncpu];
63}
64
65/* setup interrupt sample buffers */
66int
67kperf_init(void)
68{
69	unsigned ncpus = 0;
70
71	if( kperf_initted )
72		return 0;
73
74	/* get number of cpus */
75	ncpus = machine_info.logical_cpu_max;
76
77	/* make the CPU array
78	 * FIXME: cache alignment
79	 */
80	intr_samplev = kalloc( ncpus * sizeof(*intr_samplev));
81
82	if( intr_samplev == NULL )
83		return ENOMEM;
84
85	/* clear it */
86	bzero( intr_samplev, ncpus * sizeof(*intr_samplev) );
87
88	chudxnu_thread_ast_handler = kperf_thread_ast_handler;
89
90	/* we're done */
91	intr_samplec = ncpus;
92	kperf_initted = 1;
93
94	return 0;
95}
96
97
98/** kext start/stop functions **/
99kern_return_t kperf_start (kmod_info_t * ki, void * d);
100
101kern_return_t
102kperf_start (kmod_info_t * ki, void * d)
103{
104	(void) ki;
105	(void) d;
106
107	/* say hello */
108	printf( "aprof: kext starting\n" );
109
110	/* register modules */
111	// kperf_action_init();
112	kperf_filter_init();
113	kperf_pet_init();
114
115	/* register the sysctls */
116	//kperf_register_profiling();
117
118	return KERN_SUCCESS;
119}
120
121
122/* random misc-ish functions */
123uint32_t
124kperf_get_thread_bits( thread_t thread )
125{
126	return thread->t_chud;
127}
128
129void
130kperf_set_thread_bits( thread_t thread, uint32_t bits )
131{
132	thread->t_chud = bits;
133}
134
135/* mark an AST to fire on a thread */
136void
137kperf_set_thread_ast( thread_t thread )
138{
139	/* FIXME: only call this on current thread from an interrupt
140	 * handler for now...
141	 */
142	if( thread != current_thread() )
143		panic( "unsafe AST set" );
144
145	act_set_kperf(thread);
146}
147
148unsigned
149kperf_sampling_status(void)
150{
151	return sampling_status;
152}
153
154int
155kperf_sampling_enable(void)
156{
157	/* already running! */
158	if( sampling_status == KPERF_SAMPLING_ON )
159		return 0;
160
161	if ( sampling_status != KPERF_SAMPLING_OFF )
162		panic( "kperf: sampling wasn't off" );
163
164	/* make sure interrupt tables and actions are initted */
165	if( !kperf_initted
166	    || (kperf_action_get_count() == 0) )
167		return ECANCELED;
168
169	/* mark as running */
170	sampling_status = KPERF_SAMPLING_ON;
171
172	/* tell timers to enable */
173	kperf_timer_go();
174
175	return 0;
176}
177
178int
179kperf_sampling_disable(void)
180{
181	if( sampling_status != KPERF_SAMPLING_ON )
182		return 0;
183
184	/* mark a shutting down */
185	sampling_status = KPERF_SAMPLING_SHUTDOWN;
186
187	/* tell timers to disable */
188	kperf_timer_stop();
189
190	/* mark as off */
191	sampling_status = KPERF_SAMPLING_OFF;
192
193	return 0;
194}
195