File indexing completed on 2025-02-02 04:25:58

0001 /* CpuArch.c -- CPU specific code
0002 2012-05-29: Igor Pavlov : Public domain */
0003 
0004 #include "Precomp.h"
0005 
0006 #include "CpuArch.h"
0007 
0008 #ifdef MY_CPU_X86_OR_AMD64
0009 
0010 #if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__)
0011 #define USE_ASM
0012 #endif
0013 
0014 #if !defined(USE_ASM) && _MSC_VER >= 1500
0015 #include <intrin.h>
0016 #endif
0017 
0018 #if defined(USE_ASM) && !defined(MY_CPU_AMD64)
0019 static UInt32 CheckFlag(UInt32 flag)
0020 {
0021   #ifdef _MSC_VER
0022   __asm pushfd;
0023   __asm pop EAX;
0024   __asm mov EDX, EAX;
0025   __asm xor EAX, flag;
0026   __asm push EAX;
0027   __asm popfd;
0028   __asm pushfd;
0029   __asm pop EAX;
0030   __asm xor EAX, EDX;
0031   __asm push EDX;
0032   __asm popfd;
0033   __asm and flag, EAX;
0034   #else
0035   __asm__ __volatile__ (
0036     "pushf\n\t"
0037     "pop  %%EAX\n\t"
0038     "movl %%EAX,%%EDX\n\t"
0039     "xorl %0,%%EAX\n\t"
0040     "push %%EAX\n\t"
0041     "popf\n\t"
0042     "pushf\n\t"
0043     "pop  %%EAX\n\t"
0044     "xorl %%EDX,%%EAX\n\t"
0045     "push %%EDX\n\t"
0046     "popf\n\t"
0047     "andl %%EAX, %0\n\t":
0048     "=c" (flag) : "c" (flag));
0049   #endif
0050   return flag;
0051 }
0052 #define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False;
0053 #else
0054 #define CHECK_CPUID_IS_SUPPORTED
0055 #endif
0056 
0057 static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
0058 {
0059   #ifdef USE_ASM
0060 
0061   #ifdef _MSC_VER
0062 
0063   UInt32 a2, b2, c2, d2;
0064   __asm xor EBX, EBX;
0065   __asm xor ECX, ECX;
0066   __asm xor EDX, EDX;
0067   __asm mov EAX, function;
0068   __asm cpuid;
0069   __asm mov a2, EAX;
0070   __asm mov b2, EBX;
0071   __asm mov c2, ECX;
0072   __asm mov d2, EDX;
0073 
0074   *a = a2;
0075   *b = b2;
0076   *c = c2;
0077   *d = d2;
0078 
0079   #else
0080 
0081   __asm__ __volatile__ (
0082   #if defined(MY_CPU_X86) && defined(__PIC__)
0083     "mov %%ebx, %%edi;"
0084     "cpuid;"
0085     "xchgl %%ebx, %%edi;"
0086     : "=a" (*a) ,
0087       "=D" (*b) ,
0088   #else
0089     "cpuid"
0090     : "=a" (*a) ,
0091       "=b" (*b) ,
0092   #endif
0093       "=c" (*c) ,
0094       "=d" (*d)
0095     : "0" (function)) ;
0096 
0097   #endif
0098   
0099   #else
0100 
0101   int CPUInfo[4];
0102   __cpuid(CPUInfo, function);
0103   *a = CPUInfo[0];
0104   *b = CPUInfo[1];
0105   *c = CPUInfo[2];
0106   *d = CPUInfo[3];
0107 
0108   #endif
0109 }
0110 
0111 Bool x86cpuid_CheckAndRead(Cx86cpuid *p)
0112 {
0113   CHECK_CPUID_IS_SUPPORTED
0114   MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]);
0115   MyCPUID(1, &p->ver, &p->b, &p->c, &p->d);
0116   return True;
0117 }
0118 
0119 static UInt32 kVendors[][3] =
0120 {
0121   { 0x756E6547, 0x49656E69, 0x6C65746E},
0122   { 0x68747541, 0x69746E65, 0x444D4163},
0123   { 0x746E6543, 0x48727561, 0x736C7561}
0124 };
0125 
0126 int x86cpuid_GetFirm(const Cx86cpuid *p)
0127 {
0128   unsigned i;
0129   for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++)
0130   {
0131     const UInt32 *v = kVendors[i];
0132     if (v[0] == p->vendor[0] &&
0133         v[1] == p->vendor[1] &&
0134         v[2] == p->vendor[2])
0135       return (int)i;
0136   }
0137   return -1;
0138 }
0139 
0140 Bool CPU_Is_InOrder()
0141 {
0142   Cx86cpuid p;
0143   int firm;
0144   UInt32 family, model;
0145   if (!x86cpuid_CheckAndRead(&p))
0146     return True;
0147   family = x86cpuid_GetFamily(&p);
0148   model = x86cpuid_GetModel(&p);
0149   firm = x86cpuid_GetFirm(&p);
0150   switch (firm)
0151   {
0152     case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && (
0153         /* Atom CPU */
0154            model == 0x100C  /* 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 */
0155         || model == 0x2006  /* 45 nm, Z6xx */
0156         || model == 0x2007  /* 32 nm, Z2460 */
0157         || model == 0x3005  /* 32 nm, Z2760 */
0158         || model == 0x3006  /* 32 nm, N2xxx, D2xxx */
0159         )));
0160     case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA)));
0161     case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF));
0162   }
0163   return True;
0164 }
0165 
0166 #if !defined(MY_CPU_AMD64) && defined(_WIN32)
0167 #include <windows.h>
0168 static Bool CPU_Sys_Is_SSE_Supported()
0169 {
0170   OSVERSIONINFO vi;
0171   vi.dwOSVersionInfoSize = sizeof(vi);
0172   if (!GetVersionEx(&vi))
0173     return False;
0174   return (vi.dwMajorVersion >= 5);
0175 }
0176 #define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False;
0177 #else
0178 #define CHECK_SYS_SSE_SUPPORT
0179 #endif
0180 
0181 Bool CPU_Is_Aes_Supported()
0182 {
0183   Cx86cpuid p;
0184   CHECK_SYS_SSE_SUPPORT
0185   if (!x86cpuid_CheckAndRead(&p))
0186     return False;
0187   return (p.c >> 25) & 1;
0188 }
0189 
0190 #endif