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