Home | History | Annotate | Download | only in C
      1 /* CpuArch.c -- CPU specific code
      2 2012-05-29: Igor Pavlov : Public domain */
      3 
      4 #include "Precomp.h"
      5 
      6 #include "CpuArch.h"
      7 
      8 #ifdef MY_CPU_X86_OR_AMD64
      9 
     10 #if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__)
     11 #define USE_ASM
     12 #endif
     13 
     14 #if !defined(USE_ASM) && _MSC_VER >= 1500
     15 #include <intrin.h>
     16 #endif
     17 
     18 #if defined(USE_ASM) && !defined(MY_CPU_AMD64)
     19 static UInt32 CheckFlag(UInt32 flag)
     20 {
     21   #ifdef _MSC_VER
     22   __asm pushfd;
     23   __asm pop EAX;
     24   __asm mov EDX, EAX;
     25   __asm xor EAX, flag;
     26   __asm push EAX;
     27   __asm popfd;
     28   __asm pushfd;
     29   __asm pop EAX;
     30   __asm xor EAX, EDX;
     31   __asm push EDX;
     32   __asm popfd;
     33   __asm and flag, EAX;
     34   #else
     35   __asm__ __volatile__ (
     36     "pushf\n\t"
     37     "pop  %%EAX\n\t"
     38     "movl %%EAX,%%EDX\n\t"
     39     "xorl %0,%%EAX\n\t"
     40     "push %%EAX\n\t"
     41     "popf\n\t"
     42     "pushf\n\t"
     43     "pop  %%EAX\n\t"
     44     "xorl %%EDX,%%EAX\n\t"
     45     "push %%EDX\n\t"
     46     "popf\n\t"
     47     "andl %%EAX, %0\n\t":
     48     "=c" (flag) : "c" (flag));
     49   #endif
     50   return flag;
     51 }
     52 #define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False;
     53 #else
     54 #define CHECK_CPUID_IS_SUPPORTED
     55 #endif
     56 
     57 static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
     58 {
     59   #ifdef USE_ASM
     60 
     61   #ifdef _MSC_VER
     62 
     63   UInt32 a2, b2, c2, d2;
     64   __asm xor EBX, EBX;
     65   __asm xor ECX, ECX;
     66   __asm xor EDX, EDX;
     67   __asm mov EAX, function;
     68   __asm cpuid;
     69   __asm mov a2, EAX;
     70   __asm mov b2, EBX;
     71   __asm mov c2, ECX;
     72   __asm mov d2, EDX;
     73 
     74   *a = a2;
     75   *b = b2;
     76   *c = c2;
     77   *d = d2;
     78 
     79   #else
     80 
     81   __asm__ __volatile__ (
     82   #if defined(MY_CPU_X86) && defined(__PIC__)
     83     "mov %%ebx, %%edi;"
     84     "cpuid;"
     85     "xchgl %%ebx, %%edi;"
     86     : "=a" (*a) ,
     87       "=D" (*b) ,
     88   #else
     89     "cpuid"
     90     : "=a" (*a) ,
     91       "=b" (*b) ,
     92   #endif
     93       "=c" (*c) ,
     94       "=d" (*d)
     95     : "0" (function)) ;
     96 
     97   #endif
     98 
     99   #else
    100 
    101   int CPUInfo[4];
    102   __cpuid(CPUInfo, function);
    103   *a = CPUInfo[0];
    104   *b = CPUInfo[1];
    105   *c = CPUInfo[2];
    106   *d = CPUInfo[3];
    107 
    108   #endif
    109 }
    110 
    111 Bool x86cpuid_CheckAndRead(Cx86cpuid *p)
    112 {
    113   CHECK_CPUID_IS_SUPPORTED
    114   MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]);
    115   MyCPUID(1, &p->ver, &p->b, &p->c, &p->d);
    116   return True;
    117 }
    118 
    119 static UInt32 kVendors[][3] =
    120 {
    121   { 0x756E6547, 0x49656E69, 0x6C65746E},
    122   { 0x68747541, 0x69746E65, 0x444D4163},
    123   { 0x746E6543, 0x48727561, 0x736C7561}
    124 };
    125 
    126 int x86cpuid_GetFirm(const Cx86cpuid *p)
    127 {
    128   unsigned i;
    129   for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++)
    130   {
    131     const UInt32 *v = kVendors[i];
    132     if (v[0] == p->vendor[0] &&
    133         v[1] == p->vendor[1] &&
    134         v[2] == p->vendor[2])
    135       return (int)i;
    136   }
    137   return -1;
    138 }
    139 
    140 Bool CPU_Is_InOrder()
    141 {
    142   Cx86cpuid p;
    143   int firm;
    144   UInt32 family, model;
    145   if (!x86cpuid_CheckAndRead(&p))
    146     return True;
    147   family = x86cpuid_GetFamily(&p);
    148   model = x86cpuid_GetModel(&p);
    149   firm = x86cpuid_GetFirm(&p);
    150   switch (firm)
    151   {
    152     case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && (
    153         /* Atom CPU */
    154            model == 0x100C  /* 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 */
    155         || model == 0x2006  /* 45 nm, Z6xx */
    156         || model == 0x2007  /* 32 nm, Z2460 */
    157         || model == 0x3005  /* 32 nm, Z2760 */
    158         || model == 0x3006  /* 32 nm, N2xxx, D2xxx */
    159         )));
    160     case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA)));
    161     case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF));
    162   }
    163   return True;
    164 }
    165 
    166 #if !defined(MY_CPU_AMD64) && defined(_WIN32)
    167 #include <windows.h>
    168 static Bool CPU_Sys_Is_SSE_Supported()
    169 {
    170   OSVERSIONINFO vi;
    171   vi.dwOSVersionInfoSize = sizeof(vi);
    172   if (!GetVersionEx(&vi))
    173     return False;
    174   return (vi.dwMajorVersion >= 5);
    175 }
    176 #define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False;
    177 #else
    178 #define CHECK_SYS_SSE_SUPPORT
    179 #endif
    180 
    181 Bool CPU_Is_Aes_Supported()
    182 {
    183   Cx86cpuid p;
    184   CHECK_SYS_SSE_SUPPORT
    185   if (!x86cpuid_CheckAndRead(&p))
    186     return False;
    187   return (p.c >> 25) & 1;
    188 }
    189 
    190 #endif
    191