| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2012 The Native Client Authors. All rights reserved. | 2 * Copyright (c) 2012 The Native Client Authors. All rights reserved. |
| 3 * Use of this source code is governed by a BSD-style license that can be | 3 * Use of this source code is governed by a BSD-style license that can be |
| 4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
| 5 */ | 5 */ |
| 6 | 6 |
| 7 #include "native_client/src/trusted/validator/x86/nacl_cpuid.h" | 7 #include "native_client/src/trusted/cpu_features/arch/x86/cpu_x86.h" |
| 8 | 8 |
| 9 /* | 9 /* |
| 10 * nacl_cpuid.c | 10 * cpu_x86.c |
| 11 * Retrieve and decode CPU model specific feature mask. | 11 * Retrieve and decode CPU model specific feature mask. |
| 12 */ | 12 */ |
| 13 #if NACL_WINDOWS | 13 #if NACL_WINDOWS |
| 14 #include <intrin.h> /* __cpuid intrinsic */ | 14 #include <intrin.h> /* __cpuid intrinsic */ |
| 15 #endif /* NACL_WINDOWS */ | 15 #endif /* NACL_WINDOWS */ |
| 16 | 16 |
| 17 #include <stdio.h> | 17 #include <stdio.h> |
| 18 #include <string.h> | 18 #include <string.h> |
| 19 #include <assert.h> | 19 #include <assert.h> |
| 20 #include <stdlib.h> | 20 #include <stdlib.h> |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 237 static const char Cyrix_CPUID0[kVendorIDLength] = "CyrixInstead"; | 237 static const char Cyrix_CPUID0[kVendorIDLength] = "CyrixInstead"; |
| 238 static const char NexGen_CPUID0[kVendorIDLength] = "NexGenDriven"; | 238 static const char NexGen_CPUID0[kVendorIDLength] = "NexGenDriven"; |
| 239 static const char Cantaur_CPUID0[kVendorIDLength] = "CentaurHauls"; | 239 static const char Cantaur_CPUID0[kVendorIDLength] = "CentaurHauls"; |
| 240 static const char Rise_CPUID0[kVendorIDLength] = "RiseRiseRise"; | 240 static const char Rise_CPUID0[kVendorIDLength] = "RiseRiseRise"; |
| 241 static const char SiS_CPUID0[kVendorIDLength] = "SiS SiS SiS "; | 241 static const char SiS_CPUID0[kVendorIDLength] = "SiS SiS SiS "; |
| 242 static const char TM_CPUID0[kVendorIDLength] = "GenuineTMx86"; | 242 static const char TM_CPUID0[kVendorIDLength] = "GenuineTMx86"; |
| 243 static const char NSC_CPUID0[kVendorIDLength] = "Geode by NSC"; | 243 static const char NSC_CPUID0[kVendorIDLength] = "Geode by NSC"; |
| 244 #endif | 244 #endif |
| 245 | 245 |
| 246 static int asm_HasCPUID(void) { | 246 static int asm_HasCPUID(void) { |
| 247 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 |
| 247 volatile int before, after, result; | 248 volatile int before, after, result; |
| 248 #if NACL_BUILD_SUBARCH == 64 | 249 #if NACL_BUILD_SUBARCH == 64 |
| 249 /* Note: If we are running in x86-64, then cpuid must be defined, | 250 /* Note: If we are running in x86-64, then cpuid must be defined, |
| 250 * since CPUID dates from DX2 486, and x86-64 was added after this. | 251 * since CPUID dates from DX2 486, and x86-64 was added after this. |
| 251 */ | 252 */ |
| 252 return 1; | 253 return 1; |
| 253 /* TODO(bradchen): split into separate Windows, etc., files */ | 254 /* TODO(bradchen): split into separate Windows, etc., files */ |
| 254 #elif defined(__GNUC__) | 255 #elif defined(__GNUC__) |
| 255 __asm__ volatile("pushfl \n\t" /* save EFLAGS to eax */ | 256 __asm__ volatile("pushfl \n\t" /* save EFLAGS to eax */ |
| 256 "pop %%eax \n\t" | 257 "pop %%eax \n\t" |
| (...skipping 21 matching lines...) Expand all Loading... |
| 278 push eax | 279 push eax |
| 279 popfd | 280 popfd |
| 280 pushfd | 281 pushfd |
| 281 pop after | 282 pop after |
| 282 } | 283 } |
| 283 #else | 284 #else |
| 284 # error Unsupported platform | 285 # error Unsupported platform |
| 285 #endif | 286 #endif |
| 286 result = (before ^ after) & 0x0200000; | 287 result = (before ^ after) & 0x0200000; |
| 287 return result; | 288 return result; |
| 289 #else /* NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 */ |
| 290 return 0; |
| 291 #endif |
| 288 } | 292 } |
| 289 | 293 |
| 290 static void asm_CPUID(uint32_t op, volatile uint32_t reg[4]) { | 294 static void asm_CPUID(uint32_t op, volatile uint32_t reg[4]) { |
| 295 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 |
| 291 #if defined(__GNUC__) | 296 #if defined(__GNUC__) |
| 292 #if NACL_BUILD_SUBARCH == 64 | 297 #if NACL_BUILD_SUBARCH == 64 |
| 293 __asm__ volatile("push %%rbx \n\t" /* save %ebx */ | 298 __asm__ volatile("push %%rbx \n\t" /* save %ebx */ |
| 294 #else | 299 #else |
| 295 __asm__ volatile("pushl %%ebx \n\t" | 300 __asm__ volatile("pushl %%ebx \n\t" |
| 296 #endif | 301 #endif |
| 297 "cpuid \n\t" | 302 "cpuid \n\t" |
| 298 "movl %%ebx, %1 \n\t" | 303 "movl %%ebx, %1 \n\t" |
| 299 /* save what cpuid just put in %ebx */ | 304 /* save what cpuid just put in %ebx */ |
| 300 #if NACL_BUILD_SUBARCH == 64 | 305 #if NACL_BUILD_SUBARCH == 64 |
| 301 "pop %%rbx \n\t" | 306 "pop %%rbx \n\t" |
| 302 #else | 307 #else |
| 303 "popl %%ebx \n\t" /* restore the old %ebx */ | 308 "popl %%ebx \n\t" /* restore the old %ebx */ |
| 304 #endif | 309 #endif |
| 305 : "=a"(reg[0]), "=S"(reg[1]), "=c"(reg[2]), "=d"(reg[3]) | 310 : "=a"(reg[0]), "=S"(reg[1]), "=c"(reg[2]), "=d"(reg[3]) |
| 306 : "a"(op) | 311 : "a"(op) |
| 307 : "cc"); | 312 : "cc"); |
| 308 #elif NACL_WINDOWS | 313 #elif NACL_WINDOWS |
| 309 __cpuid((uint32_t*)reg, op); | 314 __cpuid((uint32_t*)reg, op); |
| 310 #else | 315 #else |
| 311 # error Unsupported platform | 316 # error Unsupported platform |
| 312 #endif | 317 #endif |
| 318 #else /* NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 */ |
| 319 UNREFERENCED_PARAMETER(op); |
| 320 reg[0] = 0; |
| 321 reg[1] = 0; |
| 322 reg[2] = 0; |
| 323 reg[3] = 0; |
| 324 return; |
| 325 #endif |
| 313 } | 326 } |
| 314 | 327 |
| 315 /* | 328 /* |
| 316 * Historically CPUID only used eax to select "CPUID function". Function 07h | 329 * Historically CPUID only used eax to select "CPUID function". Function 07h |
| 317 * broke this tradition: it's now required to specify "leaf" in ECX register. | 330 * broke this tradition: it's now required to specify "leaf" in ECX register. |
| 318 * | 331 * |
| 319 * We can specify leaf in all cases (older "CPUID functions" will just ignore | 332 * We can specify leaf in all cases (older "CPUID functions" will just ignore |
| 320 * it), but there is a catch: MSVC 2005 or below don't include __cpuidex | 333 * it), but there is a catch: MSVC 2005 or below don't include __cpuidex |
| 321 * intrinsic required to call CPUID with leaf support! | 334 * intrinsic required to call CPUID with leaf support! |
| 322 * | 335 * |
| 323 * Thus we have two functions: asm_CPUID (for "CPUID functions" without leaves) | 336 * Thus we have two functions: asm_CPUID (for "CPUID functions" without leaves) |
| 324 * and asm_CPUIDx (for "CPUID functions" with leaves). If code is compiled using | 337 * and asm_CPUIDx (for "CPUID functions" with leaves). If code is compiled using |
| 325 * MSVC 2005 or MSVC 2008 then features detected using function 07h will not be | 338 * MSVC 2005 or MSVC 2008 then features detected using function 07h will not be |
| 326 * available. | 339 * available. |
| 327 * | 340 * |
| 328 * Note: MSVC 2008 is particularly problematic: MSVC 2008 does not support | 341 * Note: MSVC 2008 is particularly problematic: MSVC 2008 does not support |
| 329 * __cpuidex while MSVC 2008 SP1 does. Unfortunatelly there are no easy way | 342 * __cpuidex while MSVC 2008 SP1 does. Unfortunatelly there are no easy way |
| 330 * to distinguish MSVC 2008 SP1 from MSVC 2008 using ifdef's thus we disable | 343 * to distinguish MSVC 2008 SP1 from MSVC 2008 using ifdef's thus we disable |
| 331 * __cpuidex for MSVC 2008 unconditionally. | 344 * __cpuidex for MSVC 2008 unconditionally. |
| 332 */ | 345 */ |
| 333 static void asm_CPUIDx(uint32_t op, volatile uint32_t reg[4], uint32_t ecx) { | 346 static void asm_CPUIDx(uint32_t op, volatile uint32_t reg[4], uint32_t ecx) { |
| 347 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 |
| 334 #if defined(__GNUC__) | 348 #if defined(__GNUC__) |
| 335 #if NACL_BUILD_SUBARCH == 64 | 349 #if NACL_BUILD_SUBARCH == 64 |
| 336 __asm__ volatile("push %%rbx \n\t" /* save %ebx */ | 350 __asm__ volatile("push %%rbx \n\t" /* save %ebx */ |
| 337 #else | 351 #else |
| 338 __asm__ volatile("pushl %%ebx \n\t" | 352 __asm__ volatile("pushl %%ebx \n\t" |
| 339 #endif | 353 #endif |
| 340 "cpuid \n\t" | 354 "cpuid \n\t" |
| 341 "movl %%ebx, %1 \n\t" | 355 "movl %%ebx, %1 \n\t" |
| 342 /* save what cpuid just put in %ebx */ | 356 /* save what cpuid just put in %ebx */ |
| 343 #if NACL_BUILD_SUBARCH == 64 | 357 #if NACL_BUILD_SUBARCH == 64 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 358 #else | 372 #else |
| 359 __cpuidex((uint32_t*)reg, op, ecx); | 373 __cpuidex((uint32_t*)reg, op, ecx); |
| 360 #endif | 374 #endif |
| 361 #else /* NACL_WINDOWS, but _MSC_VER is not defined */ | 375 #else /* NACL_WINDOWS, but _MSC_VER is not defined */ |
| 362 /* This is Windows but not MSVC: who knows if __cpuidex is available? */ | 376 /* This is Windows but not MSVC: who knows if __cpuidex is available? */ |
| 363 # error Unsupported compiler | 377 # error Unsupported compiler |
| 364 #endif | 378 #endif |
| 365 #else | 379 #else |
| 366 # error Unsupported platform | 380 # error Unsupported platform |
| 367 #endif | 381 #endif |
| 382 #else /* NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 */ |
| 383 UNREFERENCED_PARAMETER(op); |
| 384 UNREFERENCED_PARAMETER(ecx); |
| 385 reg[0] = 0; |
| 386 reg[1] = 0; |
| 387 reg[2] = 0; |
| 388 reg[3] = 0; |
| 389 return; |
| 390 #endif |
| 368 } | 391 } |
| 369 | 392 |
| 370 static void CacheCPUVersionID(NaClCPUData* data) { | 393 static void CacheCPUVersionID(NaClCPUData* data) { |
| 371 uint32_t reg[4] = {0, 0, 0, 0 }; | 394 uint32_t reg[4] = {0, 0, 0, 0 }; |
| 372 asm_CPUID(0, reg); | 395 asm_CPUID(0, reg); |
| 373 data->_vidwords[0] = reg[1]; | 396 data->_vidwords[0] = reg[1]; |
| 374 data->_vidwords[1] = reg[3]; | 397 data->_vidwords[1] = reg[3]; |
| 375 data->_vidwords[2] = reg[2]; | 398 data->_vidwords[2] = reg[2]; |
| 376 data->_vidwords[3] = 0; | 399 data->_vidwords[3] = 0; |
| 377 } | 400 } |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 628 | 651 |
| 629 void NaClCopyCPUFeaturesX86(NaClCPUFeaturesX86 *target, | 652 void NaClCopyCPUFeaturesX86(NaClCPUFeaturesX86 *target, |
| 630 const NaClCPUFeaturesX86 *source) { | 653 const NaClCPUFeaturesX86 *source) { |
| 631 memcpy(target, source, sizeof(*target)); | 654 memcpy(target, source, sizeof(*target)); |
| 632 } | 655 } |
| 633 | 656 |
| 634 int NaClArchSupportedX86(const NaClCPUFeaturesX86 *f) { | 657 int NaClArchSupportedX86(const NaClCPUFeaturesX86 *f) { |
| 635 return (NaClGetCPUFeatureX86(f, NaClCPUFeatureX86_CPUIDSupported) && | 658 return (NaClGetCPUFeatureX86(f, NaClCPUFeatureX86_CPUIDSupported) && |
| 636 NaClGetCPUFeatureX86(f, NaClCPUFeatureX86_CPUSupported)); | 659 NaClGetCPUFeatureX86(f, NaClCPUFeatureX86_CPUSupported)); |
| 637 } | 660 } |
| OLD | NEW |