/* * @file architecture specific interfaces * @remark Copyright 2008 Intel Corporation * @remark Read the file COPYING * @author Andi Kleen */ #if (defined(__i386__) || defined(__x86_64__)) && !defined(ANDROID_HOST) /* Assume we run on the same host as the profilee */ #define num_to_mask(x) ((1U << (x)) - 1) static inline int cpuid_vendor(char *vnd) { union { struct { unsigned b,d,c; }; char v[12]; } v; unsigned eax; #ifdef __PIC__ __asm__ __volatile__( "pushl %%ebx\n" /* must be preserved due to PIC code */ "cpuid\n" "mov %%ebx, 0(%%edi)\n" "mov %%ecx, 4(%%edi)\n" "mov %%edx, 8(%%edi)\n" "popl %%ebx\n" : "=a" (eax) : "a"(0), "D"(v.v) : "%ecx", "%edx" ); #else asm("cpuid" : "=a" (eax), "=b" (v.b), "=c" (v.c), "=d" (v.d) : "0" (0)); #endif return !strncmp(v.v, vnd, 12); } static inline unsigned arch_cpuid_1(int code) { unsigned val; #ifdef __PIC__ __asm__ __volatile__ ( "pushl %%ebx\n" "cpuid\n" "popl %%ebx\n" : "=a" (val) : "a" (code) : "ecx", "edx" ); #else asm("cpuid" : "=a" (v.eax) : "a" (code) : "ecx","ebx","edx"); #endif return val; } static inline unsigned int cpuid_signature() { return arch_cpuid_1(1); } static inline unsigned int cpu_model(unsigned int eax) { unsigned model = (eax & 0xf0) >> 4; unsigned ext_model = (eax & 0xf0000) >> 12; return ext_model + model; } static inline unsigned int cpu_family(unsigned int eax) { unsigned family = (eax & 0xf00) >> 8; unsigned ext_family = (eax & 0xff00000) >> 20; return ext_family + family; } static inline unsigned int cpu_stepping(unsigned int eax) { return (eax & 0xf); } /* Work around Nehalem spec update AAJ79: CPUID incorrectly indicates unhalted reference cycle architectural event is supported. We assume steppings after C0 report correct data in CPUID. */ static inline void workaround_nehalem_aaj79(unsigned *ebx) { unsigned eax; if (!cpuid_vendor("GenuineIntel")) return; eax = cpuid_signature(); if (cpu_family(eax) != 6 || cpu_model(eax) != 26 || cpu_stepping(eax) > 4) return; *ebx |= (1 << 2); /* disable unsupported event */ } static inline unsigned arch_get_filter(op_cpu cpu_type) { if (op_cpu_base_type(cpu_type) == CPU_ARCH_PERFMON) { unsigned ebx, eax; #ifdef __PIC__ __asm__ __volatile__ ( "pushl %%ebx\n" "cpuid\n" "mov %%ebx, %%ecx\n" "popl %%ebx" : "=a" (eax), "=c" (ebx) : "a" (0xa) : "edx" ); #else asm("cpuid" : "=a" (eax), "=b" (ebx) : "0" (0xa) : "ecx","edx"); #endif workaround_nehalem_aaj79(&ebx); return ebx & num_to_mask(eax >> 24); } return -1U; } static inline int arch_num_counters(op_cpu cpu_type) { if (op_cpu_base_type(cpu_type) == CPU_ARCH_PERFMON) { unsigned v = arch_cpuid_1(0xa); return (v >> 8) & 0xff; } return -1; } static inline unsigned arch_get_counter_mask(void) { unsigned v = arch_cpuid_1(0xa); return num_to_mask((v >> 8) & 0xff); } static inline op_cpu op_cpu_specific_type(op_cpu cpu_type) { if (cpu_type == CPU_ARCH_PERFMON) { /* Already know is Intel family 6, so just check the model. */ int model = cpu_model(cpuid_signature()); switch(model) { case 0x0f: case 0x16: case 0x17: case 0x1d: return CPU_CORE_2; case 0x1a: case 0x1e: case 0x2e: return CPU_CORE_I7; case 0x1c: return CPU_ATOM; case 0x25: return CPU_WESTMERE; } } return cpu_type; } #else static inline unsigned arch_get_filter(op_cpu cpu_type) { /* Do something with passed arg to shut up the compiler warning */ if (cpu_type != CPU_NO_GOOD) return 0; return 0; } static inline int arch_num_counters(op_cpu cpu_type) { /* Do something with passed arg to shut up the compiler warning */ if (cpu_type != CPU_NO_GOOD) return -1; return -1; } static inline unsigned arch_get_counter_mask(void) { return 0; } static inline op_cpu op_cpu_specific_type(op_cpu cpu_type) { return cpu_type; } #endif