15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* CpuArch.c -- CPU specific code
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)2010-10-26: Igor Pavlov : Public domain */
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "CpuArch.h"
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef MY_CPU_X86_OR_AMD64
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define USE_ASM
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_ASM) && !defined(MY_CPU_AMD64)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static UInt32 CheckFlag(UInt32 flag)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  #ifdef _MSC_VER
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm pushfd;
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm pop EAX;
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm mov EDX, EAX;
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm xor EAX, flag;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm push EAX;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm popfd;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm pushfd;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm pop EAX;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm xor EAX, EDX;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm push EDX;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm popfd;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm and flag, EAX;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  #else
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm__ __volatile__ (
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "pushf\n\t"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "pop  %%EAX\n\t"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "movl %%EAX,%%EDX\n\t"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "xorl %0,%%EAX\n\t"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "push %%EAX\n\t"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "popf\n\t"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "pushf\n\t"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "pop  %%EAX\n\t"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "xorl %%EDX,%%EAX\n\t"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "push %%EDX\n\t"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "popf\n\t"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "andl %%EAX, %0\n\t":
42ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    "=c" (flag) : "c" (flag):
43ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    "%eax", "%edx" );
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  #endif
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return flag;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CHECK_CPUID_IS_SUPPORTED
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  #ifdef USE_ASM
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  #ifdef _MSC_VER
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UInt32 a2, b2, c2, d2;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm xor EBX, EBX;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm xor ECX, ECX;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm xor EDX, EDX;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm mov EAX, function;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm cpuid;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm mov a2, EAX;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm mov b2, EBX;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm mov c2, ECX;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm mov d2, EDX;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *a = a2;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *b = b2;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *c = c2;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *d = d2;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  #else
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  #if defined(MY_CPU_AMD64)
777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  __asm__ __volatile__ (
797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    "mov %%rbx, %%rdi\n"
807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    "cpuid\n"
817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    "xchg %%rdi, %%rbx\n"
827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    : "=a" (*a) ,
837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      "=D" (*b) ,
847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      "=c" (*c) ,
857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      "=d" (*d)
867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    : "0" (function)) ;
877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  #else
897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm__ __volatile__ (
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "mov %%ebx, %%edi\n"
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "cpuid\n"
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "xchg %%edi, %%ebx\n"
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : "=a" (*a) ,
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "=D" (*b) ,
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "=c" (*c) ,
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "=d" (*d)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : "0" (function)) ;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  #endif
1017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  #endif
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  #else
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int CPUInfo[4];
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __cpuid(CPUInfo, function);
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *a = CPUInfo[0];
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *b = CPUInfo[1];
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *c = CPUInfo[2];
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *d = CPUInfo[3];
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  #endif
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Bool x86cpuid_CheckAndRead(Cx86cpuid *p)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_CPUID_IS_SUPPORTED
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MyCPUID(1, &p->ver, &p->b, &p->c, &p->d);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return True;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static UInt32 kVendors[][3] =
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { 0x756E6547, 0x49656E69, 0x6C65746E},
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { 0x68747541, 0x69746E65, 0x444D4163},
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { 0x746E6543, 0x48727561, 0x736C7561}
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int x86cpuid_GetFirm(const Cx86cpuid *p)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned i;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const UInt32 *v = kVendors[i];
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (v[0] == p->vendor[0] &&
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        v[1] == p->vendor[1] &&
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        v[2] == p->vendor[2])
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return (int)i;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return -1;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Bool CPU_Is_InOrder()
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Cx86cpuid p;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int firm;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UInt32 family, model;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!x86cpuid_CheckAndRead(&p))
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return True;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  family = x86cpuid_GetFamily(&p);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model = x86cpuid_GetModel(&p);
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  firm = x86cpuid_GetFirm(&p);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (firm)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && model == 0x100C));
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA)));
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF));
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return True;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(MY_CPU_AMD64) && defined(_WIN32)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static Bool CPU_Sys_Is_SSE_Supported()
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSVERSIONINFO vi;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  vi.dwOSVersionInfoSize = sizeof(vi);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetVersionEx(&vi))
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return False;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (vi.dwMajorVersion >= 5);
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CHECK_SYS_SSE_SUPPORT
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Bool CPU_Is_Aes_Supported()
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Cx86cpuid p;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_SYS_SSE_SUPPORT
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!x86cpuid_CheckAndRead(&p))
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return False;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (p.c >> 25) & 1;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
188