kconfig: use pkg-config for ncurses detection
[akaros.git] / user / perfmon / pfmlib_intel_x86_arch.c
1 /*
2  * pfmlib_intel_x86_arch.c : Intel architectural PMU v1, v2, v3
3  *
4  * Copyright (c) 2005-2007 Hewlett-Packard Development Company, L.P.
5  * Contributed by Stephane Eranian <eranian@hpl.hp.com>
6  *
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12  * of the Software, and to permit persons to whom the Software is furnished to do so,
13  * subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in all
16  * copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
19  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
20  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
22  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
23  * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  *
25  *
26  * This file implements supports for the IA-32 architectural PMU as specified
27  * in the following document:
28  *      "IA-32 Intel Architecture Software Developer's Manual - Volume 3B: System
29  *      Programming Guide"
30  */
31 #include <sys/types.h>
32 #include <ctype.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36
37 /* private headers */
38 #include "pfmlib_priv.h"                        /* library private */
39 #include "pfmlib_intel_x86_priv.h"              /* architecture private */
40
41 #include "events/intel_x86_arch_events.h"       /* architected event table */
42
43 extern pfmlib_pmu_t intel_x86_arch_support;
44
45 static intel_x86_entry_t *x86_arch_pe;
46 /*
47  * .byte 0x53 == push ebx. it's universal for 32 and 64 bit
48  * .byte 0x5b == pop ebx.
49  * Some gcc's (4.1.2 on Core2) object to pairing push/pop and ebx in 64 bit mode.
50  * Using the opcode directly avoids this problem.
51  */
52 static inline void
53 cpuid(unsigned int op, unsigned int *a, unsigned int *b, unsigned int *c, unsigned int *d)
54 {
55   __asm__ __volatile__ (".byte 0x53\n\tcpuid\n\tmovl %%ebx, %%esi\n\t.byte 0x5b"
56        : "=a" (*a),
57              "=S" (*b),
58                  "=c" (*c),
59                  "=d" (*d)
60        : "a" (op));
61 }
62
63
64 /*
65  * create architected event table
66  */
67 static int
68 create_arch_event_table(unsigned int mask, int version)
69 {
70         intel_x86_entry_t *pe;
71         int i, num_events = 0;
72         int m;
73
74         DPRINT("version=%d evt_msk=0x%x\n", version, mask);
75
76         /*
77          * first pass: count the number of supported events
78          */
79         m = mask;
80         for(i=0; i < 7; i++, m>>=1) {
81                 if ((m & 0x1)  == 0)
82                         num_events++;
83         }
84         intel_x86_arch_support.pme_count = num_events;
85
86         pe = calloc(num_events, sizeof(intel_x86_entry_t));
87         if (pe == NULL)
88                 return PFM_ERR_NOTSUPP;
89
90         x86_arch_pe = pe;
91         intel_x86_arch_support.pe = pe;
92
93         /*
94          * second pass: populate the table
95          */
96         m = mask;
97         for(i=0; i < 7; i++, m>>=1) {
98                 if (!(m & 0x1)) {
99                         *pe = intel_x86_arch_pe[i];
100
101                         switch(version) {
102                         case 3:
103                                 pe->modmsk = INTEL_V3_ATTRS;
104                                 break;
105                         default:
106                                 pe->modmsk = INTEL_V2_ATTRS;
107                                 break;
108                         }
109                         pe++;
110                 }
111         }
112         return PFM_SUCCESS;
113 }
114
115 static int
116 check_arch_pmu(int family)
117 {
118         union {
119                 unsigned int val;
120                 intel_x86_pmu_eax_t eax;
121                 intel_x86_pmu_edx_t edx;
122         } eax, ecx, edx, ebx;
123
124         /*
125          * check family number to reject for processors
126          * older than Pentium (family=5). Those processors
127          * did not have the CPUID instruction
128          */
129         if (family < 5 || family == 15)
130                 return PFM_ERR_NOTSUPP;
131
132         /*
133          * check if CPU supports 0xa function of CPUID
134          * 0xa started with Core Duo. Needed to detect if
135          * architected PMU is present
136          */
137         cpuid(0x0, &eax.val, &ebx.val, &ecx.val, &edx.val);
138         if (eax.val < 0xa)
139                 return PFM_ERR_NOTSUPP;
140
141         /*
142          * extract architected PMU information
143          */
144         cpuid(0xa, &eax.val, &ebx.val, &ecx.val, &edx.val);
145
146         /*
147          * version must be greater than zero
148          */
149         return eax.eax.version < 1 ? PFM_ERR_NOTSUPP : PFM_SUCCESS;
150 }
151
152 static int
153 pfm_intel_x86_arch_detect(void *this)
154 {
155         int ret;
156
157         ret = pfm_intel_x86_detect();
158         if (ret != PFM_SUCCESS)
159                 return ret;
160
161         return check_arch_pmu(pfm_intel_x86_cfg.family);
162 }
163
164 static int
165 pfm_intel_x86_arch_init(void *this)
166 {
167         union {
168                 unsigned int val;
169                 intel_x86_pmu_eax_t eax;
170                 intel_x86_pmu_edx_t edx;
171         } eax, ecx, edx, ebx;
172
173         /*
174          * extract architected PMU information
175          */
176         if (!pfm_cfg.forced_pmu) {
177                 cpuid(0xa, &eax.val, &ebx.val, &ecx.val, &edx.val);
178                 intel_x86_arch_support.num_cntrs = eax.eax.num_cnt;
179                 intel_x86_arch_support.num_fixed_cntrs = edx.edx.num_cnt;
180         } else {
181                 eax.eax.version = 3;
182                 ebx.val = 0; /* no restriction */
183                 intel_x86_arch_support.num_cntrs = 0;
184                 intel_x86_arch_support.num_fixed_cntrs = 0;
185         }
186         /*
187          * must be called after impl_cntrs has been initialized
188          */
189         return create_arch_event_table(ebx.val, eax.eax.version);
190 }
191
192 void
193 pfm_intel_x86_arch_terminate(void *this)
194 {
195         /* workaround const void for intel_x86_arch_support.pe */
196         if (x86_arch_pe)
197                 free(x86_arch_pe);
198 }
199
200 /* architected PMU */
201 pfmlib_pmu_t intel_x86_arch_support={
202         .desc                   = "Intel X86 architectural PMU",
203         .name                   = "ix86arch",
204         .pmu                    = PFM_PMU_INTEL_X86_ARCH,
205         .pme_count              = 0,
206         .pe                     = NULL,
207         .atdesc                 = intel_x86_mods,
208         .flags                  = PFMLIB_PMU_FL_RAW_UMASK | PFMLIB_PMU_FL_ARCH_DFL,
209         .type                   = PFM_PMU_TYPE_CORE,
210         .max_encoding           = 1,
211
212         .pmu_detect             = pfm_intel_x86_arch_detect,
213         .pmu_init               = pfm_intel_x86_arch_init,
214         .pmu_terminate          = pfm_intel_x86_arch_terminate,
215         .get_event_encoding[PFM_OS_NONE] = pfm_intel_x86_get_encoding,
216          PFMLIB_ENCODE_PERF(pfm_intel_x86_get_perf_encoding),
217         .get_event_first        = pfm_intel_x86_get_event_first,
218         .get_event_next         = pfm_intel_x86_get_event_next,
219         .event_is_valid         = pfm_intel_x86_event_is_valid,
220         .get_event_info         = pfm_intel_x86_get_event_info,
221         .get_event_attr_info    = pfm_intel_x86_get_event_attr_info,
222         PFMLIB_VALID_PERF_PATTRS(pfm_intel_x86_perf_validate_pattrs),
223         .get_event_nattrs       = pfm_intel_x86_get_event_nattrs,
224 };