recog_amd.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  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 <stdio.h>
  27. #include <string.h>
  28. #include <ctype.h>
  29. #include "libcpuid.h"
  30. #include "libcpuid_util.h"
  31. #include "libcpuid_internal.h"
  32. #include "recog_amd.h"
  33. const struct amd_code_str { amd_code_t code; char *str; } amd_code_str[] = {
  34. #define CODE(x) { x, #x }
  35. #define CODE2(x, y) CODE(x)
  36. #include "amd_code_t.h"
  37. #undef CODE
  38. };
  39. struct amd_code_and_bits_t {
  40. int code;
  41. uint64_t bits;
  42. };
  43. enum _amd_model_codes_t {
  44. // Only for Ryzen CPUs:
  45. _1400,
  46. _1500,
  47. _1600,
  48. _1900,
  49. _2400,
  50. _2500,
  51. _2700,
  52. };
  53. const struct match_entry_t cpudb_amd[] = {
  54. { -1, -1, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Unknown AMD CPU" },
  55. /* 486 and the likes */
  56. { 4, -1, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Unknown AMD 486" },
  57. { 4, 3, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "AMD 486DX2" },
  58. { 4, 7, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "AMD 486DX2WB" },
  59. { 4, 8, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "AMD 486DX4" },
  60. { 4, 9, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "AMD 486DX4WB" },
  61. /* Pentia clones */
  62. { 5, -1, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Unknown AMD 586" },
  63. { 5, 0, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "K5" },
  64. { 5, 1, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "K5" },
  65. { 5, 2, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "K5" },
  66. { 5, 3, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "K5" },
  67. /* The K6 */
  68. { 5, 6, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "K6" },
  69. { 5, 7, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "K6" },
  70. { 5, 8, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "K6-2" },
  71. { 5, 9, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "K6-III" },
  72. { 5, 10, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Unknown K6" },
  73. { 5, 11, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Unknown K6" },
  74. { 5, 12, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Unknown K6" },
  75. { 5, 13, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "K6-2+" },
  76. /* Athlon et al. */
  77. { 6, 1, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Athlon (Slot-A)" },
  78. { 6, 2, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Athlon (Slot-A)" },
  79. { 6, 3, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Duron (Spitfire)" },
  80. { 6, 4, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Athlon (ThunderBird)" },
  81. { 6, 6, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Unknown Athlon" },
  82. { 6, 6, -1, -1, -1, 1, -1, -1, NC, ATHLON_ , 0, "Athlon (Palomino)" },
  83. { 6, 6, -1, -1, -1, 1, -1, -1, NC, ATHLON_|_MP_ , 0, "Athlon MP (Palomino)" },
  84. { 6, 6, -1, -1, -1, 1, -1, -1, NC, DURON_ , 0, "Duron (Palomino)" },
  85. { 6, 6, -1, -1, -1, 1, -1, -1, NC, ATHLON_|_XP_ , 0, "Athlon XP" },
  86. { 6, 7, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Unknown Athlon XP" },
  87. { 6, 7, -1, -1, -1, 1, -1, -1, NC, DURON_ , 0, "Duron (Morgan)" },
  88. { 6, 8, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Athlon XP" },
  89. { 6, 8, -1, -1, -1, 1, -1, -1, NC, ATHLON_ , 0, "Athlon XP (Thoroughbred)" },
  90. { 6, 8, -1, -1, -1, 1, -1, -1, NC, ATHLON_|_XP_ , 0, "Athlon XP (Thoroughbred)" },
  91. { 6, 8, -1, -1, -1, 1, -1, -1, NC, DURON_ , 0, "Duron (Applebred)" },
  92. { 6, 8, -1, -1, -1, 1, -1, -1, NC, SEMPRON_ , 0, "Sempron (Thoroughbred)" },
  93. { 6, 8, -1, -1, -1, 1, 128, -1, NC, SEMPRON_ , 0, "Sempron (Thoroughbred)" },
  94. { 6, 8, -1, -1, -1, 1, 256, -1, NC, SEMPRON_ , 0, "Sempron (Thoroughbred)" },
  95. { 6, 8, -1, -1, -1, 1, -1, -1, NC, ATHLON_|_MP_ , 0, "Athlon MP (Thoroughbred)" },
  96. { 6, 8, -1, -1, -1, 1, -1, -1, NC, ATHLON_|_XP_|_M_ , 0, "Mobile Athlon (T-Bred)" },
  97. { 6, 8, -1, -1, -1, 1, -1, -1, NC, ATHLON_|_XP_|_M_|_LV_, 0, "Mobile Athlon (T-Bred)" },
  98. { 6, 10, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Athlon XP (Barton)" },
  99. { 6, 10, -1, -1, -1, 1, 512, -1, NC, ATHLON_|_XP_ , 0, "Athlon XP (Barton)" },
  100. { 6, 10, -1, -1, -1, 1, 512, -1, NC, SEMPRON_ , 0, "Sempron (Barton)" },
  101. { 6, 10, -1, -1, -1, 1, 256, -1, NC, SEMPRON_ , 0, "Sempron (Thorton)" },
  102. { 6, 10, -1, -1, -1, 1, 256, -1, NC, ATHLON_|_XP_ , 0, "Athlon XP (Thorton)" },
  103. { 6, 10, -1, -1, -1, 1, -1, -1, NC, ATHLON_|_MP_ , 0, "Athlon MP (Barton)" },
  104. { 6, 10, -1, -1, -1, 1, -1, -1, NC, ATHLON_|_XP_|_M_ , 0, "Mobile Athlon (Barton)" },
  105. { 6, 10, -1, -1, -1, 1, -1, -1, NC, ATHLON_|_XP_|_M_|_LV_, 0, "Mobile Athlon (Barton)" },
  106. /* K8 Architecture */
  107. { 15, -1, -1, 15, -1, 1, -1, -1, NC, 0 , 0, "Unknown K8" },
  108. { 15, -1, -1, 16, -1, 1, -1, -1, NC, 0 , 0, "Unknown K9" },
  109. { 15, -1, -1, 15, -1, 1, -1, -1, NC, 0 , 0, "Unknown A64" },
  110. { 15, -1, -1, 15, -1, 1, -1, -1, NC, OPTERON_ , 0, "Opteron" },
  111. { 15, -1, -1, 15, -1, 2, -1, -1, NC, OPTERON_|_X2 , 0, "Opteron (Dual Core)" },
  112. { 15, 3, -1, 15, -1, 1, -1, -1, NC, OPTERON_ , 0, "Opteron" },
  113. { 15, 3, -1, 15, -1, 2, -1, -1, NC, OPTERON_|_X2 , 0, "Opteron (Dual Core)" },
  114. { 15, -1, -1, 15, -1, 1, 512, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (512K)" },
  115. { 15, -1, -1, 15, -1, 1, 1024, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (1024K)" },
  116. { 15, -1, -1, 15, -1, 1, -1, -1, NC, ATHLON_|_FX , 0, "Athlon FX" },
  117. { 15, -1, -1, 15, -1, 1, -1, -1, NC, ATHLON_|_64_|_FX , 0, "Athlon 64 FX" },
  118. { 15, 3, -1, 15, 35, 2, -1, -1, NC, ATHLON_|_64_|_FX , 0, "Athlon 64 FX X2 (Toledo)" },
  119. { 15, -1, -1, 15, -1, 2, 512, -1, NC, ATHLON_|_64_|_X2 , 0, "Athlon 64 X2 (512K)" },
  120. { 15, -1, -1, 15, -1, 2, 1024, -1, NC, ATHLON_|_64_|_X2 , 0, "Athlon 64 X2 (1024K)" },
  121. { 15, -1, -1, 15, -1, 1, 512, -1, NC, TURION_|_64_ , 0, "Turion 64 (512K)" },
  122. { 15, -1, -1, 15, -1, 1, 1024, -1, NC, TURION_|_64_ , 0, "Turion 64 (1024K)" },
  123. { 15, -1, -1, 15, -1, 2, 512, -1, NC, TURION_|_X2 , 0, "Turion 64 X2 (512K)" },
  124. { 15, -1, -1, 15, -1, 2, 1024, -1, NC, TURION_|_X2 , 0, "Turion 64 X2 (1024K)" },
  125. { 15, -1, -1, 15, -1, 1, 128, -1, NC, SEMPRON_ , 0, "A64 Sempron (128K)" },
  126. { 15, -1, -1, 15, -1, 1, 256, -1, NC, SEMPRON_ , 0, "A64 Sempron (256K)" },
  127. { 15, -1, -1, 15, -1, 1, 512, -1, NC, SEMPRON_ , 0, "A64 Sempron (512K)" },
  128. { 15, -1, -1, 15, 0x4f, 1, 512, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (Orleans/512K)" },
  129. { 15, -1, -1, 15, 0x5f, 1, 512, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (Orleans/512K)" },
  130. { 15, -1, -1, 15, 0x2f, 1, 512, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (Venice/512K)" },
  131. { 15, -1, -1, 15, 0x2c, 1, 512, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (Venice/512K)" },
  132. { 15, -1, -1, 15, 0x1f, 1, 512, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (Winchester/512K)" },
  133. { 15, -1, -1, 15, 0x0c, 1, 512, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (Newcastle/512K)" },
  134. { 15, -1, -1, 15, 0x27, 1, 512, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (San Diego/512K)" },
  135. { 15, -1, -1, 15, 0x37, 1, 512, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (San Diego/512K)" },
  136. { 15, -1, -1, 15, 0x04, 1, 512, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (ClawHammer/512K)" },
  137. { 15, -1, -1, 15, 0x5f, 1, 1024, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (Orleans/1024K)" },
  138. { 15, -1, -1, 15, 0x27, 1, 1024, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (San Diego/1024K)" },
  139. { 15, -1, -1, 15, 0x04, 1, 1024, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (ClawHammer/1024K)" },
  140. { 15, -1, -1, 15, 0x4b, 2, 256, -1, NC, SEMPRON_ , 0, "Athlon 64 X2 (Windsor/256K)" },
  141. { 15, -1, -1, 15, 0x23, 2, 512, -1, NC, ATHLON_|_64_|_X2 , 0, "Athlon 64 X2 (Toledo/512K)" },
  142. { 15, -1, -1, 15, 0x4b, 2, 512, -1, NC, ATHLON_|_64_|_X2 , 0, "Athlon 64 X2 (Windsor/512K)" },
  143. { 15, -1, -1, 15, 0x43, 2, 512, -1, NC, ATHLON_|_64_|_X2 , 0, "Athlon 64 X2 (Windsor/512K)" },
  144. { 15, -1, -1, 15, 0x6b, 2, 512, -1, NC, ATHLON_|_64_|_X2 , 0, "Athlon 64 X2 (Brisbane/512K)" },
  145. { 15, -1, -1, 15, 0x2b, 2, 512, -1, NC, ATHLON_|_64_|_X2 , 0, "Athlon 64 X2 (Manchester/512K)"},
  146. { 15, -1, -1, 15, 0x23, 2, 1024, -1, NC, ATHLON_|_64_|_X2 , 0, "Athlon 64 X2 (Toledo/1024K)" },
  147. { 15, -1, -1, 15, 0x43, 2, 1024, -1, NC, ATHLON_|_64_|_X2 , 0, "Athlon 64 X2 (Windsor/1024K)" },
  148. { 15, -1, -1, 15, 0x08, 1, 128, -1, NC, MOBILE_|SEMPRON_ , 0, "Mobile Sempron 64 (Dublin/128K)"},
  149. { 15, -1, -1, 15, 0x08, 1, 256, -1, NC, MOBILE_|SEMPRON_ , 0, "Mobile Sempron 64 (Dublin/256K)"},
  150. { 15, -1, -1, 15, 0x0c, 1, 256, -1, NC, SEMPRON_ , 0, "Sempron 64 (Paris)" },
  151. { 15, -1, -1, 15, 0x1c, 1, 128, -1, NC, SEMPRON_ , 0, "Sempron 64 (Palermo/128K)" },
  152. { 15, -1, -1, 15, 0x1c, 1, 256, -1, NC, SEMPRON_ , 0, "Sempron 64 (Palermo/256K)" },
  153. { 15, -1, -1, 15, 0x1c, 1, 128, -1, NC, MOBILE_| SEMPRON_ , 0, "Mobile Sempron 64 (Sonora/128K)"},
  154. { 15, -1, -1, 15, 0x1c, 1, 256, -1, NC, MOBILE_| SEMPRON_ , 0, "Mobile Sempron 64 (Sonora/256K)"},
  155. { 15, -1, -1, 15, 0x2c, 1, 128, -1, NC, SEMPRON_ , 0, "Sempron 64 (Palermo/128K)" },
  156. { 15, -1, -1, 15, 0x2c, 1, 256, -1, NC, SEMPRON_ , 0, "Sempron 64 (Palermo/256K)" },
  157. { 15, -1, -1, 15, 0x2c, 1, 128, -1, NC, MOBILE_| SEMPRON_ , 0, "Mobile Sempron 64 (Albany/128K)"},
  158. { 15, -1, -1, 15, 0x2c, 1, 256, -1, NC, MOBILE_| SEMPRON_ , 0, "Mobile Sempron 64 (Albany/256K)"},
  159. { 15, -1, -1, 15, 0x2f, 1, 128, -1, NC, SEMPRON_ , 0, "Sempron 64 (Palermo/128K)" },
  160. { 15, -1, -1, 15, 0x2f, 1, 256, -1, NC, SEMPRON_ , 0, "Sempron 64 (Palermo/256K)" },
  161. { 15, -1, -1, 15, 0x4f, 1, 128, -1, NC, SEMPRON_ , 0, "Sempron 64 (Manila/128K)" },
  162. { 15, -1, -1, 15, 0x4f, 1, 256, -1, NC, SEMPRON_ , 0, "Sempron 64 (Manila/256K)" },
  163. { 15, -1, -1, 15, 0x5f, 1, 128, -1, NC, SEMPRON_ , 0, "Sempron 64 (Manila/128K)" },
  164. { 15, -1, -1, 15, 0x5f, 1, 256, -1, NC, SEMPRON_ , 0, "Sempron 64 (Manila/256K)" },
  165. { 15, -1, -1, 15, 0x6b, 2, 256, -1, NC, SEMPRON_ , 0, "Sempron 64 Dual (Sherman/256K)"},
  166. { 15, -1, -1, 15, 0x6b, 2, 512, -1, NC, SEMPRON_ , 0, "Sempron 64 Dual (Sherman/512K)"},
  167. { 15, -1, -1, 15, 0x7f, 1, 256, -1, NC, SEMPRON_ , 0, "Sempron 64 (Sparta/256K)" },
  168. { 15, -1, -1, 15, 0x7f, 1, 512, -1, NC, SEMPRON_ , 0, "Sempron 64 (Sparta/512K)" },
  169. { 15, -1, -1, 15, 0x4c, 1, 256, -1, NC, MOBILE_| SEMPRON_ , 0, "Mobile Sempron 64 (Keene/256K)"},
  170. { 15, -1, -1, 15, 0x4c, 1, 512, -1, NC, MOBILE_| SEMPRON_ , 0, "Mobile Sempron 64 (Keene/512K)"},
  171. { 15, -1, -1, 15, -1, 2, -1, -1, NC, SEMPRON_ , 0, "Sempron Dual Core" },
  172. { 15, -1, -1, 15, 0x24, 1, 512, -1, NC, TURION_|_64_ , 0, "Turion 64 (Lancaster/512K)" },
  173. { 15, -1, -1, 15, 0x24, 1, 1024, -1, NC, TURION_|_64_ , 0, "Turion 64 (Lancaster/1024K)" },
  174. { 15, -1, -1, 15, 0x48, 2, 256, -1, NC, TURION_|_X2 , 0, "Turion X2 (Taylor)" },
  175. { 15, -1, -1, 15, 0x48, 2, 512, -1, NC, TURION_|_X2 , 0, "Turion X2 (Trinidad)" },
  176. { 15, -1, -1, 15, 0x4c, 1, 512, -1, NC, TURION_|_64_ , 0, "Turion 64 (Richmond)" },
  177. { 15, -1, -1, 15, 0x68, 2, 256, -1, NC, TURION_|_X2 , 0, "Turion X2 (Tyler/256K)" },
  178. { 15, -1, -1, 15, 0x68, 2, 512, -1, NC, TURION_|_X2 , 0, "Turion X2 (Tyler/512K)" },
  179. { 15, -1, -1, 17, 3, 2, 512, -1, NC, TURION_|_X2 , 0, "Turion X2 (Griffin/512K)" },
  180. { 15, -1, -1, 17, 3, 2, 1024, -1, NC, TURION_|_X2 , 0, "Turion X2 (Griffin/1024K)" },
  181. /* K10 Architecture (2007) */
  182. { 15, -1, -1, 16, -1, 1, -1, -1, PHENOM, 0 , 0, "Unknown AMD Phenom" },
  183. { 15, 2, -1, 16, -1, 1, -1, -1, PHENOM, 0 , 0, "Phenom" },
  184. { 15, 2, -1, 16, -1, 3, -1, -1, PHENOM, 0 , 0, "Phenom X3 (Toliman)" },
  185. { 15, 2, -1, 16, -1, 4, -1, -1, PHENOM, 0 , 0, "Phenom X4 (Agena)" },
  186. { 15, 2, -1, 16, -1, 3, 512, -1, PHENOM, 0 , 0, "Phenom X3 (Toliman/256K)" },
  187. { 15, 2, -1, 16, -1, 3, 512, -1, PHENOM, 0 , 0, "Phenom X3 (Toliman/512K)" },
  188. { 15, 2, -1, 16, -1, 4, 128, -1, PHENOM, 0 , 0, "Phenom X4 (Agena/128K)" },
  189. { 15, 2, -1, 16, -1, 4, 256, -1, PHENOM, 0 , 0, "Phenom X4 (Agena/256K)" },
  190. { 15, 2, -1, 16, -1, 4, 512, -1, PHENOM, 0 , 0, "Phenom X4 (Agena/512K)" },
  191. { 15, 2, -1, 16, -1, 2, 512, -1, NC, ATHLON_|_64_|_X2 , 0, "Athlon X2 (Kuma)" },
  192. /* Phenom II derivates: */
  193. { 15, 4, -1, 16, -1, 4, -1, -1, NC, 0 , 0, "Phenom (Deneb-based)" },
  194. { 15, 4, -1, 16, -1, 1, 1024, -1, NC, SEMPRON_ , 0, "Sempron (Sargas)" },
  195. { 15, 4, -1, 16, -1, 2, 512, -1, PHENOM2, 0 , 0, "Phenom II X2 (Callisto)" },
  196. { 15, 4, -1, 16, -1, 3, 512, -1, PHENOM2, 0 , 0, "Phenom II X3 (Heka)" },
  197. { 15, 4, -1, 16, -1, 4, 512, -1, PHENOM2, 0 , 0, "Phenom II X4" },
  198. { 15, 4, -1, 16, 4, 4, 512, -1, PHENOM2, 0 , 0, "Phenom II X4 (Deneb)" },
  199. { 15, 5, -1, 16, 5, 4, 512, -1, PHENOM2, 0 , 0, "Phenom II X4 (Deneb)" },
  200. { 15, 4, -1, 16, 10, 4, 512, -1, PHENOM2, 0 , 0, "Phenom II X4 (Zosma)" },
  201. { 15, 4, -1, 16, 10, 6, 512, -1, PHENOM2, 0 , 0, "Phenom II X6 (Thuban)" },
  202. /* Athlon II derivates: */
  203. { 15, 6, -1, 16, 6, 2, 512, -1, NC, ATHLON_|_X2 , 0, "Athlon II (Champlain)" },
  204. { 15, 6, -1, 16, 6, 2, 512, -1, NC, ATHLON_|_64_|_X2 , 0, "Athlon II X2 (Regor)" },
  205. { 15, 6, -1, 16, 6, 2, 1024, -1, NC, ATHLON_|_64_|_X2 , 0, "Athlon II X2 (Regor)" },
  206. { 15, 5, -1, 16, 5, 3, 512, -1, NC, ATHLON_|_64_|_X3 , 0, "Athlon II X3 (Rana)" },
  207. { 15, 5, -1, 16, 5, 4, 512, -1, NC, ATHLON_|_64_|_X4 , 0, "Athlon II X4 (Propus)" },
  208. /* Llano APUs (2011): */
  209. { 15, 1, -1, 18, 1, 2, -1, -1, FUSION_EA, 0 , 0, "Llano X2" },
  210. { 15, 1, -1, 18, 1, 3, -1, -1, FUSION_EA, 0 , 0, "Llano X3" },
  211. { 15, 1, -1, 18, 1, 4, -1, -1, FUSION_EA, 0 , 0, "Llano X4" },
  212. /* Family 14h: Bobcat Architecture (2011) */
  213. { 15, 2, -1, 20, -1, 1, -1, -1, FUSION_C, 0 , 0, "Brazos Ontario" },
  214. { 15, 2, -1, 20, -1, 2, -1, -1, FUSION_C, 0 , 0, "Brazos Ontario (Dual-core)" },
  215. { 15, 1, -1, 20, -1, 1, -1, -1, FUSION_E, 0 , 0, "Brazos Zacate" },
  216. { 15, 1, -1, 20, -1, 2, -1, -1, FUSION_E, 0 , 0, "Brazos Zacate (Dual-core)" },
  217. { 15, 2, -1, 20, -1, 2, -1, -1, FUSION_Z, 0 , 0, "Brazos Desna (Dual-core)" },
  218. /* Family 15h: Bulldozer Architecture (2011) */
  219. { 15, -1, -1, 21, 0, 4, -1, -1, NC, 0 , 0, "Bulldozer X2" },
  220. { 15, -1, -1, 21, 1, 4, -1, -1, NC, 0 , 0, "Bulldozer X2" },
  221. { 15, -1, -1, 21, 1, 6, -1, -1, NC, 0 , 0, "Bulldozer X3" },
  222. { 15, -1, -1, 21, 1, 8, -1, -1, NC, 0 , 0, "Bulldozer X4" },
  223. /* 2nd-gen, Piledriver core (2012): */
  224. { 15, -1, -1, 21, 2, 4, -1, -1, NC, 0 , 0, "Vishera X2" },
  225. { 15, -1, -1, 21, 2, 6, -1, -1, NC, 0 , 0, "Vishera X3" },
  226. { 15, -1, -1, 21, 2, 8, -1, -1, NC, 0 , 0, "Vishera X4" },
  227. { 15, 0, -1, 21, 16, 2, -1, -1, FUSION_A, 0 , 0, "Trinity X2" },
  228. { 15, 0, -1, 21, 16, 4, -1, -1, FUSION_A, 0 , 0, "Trinity X4" },
  229. { 15, 3, -1, 21, 19, 2, -1, -1, FUSION_A, 0 , 0, "Richland X2" },
  230. { 15, 3, -1, 21, 19, 4, -1, -1, FUSION_A, 0 , 0, "Richland X4" },
  231. /* 3rd-gen, Steamroller core (2014): */
  232. { 15, 0, -1, 21, 48, 2, -1, -1, FUSION_A, 0 , 0, "Kaveri X2" },
  233. { 15, 0, -1, 21, 48, 4, -1, -1, FUSION_A, 0 , 0, "Kaveri X4" },
  234. { 15, 8, -1, 21, 56, 4, -1, -1, FUSION_A, 0 , 0, "Godavari X4" },
  235. /* 4th-gen, Excavator core (2015): */
  236. { 15, 1, -1, 21, 96, 2, -1, -1, FUSION_A, 0 , 0, "Carrizo X2" },
  237. { 15, 1, -1, 21, 96, 4, -1, -1, FUSION_A, 0 , 0, "Carrizo X4" },
  238. { 15, 5, -1, 21, 101, 2, -1, -1, FUSION_A, 0 , 0, "Bristol Ridge X2" },
  239. { 15, 5, -1, 21, 101, 4, -1, -1, FUSION_A, 0 , 0, "Bristol Ridge X4" },
  240. { 15, 0, -1, 21, 112, 2, -1, -1, FUSION_A, 0 , 0, "Stoney Ridge X2" },
  241. { 15, 0, -1, 21, 112, 2, -1, -1, FUSION_E, 0 , 0, "Stoney Ridge X2" },
  242. /* Family 16h: Jaguar Architecture (2013) */
  243. { 15, 0, -1, 22, 0, 2, -1, -1, FUSION_A, 0 , 0, "Kabini X2" },
  244. { 15, 0, -1, 22, 0, 4, -1, -1, FUSION_A, 0 , 0, "Kabini X4" },
  245. /* 2nd-gen, Puma core (2013): */
  246. { 15, 0, -1, 22, 48, 2, -1, -1, FUSION_E, 0 , 0, "Mullins X2" },
  247. { 15, 0, -1, 22, 48, 4, -1, -1, FUSION_A, 0 , 0, "Mullins X4" },
  248. /* Family 17h: Zen Architecture (2017) */
  249. { 15, -1, -1, 23, 1, 16, -1, -1, NC, 0 , 0, "Threadripper (Summit Ridge)" },
  250. { 15, -1, -1, 23, 1, 12, -1, -1, NC, 0 , 0, "Threadripper (Summit Ridge)" },
  251. { 15, -1, -1, 23, 1, 8, -1, -1, NC, 0 , _1900, "Threadripper (Summit Ridge)" },
  252. { 15, -1, -1, 23, 1, 8, -1, -1, NC, 0 , 0, "Ryzen 7 (Summit Ridge)" },
  253. { 15, -1, -1, 23, 1, 6, -1, -1, NC, 0 , _1600, "Ryzen 5 (Summit Ridge)" },
  254. { 15, -1, -1, 23, 1, 4, -1, -1, NC, 0 , _1500, "Ryzen 5 (Summit Ridge)" },
  255. { 15, -1, -1, 23, 1, 4, -1, -1, NC, 0 , _1400, "Ryzen 5 (Summit Ridge)" },
  256. { 15, -1, -1, 23, 1, 4, -1, -1, NC, 0 , 0, "Ryzen 3 (Summit Ridge)" },
  257. /* APUs */
  258. { 15, -1, -1, 23, 17, 4, -1, -1, NC, 0 , _2700, "Ryzen 7 (Raven Ridge)" },
  259. { 15, -1, -1, 23, 17, 4, -1, -1, NC, 0 , _2500, "Ryzen 5 (Raven Ridge)" },
  260. { 15, -1, -1, 23, 17, 4, -1, -1, NC, 0 , _2400, "Ryzen 5 (Raven Ridge)" },
  261. { 15, -1, -1, 23, 17, 4, -1, -1, NC, 0 , 0, "Ryzen 3 (Raven Ridge)" },
  262. { 15, -1, -1, 23, 17, 2, -1, -1, NC, 0 , 0, "Ryzen 3 (Raven Ridge)" },
  263. /* 2nd-gen, Zen+ (2018): TBA */
  264. //{ 15, -1, -1, ??, ??, 8, -1, -1, NC, 0 , 0, "Ryzen 7 (???)" },
  265. //{ 15, -1, -1, ??, ??, 6, -1, -1, NC, 0 , 0, "Ryzen 5 (???)" },
  266. /* Newer Opterons: */
  267. { 15, 9, -1, 22, 9, 8, -1, -1, NC, OPTERON_ , 0, "Magny-Cours Opteron" },
  268. };
  269. static void load_amd_features(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
  270. {
  271. const struct feature_map_t matchtable_edx81[] = {
  272. { 20, CPU_FEATURE_NX },
  273. { 22, CPU_FEATURE_MMXEXT },
  274. { 25, CPU_FEATURE_FXSR_OPT },
  275. { 30, CPU_FEATURE_3DNOWEXT },
  276. { 31, CPU_FEATURE_3DNOW },
  277. };
  278. const struct feature_map_t matchtable_ecx81[] = {
  279. { 1, CPU_FEATURE_CMP_LEGACY },
  280. { 2, CPU_FEATURE_SVM },
  281. { 5, CPU_FEATURE_ABM },
  282. { 6, CPU_FEATURE_SSE4A },
  283. { 7, CPU_FEATURE_MISALIGNSSE },
  284. { 8, CPU_FEATURE_3DNOWPREFETCH },
  285. { 9, CPU_FEATURE_OSVW },
  286. { 10, CPU_FEATURE_IBS },
  287. { 11, CPU_FEATURE_XOP },
  288. { 12, CPU_FEATURE_SKINIT },
  289. { 13, CPU_FEATURE_WDT },
  290. { 16, CPU_FEATURE_FMA4 },
  291. { 21, CPU_FEATURE_TBM },
  292. };
  293. const struct feature_map_t matchtable_edx87[] = {
  294. { 0, CPU_FEATURE_TS },
  295. { 1, CPU_FEATURE_FID },
  296. { 2, CPU_FEATURE_VID },
  297. { 3, CPU_FEATURE_TTP },
  298. { 4, CPU_FEATURE_TM_AMD },
  299. { 5, CPU_FEATURE_STC },
  300. { 6, CPU_FEATURE_100MHZSTEPS },
  301. { 7, CPU_FEATURE_HWPSTATE },
  302. /* id 8 is handled in common */
  303. { 9, CPU_FEATURE_CPB },
  304. { 10, CPU_FEATURE_APERFMPERF },
  305. { 11, CPU_FEATURE_PFI },
  306. { 12, CPU_FEATURE_PA },
  307. };
  308. if (raw->ext_cpuid[0][0] >= 0x80000001) {
  309. match_features(matchtable_edx81, COUNT_OF(matchtable_edx81), raw->ext_cpuid[1][3], data);
  310. match_features(matchtable_ecx81, COUNT_OF(matchtable_ecx81), raw->ext_cpuid[1][2], data);
  311. }
  312. if (raw->ext_cpuid[0][0] >= 0x80000007)
  313. match_features(matchtable_edx87, COUNT_OF(matchtable_edx87), raw->ext_cpuid[7][3], data);
  314. if (raw->ext_cpuid[0][0] >= 0x8000001a) {
  315. /* We have the extended info about SSE unit size */
  316. data->detection_hints[CPU_HINT_SSE_SIZE_AUTH] = 1;
  317. data->sse_size = (raw->ext_cpuid[0x1a][0] & 1) ? 128 : 64;
  318. }
  319. }
  320. static void decode_amd_cache_info(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
  321. {
  322. int l3_result;
  323. const int assoc_table[16] = {
  324. 0, 1, 2, 0, 4, 0, 8, 0, 16, 0, 32, 48, 64, 96, 128, 255
  325. };
  326. unsigned n = raw->ext_cpuid[0][0];
  327. if (n >= 0x80000005) {
  328. data->l1_data_cache = (raw->ext_cpuid[5][2] >> 24) & 0xff;
  329. data->l1_assoc = (raw->ext_cpuid[5][2] >> 16) & 0xff;
  330. data->l1_cacheline = (raw->ext_cpuid[5][2]) & 0xff;
  331. data->l1_instruction_cache = (raw->ext_cpuid[5][3] >> 24) & 0xff;
  332. }
  333. if (n >= 0x80000006) {
  334. data->l2_cache = (raw->ext_cpuid[6][2] >> 16) & 0xffff;
  335. data->l2_assoc = assoc_table[(raw->ext_cpuid[6][2] >> 12) & 0xf];
  336. data->l2_cacheline = (raw->ext_cpuid[6][2]) & 0xff;
  337. l3_result = (raw->ext_cpuid[6][3] >> 18);
  338. if (l3_result > 0) {
  339. l3_result = 512 * l3_result; /* AMD spec says it's a range,
  340. but we take the lower bound */
  341. data->l3_cache = l3_result;
  342. data->l3_assoc = assoc_table[(raw->ext_cpuid[6][3] >> 12) & 0xf];
  343. data->l3_cacheline = (raw->ext_cpuid[6][3]) & 0xff;
  344. } else {
  345. data->l3_cache = 0;
  346. }
  347. }
  348. }
  349. static void decode_amd_number_of_cores(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
  350. {
  351. int logical_cpus = -1, num_cores = -1;
  352. if (raw->basic_cpuid[0][0] >= 1) {
  353. logical_cpus = (raw->basic_cpuid[1][1] >> 16) & 0xff;
  354. if (raw->ext_cpuid[0][0] >= 8) {
  355. num_cores = 1 + (raw->ext_cpuid[8][2] & 0xff);
  356. }
  357. }
  358. if (data->flags[CPU_FEATURE_HT]) {
  359. if (num_cores > 1) {
  360. if (data->ext_family >= 23)
  361. num_cores /= 2; // e.g., Ryzen 7 reports 16 "real" cores, but they are really just 8.
  362. data->num_cores = num_cores;
  363. data->num_logical_cpus = logical_cpus;
  364. } else {
  365. data->num_cores = 1;
  366. data->num_logical_cpus = (logical_cpus >= 2 ? logical_cpus : 2);
  367. }
  368. } else {
  369. data->num_cores = data->num_logical_cpus = 1;
  370. }
  371. }
  372. static int amd_has_turion_modelname(const char *bs)
  373. {
  374. /* We search for something like TL-60. Ahh, I miss regexes...*/
  375. int i, l, k;
  376. char code[3] = {0};
  377. const char* codes[] = { "ML", "MT", "MK", "TK", "TL", "RM", "ZM", "" };
  378. l = (int) strlen(bs);
  379. for (i = 3; i < l - 2; i++) {
  380. if (bs[i] == '-' &&
  381. isupper(bs[i-1]) && isupper(bs[i-2]) && !isupper(bs[i-3]) &&
  382. isdigit(bs[i+1]) && isdigit(bs[i+2]) && !isdigit(bs[i+3]))
  383. {
  384. code[0] = bs[i-2];
  385. code[1] = bs[i-1];
  386. for (k = 0; codes[k][0]; k++)
  387. if (!strcmp(codes[k], code)) return 1;
  388. }
  389. }
  390. return 0;
  391. }
  392. static struct amd_code_and_bits_t decode_amd_codename_part1(const char *bs)
  393. {
  394. amd_code_t code = NC;
  395. uint64_t bits = 0;
  396. struct amd_code_and_bits_t result;
  397. if (strstr(bs, "Dual Core") ||
  398. strstr(bs, "Dual-Core") ||
  399. strstr(bs, " X2 "))
  400. bits |= _X2;
  401. if (strstr(bs, " X4 ")) bits |= _X4;
  402. if (strstr(bs, " X3 ")) bits |= _X3;
  403. if (strstr(bs, "Opteron")) bits |= OPTERON_;
  404. if (strstr(bs, "Phenom")) {
  405. code = (strstr(bs, "II")) ? PHENOM2 : PHENOM;
  406. }
  407. if (amd_has_turion_modelname(bs)) {
  408. bits |= TURION_;
  409. }
  410. if (strstr(bs, "Athlon(tm)")) bits |= ATHLON_;
  411. if (strstr(bs, "Sempron(tm)")) bits |= SEMPRON_;
  412. if (strstr(bs, "Duron")) bits |= DURON_;
  413. if (strstr(bs, " 64 ")) bits |= _64_;
  414. if (strstr(bs, " FX")) bits |= _FX;
  415. if (strstr(bs, " MP")) bits |= _MP_;
  416. if (strstr(bs, "Athlon(tm) 64") || strstr(bs, "Athlon(tm) II X") || match_pattern(bs, "Athlon(tm) X#")) {
  417. bits |= ATHLON_ | _64_;
  418. }
  419. if (strstr(bs, "Turion")) bits |= TURION_;
  420. if (strstr(bs, "mobile") || strstr(bs, "Mobile")) {
  421. bits |= MOBILE_;
  422. }
  423. if (strstr(bs, "XP")) bits |= _XP_;
  424. if (strstr(bs, "XP-M")) bits |= _M_;
  425. if (strstr(bs, "(LV)")) bits |= _LV_;
  426. if (strstr(bs, " APU ")) bits |= _APU_;
  427. if (match_pattern(bs, "C-##")) code = FUSION_C;
  428. if (match_pattern(bs, "E-###")) code = FUSION_E;
  429. if (match_pattern(bs, "Z-##")) code = FUSION_Z;
  430. if (match_pattern(bs, "[EA]#-####")) code = FUSION_EA;
  431. result.code = code;
  432. result.bits = bits;
  433. return result;
  434. }
  435. static int decode_amd_ryzen_model_code(const char* bs)
  436. {
  437. const struct {
  438. int model_code;
  439. const char* match_str;
  440. } patterns[] = {
  441. { _2700, "2700" },
  442. { _2500, "2500" },
  443. { _2400, "2400" },
  444. { _1900, "1900" },
  445. { _1600, "1600" },
  446. { _1500, "1500" },
  447. { _1400, "1400" },
  448. };
  449. int i;
  450. for (i = 0; i < COUNT_OF(patterns); i++)
  451. if (strstr(bs, patterns[i].match_str))
  452. return patterns[i].model_code;
  453. //
  454. return 0;
  455. }
  456. static void decode_amd_codename(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct internal_id_info_t* internal)
  457. {
  458. struct amd_code_and_bits_t code_and_bits = decode_amd_codename_part1(data->brand_str);
  459. int i = 0;
  460. char* code_str = NULL;
  461. int model_code;
  462. for (i = 0; i < COUNT_OF(amd_code_str); i++) {
  463. if (code_and_bits.code == amd_code_str[i].code) {
  464. code_str = amd_code_str[i].str;
  465. break;
  466. }
  467. }
  468. if (/*code == ATHLON_64_X2*/ match_all(code_and_bits.bits, ATHLON_|_64_|_X2) && data->l2_cache < 512) {
  469. code_and_bits.bits &= ~(ATHLON_ | _64_);
  470. code_and_bits.bits |= SEMPRON_;
  471. }
  472. if (code_str)
  473. debugf(2, "Detected AMD brand code: %d (%s)\n", code_and_bits.code, code_str);
  474. else
  475. debugf(2, "Detected AMD brand code: %d\n", code_and_bits.code);
  476. if (code_and_bits.bits) {
  477. debugf(2, "Detected AMD bits: ");
  478. debug_print_lbits(2, code_and_bits.bits);
  479. }
  480. // is it Ryzen? if so, we need to detect discern between the four-core 1400/1500 (Ryzen 5) and the four-core Ryzen 3:
  481. model_code = (data->ext_family == 23) ? decode_amd_ryzen_model_code(data->brand_str) : 0;
  482. internal->code.amd = code_and_bits.code;
  483. internal->bits = code_and_bits.bits;
  484. internal->score = match_cpu_codename(cpudb_amd, COUNT_OF(cpudb_amd), data, code_and_bits.code,
  485. code_and_bits.bits, model_code);
  486. }
  487. int cpuid_identify_amd(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct internal_id_info_t* internal)
  488. {
  489. load_amd_features(raw, data);
  490. decode_amd_cache_info(raw, data);
  491. decode_amd_number_of_cores(raw, data);
  492. decode_amd_codename(raw, data, internal);
  493. return 0;
  494. }
  495. void cpuid_get_list_amd(struct cpu_list_t* list)
  496. {
  497. generic_get_cpu_list(cpudb_amd, COUNT_OF(cpudb_amd), list);
  498. }