cpuid_tool.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725
  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. /**
  27. * @page cpuid_tool
  28. * @date 2008-11-19
  29. * @author Veselin Georgiev
  30. * @brief Command line interface to libcpuid
  31. *
  32. * @details
  33. * This file is provides a direct interface to libcpuid. See the usage()
  34. * function (or just run the program with the `--help' switch) for a short
  35. * command line options reference.
  36. *
  37. * This file has several purposes:
  38. *
  39. * 1. When started with no arguments, the program outputs the RAW and decoded
  40. * CPU data to files (`raw.txt' and `report.txt', respectively) - this is
  41. * intended to be a dumb, doubleclicky tool for non-developer
  42. * users, that can provide debug info about unrecognized processors to
  43. * libcpuid developers.
  44. * 2. When operated from the terminal with the `--report' option, it is a
  45. * generic CPU-info utility.
  46. * 3. Can be used in shell scripts, e.g. to get the name of the CPU, cache
  47. * sizes, features, with query options like `--cache', `--brandstr', etc.
  48. * 4. Finally, it serves to self-document libcpiud itself :)
  49. */
  50. #include <stdio.h>
  51. #include <string.h>
  52. #include <stdlib.h>
  53. #include "libcpuid.h"
  54. /* Globals: */
  55. char raw_data_file[256] = "";
  56. char out_file[256] = "";
  57. typedef enum {
  58. NEED_CPUID_PRESENT,
  59. NEED_VENDOR_STR,
  60. NEED_VENDOR_ID,
  61. NEED_BRAND_STRING,
  62. NEED_FAMILY,
  63. NEED_MODEL,
  64. NEED_STEPPING,
  65. NEED_EXT_FAMILY,
  66. NEED_EXT_MODEL,
  67. NEED_NUM_CORES,
  68. NEED_NUM_LOGICAL,
  69. NEED_TOTAL_CPUS,
  70. NEED_L1D_SIZE,
  71. NEED_L1I_SIZE,
  72. NEED_L2_SIZE,
  73. NEED_L3_SIZE,
  74. NEED_L4_SIZE,
  75. NEED_L1D_ASSOC,
  76. NEED_L2_ASSOC,
  77. NEED_L3_ASSOC,
  78. NEED_L4_ASSOC,
  79. NEED_L1D_CACHELINE,
  80. NEED_L2_CACHELINE,
  81. NEED_L3_CACHELINE,
  82. NEED_L4_CACHELINE,
  83. NEED_CODENAME,
  84. NEED_FEATURES,
  85. NEED_CLOCK,
  86. NEED_CLOCK_OS,
  87. NEED_CLOCK_RDTSC,
  88. NEED_CLOCK_IC,
  89. NEED_RDMSR,
  90. NEED_RDMSR_RAW,
  91. NEED_SSE_UNIT_SIZE,
  92. } output_data_switch;
  93. int need_input = 0,
  94. need_output = 0,
  95. need_quiet = 0,
  96. need_report = 0,
  97. need_clockreport = 0,
  98. need_timed_clockreport = 0,
  99. verbose_level = 0,
  100. need_version = 0,
  101. need_cpulist = 0,
  102. need_sgx = 0,
  103. need_identify = 0;
  104. #define MAX_REQUESTS 32
  105. int num_requests = 0;
  106. output_data_switch requests[MAX_REQUESTS];
  107. FILE *fout;
  108. const struct { output_data_switch sw; const char* synopsis; int ident_required; }
  109. matchtable[] = {
  110. { NEED_CPUID_PRESENT, "--cpuid" , 0},
  111. { NEED_VENDOR_STR , "--vendorstr" , 1},
  112. { NEED_VENDOR_ID , "--vendorid" , 1},
  113. { NEED_BRAND_STRING , "--brandstr" , 1},
  114. { NEED_FAMILY , "--family" , 1},
  115. { NEED_MODEL , "--model" , 1},
  116. { NEED_STEPPING , "--stepping" , 1},
  117. { NEED_EXT_FAMILY , "--extfamily" , 1},
  118. { NEED_EXT_MODEL , "--extmodel" , 1},
  119. { NEED_NUM_CORES , "--cores" , 1},
  120. { NEED_NUM_LOGICAL , "--logical" , 1},
  121. { NEED_TOTAL_CPUS , "--total-cpus" , 1},
  122. { NEED_L1D_SIZE , "--l1d-cache" , 1},
  123. { NEED_L1I_SIZE , "--l1i-cache" , 1},
  124. { NEED_L2_SIZE , "--cache" , 1},
  125. { NEED_L2_SIZE , "--l2-cache" , 1},
  126. { NEED_L3_SIZE , "--l3-cache" , 1},
  127. { NEED_L4_SIZE , "--l4-cache" , 1},
  128. { NEED_L1D_ASSOC , "--l1d-assoc" , 1},
  129. { NEED_L2_ASSOC , "--l2-assoc" , 1},
  130. { NEED_L3_ASSOC , "--l3-assoc" , 1},
  131. { NEED_L4_ASSOC , "--l4-assoc" , 1},
  132. { NEED_L1D_CACHELINE, "--l1d-cacheline", 1},
  133. { NEED_L2_CACHELINE , "--l2-cacheline" , 1},
  134. { NEED_L3_CACHELINE , "--l3-cacheline" , 1},
  135. { NEED_L4_CACHELINE , "--l4-cacheline" , 1},
  136. { NEED_CODENAME , "--codename" , 1},
  137. { NEED_FEATURES , "--flags" , 1},
  138. { NEED_CLOCK , "--clock" , 0},
  139. { NEED_CLOCK_OS , "--clock-os" , 0},
  140. { NEED_CLOCK_RDTSC , "--clock-rdtsc" , 1},
  141. { NEED_CLOCK_IC , "--clock-ic" , 1},
  142. { NEED_RDMSR , "--rdmsr" , 0},
  143. { NEED_RDMSR_RAW , "--rdmsr-raw" , 0},
  144. { NEED_SSE_UNIT_SIZE, "--sse-size" , 1},
  145. };
  146. const int sz_match = (sizeof(matchtable) / sizeof(matchtable[0]));
  147. /* functions */
  148. static void usage(void)
  149. {
  150. int line_fill, l, i;
  151. printf("Usage: cpuid_tool [options]\n\n");
  152. printf("Options:\n");
  153. printf(" -h, --help - Show this help\n");
  154. printf(" --load=<file> - Load raw CPUID data from file\n");
  155. printf(" --save=<file> - Aquire raw CPUID data and write it to file\n");
  156. printf(" --report, --all - Report all decoded CPU info (w/o clock)\n");
  157. printf(" --clock - in conjunction to --report: print CPU clock as well\n");
  158. printf(" --clock-rdtsc - same as --clock, but use RDTSC for clock detection\n");
  159. printf(" --cpulist - list all known CPUs\n");
  160. printf(" --sgx - list SGX leaf data, if SGX is supported.\n");
  161. printf(" --quiet - disable warnings\n");
  162. printf(" --outfile=<file> - redirect all output to this file, instead of stdout\n");
  163. printf(" --verbose, -v - be extra verbose (more keys increase verbosiness level)\n");
  164. printf(" --version - print library version\n");
  165. printf("\n");
  166. printf("Query switches (generate 1 line of ouput per switch; in order of appearance):");
  167. line_fill = 80;
  168. for (i = 0; i < sz_match; i++) {
  169. l = (int) strlen(matchtable[i].synopsis);
  170. if (line_fill + l > 76) {
  171. line_fill = 2;
  172. printf("\n ");
  173. }
  174. printf("%s", matchtable[i].synopsis);
  175. if (i < sz_match - 1) {
  176. line_fill += l + 2;
  177. printf(", ");
  178. }
  179. }
  180. printf("\n\n");
  181. printf("If `-' is used for <file>, then stdin/stdout will be used instead of files.\n");
  182. printf("When no options are present, the program behaves as if it was invoked with\n");
  183. printf(" cpuid_tool \"--save=raw.txt --outfile=report.txt --report --verbose\"\n");
  184. }
  185. static int parse_cmdline(int argc, char** argv)
  186. {
  187. #define xerror(msg)\
  188. fprintf(stderr, "Error: %s\n\n", msg); \
  189. fprintf(stderr, "Use -h to get a list of supported options\n"); \
  190. return -1;
  191. int i, j, recog, num_vs;
  192. if (argc == 1) {
  193. /* Default command line options */
  194. need_output = 1;
  195. strcpy(raw_data_file, "raw.txt");
  196. strcpy(out_file, "report.txt");
  197. need_report = 1;
  198. verbose_level = 1;
  199. return 1;
  200. }
  201. for (i = 1; i < argc; i++) {
  202. char *arg = argv[i];
  203. recog = 0;
  204. if (!strcmp(arg, "-h") || !strcmp(arg, "--help")) {
  205. usage();
  206. return 0;
  207. }
  208. if (!strncmp(arg, "--load=", 7)) {
  209. if (need_input) {
  210. xerror("Too many `--load' options!");
  211. }
  212. if (need_output) {
  213. xerror("Cannot have both `--load' and `--save' options!");
  214. }
  215. if (strlen(arg) <= 7) {
  216. xerror("--load: bad file specification!");
  217. }
  218. need_input = 1;
  219. strcpy(raw_data_file, arg + 7);
  220. recog = 1;
  221. }
  222. if (!strncmp(arg, "--save=", 7)) {
  223. if (need_output) {
  224. xerror("Too many `--save' options!");
  225. }
  226. if (need_input) {
  227. xerror("Cannot have both `--load' and `--save' options!");
  228. }
  229. if (strlen(arg) <= 7) {
  230. xerror("--save: bad file specification!");
  231. }
  232. need_output = 1;
  233. strcpy(raw_data_file, arg + 7);
  234. recog = 1;
  235. }
  236. if (!strncmp(arg, "--outfile=", 10)) {
  237. if (strlen(arg) <= 10) {
  238. xerror("--output: bad file specification!");
  239. }
  240. strcpy(out_file, arg + 10);
  241. recog = 1;
  242. }
  243. if (!strcmp(arg, "--report") || !strcmp(arg, "--all")) {
  244. need_report = 1;
  245. recog = 1;
  246. }
  247. if (!strcmp(arg, "--clock")) {
  248. need_clockreport = 1;
  249. recog = 1;
  250. }
  251. if (!strcmp(arg, "--clock-rdtsc")) {
  252. need_clockreport = 1;
  253. need_timed_clockreport = 1;
  254. recog = 1;
  255. }
  256. if (!strcmp(arg, "--quiet")) {
  257. need_quiet = 1;
  258. recog = 1;
  259. }
  260. if (!strcmp(arg, "--verbose")) {
  261. verbose_level++;
  262. recog = 1;
  263. }
  264. if (!strcmp(arg, "--version")) {
  265. need_version = 1;
  266. recog = 1;
  267. }
  268. if (!strcmp(arg, "--cpulist")) {
  269. need_cpulist = 1;
  270. recog = 1;
  271. }
  272. if (!strcmp(arg, "--sgx")) {
  273. need_sgx = 1;
  274. need_identify = 1;
  275. recog = 1;
  276. }
  277. if (arg[0] == '-' && arg[1] == 'v') {
  278. num_vs = 1;
  279. while (arg[num_vs] == 'v')
  280. num_vs++;
  281. if (arg[num_vs] == '\0') {
  282. verbose_level += num_vs-1;
  283. recog = 1;
  284. }
  285. }
  286. for (j = 0; j < sz_match; j++)
  287. if (!strcmp(arg, matchtable[j].synopsis)) {
  288. if (num_requests >= MAX_REQUESTS) {
  289. xerror("Too many requests!");
  290. }
  291. requests[num_requests++] = matchtable[j].sw;
  292. recog = 1;
  293. break;
  294. }
  295. if (!recog) {
  296. fprintf(stderr, "Unrecognized option: `%s'\n\n", arg);
  297. fprintf(stderr, "Use -h to get a list of supported options\n");
  298. return -1;
  299. }
  300. }
  301. return 1;
  302. }
  303. static void close_out(void)
  304. {
  305. fclose(fout);
  306. }
  307. static int check_need_raw_data(void)
  308. {
  309. int i, j;
  310. if (need_output || need_report || need_identify) return 1;
  311. for (i = 0; i < num_requests; i++) {
  312. for (j = 0; j < sz_match; j++)
  313. if (requests[i] == matchtable[j].sw &&
  314. matchtable[j].ident_required) return 1;
  315. }
  316. return 0;
  317. }
  318. static void print_info(output_data_switch query, struct cpu_raw_data_t* raw,
  319. struct cpu_id_t* data)
  320. {
  321. int i, value;
  322. struct msr_driver_t* handle;
  323. switch (query) {
  324. case NEED_CPUID_PRESENT:
  325. fprintf(fout, "%d\n", cpuid_present());
  326. break;
  327. case NEED_VENDOR_STR:
  328. fprintf(fout, "%s\n", data->vendor_str);
  329. break;
  330. case NEED_VENDOR_ID:
  331. fprintf(fout, "%d\n", data->vendor);
  332. break;
  333. case NEED_BRAND_STRING:
  334. fprintf(fout, "%s\n", data->brand_str);
  335. break;
  336. case NEED_FAMILY:
  337. fprintf(fout, "%d\n", data->family);
  338. break;
  339. case NEED_MODEL:
  340. fprintf(fout, "%d\n", data->model);
  341. break;
  342. case NEED_STEPPING:
  343. fprintf(fout, "%d\n", data->stepping);
  344. break;
  345. case NEED_EXT_FAMILY:
  346. fprintf(fout, "%d\n", data->ext_family);
  347. break;
  348. case NEED_EXT_MODEL:
  349. fprintf(fout, "%d\n", data->ext_model);
  350. break;
  351. case NEED_NUM_CORES:
  352. fprintf(fout, "%d\n", data->num_cores);
  353. break;
  354. case NEED_NUM_LOGICAL:
  355. fprintf(fout, "%d\n", data->num_logical_cpus);
  356. break;
  357. case NEED_TOTAL_CPUS:
  358. fprintf(fout, "%d\n", cpuid_get_total_cpus());
  359. break;
  360. case NEED_L1D_SIZE:
  361. fprintf(fout, "%d\n", data->l1_data_cache);
  362. break;
  363. case NEED_L1I_SIZE:
  364. fprintf(fout, "%d\n", data->l1_instruction_cache);
  365. break;
  366. case NEED_L2_SIZE:
  367. fprintf(fout, "%d\n", data->l2_cache);
  368. break;
  369. case NEED_L3_SIZE:
  370. fprintf(fout, "%d\n", data->l3_cache);
  371. break;
  372. case NEED_L4_SIZE:
  373. fprintf(fout, "%d\n", data->l4_cache);
  374. break;
  375. case NEED_L1D_ASSOC:
  376. fprintf(fout, "%d\n", data->l1_assoc);
  377. break;
  378. case NEED_L2_ASSOC:
  379. fprintf(fout, "%d\n", data->l2_assoc);
  380. break;
  381. case NEED_L3_ASSOC:
  382. fprintf(fout, "%d\n", data->l3_assoc);
  383. break;
  384. case NEED_L4_ASSOC:
  385. fprintf(fout, "%d\n", data->l4_assoc);
  386. break;
  387. case NEED_L1D_CACHELINE:
  388. fprintf(fout, "%d\n", data->l1_cacheline);
  389. break;
  390. case NEED_L2_CACHELINE:
  391. fprintf(fout, "%d\n", data->l2_cacheline);
  392. break;
  393. case NEED_L3_CACHELINE:
  394. fprintf(fout, "%d\n", data->l3_cacheline);
  395. break;
  396. case NEED_L4_CACHELINE:
  397. fprintf(fout, "%d\n", data->l4_cacheline);
  398. break;
  399. case NEED_CODENAME:
  400. fprintf(fout, "%s\n", data->cpu_codename);
  401. break;
  402. case NEED_FEATURES:
  403. {
  404. for (i = 0; i < NUM_CPU_FEATURES; i++)
  405. if (data->flags[i])
  406. fprintf(fout, " %s", cpu_feature_str(i));
  407. fprintf(fout, "\n");
  408. break;
  409. }
  410. case NEED_CLOCK:
  411. fprintf(fout, "%d\n", cpu_clock());
  412. break;
  413. case NEED_CLOCK_OS:
  414. fprintf(fout, "%d\n", cpu_clock_by_os());
  415. break;
  416. case NEED_CLOCK_RDTSC:
  417. fprintf(fout, "%d\n", cpu_clock_measure(400, 1));
  418. break;
  419. case NEED_CLOCK_IC:
  420. fprintf(fout, "%d\n", cpu_clock_by_ic(25, 16));
  421. break;
  422. case NEED_RDMSR:
  423. {
  424. if ((handle = cpu_msr_driver_open()) == NULL) {
  425. fprintf(fout, "Cannot open MSR driver: %s\n", cpuid_error());
  426. } else {
  427. if ((value = cpu_msrinfo(handle, INFO_MPERF)) != CPU_INVALID_VALUE)
  428. fprintf(fout, " MSR.mperf : %d MHz\n", value);
  429. if ((value = cpu_msrinfo(handle, INFO_APERF)) != CPU_INVALID_VALUE)
  430. fprintf(fout, " MSR.aperf : %d MHz\n", value);
  431. if ((value = cpu_msrinfo(handle, INFO_MIN_MULTIPLIER)) != CPU_INVALID_VALUE)
  432. fprintf(fout, " min. multi.: %.2lf\n", value / 100.0);
  433. if ((value = cpu_msrinfo(handle, INFO_CUR_MULTIPLIER)) != CPU_INVALID_VALUE)
  434. fprintf(fout, " cur. multi.: %.2lf\n", value / 100.0);
  435. if ((value = cpu_msrinfo(handle, INFO_MAX_MULTIPLIER)) != CPU_INVALID_VALUE)
  436. fprintf(fout, " max. multi.: %.2lf\n", value / 100.0);
  437. if ((value = cpu_msrinfo(handle, INFO_TEMPERATURE)) != CPU_INVALID_VALUE)
  438. fprintf(fout, " temperature: %d degrees Celsius\n", value);
  439. if ((value = cpu_msrinfo(handle, INFO_THROTTLING)) != CPU_INVALID_VALUE)
  440. fprintf(fout, " throttling : %s\n", value ? "yes" : "no");
  441. if ((value = cpu_msrinfo(handle, INFO_VOLTAGE)) != CPU_INVALID_VALUE)
  442. fprintf(fout, " core volt. : %.2lf Volts\n", value / 100.0);
  443. if ((value = cpu_msrinfo(handle, INFO_BUS_CLOCK)) != CPU_INVALID_VALUE)
  444. fprintf(fout, " bus clock : %.2lf MHz\n", value / 100.0);
  445. cpu_msr_driver_close(handle);
  446. }
  447. break;
  448. }
  449. case NEED_RDMSR_RAW:
  450. {
  451. if ((handle = cpu_msr_driver_open()) == NULL) {
  452. fprintf(fout, "Cannot open MSR driver: %s\n", cpuid_error());
  453. } else {
  454. msr_serialize_raw_data(handle, "");
  455. cpu_msr_driver_close(handle);
  456. }
  457. break;
  458. }
  459. case NEED_SSE_UNIT_SIZE:
  460. {
  461. fprintf(fout, "%d (%s)\n", data->sse_size,
  462. data->detection_hints[CPU_HINT_SSE_SIZE_AUTH] ? "authoritative" : "non-authoritative");
  463. break;
  464. }
  465. default:
  466. fprintf(fout, "How did you get here?!?\n");
  467. break;
  468. }
  469. }
  470. static void print_cpulist(void)
  471. {
  472. int i, j;
  473. struct cpu_list_t list;
  474. const struct { const char *name; cpu_vendor_t vendor; } cpu_vendors[] = {
  475. { "Intel", VENDOR_INTEL },
  476. { "AMD", VENDOR_AMD },
  477. { "Cyrix", VENDOR_CYRIX },
  478. { "NexGen", VENDOR_NEXGEN },
  479. { "Transmeta", VENDOR_TRANSMETA },
  480. { "UMC", VENDOR_UMC },
  481. { "Centaur/VIA", VENDOR_CENTAUR },
  482. { "Rise", VENDOR_RISE },
  483. { "SiS", VENDOR_SIS },
  484. { "NSC", VENDOR_NSC },
  485. };
  486. for (i = 0; i < sizeof(cpu_vendors)/sizeof(cpu_vendors[0]); i++) {
  487. fprintf(fout, "-----%s-----\n", cpu_vendors[i].name);
  488. cpuid_get_cpu_list(cpu_vendors[i].vendor, &list);
  489. for (j = 0; j < list.num_entries; j++)
  490. fprintf(fout, "%s\n", list.names[j]);
  491. cpuid_free_cpu_list(&list);
  492. }
  493. }
  494. static void print_sgx_data(const struct cpu_raw_data_t* raw, const struct cpu_id_t* data)
  495. {
  496. int i;
  497. fprintf(fout, "SGX: %d (%s)\n", data->sgx.present, data->sgx.present ? "present" : "absent");
  498. if (data->sgx.present) {
  499. fprintf(fout, "SGX max enclave size (32-bit): 2^%d\n", data->sgx.max_enclave_32bit);
  500. fprintf(fout, "SGX max enclave size (64-bit): 2^%d\n", data->sgx.max_enclave_64bit);
  501. fprintf(fout, "SGX1 extensions : %d (%s)\n", data->sgx.flags[INTEL_SGX1], data->sgx.flags[INTEL_SGX1] ? "present" : "absent");
  502. fprintf(fout, "SGX2 extensions : %d (%s)\n", data->sgx.flags[INTEL_SGX2], data->sgx.flags[INTEL_SGX2] ? "present" : "absent");
  503. fprintf(fout, "SGX MISCSELECT : %08x\n", data->sgx.misc_select);
  504. fprintf(fout, "SGX SECS.ATTRIBUTES mask : %016llx\n", (unsigned long long) data->sgx.secs_attributes);
  505. fprintf(fout, "SGX SECS.XSAVE feature mask : %016llx\n", (unsigned long long) data->sgx.secs_xfrm);
  506. fprintf(fout, "SGX EPC sections count : %d\n", data->sgx.num_epc_sections);
  507. for (i = 0; i < data->sgx.num_epc_sections; i++) {
  508. struct cpu_epc_t epc = cpuid_get_epc(i, raw);
  509. fprintf(fout, " SGX EPC section #%-8d: start = %llx, size = %llu\n", i,
  510. (unsigned long long) epc.start_addr, (unsigned long long) epc.length);
  511. }
  512. }
  513. }
  514. int main(int argc, char** argv)
  515. {
  516. int parseres = parse_cmdline(argc, argv);
  517. int i, readres, writeres;
  518. int only_clock_queries;
  519. struct cpu_raw_data_t raw;
  520. struct cpu_id_t data;
  521. if (parseres != 1)
  522. return parseres;
  523. /* In quiet mode, disable libcpuid warning messages: */
  524. if (need_quiet)
  525. cpuid_set_warn_function(NULL);
  526. cpuid_set_verbosiness_level(verbose_level);
  527. /* Redirect output, if necessary: */
  528. if (strcmp(out_file, "") && strcmp(out_file, "-")) {
  529. fout = fopen(out_file, "wt");
  530. if (!fout) {
  531. if (!need_quiet)
  532. fprintf(stderr, "Cannot open `%s' for writing!\n", out_file);
  533. return -1;
  534. }
  535. atexit(close_out);
  536. } else {
  537. fout = stdout;
  538. }
  539. /* If requested, print library version: */
  540. if (need_version)
  541. fprintf(fout, "%s\n", cpuid_lib_version());
  542. if (need_input) {
  543. /* We have a request to input raw CPUID data from file: */
  544. if (!strcmp(raw_data_file, "-"))
  545. /* Input from stdin */
  546. readres = cpuid_deserialize_raw_data(&raw, "");
  547. else
  548. /* Input from file */
  549. readres = cpuid_deserialize_raw_data(&raw, raw_data_file);
  550. if (readres < 0) {
  551. if (!need_quiet) {
  552. fprintf(stderr, "Cannot deserialize raw data from ");
  553. if (!strcmp(raw_data_file, "-"))
  554. fprintf(stderr, "stdin\n");
  555. else
  556. fprintf(stderr, "file `%s'\n", raw_data_file);
  557. /* Print the error message */
  558. fprintf(stderr, "Error: %s\n", cpuid_error());
  559. }
  560. return -1;
  561. }
  562. } else {
  563. if (check_need_raw_data()) {
  564. /* Try to obtain raw CPUID data from the CPU: */
  565. readres = cpuid_get_raw_data(&raw);
  566. if (readres < 0) {
  567. if (!need_quiet) {
  568. fprintf(stderr, "Cannot obtain raw CPU data!\n");
  569. fprintf(stderr, "Error: %s\n", cpuid_error());
  570. }
  571. return -1;
  572. }
  573. }
  574. }
  575. /* Need to dump raw CPUID data to file: */
  576. if (need_output) {
  577. if (verbose_level >= 1)
  578. printf("Writing raw CPUID dump to `%s'\n", raw_data_file);
  579. if (!strcmp(raw_data_file, "-"))
  580. /* Serialize to stdout */
  581. writeres = cpuid_serialize_raw_data(&raw, "");
  582. else
  583. /* Serialize to file */
  584. writeres = cpuid_serialize_raw_data(&raw, raw_data_file);
  585. if (writeres < 0) {
  586. if (!need_quiet) {
  587. fprintf(stderr, "Cannot serialize raw data to ");
  588. if (!strcmp(raw_data_file, "-"))
  589. fprintf(stderr, "stdout\n");
  590. else
  591. fprintf(stderr, "file `%s'\n", raw_data_file);
  592. /* Print the error message */
  593. fprintf(stderr, "Error: %s\n", cpuid_error());
  594. }
  595. return -1;
  596. }
  597. }
  598. if (need_report) {
  599. if (verbose_level >= 1) {
  600. printf("Writing decoded CPU report to `%s'\n", out_file);
  601. }
  602. /* Write a thorough report of cpu_id_t structure to output (usually stdout) */
  603. fprintf(fout, "CPUID is present\n");
  604. /*
  605. * Try CPU identification
  606. * (this fill the `data' structure with decoded CPU features)
  607. */
  608. if (cpu_identify(&raw, &data) < 0)
  609. fprintf(fout, "Error identifying the CPU: %s\n", cpuid_error());
  610. /* OK, now write what we have in `data'...: */
  611. fprintf(fout, "CPU Info:\n------------------\n");
  612. fprintf(fout, " vendor_str : `%s'\n", data.vendor_str);
  613. fprintf(fout, " vendor id : %d\n", (int) data.vendor);
  614. fprintf(fout, " brand_str : `%s'\n", data.brand_str);
  615. fprintf(fout, " family : %d (%02Xh)\n", data.family, data.family);
  616. fprintf(fout, " model : %d (%02Xh)\n", data.model, data.model);
  617. fprintf(fout, " stepping : %d (%02Xh)\n", data.stepping, data.stepping);
  618. fprintf(fout, " ext_family : %d (%02Xh)\n", data.ext_family, data.ext_family);
  619. fprintf(fout, " ext_model : %d (%02Xh)\n", data.ext_model, data.ext_model);
  620. fprintf(fout, " num_cores : %d\n", data.num_cores);
  621. fprintf(fout, " num_logical: %d\n", data.num_logical_cpus);
  622. fprintf(fout, " tot_logical: %d\n", data.total_logical_cpus);
  623. fprintf(fout, " L1 D cache : %d KB\n", data.l1_data_cache);
  624. fprintf(fout, " L1 I cache : %d KB\n", data.l1_instruction_cache);
  625. fprintf(fout, " L2 cache : %d KB\n", data.l2_cache);
  626. fprintf(fout, " L3 cache : %d KB\n", data.l3_cache);
  627. fprintf(fout, " L4 cache : %d KB\n", data.l4_cache);
  628. fprintf(fout, " L1D assoc. : %d-way\n", data.l1_assoc);
  629. fprintf(fout, " L2 assoc. : %d-way\n", data.l2_assoc);
  630. fprintf(fout, " L3 assoc. : %d-way\n", data.l3_assoc);
  631. fprintf(fout, " L4 assoc. : %d-way\n", data.l4_assoc);
  632. fprintf(fout, " L1D line sz: %d bytes\n", data.l1_cacheline);
  633. fprintf(fout, " L2 line sz : %d bytes\n", data.l2_cacheline);
  634. fprintf(fout, " L3 line sz : %d bytes\n", data.l3_cacheline);
  635. fprintf(fout, " L4 line sz : %d bytes\n", data.l4_cacheline);
  636. fprintf(fout, " SSE units : %d bits (%s)\n", data.sse_size, data.detection_hints[CPU_HINT_SSE_SIZE_AUTH] ? "authoritative" : "non-authoritative");
  637. fprintf(fout, " code name : `%s'\n", data.cpu_codename);
  638. fprintf(fout, " features :");
  639. /*
  640. * Here we enumerate all CPU feature bits, and when a feature
  641. * is present output its name:
  642. */
  643. for (i = 0; i < NUM_CPU_FEATURES; i++)
  644. if (data.flags[i])
  645. fprintf(fout, " %s", cpu_feature_str(i));
  646. fprintf(fout, "\n");
  647. /* Is CPU clock info requested? */
  648. if (need_clockreport) {
  649. if (need_timed_clockreport) {
  650. /* Here we use the RDTSC-based routine */
  651. fprintf(fout, " cpu clock : %d MHz\n",
  652. cpu_clock_measure(400, 1));
  653. } else {
  654. /* Here we use the OS-provided info */
  655. fprintf(fout, " cpu clock : %d MHz\n",
  656. cpu_clock());
  657. }
  658. }
  659. }
  660. /*
  661. * Check if we have any queries to process.
  662. * We have to handle the case when `--clock' or `--clock-rdtsc' options
  663. * are present.
  664. * If in report mode, this will generate spurious output after the
  665. * report, if not handled explicitly.
  666. */
  667. only_clock_queries = 1;
  668. for (i = 0; i < num_requests; i++)
  669. if (requests[i] != NEED_CLOCK && requests[i] != NEED_CLOCK_RDTSC) {
  670. only_clock_queries = 0;
  671. break;
  672. }
  673. /* OK, process all queries. */
  674. if (((!need_report || !only_clock_queries) && num_requests > 0) || need_identify) {
  675. /* Identify the CPU. Make it do cpuid_get_raw_data() itself */
  676. if (check_need_raw_data() && cpu_identify(&raw, &data) < 0) {
  677. if (!need_quiet)
  678. fprintf(stderr,
  679. "Error identifying the CPU: %s\n",
  680. cpuid_error());
  681. return -1;
  682. }
  683. for (i = 0; i < num_requests; i++)
  684. print_info(requests[i], &raw, &data);
  685. }
  686. if (need_cpulist) {
  687. print_cpulist();
  688. }
  689. if (need_sgx) {
  690. print_sgx_data(&raw, &data);
  691. }
  692. return 0;
  693. }