]> git.saurik.com Git - apple/xnu.git/blame - osfmk/i386/perfmon.c
xnu-792.6.56.tar.gz
[apple/xnu.git] / osfmk / i386 / perfmon.c
CommitLineData
91447636
A
1/*
2 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
ff6e181a
A
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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
91447636 12 *
ff6e181a
A
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
91447636
A
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
ff6e181a
A
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
91447636
A
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <mach/std_types.h>
25#include <i386/cpu_data.h>
26#include <i386/cpu_number.h>
27#include <i386/perfmon.h>
28#include <i386/proc_reg.h>
29#include <i386/cpu_threads.h>
30#include <i386/mp.h>
31#include <i386/cpuid.h>
32#include <i386/lock.h>
33#include <vm/vm_kern.h>
34
35#ifdef DEBUG
36#define DBG(x...) kprintf(x)
37#else
38#define DBG(x...)
39#endif
40
41/*
42 * Table of ESCRs and addresses associated with performance counters/CCCRs.
43 * See Intel SDM Vol 3, Table 15-4 (section 15.9):
44 */
45static uint16_t pmc_escr_addr_table[18][8] = {
46 [MSR_BPU_COUNTER0] {
47 [MSR_BSU_ESCR0] 0x3a0,
48 [MSR_FSB_ESCR0] 0x3a2,
49 [MSR_MOB_ESCR0] 0x3aa,
50 [MSR_PMH_ESCR0] 0x3ac,
51 [MSR_BPU_ESCR0] 0x3b2,
52 [MSR_IS_ESCR0] 0x3b4,
53 [MSR_ITLB_ESCR0] 0x3b6,
54 [MSR_IX_ESCR0] 0x3c8,
55 },
56 [MSR_BPU_COUNTER1] {
57 [MSR_BSU_ESCR0] 0x3a0,
58 [MSR_FSB_ESCR0] 0x3a2,
59 [MSR_MOB_ESCR0] 0x3aa,
60 [MSR_PMH_ESCR0] 0x3ac,
61 [MSR_BPU_ESCR0] 0x3b2,
62 [MSR_IS_ESCR0] 0x3b4,
63 [MSR_ITLB_ESCR0] 0x3b6,
64 [MSR_IX_ESCR0] 0x3c8,
65 },
66 [MSR_BPU_COUNTER2] {
67 [MSR_BSU_ESCR1] 0x3a1,
68 [MSR_FSB_ESCR1] 0x3a3,
69 [MSR_MOB_ESCR1] 0x3ab,
70 [MSR_PMH_ESCR1] 0x3ad,
71 [MSR_BPU_ESCR1] 0x3b3,
72 [MSR_IS_ESCR1] 0x3b5,
73 [MSR_ITLB_ESCR1] 0x3b7,
74 [MSR_IX_ESCR1] 0x3c9,
75 },
76 [MSR_BPU_COUNTER3] {
77 [MSR_BSU_ESCR1] 0x3a1,
78 [MSR_FSB_ESCR1] 0x3a3,
79 [MSR_MOB_ESCR1] 0x3ab,
80 [MSR_PMH_ESCR1] 0x3ad,
81 [MSR_BPU_ESCR1] 0x3b3,
82 [MSR_IS_ESCR1] 0x3b5,
83 [MSR_ITLB_ESCR1] 0x3b7,
84 [MSR_IX_ESCR1] 0x3c9,
85 },
86 [MSR_MS_COUNTER0] {
87 [MSR_MS_ESCR1] 0x3c1,
88 [MSR_TBPU_ESCR1] 0x3c3,
89 [MSR_TC_ESCR1] 0x3c5,
90 },
91 [MSR_MS_COUNTER1] {
92 [MSR_MS_ESCR1] 0x3c1,
93 [MSR_TBPU_ESCR1] 0x3c3,
94 [MSR_TC_ESCR1] 0x3c5,
95 },
96 [MSR_MS_COUNTER2] {
97 [MSR_MS_ESCR1] 0x3c1,
98 [MSR_TBPU_ESCR1] 0x3c3,
99 [MSR_TC_ESCR1] 0x3c5,
100 },
101 [MSR_MS_COUNTER3] {
102 [MSR_MS_ESCR1] 0x3c1,
103 [MSR_TBPU_ESCR1] 0x3c3,
104 [MSR_TC_ESCR1] 0x3c5,
105 },
106 [MSR_FLAME_COUNTER0] {
107 [MSR_FIRM_ESCR0] 0x3a4,
108 [MSR_FLAME_ESCR0] 0x3a6,
109 [MSR_DAC_ESCR0] 0x3a8,
110 [MSR_SAT_ESCR0] 0x3ae,
111 [MSR_U2L_ESCR0] 0x3b0,
112 },
113 [MSR_FLAME_COUNTER1] {
114 [MSR_FIRM_ESCR0] 0x3a4,
115 [MSR_FLAME_ESCR0] 0x3a6,
116 [MSR_DAC_ESCR0] 0x3a8,
117 [MSR_SAT_ESCR0] 0x3ae,
118 [MSR_U2L_ESCR0] 0x3b0,
119 },
120 [MSR_FLAME_COUNTER2] {
121 [MSR_FIRM_ESCR1] 0x3a5,
122 [MSR_FLAME_ESCR1] 0x3a7,
123 [MSR_DAC_ESCR1] 0x3a9,
124 [MSR_SAT_ESCR1] 0x3af,
125 [MSR_U2L_ESCR1] 0x3b1,
126 },
127 [MSR_FLAME_COUNTER3] {
128 [MSR_FIRM_ESCR1] 0x3a5,
129 [MSR_FLAME_ESCR1] 0x3a7,
130 [MSR_DAC_ESCR1] 0x3a9,
131 [MSR_SAT_ESCR1] 0x3af,
132 [MSR_U2L_ESCR1] 0x3b1,
133 },
134 [MSR_IQ_COUNTER0] {
135 [MSR_CRU_ESCR0] 0x3b8,
136 [MSR_CRU_ESCR2] 0x3cc,
137 [MSR_CRU_ESCR4] 0x3e0,
138 [MSR_IQ_ESCR0] 0x3ba,
139 [MSR_RAT_ESCR0] 0x3bc,
140 [MSR_SSU_ESCR0] 0x3be,
141 [MSR_AFL_ESCR0] 0x3ca,
142 },
143 [MSR_IQ_COUNTER1] {
144 [MSR_CRU_ESCR0] 0x3b8,
145 [MSR_CRU_ESCR2] 0x3cc,
146 [MSR_CRU_ESCR4] 0x3e0,
147 [MSR_IQ_ESCR0] 0x3ba,
148 [MSR_RAT_ESCR0] 0x3bc,
149 [MSR_SSU_ESCR0] 0x3be,
150 [MSR_AFL_ESCR0] 0x3ca,
151 },
152 [MSR_IQ_COUNTER2] {
153 [MSR_CRU_ESCR1] 0x3b9,
154 [MSR_CRU_ESCR3] 0x3cd,
155 [MSR_CRU_ESCR5] 0x3e1,
156 [MSR_IQ_ESCR1] 0x3bb,
157 [MSR_RAT_ESCR1] 0x3bd,
158 [MSR_AFL_ESCR1] 0x3cb,
159 },
160 [MSR_IQ_COUNTER3] {
161 [MSR_CRU_ESCR1] 0x3b9,
162 [MSR_CRU_ESCR3] 0x3cd,
163 [MSR_CRU_ESCR5] 0x3e1,
164 [MSR_IQ_ESCR1] 0x3bb,
165 [MSR_RAT_ESCR1] 0x3bd,
166 [MSR_AFL_ESCR1] 0x3cb,
167 },
168 [MSR_IQ_COUNTER4] {
169 [MSR_CRU_ESCR0] 0x3b8,
170 [MSR_CRU_ESCR2] 0x3cc,
171 [MSR_CRU_ESCR4] 0x3e0,
172 [MSR_IQ_ESCR0] 0x3ba,
173 [MSR_RAT_ESCR0] 0x3bc,
174 [MSR_SSU_ESCR0] 0x3be,
175 [MSR_AFL_ESCR0] 0x3ca,
176 },
177 [MSR_IQ_COUNTER5] {
178 [MSR_CRU_ESCR1] 0x3b9,
179 [MSR_CRU_ESCR3] 0x3cd,
180 [MSR_CRU_ESCR5] 0x3e1,
181 [MSR_IQ_ESCR1] 0x3bb,
182 [MSR_RAT_ESCR1] 0x3bd,
183 [MSR_AFL_ESCR1] 0x3cb,
184 },
185};
186#define PMC_ESCR_ADDR(id,esid) pmc_escr_addr_table[id][esid]
187
188typedef struct {
189 pmc_id_t id_max; /* Maximum counter id */
190 pmc_machine_t machine_type; /* P6 or P4/Xeon */
191 uint32_t msr_counter_base; /* First counter MSR */
192 uint32_t msr_control_base; /* First control MSR */
193 boolean_t reserved[18]; /* Max-sized arrays... */
194 pmc_ovf_func_t *ovf_func[18];
195#ifdef DEBUG
196 pmc_cccr_t cccr_shadow[18]; /* Last cccr values set */
197 pmc_counter_t counter_shadow[18]; /* Last counter values set */
198 uint32_t ovfs_unexpected[18]; /* Count of unexpected intrs */
199#endif
200} pmc_table_t;
201
202static pmc_machine_t
203_pmc_machine_type(void)
204{
205 i386_cpu_info_t *infop = cpuid_info();
206
207 if (strncmp(infop->cpuid_vendor, CPUID_VID_INTEL, sizeof(CPUID_VID_INTEL)) != 0)
208 return pmc_none;
209
210 if (!pmc_is_available())
211 return pmc_none;
212
213 switch (infop->cpuid_family) {
214 case 0x6:
215 return pmc_P6;
216 case 0xf:
217 return pmc_P4_Xeon;
218 default:
219 return pmc_unknown;
220 }
221}
222
223static void
224pmc_p4_intr(void *state)
225{
226 pmc_table_t *pmc_table = (pmc_table_t *) cpu_core()->pmc;
227 uint32_t cccr_addr;
228 pmc_cccr_t cccr;
229 pmc_id_t id;
230 int my_logical_cpu = cpu_to_logical_cpu(cpu_number());
231
232 /*
233 * Scan through table for reserved counters with overflow and
234 * with a registered overflow function.
235 */
236 for (id = 0; id <= pmc_table->id_max; id++) {
237 if (!pmc_table->reserved[id])
238 continue;
239 cccr_addr = pmc_table->msr_control_base + id;
240 cccr.u_u64 = rdmsr64(cccr_addr);
241#ifdef DEBUG
242 pmc_table->cccr_shadow[id] = cccr;
243 *((uint64_t *) &pmc_table->counter_shadow[id]) =
244 rdmsr64(pmc_table->msr_counter_base + id);
245#endif
246 if (cccr.u_htt.ovf == 0)
247 continue;
248 if ((cccr.u_htt.ovf_pmi_t0 == 1 && my_logical_cpu == 0) ||
249 (cccr.u_htt.ovf_pmi_t1 == 1 && my_logical_cpu == 1)) {
250 if (pmc_table->ovf_func[id]) {
251 (*pmc_table->ovf_func[id])(id, state);
252 /* func expected to clear overflow */
253 continue;
254 }
255 }
256 /* Clear overflow for unexpected interrupt */
257#ifdef DEBUG
258 pmc_table->ovfs_unexpected[id]++;
259#endif
260 }
261}
262
263static void
264pmc_p6_intr(void *state)
265{
266 pmc_table_t *pmc_table = (pmc_table_t *) cpu_core()->pmc;
267 pmc_id_t id;
268
269 /*
270 * Can't determine which counter has overflow
271 * so call all registered functions.
272 */
273 for (id = 0; id <= pmc_table->id_max; id++)
274 if (pmc_table->reserved[id] && pmc_table->ovf_func[id])
275 (*pmc_table->ovf_func[id])(id, state);
276}
277
278int
279pmc_init(void)
280{
281 int ret;
282 cpu_core_t *my_core;
283 pmc_table_t *pmc_table;
284 pmc_machine_t pmc_type;
285
286 my_core = cpu_core();
287 assert(my_core);
288
289 pmc_type = _pmc_machine_type();
290 if (pmc_type == pmc_none) {
291 return KERN_FAILURE;
292 }
293
294 pmc_table = (pmc_table_t *) my_core->pmc;
295 if (pmc_table == NULL) {
296 ret = kmem_alloc(kernel_map,
297 (void *) &pmc_table, sizeof(pmc_table_t));
298 if (ret != KERN_SUCCESS)
299 panic("pmc_init() kmem_alloc returned %d\n", ret);
300 bzero((void *)pmc_table, sizeof(pmc_table_t));
301
302 pmc_table->machine_type = pmc_type;
303 switch (pmc_type) {
304 case pmc_P4_Xeon:
305 pmc_table->id_max = 17;
306 pmc_table->msr_counter_base = MSR_COUNTER_ADDR(0);
307 pmc_table->msr_control_base = MSR_CCCR_ADDR(0);
308 lapic_set_pmi_func(&pmc_p4_intr);
309 break;
310 case pmc_P6:
311 pmc_table->id_max = 1;
312 pmc_table->msr_counter_base = MSR_P6_COUNTER_ADDR(0);
313 pmc_table->msr_control_base = MSR_P6_PES_ADDR(0);
314 lapic_set_pmi_func(&pmc_p6_intr);
315 break;
316 default:
317 break;
318 }
319 if (!atomic_cmpxchg((uint32_t *) &my_core->pmc,
320 0, (uint32_t) pmc_table)) {
321 kmem_free(kernel_map,
322 (vm_offset_t) pmc_table, sizeof(pmc_table_t));
323 }
324 }
325 DBG("pmc_init() done for cpu %d my_core->pmc=0x%x type=%d\n",
326 cpu_number(), my_core->pmc, pmc_type);
327
328 return KERN_SUCCESS;
329}
330
331static inline pmc_table_t *
332pmc_table_valid(pmc_id_t id)
333{
334 cpu_core_t *my_core = cpu_core();
335 pmc_table_t *pmc_table;
336
337 assert(my_core);
338
339 pmc_table = (pmc_table_t *) my_core->pmc;
340 return (pmc_table == NULL ||
341 id > pmc_table->id_max ||
342 !pmc_table->reserved[id]) ? NULL : pmc_table;
343}
344
345int
346pmc_machine_type(pmc_machine_t *type)
347{
348 cpu_core_t *my_core = cpu_core();
349 pmc_table_t *pmc_table;
350
351 assert(my_core);
352
353 pmc_table = (pmc_table_t *) my_core->pmc;
354 if (pmc_table == NULL)
355 return KERN_FAILURE;
356
357 *type = pmc_table->machine_type;
358
359 return KERN_SUCCESS;
360}
361
362int
363pmc_reserve(pmc_id_t id)
364{
365 cpu_core_t *my_core = cpu_core();
366 pmc_table_t *pmc_table;
367
368 assert(my_core);
369
370 pmc_table = (pmc_table_t *) my_core->pmc;
371 if (pmc_table == NULL)
372 return KERN_FAILURE;
373 if (id > pmc_table->id_max)
374 return KERN_INVALID_ARGUMENT;
375 if (pmc_table->reserved[id])
376 return KERN_FAILURE;
377
378 pmc_table->reserved[id] = TRUE;
379
380 return KERN_SUCCESS;
381}
382
383boolean_t
384pmc_is_reserved(pmc_id_t id)
385{
386 return pmc_table_valid(id) != NULL;
387}
388
389int
390pmc_free(pmc_id_t id)
391{
392 pmc_table_t *pmc_table = pmc_table_valid(id);
393
394 if (pmc_table == NULL)
395 return KERN_INVALID_ARGUMENT;
396
397 pmc_cccr_write(id, 0x0ULL);
398 pmc_table->reserved[id] = FALSE;
399 pmc_table->ovf_func[id] = NULL;
400
401 return KERN_SUCCESS;
402}
403
404int
405pmc_counter_read(pmc_id_t id, pmc_counter_t *val)
406{
407 pmc_table_t *pmc_table = pmc_table_valid(id);
408
409 if (pmc_table == NULL)
410 return KERN_INVALID_ARGUMENT;
411
412 *(uint64_t *)val = rdmsr64(pmc_table->msr_counter_base + id);
413
414 return KERN_SUCCESS;
415}
416
417int
418pmc_counter_write(pmc_id_t id, pmc_counter_t *val)
419{
420 pmc_table_t *pmc_table = pmc_table_valid(id);
421
422 if (pmc_table == NULL)
423 return KERN_INVALID_ARGUMENT;
424
425 wrmsr64(pmc_table->msr_counter_base + id, *(uint64_t *)val);
426
427 return KERN_SUCCESS;
428}
429
430int
431pmc_cccr_read(pmc_id_t id, pmc_cccr_t *cccr)
432{
433 pmc_table_t *pmc_table = pmc_table_valid(id);
434
435 if (pmc_table == NULL)
436 return KERN_INVALID_ARGUMENT;
437
438 if (pmc_table->machine_type != pmc_P4_Xeon)
439 return KERN_FAILURE;
440
441 *(uint64_t *)cccr = rdmsr64(pmc_table->msr_control_base + id);
442
443 return KERN_SUCCESS;
444}
445
446int
447pmc_cccr_write(pmc_id_t id, pmc_cccr_t *cccr)
448{
449 pmc_table_t *pmc_table = pmc_table_valid(id);
450
451 if (pmc_table == NULL)
452 return KERN_INVALID_ARGUMENT;
453
454 if (pmc_table->machine_type != pmc_P4_Xeon)
455 return KERN_FAILURE;
456
457 wrmsr64(pmc_table->msr_control_base + id, *(uint64_t *)cccr);
458
459 return KERN_SUCCESS;
460}
461
462int
463pmc_evtsel_read(pmc_id_t id, pmc_evtsel_t *evtsel)
464{
465 pmc_table_t *pmc_table = pmc_table_valid(id);
466
467 if (pmc_table == NULL)
468 return KERN_INVALID_ARGUMENT;
469
470 if (pmc_table->machine_type != pmc_P6)
471 return KERN_FAILURE;
472
473 *(uint64_t *)evtsel = rdmsr64(pmc_table->msr_control_base + id);
474
475 return KERN_SUCCESS;
476}
477
478int
479pmc_evtsel_write(pmc_id_t id, pmc_evtsel_t *evtsel)
480{
481 pmc_table_t *pmc_table = pmc_table_valid(id);
482
483 if (pmc_table == NULL)
484 return KERN_INVALID_ARGUMENT;
485
486 if (pmc_table->machine_type != pmc_P4_Xeon)
487 return KERN_FAILURE;
488
489 wrmsr64(pmc_table->msr_control_base + id, *(uint64_t *)evtsel);
490
491 return KERN_SUCCESS;
492}
493
494int
495pmc_escr_read(pmc_id_t id, pmc_escr_id_t esid, pmc_escr_t *escr)
496{
497 uint32_t addr;
498 pmc_table_t *pmc_table = pmc_table_valid(id);
499
500 if (pmc_table == NULL)
501 return KERN_INVALID_ARGUMENT;
502
503 if (pmc_table->machine_type != pmc_P4_Xeon)
504 return KERN_FAILURE;
505
506 if (esid > PMC_ESID_MAX)
507 return KERN_INVALID_ARGUMENT;
508
509 addr = PMC_ESCR_ADDR(id, esid);
510 if (addr == 0)
511 return KERN_INVALID_ARGUMENT;
512
513 *(uint64_t *)escr = rdmsr64(addr);
514
515 return KERN_SUCCESS;
516}
517
518int
519pmc_escr_write(pmc_id_t id, pmc_escr_id_t esid, pmc_escr_t *escr)
520{
521 uint32_t addr;
522 pmc_table_t *pmc_table = pmc_table_valid(id);
523
524 if (pmc_table == NULL)
525 return KERN_FAILURE;
526
527 if (pmc_table->machine_type != pmc_P4_Xeon)
528 return KERN_FAILURE;
529
530 if (esid > PMC_ESID_MAX)
531 return KERN_INVALID_ARGUMENT;
532
533 addr = PMC_ESCR_ADDR(id, esid);
534 if (addr == 0)
535 return KERN_INVALID_ARGUMENT;
536
537 wrmsr64(addr, *(uint64_t *)escr);
538
539 return KERN_SUCCESS;
540}
541
542int
543pmc_set_ovf_func(pmc_id_t id, pmc_ovf_func_t func)
544{
545 pmc_table_t *pmc_table = pmc_table_valid(id);
546
547 if (pmc_table == NULL)
548 return KERN_INVALID_ARGUMENT;
549
550 pmc_table->ovf_func[id] = func;
551
552 return KERN_SUCCESS;
553}