PageRenderTime 57ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/source/cpuid.cpp

http://github.com/tycho/crisscross
C++ | 1288 lines | 972 code | 177 blank | 139 comment | 107 complexity | b1acc990fab07463fa9ebedba6bf88d4 MD5 | raw file
Possible License(s): BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * CrissCross
  3. * A multi-purpose cross-platform library.
  4. *
  5. * A product of Uplink Laboratories.
  6. *
  7. * (c) 2006-2010 Steven Noonan.
  8. * Licensed under the New BSD License.
  9. *
  10. */
  11. /*
  12. * Last updated 1/9/2008
  13. * using Intel CPUID documentation (AP-485) updated 12/2007
  14. */
  15. #include <crisscross/universal_include.h>
  16. #include <crisscross/string_utils.h>
  17. #include <cmath>
  18. #include <cstdio>
  19. #include <cstring>
  20. #define ENABLE_CPUID
  21. /* Doesn't work on non-x86, and Cygwin doesn't have the functionality for cpu_set_t. */
  22. #if !(defined (TARGET_CPU_X86) || defined (TARGET_CPU_X64)) || defined (TARGET_COMPILER_CYGWIN) || defined (TARGET_OS_NETBSD) || defined (TARGET_OS_OPENBSD)
  23. #undef ENABLE_CPUID
  24. #endif
  25. /* FIXME: This is disabled due to inline asm complications. */
  26. #if defined (TARGET_OS_WINDOWS) && !defined (TARGET_CPU_X86)
  27. #undef ENABLE_CPUID
  28. #endif
  29. #ifdef ENABLE_CPUID
  30. #ifdef TARGET_OS_WINDOWS
  31. #include <windows.h>
  32. #endif
  33. //#define USE_CHUD_FOR_CPUID
  34. #if defined(TARGET_OS_MACOSX)
  35. #if defined(USE_CHUD_FOR_CPUID)
  36. extern "C" {
  37. int chudProcessorCount();
  38. int utilBindThreadToCPU(int n);
  39. int utilUnbindThreadFromCPU();
  40. }
  41. #else
  42. #include <sys/types.h>
  43. #include <sys/sysctl.h>
  44. namespace {
  45. int getProcessorCount();
  46. }
  47. #endif
  48. #endif
  49. #ifdef TARGET_OS_FREEBSD
  50. #include <pthread_np.h>
  51. #include <sys/param.h>
  52. #include <sys/cpuset.h>
  53. #define CPUSET_T cpuset_t
  54. #elif defined(TARGET_OS_LINUX)
  55. #ifndef _GNU_SOURCE
  56. #define _GNU_SOURCE
  57. #endif
  58. #include <pthread.h>
  59. #define CPUSET_T cpu_set_t
  60. #endif
  61. /* The following definition enables some rather suspicious cache descriptors */
  62. /* from sandpile.org which haven't been verified with Intel's docs. */
  63. /* # define ENABLE_SANDPILE */
  64. #include <crisscross/cpuid.h>
  65. #include <crisscross/core_io.h>
  66. using namespace CrissCross::System;
  67. #if defined(TARGET_OS_MACOSX) && !defined(USE_CHUD_FOR_CPUID)
  68. namespace {
  69. int getProcessorCount()
  70. {
  71. int count;
  72. size_t size = sizeof(count);
  73. if (sysctlbyname("hw.ncpu",&count,&size,NULL,0))
  74. return 1;
  75. return count;
  76. }
  77. }
  78. #endif
  79. typedef enum
  80. {
  81. REG_NULL,
  82. REG_EAX,
  83. REG_EBX,
  84. REG_ECX,
  85. REG_EDX
  86. } Register;
  87. typedef struct
  88. {
  89. cc_uint32_t m_level;
  90. cc_uint8_t m_register;
  91. cc_uint32_t m_bitmask;
  92. cc_uint32_t m_vendor;
  93. const char *m_name;
  94. } CPUFeature;
  95. static CPUFeature features [] = {
  96. // Standard (0000_0001h)
  97. { 0x00000001, REG_EDX, 0x00000001, VENDOR_INTEL | VENDOR_AMD, "FPU"},
  98. { 0x00000001, REG_EDX, 0x00000002, VENDOR_INTEL | VENDOR_AMD, "VME"},
  99. { 0x00000001, REG_EDX, 0x00000004, VENDOR_INTEL | VENDOR_AMD, "DE"},
  100. { 0x00000001, REG_EDX, 0x00000008, VENDOR_INTEL | VENDOR_AMD, "PSE"},
  101. { 0x00000001, REG_EDX, 0x00000010, VENDOR_INTEL | VENDOR_AMD, "TSC"},
  102. { 0x00000001, REG_EDX, 0x00000020, VENDOR_INTEL | VENDOR_AMD, "MSR"},
  103. { 0x00000001, REG_EDX, 0x00000040, VENDOR_INTEL | VENDOR_AMD, "PAE"},
  104. { 0x00000001, REG_EDX, 0x00000080, VENDOR_INTEL | VENDOR_AMD, "MCE"},
  105. { 0x00000001, REG_EDX, 0x00000100, VENDOR_INTEL | VENDOR_AMD, "CX8"},
  106. { 0x00000001, REG_EDX, 0x00000200, VENDOR_INTEL | VENDOR_AMD, "APIC"},
  107. // { 0x00000001, REG_EDX, 0x00000400, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  108. { 0x00000001, REG_EDX, 0x00000800, VENDOR_INTEL | VENDOR_AMD, "SEP"},
  109. { 0x00000001, REG_EDX, 0x00001000, VENDOR_INTEL | VENDOR_AMD, "MTRR"},
  110. { 0x00000001, REG_EDX, 0x00002000, VENDOR_INTEL | VENDOR_AMD, "PGE"},
  111. { 0x00000001, REG_EDX, 0x00004000, VENDOR_INTEL | VENDOR_AMD, "MCA"},
  112. { 0x00000001, REG_EDX, 0x00008000, VENDOR_INTEL | VENDOR_AMD, "CMOV"},
  113. { 0x00000001, REG_EDX, 0x00010000, VENDOR_INTEL | VENDOR_AMD, "PAT"},
  114. { 0x00000001, REG_EDX, 0x00020000, VENDOR_INTEL | VENDOR_AMD, "PSE-36"},
  115. { 0x00000001, REG_EDX, 0x00040000, VENDOR_INTEL , "PSN"},
  116. { 0x00000001, REG_EDX, 0x00080000, VENDOR_INTEL | VENDOR_AMD, "CLFSH"},
  117. // { 0x00000001, REG_EDX, 0x00100000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  118. { 0x00000001, REG_EDX, 0x00200000, VENDOR_INTEL , "DS"},
  119. { 0x00000001, REG_EDX, 0x00400000, VENDOR_INTEL , "ACPI"},
  120. { 0x00000001, REG_EDX, 0x00800000, VENDOR_INTEL | VENDOR_AMD, "MMX"},
  121. { 0x00000001, REG_EDX, 0x01000000, VENDOR_INTEL | VENDOR_AMD, "FXSR"},
  122. { 0x00000001, REG_EDX, 0x02000000, VENDOR_INTEL | VENDOR_AMD, "SSE"},
  123. { 0x00000001, REG_EDX, 0x04000000, VENDOR_INTEL | VENDOR_AMD, "SSE2"},
  124. { 0x00000001, REG_EDX, 0x08000000, VENDOR_INTEL , "SS"},
  125. { 0x00000001, REG_EDX, 0x10000000, VENDOR_INTEL | VENDOR_AMD, "HTT"},
  126. { 0x00000001, REG_EDX, 0x20000000, VENDOR_INTEL , "TM"},
  127. // { 0x00000001, REG_EDX, 0x40000000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  128. { 0x00000001, REG_EDX, 0x80000000, VENDOR_INTEL , "PBE"},
  129. { 0x00000001, REG_ECX, 0x00000001, VENDOR_INTEL | VENDOR_AMD, "SSE3"},
  130. { 0x00000001, REG_ECX, 0x00000002, VENDOR_INTEL , "PCLMULDQ"},
  131. { 0x00000001, REG_ECX, 0x00000004, VENDOR_INTEL , "DTES64"},
  132. { 0x00000001, REG_ECX, 0x00000008, VENDOR_INTEL | VENDOR_AMD, "MONITOR"},
  133. { 0x00000001, REG_ECX, 0x00000010, VENDOR_INTEL , "DS-CPL"},
  134. { 0x00000001, REG_ECX, 0x00000020, VENDOR_INTEL , "VMX"},
  135. { 0x00000001, REG_ECX, 0x00000040, VENDOR_INTEL , "SMX"},
  136. { 0x00000001, REG_ECX, 0x00000080, VENDOR_INTEL , "EST"},
  137. { 0x00000001, REG_ECX, 0x00000100, VENDOR_INTEL , "TM2"},
  138. { 0x00000001, REG_ECX, 0x00000200, VENDOR_INTEL | VENDOR_AMD, "SSSE3"},
  139. { 0x00000001, REG_ECX, 0x00000400, VENDOR_INTEL , "CNXT-ID"},
  140. // { 0x00000001, REG_ECX, 0x00000800, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  141. // { 0x00000001, REG_ECX, 0x00001000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  142. { 0x00000001, REG_ECX, 0x00002000, VENDOR_INTEL | VENDOR_AMD, "CX16"},
  143. { 0x00000001, REG_ECX, 0x00004000, VENDOR_INTEL , "xTPR"},
  144. { 0x00000001, REG_ECX, 0x00008000, VENDOR_INTEL , "PDCM"},
  145. // { 0x00000001, REG_ECX, 0x00010000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  146. // { 0x00000001, REG_ECX, 0x00020000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  147. { 0x00000001, REG_ECX, 0x00040000, VENDOR_INTEL , "DCA"},
  148. { 0x00000001, REG_ECX, 0x00080000, VENDOR_INTEL | VENDOR_AMD, "SSE4.1"},
  149. { 0x00000001, REG_ECX, 0x00100000, VENDOR_INTEL , "SSE4.2"},
  150. { 0x00000001, REG_ECX, 0x00200000, VENDOR_INTEL , "x2APIC"},
  151. { 0x00000001, REG_ECX, 0x00400000, VENDOR_INTEL , "MOVBE"},
  152. { 0x00000001, REG_ECX, 0x00800000, VENDOR_INTEL | VENDOR_AMD, "POPCNT"},
  153. // { 0x00000001, REG_ECX, 0x01000000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  154. { 0x00000001, REG_ECX, 0x02000000, VENDOR_INTEL , "AES"},
  155. { 0x00000001, REG_ECX, 0x04000000, VENDOR_INTEL , "XSAVE"},
  156. { 0x00000001, REG_ECX, 0x08000000, VENDOR_INTEL , "OSXSAVE"},
  157. // { 0x00000001, REG_ECX, 0x10000000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  158. // { 0x00000001, REG_ECX, 0x20000000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  159. // { 0x00000001, REG_ECX, 0x40000000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  160. // { 0x00000001, REG_ECX, 0x80000000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  161. // Extended (8000_0001h)
  162. // { 0x80000001, REG_EDX, 0x00000001, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  163. // { 0x80000001, REG_EDX, 0x00000002, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  164. // { 0x80000001, REG_EDX, 0x00000004, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  165. // { 0x80000001, REG_EDX, 0x00000008, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  166. // { 0x80000001, REG_EDX, 0x00000010, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  167. // { 0x80000001, REG_EDX, 0x00000020, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  168. // { 0x80000001, REG_EDX, 0x00000040, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  169. // { 0x80000001, REG_EDX, 0x00000080, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  170. // { 0x80000001, REG_EDX, 0x00000100, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  171. // { 0x80000001, REG_EDX, 0x00000200, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  172. // { 0x80000001, REG_EDX, 0x00000400, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  173. { 0x80000001, REG_EDX, 0x00000800, VENDOR_INTEL | VENDOR_AMD, "SYSCALL"},
  174. // { 0x80000001, REG_EDX, 0x00001000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  175. // { 0x80000001, REG_EDX, 0x00002000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  176. // { 0x80000001, REG_EDX, 0x00004000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  177. // { 0x80000001, REG_EDX, 0x00008000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  178. // { 0x80000001, REG_EDX, 0x00010000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  179. // { 0x80000001, REG_EDX, 0x00020000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  180. // { 0x80000001, REG_EDX, 0x00040000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  181. // { 0x80000001, REG_EDX, 0x00080000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  182. { 0x80000001, REG_EDX, 0x00100000, VENDOR_INTEL , "XD"},
  183. { 0x80000001, REG_EDX, 0x00100000, VENDOR_AMD, "NX"},
  184. // { 0x80000001, REG_EDX, 0x00200000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  185. { 0x80000001, REG_EDX, 0x00400000, VENDOR_AMD, "MMXEXT"},
  186. // { 0x80000001, REG_EDX, 0x00800000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  187. // { 0x80000001, REG_EDX, 0x01000000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  188. { 0x80000001, REG_EDX, 0x02000000, VENDOR_AMD, "FFXSR"},
  189. // { 0x80000001, REG_EDX, 0x04000000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  190. { 0x80000001, REG_EDX, 0x08000000, VENDOR_AMD, "RDTSCP"},
  191. // { 0x80000001, REG_EDX, 0x10000000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  192. { 0x80000001, REG_EDX, 0x20000000, VENDOR_INTEL , "EM64T"},
  193. { 0x80000001, REG_EDX, 0x20000000, VENDOR_AMD, "LM"},
  194. { 0x80000001, REG_EDX, 0x40000000, VENDOR_AMD, "3DNOWEXT"},
  195. { 0x80000001, REG_EDX, 0x80000000, VENDOR_AMD, "3DNOW"},
  196. { 0x80000001, REG_ECX, 0x00000001, VENDOR_INTEL | VENDOR_AMD, "LAHF"},
  197. { 0x80000001, REG_ECX, 0x00000002, VENDOR_AMD, "CL"},
  198. { 0x80000001, REG_ECX, 0x00000004, VENDOR_AMD, "SVM"},
  199. { 0x80000001, REG_ECX, 0x00000008, VENDOR_AMD, "EAS"},
  200. { 0x80000001, REG_ECX, 0x00000010, VENDOR_AMD, "AMC8"},
  201. { 0x80000001, REG_ECX, 0x00000020, VENDOR_AMD, "ABM"},
  202. { 0x80000001, REG_ECX, 0x00000040, VENDOR_AMD, "SSE4A"},
  203. { 0x80000001, REG_ECX, 0x00000080, VENDOR_AMD, "MAS"},
  204. { 0x80000001, REG_ECX, 0x00000100, VENDOR_AMD, "3DNP"},
  205. { 0x80000001, REG_ECX, 0x00000200, VENDOR_AMD, "OSVW"},
  206. { 0x80000001, REG_ECX, 0x00000400, VENDOR_AMD, "IBS"},
  207. { 0x80000001, REG_ECX, 0x00000800, VENDOR_AMD, "SSE5"},
  208. { 0x80000001, REG_ECX, 0x00001000, VENDOR_AMD, "SKINIT"},
  209. { 0x80000001, REG_ECX, 0x00002000, VENDOR_AMD, "WDT"},
  210. // { 0x80000001, REG_ECX, 0x00004000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  211. // { 0x80000001, REG_ECX, 0x00008000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  212. // { 0x80000001, REG_ECX, 0x00010000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  213. // { 0x80000001, REG_ECX, 0x00020000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  214. // { 0x80000001, REG_ECX, 0x00040000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  215. // { 0x80000001, REG_ECX, 0x00080000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  216. // { 0x80000001, REG_ECX, 0x00100000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  217. // { 0x80000001, REG_ECX, 0x00200000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  218. // { 0x80000001, REG_ECX, 0x00400000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  219. // { 0x80000001, REG_ECX, 0x00800000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  220. // { 0x80000001, REG_ECX, 0x01000000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  221. // { 0x80000001, REG_ECX, 0x02000000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  222. // { 0x80000001, REG_ECX, 0x04000000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  223. // { 0x80000001, REG_ECX, 0x08000000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  224. // { 0x80000001, REG_ECX, 0x10000000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  225. // { 0x80000001, REG_ECX, 0x20000000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  226. // { 0x80000001, REG_ECX, 0x40000000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  227. // { 0x80000001, REG_ECX, 0x80000000, VENDOR_INTEL | VENDOR_AMD, ""}, // Reserved
  228. { 0, REG_NULL, 0, 0, NULL},
  229. };
  230. namespace CrissCross
  231. {
  232. namespace System
  233. {
  234. struct Registers
  235. {
  236. unsigned int eax;
  237. unsigned int ebx;
  238. unsigned int ecx;
  239. unsigned int edx;
  240. };
  241. struct Registers *Std;
  242. unsigned int StdMax;
  243. struct Registers *Ext;
  244. unsigned int ExtMax;
  245. /* If the current processor supports the CPUID instruction, execute
  246. * one, with REQUEST in %eax, and set *EAX, *EBX, *ECX, and *EDX to
  247. * the values the 'cpuid' stored in those registers. Return true if
  248. * the current processor supports CPUID, false otherwise. */
  249. namespace
  250. {
  251. struct GoThreadProc_Params
  252. {
  253. CPUID *cpuid_class;
  254. int processor;
  255. };
  256. #ifdef TARGET_OS_WINDOWS
  257. static DWORD CALLBACK s_GoThreadProc(LPVOID lpParameter)
  258. {
  259. GoThreadProc_Params *params = (GoThreadProc_Params *)lpParameter;
  260. return params->cpuid_class->GoThread(params->processor);
  261. }
  262. #endif
  263. bool call_cpuid(unsigned int request, unsigned int *_eax, unsigned int *_ebx, unsigned int *_ecx, unsigned int *_edx)
  264. {
  265. #ifndef TARGET_CPU_X64
  266. unsigned int pre_change, post_change;
  267. const unsigned int id_flag = 0x200000;
  268. #endif
  269. /* This is pretty much the standard way to detect whether the CPUID
  270. * instruction is supported: try to change the ID bit in the EFLAGS
  271. * register. If we can change it, then the CPUID instruction is
  272. * implemented. */
  273. #ifndef TARGET_CPU_X64
  274. #if defined (TARGET_COMPILER_GCC)
  275. asm ("pushfl\n\t" /* Save %eflags to restore later. */
  276. "pushfl\n\t" /* Push second copy, for manipulation. */
  277. "popl %1\n\t" /* Pop it into post_change. */
  278. "movl %1,%0\n\t" /* Save copy in pre_change. */
  279. "xorl %2,%1\n\t" /* Tweak bit in post_change. */
  280. "pushl %1\n\t" /* Push tweaked copy... */
  281. "popfl\n\t" /* ... and pop it into %eflags. */
  282. "pushfl\n\t" /* Did it change? Push new %eflags... */
  283. "popl %1\n\t" /* ... and pop it into post_change. */
  284. "popfl" /* Restore original value. */
  285. : "=&r" (pre_change), "=&r" (post_change)
  286. : "ir" (id_flag));
  287. #else
  288. __asm {
  289. mov edx, id_flag;
  290. pushfd; /* Save %eflags to restore later. */
  291. pushfd; /* Push second copy, for manipulation. */
  292. pop ebx; /* Pop it into post_change. */
  293. mov eax, ebx; /* Save copy in pre_change. */
  294. xor ebx, edx; /* Tweak bit in post_change. */
  295. push ebx; /* Push tweaked copy... */
  296. popfd; /* ... and pop it into eflags. */
  297. pushfd; /* Did it change? Push new %eflags... */
  298. pop ebx; /* ... and pop it into post_change. */
  299. popfd; /* Restore original value. */
  300. mov pre_change, eax;
  301. mov post_change, ebx;
  302. }
  303. #endif
  304. #endif
  305. /* If the bit changed, then we support the CPUID instruction. */
  306. #ifndef TARGET_CPU_X64
  307. if ((pre_change ^ post_change) & id_flag) {
  308. #endif
  309. #if defined (TARGET_COMPILER_GCC)
  310. asm volatile ("mov %%ebx, %%esi\n\t" /* Save %ebx. */
  311. "xorl %%ecx, %%ecx\n\t"
  312. "cpuid\n\t"
  313. "xchgl %%ebx, %%esi" /* Restore %ebx. */
  314. : "=a" (*_eax), "=S" (*_ebx), "=c" (*_ecx), "=d" (*_edx)
  315. : "0" (request)
  316. : "memory");
  317. #else
  318. __asm {
  319. push esi;
  320. push edi;
  321. xor ecx, ecx;
  322. mov eax, request;
  323. cpuid;
  324. mov edi, [_eax];
  325. mov esi, [_ebx];
  326. mov[edi], eax;
  327. mov[esi], ebx;
  328. mov edi, [_ecx];
  329. mov esi, [_edx];
  330. mov[edi], ecx;
  331. mov[esi], edx;
  332. pop edi;
  333. pop esi;
  334. }
  335. #endif
  336. return true;
  337. #ifndef TARGET_CPU_X64
  338. } else
  339. return false;
  340. #endif
  341. }
  342. }
  343. X86Processor::X86Processor()
  344. : m_vendor(VENDOR_UNKNOWN),
  345. m_name(NULL),
  346. m_logical(0),
  347. m_cores(0),
  348. m_family(0),
  349. m_model(0),
  350. m_stepping(0),
  351. m_brandID(0),
  352. m_apicID(0)
  353. {
  354. }
  355. X86Processor::X86Processor(X86Processor const &_copy)
  356. : m_vendor(_copy.m_vendor),
  357. m_name(cc_newstr(_copy.m_name)),
  358. m_logical(_copy.m_logical),
  359. m_cores(_copy.m_cores),
  360. m_family(_copy.m_family),
  361. m_model(_copy.m_model),
  362. m_stepping(_copy.m_stepping),
  363. m_brandID(_copy.m_brandID),
  364. m_apicID(_copy.m_apicID)
  365. {
  366. CrissCross::Data::DArray<const char *> *features = _copy.m_features.ConvertIndexToDArray();
  367. for (size_t i = 0; i < features->size(); i++) {
  368. if (!features->valid(i)) continue;
  369. m_features.insert(features->get(i), NULL);
  370. }
  371. delete features;
  372. m_caches.setSize(_copy.m_caches.size());
  373. for (size_t i = 0; i < _copy.m_caches.size(); i++)
  374. {
  375. if (!_copy.m_caches.valid(i)) continue;
  376. m_caches.insert(cc_newstr(_copy.m_caches.get(i)));
  377. }
  378. }
  379. X86Processor::~X86Processor()
  380. {
  381. }
  382. void X86Processor::Print(CrissCross::IO::CoreIOWriter *_writer) const
  383. {
  384. /* Print the Manufacturer tag if it was read properly. */
  385. switch(Manufacturer()) {
  386. case VENDOR_INTEL:
  387. _writer->WriteLine("CPU[%u] Manufacturer: %s", m_index, "GenuineIntel");
  388. break;
  389. case VENDOR_AMD:
  390. _writer->WriteLine("CPU[%u] Manufacturer: %s", m_index, "AuthenticAMD");
  391. break;
  392. default:
  393. /* Don't print anything. */
  394. break;
  395. }
  396. /* Print the Name tag if it was read properly. */
  397. if (Name() && strlen(Name()) > 1)
  398. _writer->WriteLine("CPU[%u] Name: %s", m_index, Name());
  399. if (Family() > 0 && Model() > 0 && Stepping() > 0)
  400. _writer->WriteLine("CPU[%u] Family %2d Model %2d Stepping %2d", m_index,
  401. Family(), Model(), Stepping());
  402. /* Print out the CPU cache info. */
  403. const CrissCross::System::caches_t *caches = Caches();
  404. if (caches->size() > 0) {
  405. _writer->WriteLine("CPU[%u] Caches:", m_index);
  406. for (size_t j = 0; j < caches->size(); j++) {
  407. if (caches->valid(j))
  408. _writer->Write(" %s\n", caches->get(j));
  409. }
  410. _writer->WriteLine();
  411. }
  412. /* Print out CPU features (MMX, SSE, and so on). */
  413. if (Features()->size() > 0) {
  414. _writer->Write("CPU[%u] Features: ", m_index);
  415. CrissCross::Data::DArray<const char *> *featureIDs =
  416. Features()->ConvertIndexToDArray();
  417. for (size_t i = 0; i < featureIDs->size(); i++) {
  418. if (featureIDs->valid(i))
  419. _writer->Write("%s ", featureIDs->get(i));
  420. }
  421. delete featureIDs;
  422. _writer->WriteLine();
  423. }
  424. _writer->WriteLine();
  425. }
  426. CPUVendor X86Processor::Manufacturer() const
  427. {
  428. return m_vendor;
  429. }
  430. const char *X86Processor::Name() const
  431. {
  432. return m_name;
  433. }
  434. char X86Processor::Family() const
  435. {
  436. return m_family;
  437. }
  438. char X86Processor::Model() const
  439. {
  440. return m_model;
  441. }
  442. char X86Processor::Stepping() const
  443. {
  444. return m_stepping;
  445. }
  446. char X86Processor::BrandID() const
  447. {
  448. return m_brandID;
  449. }
  450. char X86Processor::APICID() const
  451. {
  452. return m_apicID;
  453. }
  454. const features_t *X86Processor::Features() const
  455. {
  456. return &m_features;
  457. }
  458. const caches_t *X86Processor::Caches() const
  459. {
  460. return &m_caches;
  461. }
  462. CPUID::CPUID()
  463. {
  464. unsigned int i = 0;
  465. Std = new Registers[32];
  466. CoreAssert(Std);
  467. Ext = new Registers[32];
  468. CoreAssert(Ext);
  469. memset(Std, 0, sizeof(Registers) * 32);
  470. memset(Ext, 0, sizeof(Registers) * 32);
  471. StdMax = 0;
  472. ExtMax = 0;
  473. /* Basic initializations complete */
  474. call_cpuid(0, &Std[0].eax, &Std[0].ebx, &Std[0].ecx, &Std[0].edx);
  475. StdMax = Std[0].eax;
  476. if (StdMax > 31) {
  477. #ifdef CPUID_DEBUG
  478. g_console->WriteLine("CPUID.0.EAX has an invalid value: %d",
  479. StdMax);
  480. #endif
  481. StdMax = 31;
  482. } else {
  483. #ifdef CPUID_DEBUG
  484. g_console->WriteLine("Standard CPUID maximum input is %d.",
  485. StdMax);
  486. #endif
  487. }
  488. for (i = 1; i <= StdMax; i++) {
  489. call_cpuid(i, &Std[i].eax, &Std[i].ebx, &Std[i].ecx, &Std[i].edx);
  490. }
  491. call_cpuid(0x80000000, &Ext[0].eax, &Ext[0].ebx, &Ext[0].ecx, &Ext[0].edx);
  492. if (Ext[0].eax < 0x80000004) {
  493. return;
  494. } else {
  495. ExtMax = Ext[0].eax - 0x80000000;
  496. }
  497. for (i = 0; i <= ExtMax; i++) {
  498. call_cpuid(0x80000000 + i, &Ext[i].eax, &Ext[i].ebx, &Ext[i].ecx, &Ext[i].edx);
  499. }
  500. }
  501. CPUID::~CPUID()
  502. {
  503. /* Time to deallocate all the memory we allocated. */
  504. size_t i = 0, j = 0;
  505. delete [] Std;
  506. delete [] Ext;
  507. for (i = 0; i < proc.size(); i++) {
  508. if (!proc.valid(i)) continue;
  509. for (j = 0; j < proc[i]->m_caches.size(); j++) {
  510. if (proc[i]->m_caches.valid(j))
  511. delete [] proc[i]->m_caches.get(j);
  512. }
  513. delete [] (char *)proc[i]->m_name;
  514. delete proc[i];
  515. proc.remove(i);
  516. }
  517. }
  518. int CPUID::VirtualCount()
  519. {
  520. CoreAssert(this != NULL);
  521. int count = 0;
  522. for (size_t i = 0; i < proc.size(); i++) {
  523. if (proc.valid(i))
  524. count++;
  525. }
  526. return count;
  527. }
  528. int CPUID::CoresPerPackage()
  529. {
  530. CoreAssert(this != NULL);
  531. return proc[0]->m_cores;
  532. }
  533. int CPUID::LogicalPerPackage()
  534. {
  535. CoreAssert(this != NULL);
  536. return proc[0]->m_logical;
  537. }
  538. long int CPUID::GoThread(int processor)
  539. {
  540. CoreAssert(this != NULL);
  541. if (processor < 0) {
  542. return 1;
  543. }
  544. DetectManufacturer(processor);
  545. DetectProcessorName(processor);
  546. DetectFeatures(processor);
  547. DetectCacheInfo(processor);
  548. DetectFMS(processor);
  549. DetectBrandID(processor);
  550. DetectCount(processor);
  551. DetectAPIC(processor);
  552. return 0;
  553. }
  554. void CPUID::Go()
  555. {
  556. CoreAssert(this != NULL);
  557. #ifdef TARGET_OS_WINDOWS
  558. DWORD dThread = NULL;
  559. SYSTEM_INFO siSystem;
  560. int iCount = 0;
  561. struct GoThreadProc_Params params;
  562. params.cpuid_class = this;
  563. GetSystemInfo(&siSystem);
  564. iCount = siSystem.dwNumberOfProcessors;
  565. for (params.processor = 0; params.processor < iCount;
  566. params.processor++) {
  567. proc.insert(new X86Processor(), params.processor);
  568. HANDLE hThread =
  569. CreateThread(NULL, 0, ( LPTHREAD_START_ROUTINE )s_GoThreadProc,
  570. &params, CREATE_SUSPENDED, &dThread);
  571. SetThreadAffinityMask(hThread,
  572. ( DWORD )pow(( double )2,
  573. ( double )params.
  574. processor));
  575. Sleep(0); /* Wait for affinity switch. */
  576. SetThreadPriority(hThread, THREAD_PRIORITY_ABOVE_NORMAL);
  577. ResumeThread(hThread);
  578. WaitForSingleObject(hThread, INFINITE);
  579. proc[params.processor]->m_index = params.processor;
  580. }
  581. #elif defined (TARGET_OS_LINUX) || defined(TARGET_OS_FREEBSD)
  582. int NUM_PROCS = sysconf(_SC_NPROCESSORS_CONF), i;
  583. CPUSET_T mask, originalmask;
  584. pthread_t pth = pthread_self();
  585. CPU_ZERO(&originalmask);
  586. pthread_getaffinity_np(pth, sizeof(originalmask), &originalmask);
  587. for (i = 0; i < NUM_PROCS; i++) {
  588. proc.insert(new X86Processor(), i);
  589. CPU_ZERO(&mask);
  590. CPU_SET(( int )pow(2, i), &mask);
  591. pthread_setaffinity_np(pth, sizeof(mask), &mask);
  592. GoThread(i);
  593. proc[i]->m_index = i;
  594. }
  595. pthread_setaffinity_np(pth, sizeof(originalmask), &originalmask);
  596. #elif defined (TARGET_OS_MACOSX)
  597. #if defined(USE_CHUD_FOR_CPUID)
  598. int NUM_PROCS = chudProcessorCount();
  599. for (int i = 0; i < NUM_PROCS; i++) {
  600. proc.insert(new X86Processor(), i);
  601. utilUnbindThreadFromCPU();
  602. utilBindThreadToCPU(i);
  603. GoThread(i);
  604. procs[i]->m_index = i;
  605. }
  606. utilUnbindThreadFromCPU();
  607. #else
  608. int NUM_PROCS = getProcessorCount();
  609. proc.insert(new X86Processor(), 0);
  610. GoThread(0);
  611. proc[0]->m_index = 0;
  612. for (int i = 1; i < NUM_PROCS; i++) {
  613. proc.insert(new X86Processor(*proc[0]), i);
  614. proc[i]->m_index = i;
  615. }
  616. #endif
  617. #endif
  618. }
  619. void CPUID::DetectManufacturer(int processor)
  620. {
  621. CoreAssert(this != NULL);
  622. char manufacturer[13];
  623. char *_man = manufacturer;
  624. memcpy(_man, &Std[0].ebx, 4);
  625. _man += 4;
  626. memcpy(_man, &Std[0].edx, 4);
  627. _man += 4;
  628. memcpy(_man, &Std[0].ecx, 4);
  629. _man += 4;
  630. *_man = '\x0';
  631. proc[processor]->m_vendor = VENDOR_UNKNOWN;
  632. if (strcmp(manufacturer, "GenuineIntel") == 0)
  633. proc[processor]->m_vendor = VENDOR_INTEL;
  634. else if (strcmp(manufacturer, "AuthenticAMD") == 0)
  635. proc[processor]->m_vendor = VENDOR_AMD;
  636. }
  637. char *squeeze(char *str)
  638. {
  639. int r; /* next character to be read */
  640. int w; /* next character to be written */
  641. r=w=0;
  642. while (str[r])
  643. {
  644. if (isspace(str[r]) || iscntrl(str[r]))
  645. {
  646. if (w > 0 && !isspace(str[w-1]))
  647. str[w++] = ' ';
  648. }
  649. else
  650. str[w++] = str[r];
  651. r++;
  652. }
  653. str[w] = 0;
  654. return str;
  655. }
  656. void CPUID::DetectProcessorName(int processor)
  657. {
  658. CoreAssert(this != NULL);
  659. char *processorname = new char[(4 * 12) + 1];
  660. char *_proc = &processorname[0];
  661. memcpy(_proc, &Ext[2].eax, 4);
  662. _proc += 4;
  663. memcpy(_proc, &Ext[2].ebx, 4);
  664. _proc += 4;
  665. memcpy(_proc, &Ext[2].ecx, 4);
  666. _proc += 4;
  667. memcpy(_proc, &Ext[2].edx, 4);
  668. _proc += 4;
  669. memcpy(_proc, &Ext[3].eax, 4);
  670. _proc += 4;
  671. memcpy(_proc, &Ext[3].ebx, 4);
  672. _proc += 4;
  673. memcpy(_proc, &Ext[3].ecx, 4);
  674. _proc += 4;
  675. memcpy(_proc, &Ext[3].edx, 4);
  676. _proc += 4;
  677. memcpy(_proc, &Ext[4].eax, 4);
  678. _proc += 4;
  679. memcpy(_proc, &Ext[4].ebx, 4);
  680. _proc += 4;
  681. memcpy(_proc, &Ext[4].ecx, 4);
  682. _proc += 4;
  683. memcpy(_proc, &Ext[4].edx, 4);
  684. _proc += 4;
  685. *_proc = '\x0';
  686. proc[processor]->m_name = squeeze(processorname);
  687. }
  688. void CPUID::DetectCacheInfo(int processor)
  689. {
  690. CoreAssert(this != NULL);
  691. if (proc[processor]->m_vendor != VENDOR_UNKNOWN) {
  692. if (proc[processor]->m_vendor == VENDOR_INTEL ) {
  693. int ntlb = 255, i;
  694. for (i = 0; i < ntlb; i++) {
  695. ntlb = Std[2].eax & 0xff;
  696. AddIntelCacheData(processor, Std[2].eax >> 8);
  697. AddIntelCacheData(processor, Std[2].eax >> 16);
  698. AddIntelCacheData(processor, Std[2].eax >> 24);
  699. if ((Std[2].ebx & 0x80000000) == 0) {
  700. AddIntelCacheData(processor, Std[2].ebx);
  701. AddIntelCacheData(processor, Std[2].ebx >> 8);
  702. AddIntelCacheData(processor, Std[2].ebx >> 16);
  703. AddIntelCacheData(processor, Std[2].ebx >> 24);
  704. }
  705. if ((Std[2].ecx & 0x80000000) == 0) {
  706. AddIntelCacheData(processor, Std[2].ecx);
  707. AddIntelCacheData(processor, Std[2].ecx >> 8);
  708. AddIntelCacheData(processor, Std[2].ecx >> 16);
  709. AddIntelCacheData(processor, Std[2].ecx >> 24);
  710. }
  711. if ((Std[2].edx & 0x80000000) == 0) {
  712. AddIntelCacheData(processor, Std[2].edx);
  713. AddIntelCacheData(processor, Std[2].edx >> 8);
  714. AddIntelCacheData(processor, Std[2].edx >> 16);
  715. AddIntelCacheData(processor, Std[2].edx >> 24);
  716. }
  717. }
  718. } else if (proc[processor]->m_vendor == VENDOR_AMD) {
  719. DecodeAMDCacheIdentifiers(processor);
  720. }
  721. }
  722. CrissCross::Data::QuickSort<char *> sorter;
  723. proc[processor]->m_caches.sort(sorter);
  724. }
  725. const char *CPUID::CreateCacheDescription(cacheType _type, const char *_pages, unsigned int _size, unsigned int _assoc, unsigned int _entries, unsigned int _linesize, bool _sectored)
  726. {
  727. CoreAssert(this != NULL);
  728. static char description[512];
  729. char assoc[64], prefix[64], size[32], sectored[32], linesz[32], entries[32];
  730. /* No associativity? Invalid cache entry. Abort, abort! */
  731. if (_assoc == 0)
  732. return NULL;
  733. memset(prefix, 0, sizeof(prefix));
  734. /* Get the prefix worked out. */
  735. switch (_type)
  736. {
  737. case CACHE_TYPE_TRACE:
  738. sprintf(prefix, "Trace cache: ");
  739. break;
  740. case CACHE_TYPE_L0DATA_TLB:
  741. sprintf(prefix, "L0 Data TLB: %s pages, ", _pages);
  742. break;
  743. case CACHE_TYPE_L1DATA_TLB:
  744. sprintf(prefix, "L1 Data TLB: %s pages, ", _pages);
  745. break;
  746. case CACHE_TYPE_L2DATA_TLB:
  747. sprintf(prefix, "L2 Data TLB: %s pages, ", _pages);
  748. break;
  749. case CACHE_TYPE_L0CODE_TLB:
  750. sprintf(prefix, "L0 Code TLB: %s pages, ", _pages);
  751. break;
  752. case CACHE_TYPE_L1CODE_TLB:
  753. sprintf(prefix, "L1 Code TLB: %s pages, ", _pages);
  754. break;
  755. case CACHE_TYPE_L2CODE_TLB:
  756. sprintf(prefix, "L2 Code TLB: %s pages, ", _pages);
  757. break;
  758. case CACHE_TYPE_DATA_TLB:
  759. sprintf(prefix, "Data TLB: %s pages, ", _pages);
  760. break;
  761. case CACHE_TYPE_CODE_TLB:
  762. sprintf(prefix, "Code TLB: %s pages, ", _pages);
  763. break;
  764. case CACHE_TYPE_L1CODE:
  765. sprintf(prefix, "1st-level code cache: ");
  766. break;
  767. case CACHE_TYPE_L1DATA:
  768. sprintf(prefix, "1st-level data cache: ");
  769. break;
  770. case CACHE_TYPE_L2:
  771. sprintf(prefix, "2nd-level cache: ");
  772. break;
  773. case CACHE_TYPE_L3:
  774. sprintf(prefix, "3rd-level cache: ");
  775. break;
  776. }
  777. /* Figure out the appropriate size descriptor. */
  778. memset(size, 0, sizeof(size));
  779. switch (_type)
  780. {
  781. case CACHE_TYPE_L0DATA_TLB:
  782. case CACHE_TYPE_L1DATA_TLB:
  783. case CACHE_TYPE_L2DATA_TLB:
  784. case CACHE_TYPE_L0CODE_TLB:
  785. case CACHE_TYPE_L1CODE_TLB:
  786. case CACHE_TYPE_L2CODE_TLB:
  787. case CACHE_TYPE_DATA_TLB:
  788. case CACHE_TYPE_CODE_TLB:
  789. break;
  790. case CACHE_TYPE_TRACE:
  791. sprintf(size, "%dK-uops, ", _size);
  792. break;
  793. default:
  794. if (_size >= 1024)
  795. sprintf(size, "%dMB, ", _size / 1024);
  796. else
  797. sprintf(size, "%dKB, ", _size);
  798. }
  799. /* Get the associativity part set up */
  800. switch (_assoc)
  801. {
  802. case 0x01: sprintf(assoc, "direct mapped"); break;
  803. case 0xFF: sprintf(assoc, "fully associative"); break;
  804. default: sprintf(assoc, "%d-way set associative", _assoc); break;
  805. }
  806. /* If this is a TLB, we have entries */
  807. if (_entries)
  808. sprintf(entries, ", %d entries", _entries);
  809. else
  810. memset(entries, 0, sizeof(entries));
  811. /* Is it a sectored cache? */
  812. sprintf(sectored, "%s", _sectored ? ", sectored cache" : "");
  813. /* If there's a line size, we append it. */
  814. if (_linesize)
  815. sprintf(linesz, ", %d byte line size", _linesize);
  816. else
  817. memset(linesz, 0, sizeof(linesz));
  818. sprintf(description, "%s%s%s%s%s%s\n", prefix, size, assoc, entries, sectored, linesz);
  819. return description;
  820. }
  821. void CPUID::DecodeAMDCacheIdentifiers(int processor)
  822. {
  823. CoreAssert(this != NULL);
  824. /* L1 Cache Information */
  825. unsigned int L1DTlb2and4MAssoc, L1DTlb2and4MSize, L1ITlb2and4MAssoc, L1ITlb2and4MSize;
  826. unsigned int L1DTlb4KAssoc, L1DTlb4KSize, L1ITlb4KAssoc, L1ITlb4KSize;
  827. unsigned int L1DcSize, L1DcAssoc, L1DcLinesPerTag, L1DcLineSize;
  828. unsigned int L1IcSize, L1IcAssoc, L1IcLinesPerTag, L1IcLineSize;
  829. /* */
  830. /* L1 Data 2MB/4MB TLB */
  831. L1DTlb2and4MAssoc = (Ext[5].eax & 0xFF000000) >> 24;
  832. L1DTlb2and4MSize = (Ext[5].eax & 0x00FF0000) >> 16;
  833. AddCacheDescription(processor, CreateCacheDescription(CACHE_TYPE_DATA_TLB, "2MB or 4MB", 0, L1DTlb2and4MAssoc, L1DTlb2and4MSize, 0, false));
  834. /* */
  835. /* L1 Code 2MB/4MB TLB */
  836. L1ITlb2and4MAssoc = (Ext[5].eax & 0x0000FF00) >> 8;
  837. L1ITlb2and4MSize = (Ext[5].eax & 0x000000FF);
  838. AddCacheDescription(processor, CreateCacheDescription(CACHE_TYPE_CODE_TLB, "2MB or 4MB", 0, L1ITlb2and4MAssoc, L1ITlb2and4MSize, 0, false));
  839. /* */
  840. /* L1 Data 4KB TLB */
  841. L1DTlb4KAssoc = (Ext[5].ebx & 0xFF000000) >> 24;
  842. L1DTlb4KSize = (Ext[5].ebx & 0x00FF0000) >> 16;
  843. AddCacheDescription(processor, CreateCacheDescription(CACHE_TYPE_DATA_TLB, "4KB", 0, L1DTlb4KAssoc, L1DTlb4KSize, 0, false));
  844. /* */
  845. /* L1 Code 4KB TLB */
  846. L1ITlb4KAssoc = (Ext[5].ebx & 0x0000FF00) >> 8;
  847. L1ITlb4KSize = (Ext[5].ebx & 0x000000FF);
  848. AddCacheDescription(processor, CreateCacheDescription(CACHE_TYPE_CODE_TLB, "4KB", 0, L1ITlb4KAssoc, L1ITlb4KSize, 0, false));
  849. /* */
  850. /* L1 Data Cache */
  851. L1DcSize = (Ext[5].ecx & 0xFF000000) >> 24;
  852. L1DcAssoc = (Ext[5].ecx & 0x00FF0000) >> 16;
  853. L1DcLinesPerTag = (Ext[5].ecx & 0x0000FF00) >> 8;
  854. L1DcLineSize = (Ext[5].ecx & 0x000000FF);
  855. AddCacheDescription(processor, CreateCacheDescription(CACHE_TYPE_L1DATA, NULL, L1DcSize, L1DcAssoc, 0, L1DcLineSize, false));
  856. /* */
  857. /* L1 Code Cache */
  858. L1IcSize = (Ext[5].edx & 0xFF000000) >> 24;
  859. L1IcAssoc = (Ext[5].edx & 0x00FF0000) >> 16;
  860. L1IcLinesPerTag = (Ext[5].edx & 0x0000FF00) >> 8;
  861. L1IcLineSize = (Ext[5].edx & 0x000000FF);
  862. AddCacheDescription(processor, CreateCacheDescription(CACHE_TYPE_L1CODE, NULL, L1IcSize, L1IcAssoc, 0, L1IcLineSize, false));
  863. /* L2 Cache Information */
  864. unsigned int L2DTlb2and4MAssoc, L2DTlb2and4MSize, L2ITlb2and4MAssoc, L2ITlb2and4MSize;
  865. unsigned int L2DTlb4KAssoc, L2DTlb4KSize, L2ITlb4KAssoc, L2ITlb4KSize;
  866. unsigned int L2Size, L2Assoc, L2LinesPerTag, L2LineSize;
  867. /* */
  868. /* L2 Data 2MB/4MB TLB */
  869. L2DTlb2and4MAssoc = (Ext[6].eax & 0xF0000000) >> 28;
  870. L2DTlb2and4MSize = (Ext[6].eax & 0x0FFF0000) >> 16;
  871. AddCacheDescription(processor, CreateCacheDescription(CACHE_TYPE_L2DATA_TLB, "2MB or 4MB", 0, L2DTlb2and4MAssoc, L2DTlb2and4MSize, 0, false));
  872. /* */
  873. /* L2 Code 2MB/4MB TLB */
  874. L2ITlb2and4MAssoc = (Ext[6].eax & 0x0000F000) >> 12;
  875. L2ITlb2and4MSize = (Ext[6].eax & 0x00000FFF);
  876. AddCacheDescription(processor, CreateCacheDescription(CACHE_TYPE_L2CODE_TLB, "2MB or 4MB", 0, L2ITlb2and4MAssoc, L2ITlb2and4MSize, 0, false));
  877. /* */
  878. /* L2 Data 4KB TLB */
  879. L2DTlb4KAssoc = (Ext[6].ebx & 0xF0000000) >> 28;
  880. L2DTlb4KSize = (Ext[6].ebx & 0x0FFF0000) >> 16;
  881. AddCacheDescription(processor, CreateCacheDescription(CACHE_TYPE_L2DATA_TLB, "4KB", 0, L2DTlb4KAssoc, L2DTlb4KSize, 0, false));
  882. /* */
  883. /* L2 Code 4KB TLB */
  884. L2ITlb4KAssoc = (Ext[6].ebx & 0x0000F000) >> 12;
  885. L2ITlb4KSize = (Ext[6].ebx & 0x00000FFF);
  886. AddCacheDescription(processor, CreateCacheDescription(CACHE_TYPE_L2CODE_TLB, "4KB", 0, L2ITlb4KAssoc, L2ITlb4KSize, 0, false));
  887. /* */
  888. /* L2 Cache */
  889. L2Size = (Ext[6].ecx & 0xFFFF0000) >> 16;
  890. L2Assoc = (Ext[6].ecx & 0x0000F000) >> 12;
  891. L2LinesPerTag = (Ext[6].ecx & 0x00000F00) >> 8;
  892. L2LineSize = (Ext[6].ecx & 0x000000FF);
  893. AddCacheDescription(processor, CreateCacheDescription(CACHE_TYPE_L2, NULL, L2Size, L2Assoc, 0, L2LineSize, false));
  894. /* L3 Cache Information */
  895. unsigned int L3Size, L3Assoc, L3LinesPerTag, L3LineSize;
  896. /* */
  897. /* L3 Cache */
  898. L3Size = (Ext[6].edx & 0xFFFC0000) >> 18;
  899. L3Assoc = (Ext[6].edx & 0x0000F000) >> 12;
  900. L3LinesPerTag = (Ext[6].edx & 0x00000F00) >> 8;
  901. L3LineSize = (Ext[6].edx & 0x000000FF);
  902. AddCacheDescription(processor, CreateCacheDescription(CACHE_TYPE_L3, NULL, L3Size * 512, L3Assoc, 0, L3LineSize, false));
  903. }
  904. void CPUID::AddCacheDescription(int processor, const char *description)
  905. {
  906. CoreAssert(this != NULL);
  907. if (!description) return;
  908. char *temp = new char[strlen(description) + 1];
  909. CoreAssert(temp);
  910. strcpy(temp, description);
  911. proc[processor]->m_caches.insert(temp);
  912. temp = NULL;
  913. }
  914. void CPUID::AddIntelCacheData(int processor, int x)
  915. {
  916. CoreAssert(this != NULL);
  917. /* Compliant with Intel document #241618, save for the ENABLE_SANDPILE sections. */
  918. x &= 0xff;
  919. switch (x)
  920. {
  921. case 0: break;
  922. case 0x1: AddCacheDescription(processor, "Code TLB: 4KB pages, 4-way set associative, 32 entries"); break;
  923. case 0x2: AddCacheDescription(processor, "Code TLB: 4MB pages, fully associative, 2 entries"); break;
  924. case 0x3: AddCacheDescription(processor, "Data TLB: 4KB pages, 4-way set associative, 64 entries"); break;
  925. case 0x4: AddCacheDescription(processor, "Data TLB: 4MB pages, 4-way set associative, 8 entries"); break;
  926. case 0x5: AddCacheDescription(processor, "Data TLB: 4MB pages, 4-way set associative, 32 entries"); break;
  927. case 0x6: AddCacheDescription(processor, "1st-level code cache: 8KB, 4-way set associative, 32 byte line size"); break;
  928. case 0x8: AddCacheDescription(processor, "1st-level code cache: 16KB, 4-way set associative, 32 byte line size"); break;
  929. case 0x9: AddCacheDescription(processor, "1st-level code cache: 32KB, 4-way set associative, 32 byte line size"); break;
  930. case 0xa: AddCacheDescription(processor, "1st-level data cache: 8KB, 2-way set associative, 32 byte line size"); break;
  931. case 0xc: AddCacheDescription(processor, "1st-level data cache: 16KB, 4-way set associative, 32 byte line size"); break;
  932. case 0xd: AddCacheDescription(processor, "1st-level data cache: 16KB, 4-way set associative, 64 byte line size, ECC"); break;
  933. case 0x21: AddCacheDescription(processor, "2nd-level cache: 256KB, 8-way set associative, 64 byte line size"); break;
  934. case 0x22: AddCacheDescription(processor, "3rd-level cache: 512KB, 4-way set associative, sectored cache, 64 byte line size"); break;
  935. case 0x23: AddCacheDescription(processor, "3rd-level cache: 1MB, 8-way set associative, sectored cache, 64 byte line size"); break;
  936. case 0x25: AddCacheDescription(processor, "3rd-level cache: 2MB, 8-way set associative, sectored cache, 64 byte line size"); break;
  937. case 0x29: AddCacheDescription(processor, "3rd-level cache: 4MB, 8-way set associative, sectored cache, 64 byte line size"); break;
  938. case 0x2C: AddCacheDescription(processor, "1st-level data cache: 32KB, 8-way set assocative, 64 byte line size"); break;
  939. case 0x30: AddCacheDescription(processor, "1st-level code cache: 32KB, 8-way set associative, 64 byte line size"); break;
  940. case 0x39: AddCacheDescription(processor, "2nd-level cache: 128KB, 4-way set associative, sectored cache, 64 byte line size"); break;
  941. case 0x3A: AddCacheDescription(processor, "2nd-level cache: 192KB, 6-way set associative, sectored cache, 64 byte line size"); break;
  942. case 0x3B: AddCacheDescription(processor, "2nd-level cache: 128KB, 2-way set associative, sectored cache, 64 byte line size"); break;
  943. case 0x3C: AddCacheDescription(processor, "2nd-level cache: 256KB, 4-way set associative, sectored cache, 64 byte line size"); break;
  944. case 0x3D: AddCacheDescription(processor, "2nd-level cache: 384KB, 6-way set associative, sectored cache, 64 byte line size"); break;
  945. case 0x3E: AddCacheDescription(processor, "2nd-level cache: 512KB, 4-way set associative, sectored cache, 64 byte line size"); break;
  946. case 0x40: AddCacheDescription(processor, "No 2nd-level cache, or if 2nd-level cache exists, no 3rd-level cache\n"); break;
  947. case 0x41: AddCacheDescription(processor, "2nd-level cache: 128KB, 4-way set associative, 32 byte line size"); break;
  948. case 0x42: AddCacheDescription(processor, "2nd-level cache: 256KB, 4-way set associative, 32 byte line size"); break;
  949. case 0x43: AddCacheDescription(processor, "2nd-level cache: 512KB, 4-way set associative, 32 byte line size"); break;
  950. case 0x44: AddCacheDescription(processor, "2nd-level cache: 1MB, 4-way set associative, 32 byte line size"); break;
  951. case 0x45: AddCacheDescription(processor, "2nd-level cache: 2MB, 4-way set associative, 32 byte line size"); break;
  952. case 0x46: AddCacheDescription(processor, "3rd-level cache: 4MB, 4-way set associative, 64 byte line size"); break;
  953. case 0x47: AddCacheDescription(processor, "3rd-level cache: 8MB, 8-way set associative, 64 byte line size"); break;
  954. case 0x48: AddCacheDescription(processor, "2nd-level cache: 3MB, 12-way set associative, 64 byte line size"); break;
  955. case 0x49: AddCacheDescription(processor, /* This is an L3 on the P4 and an L2 on the Core 2 */
  956. proc[processor]->m_features.exists("SSSE3") ?
  957. "2nd-level cache: 4MB, 16-way set associative, 64 byte line size":
  958. "3rd-level cache: 4MB, 16-way set associative, 64 byte line size"); break;
  959. case 0x4A: AddCacheDescription(processor, "3rd-level cache: 6MB, 12-way set associative, 64 byte line size"); break;
  960. case 0x4B: AddCacheDescription(processor, "3rd-level cache: 8MB, 16-way set associative, 64 byte line size"); break;
  961. case 0x4C: AddCacheDescription(processor, "3rd-level cache: 12MB, 12-way set associative, 64 byte line size"); break;
  962. case 0x4D: AddCacheDescription(processor, "3rd-level cache: 16MB, 16-way set associative, 64 byte line size"); break;
  963. case 0x4E: AddCacheDescription(processor, "2nd-level cache: 6MB, 24-way set associative, 64 byte line size"); break;
  964. case 0x50: AddCacheDescription(processor, "Code TLB: 4KB, 2MB, or 4MB pages, fully associative, 64 entries"); break;
  965. case 0x51: AddCacheDescription(processor, "Code TLB: 4KB, 2MB, or 4MB pages, fully associative, 128 entries"); break;
  966. case 0x52: AddCacheDescription(processor, "Code TLB: 4KB, 2MB, or 4MB pages, fully associative, 256 entries"); break;
  967. case 0x55: AddCacheDescription(processor, "Code TLB: 2MB or 4MB pages, fully associative, 256 entries"); break;
  968. case 0x56: AddCacheDescription(processor, "L1 Data TLB: 4MB pages, 4-way set associative associative, 16 entries"); break;
  969. case 0x57: AddCacheDescription(processor, "L1 Data TLB: 4KB pages, 4-way set associative, 16 entries"); break;
  970. case 0x5a: AddCacheDescription(processor, "Data TLB0: 2MB or 4MB pages, 4-way set associative, 32 entries"); break;
  971. case 0x5b: AddCacheDescription(processor, "Data TLB: 4KB or 4MB pages, fully associative, 64 entries"); break;
  972. case 0x5c: AddCacheDescription(processor, "Data TLB: 4KB or 4MB pages, fully associative, 128 entries"); break;
  973. case 0x5d: AddCacheDescription(processor, "Data TLB: 4KB or 4MB pages, fully associative, 256 entries"); break;
  974. case 0x60: AddCacheDescription(processor, "1st-level data cache: 16KB, 8-way set associative, sectored cache, 64 byte line size"); break;
  975. case 0x66: AddCacheDescription(processor, "1st-level data cache: 8KB, 4-way set associative, sectored cache, 64 byte line size"); break;
  976. case 0x67: AddCacheDescription(processor, "1st-level data cache: 16KB, 4-way set associative, sectored cache, 64 byte line size"); break;
  977. case 0x68: AddCacheDescription(processor, "1st-level data cache: 32KB, 4-way set associative, sectored cache, 64 byte line size"); break;
  978. case 0x70: AddCacheDescription(processor, "12K-uops, 8-way set associative"); break;
  979. case 0x71: AddCacheDescription(processor, "16K-uops, 8-way set associative"); break;
  980. case 0x72: AddCacheDescription(processor, "32K-uops, 8-way set associative"); break;
  981. case 0x73: AddCacheDescription(processor, "64K-uops, 8-way set associative"); break;
  982. case 0x78: AddCacheDescription(processor, "2nd-level cache: 1MB, 4-way set associative, 64 byte line size"); break;
  983. case 0x79: AddCacheDescription(processor, "2nd-level cache: 128KB, 8-way set associative, sectored cache, 64 byte line size"); break;
  984. case 0x7A: AddCacheDescription(processor, "2nd-level cache: 256KB, 4-way set associative, sectored cache, 64 byte line size"); break;
  985. case 0x7B: AddCacheDescription(processor, "2nd-level cache: 512KB, 4-way set associative, sectored cache, 64 byte line size"); break;
  986. case 0x7C: AddCacheDescription(processor, "2nd-level cache: 1MB, 4-way set associative, sectored cache, 64 byte line size"); break;
  987. case 0x7D: AddCacheDescription(processor, "2nd-level cache: 2MB, 8-way set associative, 64 byte line size"); break;
  988. case 0x7F: AddCacheDescription(processor, "2nd-level cache: 512KB, 2-way set associative, 64 byte line size"); break;
  989. case 0x82: AddCacheDescription(processor, "2nd-level cache: 256KB, 8-way set associative, 32 byte line size"); break;
  990. case 0x83: AddCacheDescription(processor, "2nd-level cache: 512KB, 8-way set associative, 32 byte line size"); break;
  991. case 0x84: AddCacheDescription(processor, "2nd-level cache: 1MB, 8-way set associative, 32 byte line size"); break;
  992. case 0x85: AddCacheDescription(processor, "2nd-level cache: 2MB, 8-way set associative, 32 byte line size"); break;
  993. case 0x86: AddCacheDescription(processor, "2nd-level cache: 512KB, 4-way set associative, 64 byte line size"); break;
  994. case 0x87: AddCacheDescription(processor, "2nd-level cache: 1MB, 8-way set associative, 64 byte line size"); break;
  995. case 0xB0: AddCacheDescription(processor, "Code TLB: 4KB pages, 4-way set associative, 128 entries"); break;
  996. case 0xB1: /* Intel oddly says this can be either of the below two, but doesn't say any conditions for when these will show up. */
  997. AddCacheDescription(processor, "Code TLB: 2MB pages, 4-way set associative, 8 entries");
  998. AddCacheDescription(processor, "Code TLB: 4MB pages, 4-way set associative, 4 entries"); break;
  999. case 0xB2: AddCacheDescription(processor, "Data TLB: 4KB pages, 4-way set associative, 64 entries"); break;
  1000. case 0xB3: AddCacheDescription(processor, "Data TLB: 4KB pages, 4-way set associative, 128 entries"); break;
  1001. case 0xB4: AddCacheDescription(processor, "Data TLB: 4KB pages, 4-way set associative, 256 entries"); break;
  1002. case 0xCA: AddCacheDescription(processor, "Shared 2nd-level TLB: 4KB pages, 4-way set associative, 512 entries"); break;
  1003. case 0xD0: AddCacheDescription(processor, "3rd-level cache: 512KB, 4-way set associative, 64 byte line size"); break;
  1004. case 0xD1: AddCacheDescription(processor, "3rd-level cache: 1MB, 4-way set associative, 64 byte line size"); break;
  1005. case 0xD2: AddCacheDescription(processor, "3rd-level cache: 2MB, 4-way set associative, 64 byte line size"); break;
  1006. case 0xD6: AddCacheDescription(processor, "3rd-level cache: 1MB, 8-way set associative, 64 byte line size"); break;
  1007. case 0xD7: AddCacheDescription(processor, "3rd-level cache: 2MB, 8-way set associative, 64 byte line size"); break;
  1008. case 0xD8: AddCacheDescription(processor, "3rd-level cache: 4MB, 8-way set associative, 64 byte line size"); break;
  1009. case 0xDC: AddCacheDescription(processor, "3rd-level cache: 1.5MB, 12-way set associative, 64 byte line size"); break;
  1010. case 0xDD: AddCacheDescription(processor, "3rd-level cache: 3MB, 12-way set associative, 64 byte line size"); break;
  1011. case 0xDE: AddCacheDescription(processor, "3rd-level cache: 6MB, 12-way set associative, 64 byte line size"); break;
  1012. case 0xE2: AddCacheDescription(processor, "3rd-level cache: 2MB, 16-way set associative, 64 byte line size"); break;
  1013. case 0xE3: AddCacheDescription(processor, "3rd-level cache: 4MB, 16-way set associative, 64 byte line size"); break;
  1014. case 0xE4: AddCacheDescription(processor, "3rd-level cache: 8MB, 16-way set associative, 64 byte line size"); break;
  1015. case 0xEA: AddCacheDescription(processor, "3rd-level cache: 12MB, 24-way set associative, 64 byte line size"); break;
  1016. case 0xEB: AddCacheDescription(processor, "3rd-level cache: 18MB, 24-way set associative, 64 byte line size"); break;
  1017. case 0xEC: AddCacheDescription(processor, "3rd-level cache: 24MB, 24-way set associative, 64 byte line size"); break;
  1018. case 0xF0: AddCacheDescription(processor, "64 byte prefetching"); break;
  1019. case 0xF1: AddCacheDescription(processor, "128 byte prefetching"); break;
  1020. default:
  1021. {
  1022. char temp[256];
  1023. sprintf(temp, "Unknown cache descriptor 0x%02x", x);
  1024. AddCacheDescription(processor, temp);
  1025. }
  1026. break;
  1027. }
  1028. }
  1029. void CPUID::DetectFMS(int processor)
  1030. {
  1031. CoreAssert(this != NULL);
  1032. /* Compliant with Intel document #241618. */
  1033. proc[processor]->m_family = (char)(((Std[1].eax >> 8) + (Std[1].eax >> 20)) & 0xff);
  1034. proc[processor]->m_model = (char)(((((Std[1].eax >> 16) & 0xf) << 4) + ((Std[1].eax >> 4) & 0xf)) & 0xff);
  1035. proc[processor]->m_stepping = (char)(Std[1].eax & 0xf);
  1036. }
  1037. void CPUID::DetectBrandID(int processor)
  1038. {
  1039. CoreAssert(this != NULL);
  1040. /* Compliant with Intel document #241618. */
  1041. proc[processor]->m_brandID = (char)(Std[1].ebx & 0xff);
  1042. }
  1043. void CPUID::DetectCount(int processor)
  1044. {
  1045. CoreAssert(this != NULL);
  1046. /* Compliant with Intel document #241618. */
  1047. /* Do we have HTT flag set? */
  1048. if (proc[processor]->m_features.exists("HTT")) {
  1049. /* AMD and Intel documentations state that if HTT is supported */
  1050. /* then this the EBX:16 will reflect the logical processor count */
  1051. /* otherwise the flag is reserved. */
  1052. proc[processor]->m_features.insert("CMP", NULL);
  1053. proc[processor]->m_cores = (char)((Std[4].eax & 0xFC000000) >> 26) + 1;
  1054. proc[processor]->m_logical = (char)((Std[1].ebx & 0x00FF0000) >> 16);
  1055. if (proc[processor]->m_cores < 1)
  1056. proc[processor]->m_cores = 1;
  1057. if (proc[processor]->m_logical < 1)
  1058. proc[processor]->m_logical = 1;
  1059. if (proc[processor]->m_cores > 1 &&
  1060. proc[processor]->m_logical > proc[processor]->m_cores) {
  1061. /* Hyperthreaded multi-core. */
  1062. } else if (proc[processor]->m_cores > 1 &&
  1063. proc[processor]->m_logical == proc[processor]->m_cores) {
  1064. /* Multi-core processor not presenting HTT */
  1065. proc[processor]->m_features.erase("HTT");
  1066. } else if (proc[processor]->m_cores == 1 &&
  1067. proc[processor]->m_logical > proc[processor]->m_cores) {
  1068. /* Hyperthreaded. */
  1069. proc[processor]->m_features.erase("CMP");
  1070. }
  1071. } else {
  1072. /* HTT not supported. Report cores and logical processor count as equal. */
  1073. proc[processor]->m_cores = (char)(((Std[4].eax & 0xFC000000) >> 26) + 1);
  1074. proc[processor]->m_logical = proc[processor]->m_cores;
  1075. }
  1076. }
  1077. void CPUID::DetectAPIC(int processor)
  1078. {
  1079. CoreAssert(this != NULL);
  1080. /* Found at http://www.intel.com/cd/ids/developer/asmo-na/eng/211924.htm */
  1081. proc[processor]->m_apicID = (char)((Std[1].ebx & 0xFF000000) >> 24);
  1082. }
  1083. void CPUID::DetectFeatures(int processor)

Large files files are truncated, but you can click here to view the full file