PageRenderTime 35ms CodeModel.GetById 36ms RepoModel.GetById 1ms app.codeStats 0ms

/source/cpuid.cpp

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