1 /* 2 * @file architecture specific interfaces 3 * @remark Copyright 2008 Intel Corporation 4 * @remark Read the file COPYING 5 * @author Andi Kleen 6 */ 7 8 #if (defined(__i386__) || defined(__x86_64__)) && !defined(ANDROID_HOST) 9 10 /* Assume we run on the same host as the profilee */ 11 12 #define num_to_mask(x) ((1U << (x)) - 1) 13 14 static inline int cpuid_vendor(char *vnd) 15 { 16 union { 17 struct { 18 unsigned b,d,c; 19 }; 20 char v[12]; 21 } v; 22 unsigned eax; 23 #ifdef __PIC__ 24 __asm__ __volatile__( 25 "pushl %%ebx\n" /* must be preserved due to PIC code */ 26 "cpuid\n" 27 "mov %%ebx, 0(%%edi)\n" 28 "mov %%ecx, 4(%%edi)\n" 29 "mov %%edx, 8(%%edi)\n" 30 "popl %%ebx\n" 31 : "=a" (eax) 32 : "a"(0), "D"(v.v) 33 : "%ecx", "%edx" 34 ); 35 #else 36 asm("cpuid" : "=a" (eax), "=b" (v.b), "=c" (v.c), "=d" (v.d) : "0" (0)); 37 #endif 38 return !strncmp(v.v, vnd, 12); 39 } 40 41 static inline unsigned arch_cpuid_1(int code) 42 { 43 unsigned val; 44 #ifdef __PIC__ 45 __asm__ __volatile__ ( 46 "pushl %%ebx\n" 47 "cpuid\n" 48 "popl %%ebx\n" 49 : "=a" (val) 50 : "a" (code) 51 : "ecx", "edx" 52 ); 53 #else 54 asm("cpuid" : "=a" (v.eax) : "a" (code) : "ecx","ebx","edx"); 55 #endif 56 return val; 57 } 58 59 static inline unsigned int cpuid_signature() 60 { 61 return arch_cpuid_1(1); 62 } 63 64 static inline unsigned int cpu_model(unsigned int eax) 65 { 66 unsigned model = (eax & 0xf0) >> 4; 67 unsigned ext_model = (eax & 0xf0000) >> 12; 68 return ext_model + model; 69 } 70 71 static inline unsigned int cpu_family(unsigned int eax) 72 { 73 unsigned family = (eax & 0xf00) >> 8; 74 unsigned ext_family = (eax & 0xff00000) >> 20; 75 return ext_family + family; 76 } 77 78 static inline unsigned int cpu_stepping(unsigned int eax) 79 { 80 return (eax & 0xf); 81 } 82 83 84 /* Work around Nehalem spec update AAJ79: CPUID incorrectly indicates 85 unhalted reference cycle architectural event is supported. We assume 86 steppings after C0 report correct data in CPUID. */ 87 static inline void workaround_nehalem_aaj79(unsigned *ebx) 88 { 89 unsigned eax; 90 91 if (!cpuid_vendor("GenuineIntel")) 92 return; 93 eax = cpuid_signature(); 94 if (cpu_family(eax) != 6 || cpu_model(eax) != 26 95 || cpu_stepping(eax) > 4) 96 return; 97 *ebx |= (1 << 2); /* disable unsupported event */ 98 } 99 100 static inline unsigned arch_get_filter(op_cpu cpu_type) 101 { 102 if (op_cpu_base_type(cpu_type) == CPU_ARCH_PERFMON) { 103 unsigned ebx, eax; 104 #ifdef __PIC__ 105 __asm__ __volatile__ ( 106 "pushl %%ebx\n" 107 "cpuid\n" 108 "mov %%ebx, %%ecx\n" 109 "popl %%ebx" 110 : "=a" (eax), "=c" (ebx) 111 : "a" (0xa) 112 : "edx" 113 ); 114 #else 115 asm("cpuid" : "=a" (eax), "=b" (ebx) : "0" (0xa) : "ecx","edx"); 116 #endif 117 workaround_nehalem_aaj79(&ebx); 118 return ebx & num_to_mask(eax >> 24); 119 } 120 return -1U; 121 } 122 123 static inline int arch_num_counters(op_cpu cpu_type) 124 { 125 if (op_cpu_base_type(cpu_type) == CPU_ARCH_PERFMON) { 126 unsigned v = arch_cpuid_1(0xa); 127 return (v >> 8) & 0xff; 128 } 129 return -1; 130 } 131 132 static inline unsigned arch_get_counter_mask(void) 133 { 134 unsigned v = arch_cpuid_1(0xa); 135 return num_to_mask((v >> 8) & 0xff); 136 } 137 138 static inline op_cpu op_cpu_specific_type(op_cpu cpu_type) 139 { 140 if (cpu_type == CPU_ARCH_PERFMON) { 141 /* Already know is Intel family 6, so just check the model. */ 142 int model = cpu_model(cpuid_signature()); 143 switch(model) { 144 case 0x0f: 145 case 0x16: 146 case 0x17: 147 case 0x1d: 148 return CPU_CORE_2; 149 case 0x1a: 150 case 0x1e: 151 case 0x2e: 152 return CPU_CORE_I7; 153 case 0x1c: 154 return CPU_ATOM; 155 case 0x25: 156 return CPU_WESTMERE; 157 } 158 } 159 return cpu_type; 160 } 161 162 #else 163 164 static inline unsigned arch_get_filter(op_cpu cpu_type) 165 { 166 /* Do something with passed arg to shut up the compiler warning */ 167 if (cpu_type != CPU_NO_GOOD) 168 return 0; 169 return 0; 170 } 171 172 static inline int arch_num_counters(op_cpu cpu_type) 173 { 174 /* Do something with passed arg to shut up the compiler warning */ 175 if (cpu_type != CPU_NO_GOOD) 176 return -1; 177 return -1; 178 } 179 180 static inline unsigned arch_get_counter_mask(void) 181 { 182 return 0; 183 } 184 185 static inline op_cpu op_cpu_specific_type(op_cpu cpu_type) 186 { 187 return cpu_type; 188 } 189 #endif 190