CpuArch.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /* CpuArch.c -- CPU specific code
  2. 2018-02-18: Igor Pavlov : Public domain */
  3. #include "Precomp.h"
  4. #include "CpuArch.h"
  5. #ifdef MY_CPU_X86_OR_AMD64
  6. #if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__)
  7. #define USE_ASM
  8. #endif
  9. #if !defined(USE_ASM) && _MSC_VER >= 1500
  10. #include <intrin.h>
  11. #endif
  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. void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
  52. {
  53. #ifdef USE_ASM
  54. #ifdef _MSC_VER
  55. UInt32 a2, b2, c2, d2;
  56. __asm xor EBX, EBX;
  57. __asm xor ECX, ECX;
  58. __asm xor EDX, EDX;
  59. __asm mov EAX, function;
  60. __asm cpuid;
  61. __asm mov a2, EAX;
  62. __asm mov b2, EBX;
  63. __asm mov c2, ECX;
  64. __asm mov d2, EDX;
  65. *a = a2;
  66. *b = b2;
  67. *c = c2;
  68. *d = d2;
  69. #else
  70. __asm__ __volatile__ (
  71. #if defined(MY_CPU_AMD64) && defined(__PIC__)
  72. "mov %%rbx, %%rdi;"
  73. "cpuid;"
  74. "xchg %%rbx, %%rdi;"
  75. : "=a" (*a) ,
  76. "=D" (*b) ,
  77. #elif defined(MY_CPU_X86) && defined(__PIC__)
  78. "mov %%ebx, %%edi;"
  79. "cpuid;"
  80. "xchgl %%ebx, %%edi;"
  81. : "=a" (*a) ,
  82. "=D" (*b) ,
  83. #else
  84. "cpuid"
  85. : "=a" (*a) ,
  86. "=b" (*b) ,
  87. #endif
  88. "=c" (*c) ,
  89. "=d" (*d)
  90. : "0" (function)) ;
  91. #endif
  92. #else
  93. int CPUInfo[4];
  94. __cpuid(CPUInfo, function);
  95. *a = CPUInfo[0];
  96. *b = CPUInfo[1];
  97. *c = CPUInfo[2];
  98. *d = CPUInfo[3];
  99. #endif
  100. }
  101. BoolInt x86cpuid_CheckAndRead(Cx86cpuid *p)
  102. {
  103. CHECK_CPUID_IS_SUPPORTED
  104. MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]);
  105. MyCPUID(1, &p->ver, &p->b, &p->c, &p->d);
  106. return True;
  107. }
  108. static const UInt32 kVendors[][3] =
  109. {
  110. { 0x756E6547, 0x49656E69, 0x6C65746E},
  111. { 0x68747541, 0x69746E65, 0x444D4163},
  112. { 0x746E6543, 0x48727561, 0x736C7561}
  113. };
  114. int x86cpuid_GetFirm(const Cx86cpuid *p)
  115. {
  116. unsigned i;
  117. for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++)
  118. {
  119. const UInt32 *v = kVendors[i];
  120. if (v[0] == p->vendor[0] &&
  121. v[1] == p->vendor[1] &&
  122. v[2] == p->vendor[2])
  123. return (int)i;
  124. }
  125. return -1;
  126. }
  127. BoolInt CPU_Is_InOrder()
  128. {
  129. Cx86cpuid p;
  130. int firm;
  131. UInt32 family, model;
  132. if (!x86cpuid_CheckAndRead(&p))
  133. return True;
  134. family = x86cpuid_GetFamily(p.ver);
  135. model = x86cpuid_GetModel(p.ver);
  136. firm = x86cpuid_GetFirm(&p);
  137. switch (firm)
  138. {
  139. case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && (
  140. /* In-Order Atom CPU */
  141. model == 0x1C /* 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 */
  142. || model == 0x26 /* 45 nm, Z6xx */
  143. || model == 0x27 /* 32 nm, Z2460 */
  144. || model == 0x35 /* 32 nm, Z2760 */
  145. || model == 0x36 /* 32 nm, N2xxx, D2xxx */
  146. )));
  147. case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA)));
  148. case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF));
  149. }
  150. return True;
  151. }
  152. #if !defined(MY_CPU_AMD64) && defined(_WIN32)
  153. #include <windows.h>
  154. static BoolInt CPU_Sys_Is_SSE_Supported()
  155. {
  156. OSVERSIONINFO vi;
  157. vi.dwOSVersionInfoSize = sizeof(vi);
  158. if (!GetVersionEx(&vi))
  159. return False;
  160. return (vi.dwMajorVersion >= 5);
  161. }
  162. #define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False;
  163. #else
  164. #define CHECK_SYS_SSE_SUPPORT
  165. #endif
  166. BoolInt CPU_Is_Aes_Supported()
  167. {
  168. Cx86cpuid p;
  169. CHECK_SYS_SSE_SUPPORT
  170. if (!x86cpuid_CheckAndRead(&p))
  171. return False;
  172. return (p.c >> 25) & 1;
  173. }
  174. BoolInt CPU_IsSupported_PageGB()
  175. {
  176. Cx86cpuid cpuid;
  177. if (!x86cpuid_CheckAndRead(&cpuid))
  178. return False;
  179. {
  180. UInt32 d[4] = { 0 };
  181. MyCPUID(0x80000000, &d[0], &d[1], &d[2], &d[3]);
  182. if (d[0] < 0x80000001)
  183. return False;
  184. }
  185. {
  186. UInt32 d[4] = { 0 };
  187. MyCPUID(0x80000001, &d[0], &d[1], &d[2], &d[3]);
  188. return (d[3] >> 26) & 1;
  189. }
  190. }
  191. #endif