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