]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/kpc_common.c
xnu-2422.90.20.tar.gz
[apple/xnu.git] / osfmk / kern / kpc_common.c
1 /*
2 * Copyright (c) 2012 Apple 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 #include <mach/mach_types.h>
30 #include <machine/machine_routines.h>
31 #include <kern/processor.h>
32 #include <kern/kalloc.h>
33 #include <sys/errno.h>
34 #include <kperf/buffer.h>
35 #include <kern/thread.h>
36
37 #include <kern/kpc.h>
38
39 #include <kperf/kperf.h>
40 #include <kperf/sample.h>
41 #include <kperf/context.h>
42 #include <kperf/action.h>
43
44 #include <chud/chud_xnu.h>
45
46 uint32_t kpc_actionid[KPC_MAX_COUNTERS];
47
48 /* locks */
49 static lck_grp_attr_t *kpc_config_lckgrp_attr = NULL;
50 static lck_grp_t *kpc_config_lckgrp = NULL;
51 static lck_mtx_t kpc_config_lock;
52
53 void kpc_arch_init(void);
54 void
55 kpc_arch_init(void)
56 {
57 kpc_config_lckgrp_attr = lck_grp_attr_alloc_init();
58 kpc_config_lckgrp = lck_grp_alloc_init("kpc", kpc_config_lckgrp_attr);
59 lck_mtx_init(&kpc_config_lock, kpc_config_lckgrp, LCK_ATTR_NULL);
60 }
61
62 uint32_t
63 kpc_get_running(void)
64 {
65 uint32_t cur_state = 0;
66
67 if( kpc_is_running_fixed() )
68 cur_state |= KPC_CLASS_FIXED_MASK;
69
70 if( kpc_is_running_configurable() )
71 cur_state |= KPC_CLASS_CONFIGURABLE_MASK;
72
73 return cur_state;
74 }
75
76 /* generic counter reading function */
77 int
78 kpc_get_cpu_counters( boolean_t all_cpus, uint32_t classes,
79 int *curcpu, uint64_t *buf )
80 {
81 int r, enabled, offset = 0;
82
83 (void) all_cpus;
84
85 /* grab counters and CPU number as close as possible */
86 enabled = ml_set_interrupts_enabled(FALSE);
87
88 /* and the CPU ID */
89 if( curcpu )
90 *curcpu = current_processor()->cpu_id;
91
92 if( classes & KPC_CLASS_FIXED_MASK )
93 {
94 kpc_get_fixed_counters( &buf[offset] );
95
96 offset += kpc_get_counter_count(KPC_CLASS_FIXED_MASK);
97 }
98
99 if( classes & KPC_CLASS_CONFIGURABLE_MASK )
100 {
101 r = kpc_get_configurable_counters( &buf[offset] );
102
103 offset += kpc_get_counter_count(KPC_CLASS_CONFIGURABLE_MASK);
104 }
105
106 ml_set_interrupts_enabled(enabled);
107
108 return offset;
109 }
110
111 int
112 kpc_get_shadow_counters( boolean_t all_cpus, uint32_t classes,
113 int *curcpu, uint64_t *buf )
114 {
115 int enabled, count, offset = 0;
116
117 (void)all_cpus;
118
119 enabled = ml_set_interrupts_enabled(FALSE);
120
121 if( curcpu )
122 *curcpu = current_processor()->cpu_id;
123
124 if( classes & KPC_CLASS_FIXED_MASK )
125 {
126 count = kpc_get_counter_count(KPC_CLASS_FIXED_MASK);
127
128 memcpy( &buf[offset], &FIXED_SHADOW(0), count*sizeof(uint64_t) );
129
130 offset += count;
131 }
132
133 if( classes & KPC_CLASS_CONFIGURABLE_MASK )
134 {
135 count = kpc_get_counter_count(KPC_CLASS_CONFIGURABLE_MASK);
136
137 memcpy( &buf[offset], &CONFIGURABLE_SHADOW(0), count*sizeof(uint64_t) );
138
139 offset += count;
140 }
141
142 ml_set_interrupts_enabled(enabled);
143
144 return offset;
145 }
146
147 uint32_t
148 kpc_get_counter_count(uint32_t classes)
149 {
150 int count = 0;
151
152 if( classes & KPC_CLASS_FIXED_MASK )
153 count += kpc_fixed_count();
154
155 if( classes & KPC_CLASS_CONFIGURABLE_MASK )
156 count += kpc_configurable_count() ;
157
158 return count;
159 }
160
161 uint32_t
162 kpc_get_config_count(uint32_t classes)
163 {
164 int count = 0;
165
166 if( classes & KPC_CLASS_FIXED_MASK )
167 count += kpc_fixed_config_count();
168
169 if( classes & KPC_CLASS_CONFIGURABLE_MASK )
170 count += kpc_configurable_config_count();
171
172 return count;
173 }
174
175 int
176 kpc_get_config(uint32_t classes, kpc_config_t *current_config)
177 {
178 int count = 0;
179
180 if( classes & KPC_CLASS_FIXED_MASK )
181 {
182 kpc_get_fixed_config(&current_config[count]);
183 count += kpc_get_config_count(KPC_CLASS_FIXED_MASK);
184 }
185
186 if( classes & KPC_CLASS_CONFIGURABLE_MASK )
187 {
188 kpc_get_configurable_config(&current_config[count]);
189 count += kpc_get_config_count(KPC_CLASS_CONFIGURABLE_MASK);
190 }
191
192 return 0;
193 }
194
195 int
196 kpc_set_config(uint32_t classes, kpc_config_t *configv)
197 {
198 struct kpc_config_remote mp_config;
199
200 lck_mtx_lock(&kpc_config_lock);
201
202 mp_config.classes = classes;
203 mp_config.configv = configv;
204
205 kpc_set_config_arch( &mp_config );
206
207 lck_mtx_unlock(&kpc_config_lock);
208
209 return 0;
210 }
211
212 /* allocate a buffer big enough for all the counters */
213 uint64_t *
214 kpc_counterbuf_alloc(void)
215 {
216 uint64_t *buf;
217
218 buf = kalloc(KPC_MAX_COUNTERS * sizeof(uint64_t));
219 if(buf)
220 bzero( buf, KPC_MAX_COUNTERS * sizeof(uint64_t) );
221
222 return buf;
223 }
224
225 void
226 kpc_counterbuf_free(uint64_t *buf)
227 {
228 if( buf )
229 kfree(buf, KPC_MAX_COUNTERS * sizeof(uint64_t));
230 }
231
232 void kpc_sample_kperf(uint32_t actionid)
233 {
234 struct kperf_sample sbuf;
235 struct kperf_context ctx;
236 task_t task = NULL;
237 int r;
238
239 BUF_DATA1(PERF_KPC_HNDLR | DBG_FUNC_START, 0);
240
241 ctx.cur_pid = 0;
242 ctx.cur_thread = current_thread();
243
244 task = chudxnu_task_for_thread(ctx.cur_thread);
245 if (task)
246 ctx.cur_pid = chudxnu_pid_for_task(task);
247
248 ctx.trigger_type = TRIGGER_TYPE_PMI;
249 ctx.trigger_id = 0;
250
251 r = kperf_sample(&sbuf, &ctx, actionid, SAMPLE_FLAG_PEND_USER);
252
253 BUF_INFO1(PERF_KPC_HNDLR | DBG_FUNC_END, r);
254 }
255
256
257 int kpc_set_period(uint32_t classes, uint64_t *val)
258 {
259 struct kpc_config_remote mp_config;
260
261 lck_mtx_lock(&kpc_config_lock);
262
263 #ifndef FIXED_COUNTER_SHADOW
264 if (classes & KPC_CLASS_FIXED_MASK) {
265 lck_mtx_unlock(&kpc_config_lock);
266 return -1;
267 }
268 #endif
269
270 kprintf("setting period %u\n", classes);
271
272 mp_config.classes = classes;
273 mp_config.configv = val;
274
275 kpc_set_period_arch( &mp_config );
276
277 lck_mtx_unlock(&kpc_config_lock);
278
279 return 0;
280 }
281
282
283 int kpc_get_period(uint32_t classes, uint64_t *val)
284 {
285 uint32_t i, count, offset = 0;
286
287 lck_mtx_lock(&kpc_config_lock);
288
289 if (classes & KPC_CLASS_FIXED_MASK) {
290 count = kpc_get_counter_count(KPC_CLASS_FIXED_MASK);
291
292 /* convert reload values to periods */
293 for (i = 0; i < count; i++)
294 val[i] = kpc_fixed_max() - FIXED_RELOAD(i);
295
296 offset += count;
297 }
298
299 if (classes & KPC_CLASS_CONFIGURABLE_MASK) {
300 count = kpc_get_counter_count(KPC_CLASS_CONFIGURABLE_MASK);
301
302 /* convert reload values to periods */
303 for (i = 0; i < count; i++)
304 val[i + offset] = kpc_configurable_max() - CONFIGURABLE_RELOAD(i);
305 }
306
307 lck_mtx_unlock(&kpc_config_lock);
308
309 return 0;
310 }
311
312 int kpc_set_actionid(uint32_t classes, uint32_t *val)
313 {
314 uint32_t count, offset = 0;
315
316 /* NOTE: what happens if a pmi occurs while actionids are being
317 * set is undefined. */
318 lck_mtx_lock(&kpc_config_lock);
319
320 if (classes & KPC_CLASS_FIXED_MASK) {
321 count = kpc_get_counter_count(KPC_CLASS_FIXED_MASK);
322
323 memcpy(&FIXED_ACTIONID(0), val, count*sizeof(uint32_t));
324
325 offset += count;
326 }
327
328 if (classes & KPC_CLASS_CONFIGURABLE_MASK) {
329 count = kpc_get_counter_count(KPC_CLASS_CONFIGURABLE_MASK);
330
331 memcpy(&CONFIGURABLE_ACTIONID(0), &val[offset], count*sizeof(uint32_t));
332 }
333
334 lck_mtx_unlock(&kpc_config_lock);
335
336 return 0;
337 }
338
339 int kpc_get_actionid(uint32_t classes, uint32_t *val)
340 {
341 uint32_t count, offset = 0;
342
343 lck_mtx_lock(&kpc_config_lock);
344
345 if (classes & KPC_CLASS_FIXED_MASK) {
346 count = kpc_get_counter_count(KPC_CLASS_FIXED_MASK);
347
348 memcpy(val, &FIXED_ACTIONID(0), count*sizeof(uint32_t));
349
350 offset += count;
351 }
352
353 if (classes & KPC_CLASS_CONFIGURABLE_MASK) {
354 count = kpc_get_counter_count(KPC_CLASS_CONFIGURABLE_MASK);
355
356 memcpy(&val[offset], &CONFIGURABLE_ACTIONID(0), count*sizeof(uint32_t));
357 }
358
359 lck_mtx_unlock(&kpc_config_lock);
360
361 return 0;
362
363 }
364