Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/cpu.h"
      6 
      7 #if defined(ARCH_CPU_X86_FAMILY)
      8 #if defined(_MSC_VER)
      9 #include <intrin.h>
     10 #endif
     11 #endif
     12 
     13 #include <string.h>
     14 
     15 namespace base {
     16 
     17 CPU::CPU()
     18   : type_(0),
     19     family_(0),
     20     model_(0),
     21     stepping_(0),
     22     ext_model_(0),
     23     ext_family_(0),
     24     has_mmx_(false),
     25     has_sse_(false),
     26     has_sse2_(false),
     27     has_sse3_(false),
     28     has_ssse3_(false),
     29     has_sse41_(false),
     30     has_sse42_(false),
     31     cpu_vendor_("unknown") {
     32   Initialize();
     33 }
     34 
     35 #if defined(ARCH_CPU_X86_FAMILY)
     36 #ifndef _MSC_VER
     37 
     38 #if defined(__pic__) && defined(__i386__)
     39 
     40 void __cpuid(int cpu_info[4], int info_type) {
     41   __asm__ volatile (
     42     "mov %%ebx, %%edi\n"
     43     "cpuid\n"
     44     "xchg %%edi, %%ebx\n"
     45     : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
     46     : "a"(info_type)
     47   );
     48 }
     49 
     50 void __cpuidex(int cpu_info[4], int info_type, int info_index) {
     51   __asm__ volatile (
     52     "mov %%ebx, %%edi\n"
     53     "cpuid\n"
     54     "xchg %%edi, %%ebx\n"
     55     : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
     56     : "a"(info_type), "c"(info_index)
     57   );
     58 }
     59 
     60 #else
     61 
     62 void __cpuid(int cpu_info[4], int info_type) {
     63   __asm__ volatile (
     64     "cpuid \n\t"
     65     : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
     66     : "a"(info_type)
     67   );
     68 }
     69 
     70 void __cpuidex(int cpu_info[4], int info_type, int info_index) {
     71   __asm__ volatile (
     72     "cpuid \n\t"
     73     : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
     74     : "a"(info_type), "c"(info_index)
     75   );
     76 }
     77 
     78 #endif
     79 #endif  // _MSC_VER
     80 #endif  // ARCH_CPU_X86_FAMILY
     81 
     82 void CPU::Initialize() {
     83 #if defined(ARCH_CPU_X86_FAMILY)
     84   int cpu_info[4] = {-1};
     85   char cpu_string[0x20];
     86 
     87   // __cpuid with an InfoType argument of 0 returns the number of
     88   // valid Ids in CPUInfo[0] and the CPU identification string in
     89   // the other three array elements. The CPU identification string is
     90   // not in linear order. The code below arranges the information
     91   // in a human readable form.
     92   //
     93   // More info can be found here:
     94   // http://msdn.microsoft.com/en-us/library/hskdteyh.aspx
     95   __cpuid(cpu_info, 0);
     96   int num_ids = cpu_info[0];
     97   memset(cpu_string, 0, sizeof(cpu_string));
     98   *(reinterpret_cast<int*>(cpu_string)) = cpu_info[1];
     99   *(reinterpret_cast<int*>(cpu_string+4)) = cpu_info[3];
    100   *(reinterpret_cast<int*>(cpu_string+8)) = cpu_info[2];
    101 
    102   // Interpret CPU feature information.
    103   if (num_ids > 0) {
    104     __cpuid(cpu_info, 1);
    105     stepping_ = cpu_info[0] & 0xf;
    106     model_ = ((cpu_info[0] >> 4) & 0xf) + ((cpu_info[0] >> 12) & 0xf0);
    107     family_ = (cpu_info[0] >> 8) & 0xf;
    108     type_ = (cpu_info[0] >> 12) & 0x3;
    109     ext_model_ = (cpu_info[0] >> 16) & 0xf;
    110     ext_family_ = (cpu_info[0] >> 20) & 0xff;
    111     cpu_vendor_ = cpu_string;
    112     has_mmx_ = (cpu_info[3] & 0x00800000) != 0;
    113     has_sse_ = (cpu_info[3] & 0x02000000) != 0;
    114     has_sse2_ = (cpu_info[3] & 0x04000000) != 0;
    115     has_sse3_ = (cpu_info[2] & 0x00000001) != 0;
    116     has_ssse3_ = (cpu_info[2] & 0x00000200) != 0;
    117     has_sse41_ = (cpu_info[2] & 0x00080000) != 0;
    118     has_sse42_ = (cpu_info[2] & 0x00100000) != 0;
    119   }
    120 #endif
    121 }
    122 
    123 }  // namespace base
    124