recog_intel.c 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819
  1. /*
  2. * Copyright 2008 Veselin Georgiev,
  3. * anrieffNOSPAM @ mgail_DOT.com (convert to gmail)
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  16. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  17. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  18. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  19. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  20. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  21. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  22. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  24. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include <string.h>
  27. #include <ctype.h>
  28. #include "libcpuid.h"
  29. #include "recog_intel.h"
  30. #include "libcpuid_util.h"
  31. enum _intel_code_t {
  32. NA,
  33. NO_CODE,
  34. PENTIUM = 10,
  35. MOBILE_PENTIUM,
  36. XEON = 20,
  37. XEON_IRWIN,
  38. XEONMP,
  39. XEON_POTOMAC,
  40. XEON_I7,
  41. XEON_GAINESTOWN,
  42. XEON_WESTMERE,
  43. MOBILE_PENTIUM_M = 30,
  44. CELERON,
  45. MOBILE_CELERON,
  46. NOT_CELERON,
  47. CORE_SOLO = 40,
  48. MOBILE_CORE_SOLO,
  49. CORE_DUO,
  50. MOBILE_CORE_DUO,
  51. WOLFDALE = 50,
  52. MEROM,
  53. PENRYN,
  54. QUAD_CORE,
  55. DUAL_CORE_HT,
  56. QUAD_CORE_HT,
  57. MORE_THAN_QUADCORE,
  58. PENTIUM_D,
  59. ATOM = 60,
  60. ATOM_SILVERTHORNE,
  61. ATOM_DIAMONDVILLE,
  62. ATOM_PINEVIEW,
  63. ATOM_CEDARVIEW,
  64. CORE_I3 = 70,
  65. CORE_I5,
  66. CORE_I7,
  67. CORE_IVY3, /* 22nm Core-iX */
  68. CORE_IVY5,
  69. CORE_IVY7,
  70. CORE_HASWELL3, /* 22nm Core-iX, Haswell */
  71. CORE_HASWELL5,
  72. CORE_HASWELL7,
  73. CORE_BROADWELL3, /* 14nm Core-iX, Broadwell */
  74. CORE_BROADWELL5,
  75. CORE_BROADWELL7,
  76. CORE_SKYLAKE3, /* 14nm Core-iX, Skylake */
  77. CORE_SKYLAKE5,
  78. CORE_SKYLAKE7,
  79. };
  80. typedef enum _intel_code_t intel_code_t;
  81. enum _intel_model_t {
  82. UNKNOWN = -1,
  83. _3000 = 100,
  84. _3100,
  85. _3200,
  86. X3200,
  87. _3300,
  88. X3300,
  89. _5100,
  90. _5200,
  91. _5300,
  92. _5400,
  93. _2xxx, /* Core i[357] 2xxx */
  94. _3xxx, /* Core i[357] 3xxx */
  95. };
  96. typedef enum _intel_model_t intel_model_t;
  97. const struct match_entry_t cpudb_intel[] = {
  98. { -1, -1, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Unknown Intel CPU" },
  99. /* i486 */
  100. { 4, -1, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Unknown i486" },
  101. { 4, 0, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "i486 DX-25/33" },
  102. { 4, 1, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "i486 DX-50" },
  103. { 4, 2, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "i486 SX" },
  104. { 4, 3, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "i486 DX2" },
  105. { 4, 4, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "i486 SL" },
  106. { 4, 5, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "i486 SX2" },
  107. { 4, 7, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "i486 DX2 WriteBack" },
  108. { 4, 8, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "i486 DX4" },
  109. { 4, 9, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "i486 DX4 WriteBack" },
  110. /* All Pentia:
  111. Pentium 1 */
  112. { 5, -1, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Unknown Pentium" },
  113. { 5, 0, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Pentium A-Step" },
  114. { 5, 1, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Pentium 1 (0.8u)" },
  115. { 5, 2, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Pentium 1 (0.35u)" },
  116. { 5, 3, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Pentium OverDrive" },
  117. { 5, 4, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Pentium 1 (0.35u)" },
  118. { 5, 7, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Pentium 1 (0.35u)" },
  119. { 5, 8, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Pentium MMX (0.25u)" },
  120. /* Pentium 2 / 3 / M / Conroe / whatsnext - all P6 based. */
  121. { 6, -1, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Unknown P6" },
  122. { 6, 0, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Pentium Pro" },
  123. { 6, 1, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Pentium Pro" },
  124. { 6, 3, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Pentium II (Klamath)" },
  125. { 6, 5, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Pentium II (Deschutes)" },
  126. { 6, 5, -1, -1, -1, 1, -1, -1, MOBILE_PENTIUM , 0, "Mobile Pentium II (Tonga)"},
  127. { 6, 6, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Pentium II (Dixon)" },
  128. { 6, 3, -1, -1, -1, 1, -1, -1, XEON , 0, "P-II Xeon" },
  129. { 6, 5, -1, -1, -1, 1, -1, -1, XEON , 0, "P-II Xeon" },
  130. { 6, 6, -1, -1, -1, 1, -1, -1, XEON , 0, "P-II Xeon" },
  131. { 6, 5, -1, -1, -1, 1, -1, -1, CELERON , 0, "P-II Celeron (no L2)" },
  132. { 6, 6, -1, -1, -1, 1, -1, -1, CELERON , 0, "P-II Celeron (128K)" },
  133. /* -------------------------------------------------- */
  134. { 6, 7, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Pentium III (Katmai)" },
  135. { 6, 8, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Pentium III (Coppermine)"},
  136. { 6, 10, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Pentium III (Coppermine)"},
  137. { 6, 11, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Pentium III (Tualatin)" },
  138. { 6, 7, -1, -1, -1, 1, -1, -1, XEON , 0, "P-III Xeon" },
  139. { 6, 8, -1, -1, -1, 1, -1, -1, XEON , 0, "P-III Xeon" },
  140. { 6, 10, -1, -1, -1, 1, -1, -1, XEON , 0, "P-III Xeon" },
  141. { 6, 11, -1, -1, -1, 1, -1, -1, XEON , 0, "P-III Xeon" },
  142. { 6, 7, -1, -1, -1, 1, -1, -1, CELERON , 0, "P-III Celeron" },
  143. { 6, 8, -1, -1, -1, 1, -1, -1, CELERON , 0, "P-III Celeron" },
  144. { 6, 10, -1, -1, -1, 1, -1, -1, CELERON , 0, "P-III Celeron" },
  145. { 6, 11, -1, -1, -1, 1, -1, -1, CELERON , 0, "P-III Celeron" },
  146. /* Netburst based (Pentium 4 and later)
  147. classic P4s */
  148. { 15, -1, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Unknown Pentium 4" },
  149. { 15, -1, -1, 15, -1, 1, -1, -1, CELERON , 0, "Unknown P-4 Celeron" },
  150. { 15, -1, -1, 15, -1, 1, -1, -1, XEON , 0, "Unknown Xeon" },
  151. { 15, 0, -1, 15, -1, 1, -1, -1, NO_CODE , 0, "Pentium 4 (Willamette)" },
  152. { 15, 1, -1, 15, -1, 1, -1, -1, NO_CODE , 0, "Pentium 4 (Willamette)" },
  153. { 15, 2, -1, 15, -1, 1, -1, -1, NO_CODE , 0, "Pentium 4 (Northwood)" },
  154. { 15, 3, -1, 15, -1, 1, -1, -1, NO_CODE , 0, "Pentium 4 (Prescott)" },
  155. { 15, 4, -1, 15, -1, 1, -1, -1, NO_CODE , 0, "Pentium 4 (Prescott)" },
  156. { 15, 6, -1, 15, -1, 1, -1, -1, NO_CODE , 0, "Pentium 4 (Cedar Mill)" },
  157. { 15, 0, -1, 15, -1, 1, -1, -1, MOBILE_PENTIUM , 0, "Mobile P-4 (Willamette)" },
  158. { 15, 1, -1, 15, -1, 1, -1, -1, MOBILE_PENTIUM , 0, "Mobile P-4 (Willamette)" },
  159. { 15, 2, -1, 15, -1, 1, -1, -1, MOBILE_PENTIUM , 0, "Mobile P-4 (Northwood)" },
  160. { 15, 3, -1, 15, -1, 1, -1, -1, MOBILE_PENTIUM , 0, "Mobile P-4 (Prescott)" },
  161. { 15, 4, -1, 15, -1, 1, -1, -1, MOBILE_PENTIUM , 0, "Mobile P-4 (Prescott)" },
  162. { 15, 6, -1, 15, -1, 1, -1, -1, MOBILE_PENTIUM , 0, "Mobile P-4 (Cedar Mill)" },
  163. /* server CPUs */
  164. { 15, 0, -1, 15, -1, 1, -1, -1, XEON , 0, "Xeon (Foster)" },
  165. { 15, 1, -1, 15, -1, 1, -1, -1, XEON , 0, "Xeon (Foster)" },
  166. { 15, 2, -1, 15, -1, 1, -1, -1, XEON , 0, "Xeon (Prestonia)" },
  167. { 15, 2, -1, 15, -1, 1, -1, -1, XEONMP , 0, "Xeon (Gallatin)" },
  168. { 15, 3, -1, 15, -1, 1, -1, -1, XEON , 0, "Xeon (Nocona)" },
  169. { 15, 4, -1, 15, -1, 1, -1, -1, XEON , 0, "Xeon (Nocona)" },
  170. { 15, 4, -1, 15, -1, 1, -1, -1, XEON_IRWIN , 0, "Xeon (Irwindale)" },
  171. { 15, 4, -1, 15, -1, 1, -1, -1, XEONMP , 0, "Xeon (Cranford)" },
  172. { 15, 4, -1, 15, -1, 1, -1, -1, XEON_POTOMAC , 0, "Xeon (Potomac)" },
  173. { 15, 6, -1, 15, -1, 1, -1, -1, XEON , 0, "Xeon (Dempsey)" },
  174. /* Pentium Ds */
  175. { 15, 4, 4, 15, -1, 1, -1, -1, NO_CODE , 0, "Pentium D" },
  176. { 15, 4, -1, 15, -1, 1, -1, -1, PENTIUM_D , 0, "Pentium D" },
  177. { 15, 4, 7, 15, -1, 1, -1, -1, NO_CODE , 0, "Pentium D" },
  178. { 15, 6, -1, 15, -1, 1, -1, -1, PENTIUM_D , 0, "Pentium D" },
  179. /* Celeron and Celeron Ds */
  180. { 15, 1, -1, 15, -1, 1, -1, -1, CELERON , 0, "P-4 Celeron (128K)" },
  181. { 15, 2, -1, 15, -1, 1, -1, -1, CELERON , 0, "P-4 Celeron (128K)" },
  182. { 15, 3, -1, 15, -1, 1, -1, -1, CELERON , 0, "Celeron D" },
  183. { 15, 4, -1, 15, -1, 1, -1, -1, CELERON , 0, "Celeron D" },
  184. { 15, 6, -1, 15, -1, 1, -1, -1, CELERON , 0, "Celeron D" },
  185. /* -------------------------------------------------- */
  186. /* Intel Core microarchitecture - P6-based */
  187. { 6, 9, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Unknown Pentium M" },
  188. { 6, 9, -1, -1, -1, 1, -1, -1, MOBILE_PENTIUM_M , 0, "Unknown Pentium M" },
  189. { 6, 9, -1, -1, -1, 1, -1, -1, PENTIUM , 0, "Pentium M (Banias)" },
  190. { 6, 9, -1, -1, -1, 1, -1, -1, MOBILE_PENTIUM_M , 0, "Pentium M (Banias)" },
  191. { 6, 9, -1, -1, -1, 1, -1, -1, CELERON , 0, "Celeron M" },
  192. { 6, 13, -1, -1, -1, 1, -1, -1, PENTIUM , 0, "Pentium M (Dothan)" },
  193. { 6, 13, -1, -1, -1, 1, -1, -1, MOBILE_PENTIUM_M , 0, "Pentium M (Dothan)" },
  194. { 6, 13, -1, -1, -1, 1, -1, -1, CELERON , 0, "Celeron M" },
  195. { 6, 12, -1, -1, -1, -1, -1, -1, ATOM , 0, "Unknown Atom" },
  196. { 6, 12, -1, -1, -1, -1, -1, -1, ATOM_DIAMONDVILLE , 0, "Atom (Diamondville)" },
  197. { 6, 12, -1, -1, -1, -1, -1, -1, ATOM_SILVERTHORNE , 0, "Atom (Silverthorne)" },
  198. { 6, 12, -1, -1, -1, -1, -1, -1, ATOM_CEDARVIEW , 0, "Atom (Cedarview)" },
  199. { 6, 6, -1, -1, -1, -1, -1, -1, ATOM_CEDARVIEW , 0, "Atom (Cedarview)" },
  200. { 6, 12, -1, -1, -1, -1, -1, -1, ATOM_PINEVIEW , 0, "Atom (Pineview)" },
  201. /* -------------------------------------------------- */
  202. { 6, 14, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Unknown Yonah" },
  203. { 6, 14, -1, -1, -1, 1, -1, -1, CORE_SOLO , 0, "Yonah (Core Solo)" },
  204. { 6, 14, -1, -1, -1, 2, -1, -1, CORE_DUO , 0, "Yonah (Core Duo)" },
  205. { 6, 14, -1, -1, -1, 1, -1, -1, MOBILE_CORE_SOLO , 0, "Yonah (Core Solo)" },
  206. { 6, 14, -1, -1, -1, 2, -1, -1, MOBILE_CORE_DUO , 0, "Yonah (Core Duo)" },
  207. { 6, 14, -1, -1, -1, 1, -1, -1, CORE_SOLO , 0, "Yonah (Core Solo)" },
  208. { 6, 15, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Unknown Core 2" },
  209. { 6, 15, -1, -1, -1, 2, 4096, -1, CORE_DUO , 0, "Conroe (Core 2 Duo)" },
  210. { 6, 15, -1, -1, -1, 2, 1024, -1, CORE_DUO , 0, "Conroe (Core 2 Duo) 1024K" },
  211. { 6, 15, -1, -1, -1, 2, 512, -1, CORE_DUO , 0, "Conroe (Core 2 Duo) 512K" },
  212. { 6, 15, -1, -1, -1, 4, -1, -1, QUAD_CORE , 0, "Kentsfield (Core 2 Quad)" },
  213. { 6, 15, -1, -1, -1, 4, 4096, -1, QUAD_CORE , 0, "Kentsfield (Core 2 Quad)" },
  214. { 6, 15, -1, -1, -1, 400, -1, -1, MORE_THAN_QUADCORE, 0, "More than quad-core" },
  215. { 6, 15, -1, -1, -1, 2, 2048, -1, CORE_DUO , 0, "Allendale (Core 2 Duo)" },
  216. { 6, 15, -1, -1, -1, 2, -1, -1, MOBILE_CORE_DUO , 0, "Merom (Core 2 Duo)" },
  217. { 6, 15, -1, -1, -1, 2, 2048, -1, MEROM , 0, "Merom (Core 2 Duo) 2048K" },
  218. { 6, 15, -1, -1, -1, 2, 4096, -1, MEROM , 0, "Merom (Core 2 Duo) 4096K" },
  219. { 6, 15, -1, -1, 15, 1, -1, -1, CELERON , 0, "Conroe-L (Celeron)" },
  220. { 6, 6, -1, -1, 22, 1, -1, -1, CELERON , 0, "Conroe-L (Celeron)" },
  221. { 6, 15, -1, -1, 15, 2, -1, -1, CELERON , 0, "Conroe-L (Allendale)" },
  222. { 6, 6, -1, -1, 22, 2, -1, -1, CELERON , 0, "Conroe-L (Allendale)" },
  223. { 6, 6, -1, -1, 22, 1, -1, -1, NO_CODE , 0, "Unknown Core ?" },
  224. { 6, 7, -1, -1, 23, 1, -1, -1, NO_CODE , 0, "Unknown Core ?" },
  225. { 6, 6, -1, -1, 22, 400, -1, -1, MORE_THAN_QUADCORE, 0, "More than quad-core" },
  226. { 6, 7, -1, -1, 23, 400, -1, -1, MORE_THAN_QUADCORE, 0, "More than quad-core" },
  227. { 6, 7, -1, -1, 23, 1, -1, -1, CORE_SOLO , 0, "Unknown Core 45nm" },
  228. { 6, 7, -1, -1, 23, 1, -1, -1, CORE_DUO , 0, "Unknown Core 45nm" },
  229. { 6, 7, -1, -1, 23, 2, 1024, -1, WOLFDALE , 0, "Celeron Wolfdale 1M" },
  230. { 6, 7, -1, -1, 23, 2, 2048, -1, WOLFDALE , 0, "Wolfdale (Core 2 Duo) 2M" },
  231. { 6, 7, -1, -1, 23, 2, 3072, -1, WOLFDALE , 0, "Wolfdale (Core 2 Duo) 3M" },
  232. { 6, 7, -1, -1, 23, 2, 6144, -1, WOLFDALE , 0, "Wolfdale (Core 2 Duo) 6M" },
  233. { 6, 7, -1, -1, 23, 1, -1, -1, MOBILE_CORE_DUO , 0, "Penryn (Core 2 Duo)" },
  234. { 6, 7, -1, -1, 23, 2, 3072, -1, PENRYN , 0, "Penryn (Core 2 Duo) 3M" },
  235. { 6, 7, -1, -1, 23, 2, 6144, -1, PENRYN , 0, "Penryn (Core 2 Duo) 6M" },
  236. { 6, 7, -1, -1, 23, 4, 2048, -1, QUAD_CORE , 0, "Yorkfield (Core 2 Quad) 2M"},
  237. { 6, 7, -1, -1, 23, 4, 3072, -1, QUAD_CORE , 0, "Yorkfield (Core 2 Quad) 3M"},
  238. { 6, 7, -1, -1, 23, 4, 6144, -1, QUAD_CORE , 0, "Yorkfield (Core 2 Quad) 6M"},
  239. /* Core microarchitecture-based Xeons: */
  240. { 6, 14, -1, -1, 14, 1, -1, -1, XEON , 0, "Xeon LV" },
  241. { 6, 15, -1, -1, 15, 2, 4096, -1, XEON , _5100, "Xeon (Woodcrest)" },
  242. { 6, 15, -1, -1, 15, 2, 2048, -1, XEON , _3000, "Xeon (Conroe/2M)" },
  243. { 6, 15, -1, -1, 15, 2, 4096, -1, XEON , _3000, "Xeon (Conroe/4M)" },
  244. { 6, 15, -1, -1, 15, 4, 4096, -1, XEON , X3200, "Xeon (Kentsfield)" },
  245. { 6, 15, -1, -1, 15, 4, 4096, -1, XEON , _5300, "Xeon (Clovertown)" },
  246. { 6, 7, -1, -1, 23, 2, 6144, -1, XEON , _3100, "Xeon (Wolfdale)" },
  247. { 6, 7, -1, -1, 23, 2, 6144, -1, XEON , _5200, "Xeon (Wolfdale DP)" },
  248. { 6, 7, -1, -1, 23, 4, 6144, -1, XEON , _5400, "Xeon (Harpertown)" },
  249. { 6, 7, -1, -1, 23, 4, 3072, -1, XEON , X3300, "Xeon (Yorkfield/3M)" },
  250. { 6, 7, -1, -1, 23, 4, 6144, -1, XEON , X3300, "Xeon (Yorkfield/6M)" },
  251. /* Nehalem CPUs (45nm): */
  252. { 6, 10, -1, -1, 26, 4, -1, -1, XEON_GAINESTOWN , 0, "Gainestown (Xeon)" },
  253. { 6, 10, -1, -1, 26, 4, -1, 4096, XEON_GAINESTOWN , 0, "Gainestown 4M (Xeon)" },
  254. { 6, 10, -1, -1, 26, 4, -1, 8192, XEON_GAINESTOWN , 0, "Gainestown 8M (Xeon)" },
  255. { 6, 10, -1, -1, 26, 4, -1, -1, XEON_I7 , 0, "Bloomfield (Xeon)" },
  256. { 6, 10, -1, -1, 26, 4, -1, -1, CORE_I7 , 0, "Bloomfield (Core i7)" },
  257. { 6, 10, -1, -1, 30, 4, -1, -1, CORE_I7 , 0, "Lynnfield (Core i7)" },
  258. { 6, 5, -1, -1, 37, 4, -1, 8192, CORE_I5 , 0, "Lynnfield (Core i5)" },
  259. /* Westmere CPUs (32nm): */
  260. { 6, 5, -1, -1, 37, 2, -1, -1, NO_CODE , 0, "Unknown Core i3/i5" },
  261. { 6, 12, -1, -1, 44, -1, -1, -1, XEON_WESTMERE , 0, "Westmere (Xeon)" },
  262. { 6, 12, -1, -1, 44, -1, -1, 12288, XEON_WESTMERE , 0, "Gulftown (Xeon)" },
  263. { 6, 12, -1, -1, 44, 4, -1, 12288, CORE_I7 , 0, "Gulftown (Core i7)" },
  264. { 6, 5, -1, -1, 37, 2, -1, 4096, CORE_I5 , 0, "Clarkdale (Core i5)" },
  265. { 6, 5, -1, -1, 37, 2, -1, 4096, CORE_I3 , 0, "Clarkdale (Core i3)" },
  266. { 6, 5, -1, -1, 37, 2, -1, 4096, CORE_I7 , 0, "Arrandale (Core i7)" },
  267. { 6, 5, -1, -1, 37, 2, -1, 3072, CORE_I5 , 0, "Arrandale (Core i5)" },
  268. { 6, 5, -1, -1, 37, 2, -1, 3072, CORE_I3 , 0, "Arrandale (Core i3)" },
  269. /* Sandy Bridge CPUs (32nm): */
  270. { 6, 10, -1, -1, 42, -1, -1, -1, NO_CODE , 0, "Unknown Sandy Bridge" },
  271. { 6, 10, -1, -1, 42, -1, -1, -1, XEON , 0, "Sandy Bridge (Xeon)" },
  272. { 6, 10, -1, -1, 42, -1, -1, -1, CORE_I7 , 0, "Sandy Bridge (Core i7)" },
  273. { 6, 10, -1, -1, 42, 4, -1, -1, CORE_I7 , 0, "Sandy Bridge (Core i7)" },
  274. { 6, 10, -1, -1, 42, 4, -1, -1, CORE_I5 , 0, "Sandy Bridge (Core i5)" },
  275. { 6, 10, -1, -1, 42, 2, -1, -1, CORE_I3 , 0, "Sandy Bridge (Core i3)" },
  276. { 6, 10, -1, -1, 42, 2, -1, -1, PENTIUM , 0, "Sandy Bridge (Pentium)" },
  277. { 6, 10, -1, -1, 42, 1, -1, -1, CELERON , 0, "Sandy Bridge (Celeron)" },
  278. { 6, 10, -1, -1, 42, 2, -1, -1, CELERON , 0, "Sandy Bridge (Celeron)" },
  279. { 6, 13, -1, -1, 45, -1, -1, -1, NO_CODE , 0, "Sandy Bridge-E" },
  280. { 6, 13, -1, -1, 45, -1, -1, -1, XEON , 0, "Sandy Bridge-E (Xeon)" },
  281. /* Ivy Bridge CPUs (22nm): */
  282. { 6, 10, -1, -1, 58, -1, -1, -1, XEON , 0, "Ivy Bridge (Xeon)" },
  283. { 6, 10, -1, -1, 58, 4, -1, -1, CORE_IVY7 , 0, "Ivy Bridge (Core i7)" },
  284. { 6, 10, -1, -1, 58, 4, -1, -1, CORE_IVY5 , 0, "Ivy Bridge (Core i5)" },
  285. { 6, 10, -1, -1, 58, 2, -1, -1, CORE_IVY3 , 0, "Ivy Bridge (Core i3)" },
  286. { 6, 10, -1, -1, 58, 2, -1, -1, PENTIUM , 0, "Ivy Bridge (Pentium)" },
  287. { 6, 10, -1, -1, 58, 1, -1, -1, CELERON , 0, "Ivy Bridge (Celeron)" },
  288. { 6, 10, -1, -1, 58, 2, -1, -1, CELERON , 0, "Ivy Bridge (Celeron)" },
  289. { 6, 14, -1, -1, 62, -1, -1, -1, NO_CODE , 0, "Ivy Bridge-E" },
  290. /* Haswell CPUs (22nm): */
  291. { 6, 12, -1, -1, 60, -1, -1, -1, XEON , 0, "Haswell (Xeon)" },
  292. { 6, 12, -1, -1, 60, 4, -1, -1, CORE_HASWELL7 , 0, "Haswell (Core i7)" },
  293. { 6, 5, -1, -1, 69, 4, -1, -1, CORE_HASWELL7 , 0, "Haswell (Core i7)" },
  294. { 6, 12, -1, -1, 60, 4, -1, -1, CORE_HASWELL5 , 0, "Haswell (Core i5)" },
  295. { 6, 5, -1, -1, 69, 4, -1, -1, CORE_HASWELL5 , 0, "Haswell (Core i5)" },
  296. { 6, 12, -1, -1, 60, 2, -1, -1, CORE_HASWELL3 , 0, "Haswell (Core i3)" },
  297. { 6, 5, -1, -1, 69, 2, -1, -1, CORE_HASWELL3 , 0, "Haswell (Core i3)" },
  298. { 6, 12, -1, -1, 60, 2, -1, -1, PENTIUM , 0, "Haswell (Pentium)" },
  299. { 6, 12, -1, -1, 60, 2, -1, -1, CELERON , 0, "Haswell (Celeron)" },
  300. { 6, 12, -1, -1, 60, 1, -1, -1, CELERON , 0, "Haswell (Celeron)" },
  301. { 6, 15, -1, -1, 63, -1, -1, -1, NO_CODE , 0, "Haswell-E" },
  302. /* Broadwell CPUs (14nm): */
  303. { 6, 7, -1, -1, 71, 4, -1, -1, CORE_BROADWELL7 , 0, "Broadwell (Core i7)" },
  304. { 6, 7, -1, -1, 71, 4, -1, -1, CORE_BROADWELL5 , 0, "Broadwell (Core i5)" },
  305. { 6, 13, -1, -1, 61, 4, -1, -1, CORE_BROADWELL7 , 0, "Broadwell-U (Core i7)" },
  306. { 6, 13, -1, -1, 61, 2, -1, -1, CORE_BROADWELL7 , 0, "Broadwell-U (Core i7)" },
  307. { 6, 13, -1, -1, 61, 2, -1, -1, CORE_BROADWELL5 , 0, "Broadwell-U (Core i5)" },
  308. { 6, 13, -1, -1, 61, 2, -1, -1, CORE_BROADWELL3 , 0, "Broadwell-U (Core i3)" },
  309. { 6, 13, -1, -1, 61, 2, -1, -1, PENTIUM , 0, "Broadwell-U (Pentium)" },
  310. { 6, 13, -1, -1, 61, 2, -1, -1, CELERON , 0, "Broadwell-U (Celeron)" },
  311. { 6, 13, -1, -1, 61, 2, -1, -1, NA , 0, "Broadwell-U (Core M)" },
  312. /* Skylake CPUs (14nm): */
  313. { 6, 14, -1, -1, 94, 4, -1, -1, CORE_SKYLAKE7 , 0, "Skylake (Core i7)" },
  314. { 6, 14, -1, -1, 94, 4, -1, -1, CORE_SKYLAKE5 , 0, "Skylake (Core i5)" },
  315. { 6, 14, -1, -1, 94, 4, -1, -1, CORE_SKYLAKE3 , 0, "Skylake (Core i3)" },
  316. { 6, 14, -1, -1, 94, 4, -1, -1, PENTIUM , 0, "Skylake (Pentium)" },
  317. /* Itaniums */
  318. { 7, -1, -1, -1, -1, 1, -1, -1, NO_CODE , 0, "Itanium" },
  319. { 15, -1, -1, 16, -1, 1, -1, -1, NO_CODE , 0, "Itanium 2" },
  320. };
  321. static void load_intel_features(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
  322. {
  323. const struct feature_map_t matchtable_edx1[] = {
  324. { 18, CPU_FEATURE_PN },
  325. { 21, CPU_FEATURE_DTS },
  326. { 22, CPU_FEATURE_ACPI },
  327. { 27, CPU_FEATURE_SS },
  328. { 29, CPU_FEATURE_TM },
  329. { 30, CPU_FEATURE_IA64 },
  330. { 31, CPU_FEATURE_PBE },
  331. };
  332. const struct feature_map_t matchtable_ecx1[] = {
  333. { 1, CPU_FEATURE_PCLMUL },
  334. { 2, CPU_FEATURE_DTS64 },
  335. { 4, CPU_FEATURE_DS_CPL },
  336. { 5, CPU_FEATURE_VMX },
  337. { 6, CPU_FEATURE_SMX },
  338. { 7, CPU_FEATURE_EST },
  339. { 8, CPU_FEATURE_TM2 },
  340. { 10, CPU_FEATURE_CID },
  341. { 14, CPU_FEATURE_XTPR },
  342. { 15, CPU_FEATURE_PDCM },
  343. { 18, CPU_FEATURE_DCA },
  344. { 20, CPU_FEATURE_SSE4_2 },
  345. { 22, CPU_FEATURE_MOVBE },
  346. { 25, CPU_FEATURE_AES },
  347. { 26, CPU_FEATURE_XSAVE },
  348. { 27, CPU_FEATURE_OSXSAVE },
  349. { 30, CPU_FEATURE_RDRAND },
  350. };
  351. const struct feature_map_t matchtable_edx81[] = {
  352. { 20, CPU_FEATURE_XD },
  353. };
  354. if (raw->basic_cpuid[0][0] >= 1) {
  355. match_features(matchtable_edx1, COUNT_OF(matchtable_edx1), raw->basic_cpuid[1][3], data);
  356. match_features(matchtable_ecx1, COUNT_OF(matchtable_ecx1), raw->basic_cpuid[1][2], data);
  357. }
  358. if (raw->ext_cpuid[0][0] >= 1) {
  359. match_features(matchtable_edx81, COUNT_OF(matchtable_edx81), raw->ext_cpuid[1][3], data);
  360. }
  361. }
  362. enum _cache_type_t {
  363. L1I,
  364. L1D,
  365. L2,
  366. L3
  367. };
  368. typedef enum _cache_type_t cache_type_t;
  369. static void check_case(uint8_t on, cache_type_t cache, int size, int assoc, int linesize, struct cpu_id_t* data)
  370. {
  371. if (!on) return;
  372. switch (cache) {
  373. case L1I:
  374. data->l1_instruction_cache = size;
  375. break;
  376. case L1D:
  377. data->l1_data_cache = size;
  378. data->l1_assoc = assoc;
  379. data->l1_cacheline = linesize;
  380. break;
  381. case L2:
  382. data->l2_cache = size;
  383. data->l2_assoc = assoc;
  384. data->l2_cacheline = linesize;
  385. break;
  386. case L3:
  387. data->l3_cache = size;
  388. data->l3_assoc = assoc;
  389. data->l3_cacheline = linesize;
  390. default:
  391. break;
  392. }
  393. }
  394. static void decode_intel_oldstyle_cache_info(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
  395. {
  396. uint8_t f[256] = {0};
  397. int reg, off;
  398. uint32_t x;
  399. for (reg = 0; reg < 4; reg++) {
  400. x = raw->basic_cpuid[2][reg];
  401. if (x & 0x80000000) continue;
  402. for (off = 0; off < 4; off++) {
  403. f[x & 0xff] = 1;
  404. x >>= 8;
  405. }
  406. }
  407. check_case(f[0x06], L1I, 8, 4, 32, data);
  408. check_case(f[0x08], L1I, 16, 4, 32, data);
  409. check_case(f[0x0A], L1D, 8, 2, 32, data);
  410. check_case(f[0x0C], L1D, 16, 4, 32, data);
  411. check_case(f[0x22], L3, 512, 4, 64, data);
  412. check_case(f[0x23], L3, 1024, 8, 64, data);
  413. check_case(f[0x25], L3, 2048, 8, 64, data);
  414. check_case(f[0x29], L3, 4096, 8, 64, data);
  415. check_case(f[0x2C], L1D, 32, 8, 64, data);
  416. check_case(f[0x30], L1I, 32, 8, 64, data);
  417. check_case(f[0x39], L2, 128, 4, 64, data);
  418. check_case(f[0x3A], L2, 192, 6, 64, data);
  419. check_case(f[0x3B], L2, 128, 2, 64, data);
  420. check_case(f[0x3C], L2, 256, 4, 64, data);
  421. check_case(f[0x3D], L2, 384, 6, 64, data);
  422. check_case(f[0x3E], L2, 512, 4, 64, data);
  423. check_case(f[0x41], L2, 128, 4, 32, data);
  424. check_case(f[0x42], L2, 256, 4, 32, data);
  425. check_case(f[0x43], L2, 512, 4, 32, data);
  426. check_case(f[0x44], L2, 1024, 4, 32, data);
  427. check_case(f[0x45], L2, 2048, 4, 32, data);
  428. check_case(f[0x46], L3, 4096, 4, 64, data);
  429. check_case(f[0x47], L3, 8192, 8, 64, data);
  430. check_case(f[0x4A], L3, 6144, 12, 64, data);
  431. check_case(f[0x4B], L3, 8192, 16, 64, data);
  432. check_case(f[0x4C], L3, 12288, 12, 64, data);
  433. check_case(f[0x4D], L3, 16384, 16, 64, data);
  434. check_case(f[0x4E], L2, 6144, 24, 64, data);
  435. check_case(f[0x60], L1D, 16, 8, 64, data);
  436. check_case(f[0x66], L1D, 8, 4, 64, data);
  437. check_case(f[0x67], L1D, 16, 4, 64, data);
  438. check_case(f[0x68], L1D, 32, 4, 64, data);
  439. /* The following four entries are trace cache. Intel does not
  440. * specify a cache-line size, so we use -1 instead
  441. */
  442. check_case(f[0x70], L1I, 12, 8, -1, data);
  443. check_case(f[0x71], L1I, 16, 8, -1, data);
  444. check_case(f[0x72], L1I, 32, 8, -1, data);
  445. check_case(f[0x73], L1I, 64, 8, -1, data);
  446. check_case(f[0x78], L2, 1024, 4, 64, data);
  447. check_case(f[0x79], L2, 128, 8, 64, data);
  448. check_case(f[0x7A], L2, 256, 8, 64, data);
  449. check_case(f[0x7B], L2, 512, 8, 64, data);
  450. check_case(f[0x7C], L2, 1024, 8, 64, data);
  451. check_case(f[0x7D], L2, 2048, 8, 64, data);
  452. check_case(f[0x7F], L2, 512, 2, 64, data);
  453. check_case(f[0x82], L2, 256, 8, 32, data);
  454. check_case(f[0x83], L2, 512, 8, 32, data);
  455. check_case(f[0x84], L2, 1024, 8, 32, data);
  456. check_case(f[0x85], L2, 2048, 8, 32, data);
  457. check_case(f[0x86], L2, 512, 4, 64, data);
  458. check_case(f[0x87], L2, 1024, 8, 64, data);
  459. if (f[0x49]) {
  460. /* This flag is overloaded with two meanings. On Xeon MP
  461. * (family 0xf, model 0x6) this means L3 cache. On all other
  462. * CPUs (notably Conroe et al), this is L2 cache. In both cases
  463. * it means 4MB, 16-way associative, 64-byte line size.
  464. */
  465. if (data->family == 0xf && data->model == 0x6) {
  466. data->l3_cache = 4096;
  467. data->l3_assoc = 16;
  468. data->l3_cacheline = 64;
  469. } else {
  470. data->l2_cache = 4096;
  471. data->l2_assoc = 16;
  472. data->l2_cacheline = 64;
  473. }
  474. }
  475. if (f[0x40]) {
  476. /* Again, a special flag. It means:
  477. * 1) If no L2 is specified, then CPU is w/o L2 (0 KB)
  478. * 2) If L2 is specified by other flags, then, CPU is w/o L3.
  479. */
  480. if (data->l2_cache == -1) {
  481. data->l2_cache = 0;
  482. } else {
  483. data->l3_cache = 0;
  484. }
  485. }
  486. }
  487. static void decode_intel_deterministic_cache_info(struct cpu_raw_data_t* raw,
  488. struct cpu_id_t* data)
  489. {
  490. int ecx;
  491. int ways, partitions, linesize, sets, size, level, typenumber;
  492. cache_type_t type;
  493. for (ecx = 0; ecx < MAX_INTELFN4_LEVEL; ecx++) {
  494. typenumber = raw->intel_fn4[ecx][0] & 0x1f;
  495. if (typenumber == 0) break;
  496. level = (raw->intel_fn4[ecx][0] >> 5) & 0x7;
  497. if (level == 1 && typenumber == 1)
  498. type = L1D;
  499. else if (level == 1 && typenumber == 2)
  500. type = L1I;
  501. else if (level == 2 && typenumber == 3)
  502. type = L2;
  503. else if (level == 3 && typenumber == 3)
  504. type = L3;
  505. else {
  506. warnf("deterministic_cache: unknown level/typenumber combo (%d/%d), cannot\n", level, typenumber);
  507. warnf("deterministic_cache: recognize cache type\n");
  508. continue;
  509. }
  510. ways = ((raw->intel_fn4[ecx][1] >> 22) & 0x3ff) + 1;
  511. partitions = ((raw->intel_fn4[ecx][1] >> 12) & 0x3ff) + 1;
  512. linesize = (raw->intel_fn4[ecx][1] & 0xfff) + 1;
  513. sets = raw->intel_fn4[ecx][2] + 1;
  514. size = ways * partitions * linesize * sets / 1024;
  515. check_case(1, type, size, ways, linesize, data);
  516. }
  517. }
  518. static int decode_intel_extended_topology(struct cpu_raw_data_t* raw,
  519. struct cpu_id_t* data)
  520. {
  521. int i, level_type, num_smt = -1, num_core = -1;
  522. for (i = 0; i < MAX_INTELFN11_LEVEL; i++) {
  523. level_type = (raw->intel_fn11[i][2] & 0xff00) >> 8;
  524. switch (level_type) {
  525. case 0x01:
  526. num_smt = raw->intel_fn11[i][1] & 0xffff;
  527. break;
  528. case 0x02:
  529. num_core = raw->intel_fn11[i][1] & 0xffff;
  530. break;
  531. default:
  532. break;
  533. }
  534. }
  535. if (num_smt == -1 || num_core == -1) return 0;
  536. data->num_cores = num_core / num_smt;
  537. data->num_logical_cpus = num_core;
  538. return 1;
  539. }
  540. static void decode_intel_number_of_cores(struct cpu_raw_data_t* raw,
  541. struct cpu_id_t* data)
  542. {
  543. int logical_cpus = -1, num_cores = -1;
  544. if (raw->basic_cpuid[0][0] >= 11) {
  545. if (decode_intel_extended_topology(raw, data)) return;
  546. }
  547. if (raw->basic_cpuid[0][0] >= 1) {
  548. logical_cpus = (raw->basic_cpuid[1][1] >> 16) & 0xff;
  549. if (raw->basic_cpuid[0][0] >= 4) {
  550. num_cores = 1 + ((raw->basic_cpuid[4][0] >> 26) & 0x3f);
  551. }
  552. }
  553. if (data->flags[CPU_FEATURE_HT]) {
  554. if (num_cores > 1) {
  555. data->num_cores = num_cores;
  556. data->num_logical_cpus = logical_cpus;
  557. } else {
  558. data->num_cores = 1;
  559. data->num_logical_cpus = (logical_cpus >= 2 ? logical_cpus : 2);
  560. }
  561. } else {
  562. data->num_cores = data->num_logical_cpus = 1;
  563. }
  564. }
  565. static intel_code_t get_brand_code(struct cpu_id_t* data)
  566. {
  567. intel_code_t code = NO_CODE;
  568. int i, need_matchtable = 1, core_ix_base = 0;
  569. const char* bs = data->brand_str;
  570. const char* s;
  571. const struct { intel_code_t c; const char *search; } matchtable[] = {
  572. { XEONMP, "Xeon MP" },
  573. { XEONMP, "Xeon(TM) MP" },
  574. { XEON, "Xeon" },
  575. { CELERON, "Celeron" },
  576. { MOBILE_PENTIUM_M, "Pentium(R) M" },
  577. { CORE_SOLO, "Pentium(R) Dual CPU" },
  578. { PENTIUM_D, "Pentium(R) D" },
  579. { PENTIUM, "Pentium" },
  580. { CORE_SOLO, "Genuine Intel(R) CPU" },
  581. { CORE_SOLO, "Intel(R) Core(TM)" },
  582. { ATOM_DIAMONDVILLE, "Atom(TM) CPU [N ][23]## " },
  583. { ATOM_SILVERTHORNE, "Atom(TM) CPU Z" },
  584. { ATOM_PINEVIEW, "Atom(TM) CPU D" },
  585. { ATOM_CEDARVIEW, "Atom(TM) CPU N####" },
  586. { ATOM, "Atom(TM) CPU" },
  587. };
  588. if (strstr(bs, "Mobile")) {
  589. need_matchtable = 0;
  590. if (strstr(bs, "Celeron"))
  591. code = MOBILE_CELERON;
  592. else if (strstr(bs, "Pentium"))
  593. code = MOBILE_PENTIUM;
  594. }
  595. if ((i = match_pattern(bs, "Core(TM) i[357]")) != 0) {
  596. /* Core i3, Core i5 or Core i7 */
  597. need_matchtable = 0;
  598. core_ix_base = CORE_I3;
  599. /* if it has RdRand, then it is at least Ivy Bridge */
  600. if (data->flags[CPU_FEATURE_RDRAND])
  601. core_ix_base = CORE_IVY3;
  602. /* if it has FMA, then it is at least Haswell */
  603. if (data->flags[CPU_FEATURE_FMA3])
  604. core_ix_base = CORE_HASWELL3;
  605. switch (bs[i + 9]) {
  606. case '3': code = core_ix_base + 0; break;
  607. case '5': code = core_ix_base + 1; break;
  608. case '7': code = core_ix_base + 2; break;
  609. }
  610. }
  611. if (need_matchtable) {
  612. for (i = 0; i < COUNT_OF(matchtable); i++)
  613. if (match_pattern(bs, matchtable[i].search)) {
  614. code = matchtable[i].c;
  615. break;
  616. }
  617. debugf(2, "intel matchtable result is %d\n", code);
  618. }
  619. if (code == XEON) {
  620. if (match_pattern(bs, "W35##") || match_pattern(bs, "[ELXW]75##"))
  621. code = XEON_I7;
  622. else if (match_pattern(bs, "[ELXW]55##"))
  623. code = XEON_GAINESTOWN;
  624. else if (match_pattern(bs, "[ELXW]56##"))
  625. code = XEON_WESTMERE;
  626. else if (data->l3_cache > 0 && data->family == 16)
  627. /* restrict by family, since later Xeons also have L3 ... */
  628. code = XEON_IRWIN;
  629. }
  630. if (code == XEONMP && data->l3_cache > 0)
  631. code = XEON_POTOMAC;
  632. if (code == CORE_SOLO) {
  633. s = strstr(bs, "CPU");
  634. if (s) {
  635. s += 3;
  636. while (*s == ' ') s++;
  637. if (*s == 'T')
  638. code = (data->num_cores == 1) ? MOBILE_CORE_SOLO : MOBILE_CORE_DUO;
  639. }
  640. }
  641. if (code == CORE_SOLO) {
  642. switch (data->num_cores) {
  643. case 1: break;
  644. case 2:
  645. {
  646. code = CORE_DUO;
  647. if (data->num_logical_cpus > 2)
  648. code = DUAL_CORE_HT;
  649. break;
  650. }
  651. case 4:
  652. {
  653. code = QUAD_CORE;
  654. if (data->num_logical_cpus > 4)
  655. code = QUAD_CORE_HT;
  656. break;
  657. }
  658. default:
  659. code = MORE_THAN_QUADCORE; break;
  660. }
  661. }
  662. if (code == CORE_DUO && data->ext_model >= 23) {
  663. code = WOLFDALE;
  664. }
  665. if (code == PENTIUM_D && data->ext_model >= 23) {
  666. code = WOLFDALE;
  667. }
  668. if (code == MOBILE_CORE_DUO && data->model != 14) {
  669. if (data->ext_model < 23) {
  670. code = MEROM;
  671. } else {
  672. code = PENRYN;
  673. }
  674. }
  675. return code;
  676. }
  677. static intel_model_t get_model_code(struct cpu_id_t* data)
  678. {
  679. int i = 0;
  680. int l = (int) strlen(data->brand_str);
  681. const char *bs = data->brand_str;
  682. int mod_flags = 0, model_no = 0, ndigs = 0;
  683. /* If the CPU is a Core ix, then just return the model number generation: */
  684. if ((i = match_pattern(bs, "Core(TM) i[357]")) != 0) {
  685. i += 11;
  686. if (i + 4 >= l) return UNKNOWN;
  687. if (bs[i] == '2') return _2xxx;
  688. if (bs[i] == '3') return _3xxx;
  689. return UNKNOWN;
  690. }
  691. /* For Core2-based Xeons: */
  692. while (i < l - 3) {
  693. if (bs[i] == 'C' && bs[i+1] == 'P' && bs[i+2] == 'U')
  694. break;
  695. i++;
  696. }
  697. if (i >= l - 3) return UNKNOWN;
  698. i += 3;
  699. while (i < l - 4 && bs[i] == ' ') i++;
  700. if (i >= l - 4) return UNKNOWN;
  701. while (i < l - 4 && !isdigit(bs[i])) {
  702. if (bs[i] >= 'A' && bs[i] <= 'Z')
  703. mod_flags |= (1 << (bs[i] - 'A'));
  704. i++;
  705. }
  706. if (i >= l - 4) return UNKNOWN;
  707. while (isdigit(bs[i])) {
  708. ndigs++;
  709. model_no = model_no * 10 + (int) (bs[i] - '0');
  710. i++;
  711. }
  712. if (ndigs != 4) return UNKNOWN;
  713. #define HAVE(ch, flags) ((flags & (1 << ((int)(ch-'A')))) != 0)
  714. switch (model_no / 100) {
  715. case 30: return _3000;
  716. case 31: return _3100;
  717. case 32:
  718. {
  719. return (HAVE('X', mod_flags)) ? X3200 : _3200;
  720. }
  721. case 33:
  722. {
  723. return (HAVE('X', mod_flags)) ? X3300 : _3300;
  724. }
  725. case 51: return _5100;
  726. case 52: return _5200;
  727. case 53: return _5300;
  728. case 54: return _5400;
  729. default:
  730. return UNKNOWN;
  731. }
  732. #undef HAVE
  733. }
  734. int cpuid_identify_intel(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
  735. {
  736. load_intel_features(raw, data);
  737. if (raw->basic_cpuid[0][0] >= 4) {
  738. /* Deterministic way is preferred, being more generic */
  739. decode_intel_deterministic_cache_info(raw, data);
  740. } else if (raw->basic_cpuid[0][0] >= 2) {
  741. decode_intel_oldstyle_cache_info(raw, data);
  742. }
  743. decode_intel_number_of_cores(raw, data);
  744. match_cpu_codename(cpudb_intel, COUNT_OF(cpudb_intel), data,
  745. get_brand_code(data), get_model_code(data));
  746. return 0;
  747. }
  748. void cpuid_get_list_intel(struct cpu_list_t* list)
  749. {
  750. generic_get_cpu_list(cpudb_intel, COUNT_OF(cpudb_intel), list);
  751. }