Home | History | Annotate | Download | only in libop
      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