OLD | NEW |
(Empty) | |
| 1 /* Get CPU type and Features for x86 processors. |
| 2 Copyright (C) 2012 Free Software Foundation, Inc. |
| 3 Contributed by Sriraman Tallam (tmsriram@google.com) |
| 4 |
| 5 This file is part of GCC. |
| 6 |
| 7 GCC is free software; you can redistribute it and/or modify it under |
| 8 the terms of the GNU General Public License as published by the Free |
| 9 Software Foundation; either version 3, or (at your option) any later |
| 10 version. |
| 11 |
| 12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| 13 WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| 15 for more details. |
| 16 |
| 17 You should have received a copy of the GNU General Public License |
| 18 along with GCC; see the file COPYING3. If not see |
| 19 <http://www.gnu.org/licenses/>. */ |
| 20 |
| 21 #include "cpuid.h" |
| 22 #include "tsystem.h" |
| 23 |
| 24 int __cpu_indicator_init (void) __attribute__ ((constructor (101))); |
| 25 |
| 26 enum vendor_signatures |
| 27 { |
| 28 SIG_INTEL = 0x756e6547 /* Genu */, |
| 29 SIG_AMD = 0x68747541 /* Auth */ |
| 30 }; |
| 31 |
| 32 /* ISA Features supported. */ |
| 33 |
| 34 struct __processor_features |
| 35 { |
| 36 unsigned int __cpu_cmov : 1; |
| 37 unsigned int __cpu_mmx : 1; |
| 38 unsigned int __cpu_popcnt : 1; |
| 39 unsigned int __cpu_sse : 1; |
| 40 unsigned int __cpu_sse2 : 1; |
| 41 unsigned int __cpu_sse3 : 1; |
| 42 unsigned int __cpu_ssse3 : 1; |
| 43 unsigned int __cpu_sse4_1 : 1; |
| 44 unsigned int __cpu_sse4_2 : 1; |
| 45 } __cpu_features; |
| 46 |
| 47 /* Processor Vendor and Models. */ |
| 48 |
| 49 enum processor_vendor |
| 50 { |
| 51 VENDOR_INTEL = 1, |
| 52 VENDOR_AMD, |
| 53 VENDOR_MAX |
| 54 }; |
| 55 |
| 56 enum processor_types |
| 57 { |
| 58 INTEL_ATOM = 1, |
| 59 INTEL_CORE2, |
| 60 INTEL_COREI7, |
| 61 AMDFAM10H, |
| 62 AMDFAM15H, |
| 63 CPU_TYPE_MAX |
| 64 }; |
| 65 |
| 66 enum processor_subtypes |
| 67 { |
| 68 INTEL_COREI7_NEHALEM, |
| 69 INTEL_COREI7_WESTMERE, |
| 70 INTEL_COREI7_SANDYBRIDGE, |
| 71 AMDFAM10H_BARCELONA, |
| 72 AMDFAM10H_SHANGHAI, |
| 73 AMDFAM10H_ISTANBUL, |
| 74 AMDFAM15H_BDVER1, |
| 75 AMDFAM15H_BDVER2, |
| 76 CPU_SUBTYPE_MAX |
| 77 }; |
| 78 |
| 79 struct __processor_model |
| 80 { |
| 81 unsigned int __cpu_vendor; |
| 82 unsigned int __cpu_type; |
| 83 unsigned int __cpu_subtype; |
| 84 } __cpu_model; |
| 85 |
| 86 /* Get the specific type of AMD CPU. */ |
| 87 |
| 88 static void |
| 89 get_amd_cpu (unsigned int family, unsigned int model) |
| 90 { |
| 91 __cpu_model.__cpu_vendor = VENDOR_AMD; |
| 92 switch (family) |
| 93 { |
| 94 /* AMD Family 10h. */ |
| 95 case 0x10: |
| 96 switch (model) |
| 97 { |
| 98 case 0x2: |
| 99 /* Barcelona. */ |
| 100 __cpu_model.__cpu_type = AMDFAM10H; |
| 101 __cpu_model.__cpu_subtype = AMDFAM10H_BARCELONA; |
| 102 break; |
| 103 case 0x4: |
| 104 /* Shanghai. */ |
| 105 __cpu_model.__cpu_type = AMDFAM10H; |
| 106 __cpu_model.__cpu_subtype = AMDFAM10H_SHANGHAI; |
| 107 break; |
| 108 case 0x8: |
| 109 /* Istanbul. */ |
| 110 __cpu_model.__cpu_type = AMDFAM10H; |
| 111 __cpu_model.__cpu_subtype = AMDFAM10H_ISTANBUL; |
| 112 break; |
| 113 default: |
| 114 break; |
| 115 } |
| 116 break; |
| 117 /* AMD Family 15h. */ |
| 118 case 0x15: |
| 119 __cpu_model.__cpu_type = AMDFAM15H; |
| 120 /* Bulldozer version 1. */ |
| 121 if ( model <= 0xf) |
| 122 __cpu_model.__cpu_subtype = AMDFAM15H_BDVER1; |
| 123 /* Bulldozer version 2. */ |
| 124 if (model >= 0x10 && model <= 0x1f) |
| 125 __cpu_model.__cpu_subtype = AMDFAM15H_BDVER2; |
| 126 break; |
| 127 default: |
| 128 break; |
| 129 } |
| 130 } |
| 131 |
| 132 /* Get the specific type of Intel CPU. */ |
| 133 |
| 134 static void |
| 135 get_intel_cpu (unsigned int family, unsigned int model, unsigned int brand_id) |
| 136 { |
| 137 __cpu_model.__cpu_vendor = VENDOR_INTEL; |
| 138 /* Parse family and model only if brand ID is 0. */ |
| 139 if (brand_id == 0) |
| 140 { |
| 141 switch (family) |
| 142 { |
| 143 case 0x5: |
| 144 /* Pentium. */ |
| 145 break; |
| 146 case 0x6: |
| 147 switch (model) |
| 148 { |
| 149 case 0x1c: |
| 150 case 0x26: |
| 151 /* Atom. */ |
| 152 __cpu_model.__cpu_type = INTEL_ATOM; |
| 153 break; |
| 154 case 0x1a: |
| 155 case 0x1e: |
| 156 case 0x1f: |
| 157 case 0x2e: |
| 158 /* Nehalem. */ |
| 159 __cpu_model.__cpu_type = INTEL_COREI7; |
| 160 __cpu_model.__cpu_subtype = INTEL_COREI7_NEHALEM; |
| 161 break; |
| 162 case 0x25: |
| 163 case 0x2c: |
| 164 case 0x2f: |
| 165 /* Westmere. */ |
| 166 __cpu_model.__cpu_type = INTEL_COREI7; |
| 167 __cpu_model.__cpu_subtype = INTEL_COREI7_WESTMERE; |
| 168 break; |
| 169 case 0x2a: |
| 170 /* Sandy Bridge. */ |
| 171 __cpu_model.__cpu_type = INTEL_COREI7; |
| 172 __cpu_model.__cpu_subtype = INTEL_COREI7_SANDYBRIDGE; |
| 173 break; |
| 174 case 0x17: |
| 175 case 0x1d: |
| 176 /* Penryn. */ |
| 177 case 0x0f: |
| 178 /* Merom. */ |
| 179 __cpu_model.__cpu_type = INTEL_CORE2; |
| 180 break; |
| 181 default: |
| 182 break; |
| 183 } |
| 184 break; |
| 185 default: |
| 186 /* We have no idea. */ |
| 187 break; |
| 188 } |
| 189 } |
| 190 }······················· |
| 191 |
| 192 static void |
| 193 get_available_features (unsigned int ecx, unsigned int edx) |
| 194 { |
| 195 __cpu_features.__cpu_cmov = (edx & bit_CMOV) ? 1 : 0; |
| 196 __cpu_features.__cpu_mmx = (edx & bit_MMX) ? 1 : 0; |
| 197 __cpu_features.__cpu_sse = (edx & bit_SSE) ? 1 : 0; |
| 198 __cpu_features.__cpu_sse2 = (edx & bit_SSE2) ? 1 : 0; |
| 199 __cpu_features.__cpu_popcnt = (ecx & bit_POPCNT) ? 1 : 0; |
| 200 __cpu_features.__cpu_sse3 = (ecx & bit_SSE3) ? 1 : 0; |
| 201 __cpu_features.__cpu_ssse3 = (ecx & bit_SSSE3) ? 1 : 0; |
| 202 __cpu_features.__cpu_sse4_1 = (ecx & bit_SSE4_1) ? 1 : 0; |
| 203 __cpu_features.__cpu_sse4_2 = (ecx & bit_SSE4_2) ? 1 : 0; |
| 204 } |
| 205 |
| 206 /* A noinline function calling __get_cpuid. Having many calls to |
| 207 cpuid in one function in 32-bit mode causes GCC to complain: |
| 208 "can;t find a register in class CLOBBERED_REGS". This is |
| 209 related to PR rtl-optimization 44174. */ |
| 210 |
| 211 static int __attribute__ ((noinline)) |
| 212 __get_cpuid_output (unsigned int __level, |
| 213 unsigned int *__eax, unsigned int *__ebx, |
| 214 unsigned int *__ecx, unsigned int *__edx) |
| 215 { |
| 216 return __get_cpuid (__level, __eax, __ebx, __ecx, __edx); |
| 217 } |
| 218 |
| 219 |
| 220 /* A constructor function that is sets __cpu_model and __cpu_features with |
| 221 the right values. This needs to run only once. This constructor is |
| 222 given the highest priority and it should run before constructors without |
| 223 the priority set. However, it still runs after ifunc initializers and |
| 224 needs to be called explicitly there. */ |
| 225 |
| 226 int __attribute__ ((constructor (101))) |
| 227 __cpu_indicator_init (void) |
| 228 { |
| 229 unsigned int eax, ebx, ecx, edx; |
| 230 |
| 231 int max_level = 5; |
| 232 unsigned int vendor; |
| 233 unsigned int model, family, brand_id; |
| 234 unsigned int extended_model, extended_family; |
| 235 static int called = 0; |
| 236 |
| 237 /* This function needs to run just once. */ |
| 238 if (called) |
| 239 return 0; |
| 240 else |
| 241 called = 1; |
| 242 |
| 243 /* Assume cpuid insn present. Run in level 0 to get vendor id. */ |
| 244 if (!__get_cpuid_output (0, &eax, &ebx, &ecx, &edx)) |
| 245 return -1; |
| 246 |
| 247 vendor = ebx; |
| 248 max_level = eax; |
| 249 |
| 250 if (max_level < 1) |
| 251 return -1; |
| 252 |
| 253 if (!__get_cpuid_output (1, &eax, &ebx, &ecx, &edx)) |
| 254 return -1; |
| 255 |
| 256 model = (eax >> 4) & 0x0f; |
| 257 family = (eax >> 8) & 0x0f; |
| 258 brand_id = ebx & 0xff; |
| 259 extended_model = (eax >> 12) & 0xf0; |
| 260 extended_family = (eax >> 20) & 0xff; |
| 261 |
| 262 if (vendor == SIG_INTEL) |
| 263 { |
| 264 /* Adjust model and family for Intel CPUS. */ |
| 265 if (family == 0x0f) |
| 266 { |
| 267 family += extended_family; |
| 268 model += extended_model; |
| 269 } |
| 270 else if (family == 0x06) |
| 271 model += extended_model; |
| 272 |
| 273 /* Get CPU type. */ |
| 274 get_intel_cpu (family, model, brand_id); |
| 275 } |
| 276 |
| 277 if (vendor == SIG_AMD) |
| 278 { |
| 279 /* Adjust model and family for AMD CPUS. */ |
| 280 if (family == 0x0f) |
| 281 { |
| 282 family += extended_family; |
| 283 model += (extended_model << 4); |
| 284 } |
| 285 |
| 286 /* Get CPU type. */ |
| 287 get_amd_cpu (family, model); |
| 288 } |
| 289 |
| 290 /* Find available features. */ |
| 291 get_available_features (ecx, edx); |
| 292 |
| 293 gcc_assert (__cpu_model.__cpu_vendor < VENDOR_MAX); |
| 294 gcc_assert (__cpu_model.__cpu_type < CPU_TYPE_MAX); |
| 295 gcc_assert (__cpu_model.__cpu_subtype < CPU_SUBTYPE_MAX); |
| 296 |
| 297 return 0; |
| 298 } |
OLD | NEW |