1 /*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2009 Uwe Hermann <[email protected]>
5 * Copyright (C) 2009 Carl-Daniel Hailfinger
6 * Copyright (C) 2011-2013 Stefan Tauner
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <stddef.h>
23 #if HAVE_UTSNAME == 1
24 #include <sys/utsname.h>
25 #endif
26 #if IS_WINDOWS
27 #include <windows.h>
28 #undef min
29 #undef max
30 #endif
31
32 #include "flash.h"
33 #include "programmer.h"
34
test_state_to_text(enum test_state test_state)35 static const char *test_state_to_text(enum test_state test_state)
36 {
37 switch (test_state) {
38 case OK: return "OK";
39 case BAD: return "Not working";
40 case NA: return "N/A";
41 case DEP: return "Config-dependent";
42 case NT:
43 default: return "Untested";
44 }
45 }
46
print_supported_chips(void)47 static int print_supported_chips(void)
48 {
49 const char *delim = "/";
50 const int mintoklen = 5;
51 const int border = 2;
52 int i, chipcount = 0;
53 int maxvendorlen = strlen("Vendor") + 1;
54 int maxchiplen = strlen("Device") + 1;
55 int maxtypelen = strlen("Type") + 1;
56 const struct flashchip *chip;
57 char *s;
58 char *ven, *dev;
59 char *tmpven, *tmpdev, *tmpven_save, *tmpdev_save;
60 int tmpvenlen, tmpdevlen, curvenlen, curdevlen;
61
62 /* calculate maximum column widths and by iterating over all chips */
63 for (chip = flashchips; chip->name != NULL; chip++) {
64 /* Ignore generic entries. */
65 if (!strncmp(chip->vendor, "Unknown", 7) ||
66 !strncmp(chip->vendor, "Programmer", 10) ||
67 !strncmp(chip->name, "unknown", 7))
68 continue;
69 chipcount++;
70
71 /* Find maximum vendor length (respecting line splitting). */
72 tmpven = (char *)chip->vendor;
73 do {
74 /* and take minimum token lengths into account */
75 tmpvenlen = 0;
76 do {
77 tmpvenlen += strcspn(tmpven, delim);
78 /* skip to the address after the first token */
79 tmpven += tmpvenlen;
80 if (tmpven[0] == '\0')
81 break;
82 tmpven++;
83 } while (tmpvenlen < mintoklen);
84 maxvendorlen = max(maxvendorlen, tmpvenlen);
85 if (tmpven[0] == '\0')
86 break;
87 } while (1);
88
89 /* same for device name */
90 tmpdev = (char *)chip->name;
91 do {
92 tmpdevlen = 0;
93 do {
94 tmpdevlen += strcspn(tmpdev, delim);
95 tmpdev += tmpdevlen;
96 if (tmpdev[0] == '\0')
97 break;
98 tmpdev++;
99 } while (tmpdevlen < mintoklen);
100 maxchiplen = max(maxchiplen, tmpdevlen);
101 if (tmpdev[0] == '\0')
102 break;
103 } while (1);
104
105 s = flashbuses_to_text(chip->bustype);
106 if (s == NULL) {
107 msg_gerr("Out of memory!\n");
108 return 1;
109 }
110 maxtypelen = max(maxtypelen, strlen(s));
111 free(s);
112 }
113 maxvendorlen += border;
114 maxchiplen += border;
115 maxtypelen += border;
116
117 msg_ginfo("Supported flash chips (total: %d):\n\n", chipcount);
118 msg_ginfo("Vendor");
119 for (i = strlen("Vendor"); i < maxvendorlen; i++)
120 msg_ginfo(" ");
121 msg_ginfo("Device");
122 for (i = strlen("Device"); i < maxchiplen; i++)
123 msg_ginfo(" ");
124
125 msg_ginfo("Test ");
126 for (i = 0; i < border; i++)
127 msg_ginfo(" ");
128 msg_ginfo("Known");
129 for (i = 0; i < border; i++)
130 msg_ginfo(" ");
131 msg_ginfo(" Size ");
132 for (i = 0; i < border; i++)
133 msg_ginfo(" ");
134
135 msg_ginfo("Type");
136 for (i = strlen("Type"); i < maxtypelen; i++)
137 msg_ginfo(" ");
138 msg_gdbg("Voltage");
139 msg_ginfo("\n");
140
141 for (i = 0; i < maxvendorlen + maxchiplen; i++)
142 msg_ginfo(" ");
143 msg_ginfo("OK ");
144 for (i = 0; i < border; i++)
145 msg_ginfo(" ");
146 msg_ginfo("Broken");
147 for (i = 0; i < border; i++)
148 msg_ginfo(" ");
149 msg_ginfo("[kB] ");
150 for (i = 0; i < border + maxtypelen; i++)
151 msg_ginfo(" ");
152 msg_gdbg("range [V]");
153 msg_ginfo("\n\n");
154 msg_ginfo("(P = PROBE, R = READ, E = ERASE, W = WRITE, B = block-protect, - = N/A)\n\n");
155
156 for (chip = flashchips; chip->name != NULL; chip++) {
157 /* Don't print generic entries. */
158 if (!strncmp(chip->vendor, "Unknown", 7) ||
159 !strncmp(chip->vendor, "Programmer", 10) ||
160 !strncmp(chip->name, "unknown", 7))
161 continue;
162
163 /* support for multiline vendor names:
164 * - make a copy of the original vendor name
165 * - use strok to put the first token in tmpven
166 * - keep track of the length of all tokens on the current line
167 * for ' '-padding in curvenlen
168 * - check if additional tokens should be printed on the current
169 * line
170 * - after all other values are printed print the surplus tokens
171 * on fresh lines
172 */
173 ven = malloc(strlen(chip->vendor) + 1);
174 if (ven == NULL) {
175 msg_gerr("Out of memory!\n");
176 return 1;
177 }
178 strcpy(ven, chip->vendor);
179
180 tmpven = strtok_r(ven, delim, &tmpven_save);
181 msg_ginfo("%s", tmpven);
182 curvenlen = strlen(tmpven);
183 while ((tmpven = strtok_r(NULL, delim, &tmpven_save)) != NULL) {
184 msg_ginfo("%s", delim);
185 curvenlen++;
186 tmpvenlen = strlen(tmpven);
187 if (tmpvenlen >= mintoklen)
188 break; /* big enough to be on its own line */
189 msg_ginfo("%s", tmpven);
190 curvenlen += tmpvenlen;
191 }
192
193 for (i = curvenlen; i < maxvendorlen; i++)
194 msg_ginfo(" ");
195
196 /* support for multiline device names as above */
197 dev = malloc(strlen(chip->name) + 1);
198 if (dev == NULL) {
199 msg_gerr("Out of memory!\n");
200 free(ven);
201 return 1;
202 }
203 strcpy(dev, chip->name);
204
205 tmpdev = strtok_r(dev, delim, &tmpdev_save);
206 msg_ginfo("%s", tmpdev);
207 curdevlen = strlen(tmpdev);
208 while ((tmpdev = strtok_r(NULL, delim, &tmpdev_save)) != NULL) {
209 msg_ginfo("%s", delim);
210 curdevlen++;
211 tmpdevlen = strlen(tmpdev);
212 if (tmpdevlen >= mintoklen)
213 break; /* big enough to be on its own line */
214 msg_ginfo("%s", tmpdev);
215 curdevlen += tmpdevlen;
216 }
217
218 for (i = curdevlen; i < maxchiplen; i++)
219 msg_ginfo(" ");
220
221 if (chip->tested.probe == OK)
222 msg_ginfo("P");
223 else if (chip->tested.probe == NA)
224 msg_ginfo("-");
225 else
226 msg_ginfo(" ");
227 if (chip->tested.read == OK)
228 msg_ginfo("R");
229 else if (chip->tested.read == NA)
230 msg_ginfo("-");
231 else
232 msg_ginfo(" ");
233 if (chip->tested.erase == OK)
234 msg_ginfo("E");
235 else if (chip->tested.erase == NA)
236 msg_ginfo("-");
237 else
238 msg_ginfo(" ");
239 if (chip->tested.write == OK)
240 msg_ginfo("W");
241 else if (chip->tested.write == NA)
242 msg_ginfo("-");
243 else
244 msg_ginfo(" ");
245 if (chip->tested.wp == OK)
246 msg_ginfo("B");
247 else if (chip->tested.wp == NA)
248 msg_ginfo("-");
249 else
250 msg_ginfo(" ");
251 for (i = 0; i < border; i++)
252 msg_ginfo(" ");
253
254 if (chip->tested.probe == BAD)
255 msg_ginfo("P");
256 else
257 msg_ginfo(" ");
258 if (chip->tested.read == BAD)
259 msg_ginfo("R");
260 else
261 msg_ginfo(" ");
262 if (chip->tested.erase == BAD)
263 msg_ginfo("E");
264 else
265 msg_ginfo(" ");
266 if (chip->tested.write == BAD)
267 msg_ginfo("W");
268 else
269 msg_ginfo(" ");
270 if (chip->tested.wp == BAD)
271 msg_ginfo("B");
272 else
273 msg_ginfo(" ");
274 for (i = 0; i < border + 1; i++)
275 msg_ginfo(" ");
276
277 msg_ginfo("%6d", chip->total_size);
278 for (i = 0; i < border; i++)
279 msg_ginfo(" ");
280
281 s = flashbuses_to_text(chip->bustype);
282 if (s == NULL) {
283 msg_gerr("Out of memory!\n");
284 free(ven);
285 free(dev);
286 return 1;
287 }
288 msg_ginfo("%s", s);
289 for (i = strlen(s); i < maxtypelen; i++)
290 msg_ginfo(" ");
291 free(s);
292
293 if (chip->voltage.min == 0 && chip->voltage.max == 0)
294 msg_gdbg("no info");
295 else
296 msg_gdbg("%0.02f;%0.02f",
297 chip->voltage.min/(double)1000,
298 chip->voltage.max/(double)1000);
299
300 /* print surplus vendor and device name tokens */
301 while (tmpven != NULL || tmpdev != NULL) {
302 msg_ginfo("\n");
303 if (tmpven != NULL){
304 msg_ginfo("%s", tmpven);
305 curvenlen = strlen(tmpven);
306 while ((tmpven = strtok_r(NULL, delim, &tmpven_save)) != NULL) {
307 msg_ginfo("%s", delim);
308 curvenlen++;
309 tmpvenlen = strlen(tmpven);
310 /* big enough to be on its own line */
311 if (tmpvenlen >= mintoklen)
312 break;
313 msg_ginfo("%s", tmpven);
314 curvenlen += tmpvenlen;
315 }
316 } else
317 curvenlen = 0;
318
319 for (i = curvenlen; i < maxvendorlen; i++)
320 msg_ginfo(" ");
321
322 if (tmpdev != NULL){
323 msg_ginfo("%s", tmpdev);
324 curdevlen = strlen(tmpdev);
325 while ((tmpdev = strtok_r(NULL, delim, &tmpdev_save)) != NULL) {
326 msg_ginfo("%s", delim);
327 curdevlen++;
328 tmpdevlen = strlen(tmpdev);
329 /* big enough to be on its own line */
330 if (tmpdevlen >= mintoklen)
331 break;
332 msg_ginfo("%s", tmpdev);
333 curdevlen += tmpdevlen;
334 }
335 }
336 }
337 msg_ginfo("\n");
338 free(ven);
339 free(dev);
340 }
341
342 return 0;
343 }
344
345 #if CONFIG_INTERNAL == 1
print_supported_chipsets(void)346 static void print_supported_chipsets(void)
347 {
348 unsigned int i, chipsetcount = 0;
349 const struct penable *c = chipset_enables;
350 size_t maxvendorlen = strlen("Vendor") + 1;
351 size_t maxchipsetlen = strlen("Chipset") + 1;
352
353 for (c = chipset_enables; c->vendor_name != NULL; c++) {
354 chipsetcount++;
355 maxvendorlen = MAX(maxvendorlen, strlen(c->vendor_name));
356 maxchipsetlen = MAX(maxchipsetlen, strlen(c->device_name));
357 }
358 maxvendorlen++;
359 maxchipsetlen++;
360
361 msg_ginfo("Supported chipsets (total: %u):\n\n", chipsetcount);
362
363 msg_ginfo("Vendor");
364 for (i = strlen("Vendor"); i < maxvendorlen; i++)
365 msg_ginfo(" ");
366
367 msg_ginfo("Chipset");
368 for (i = strlen("Chipset"); i < maxchipsetlen; i++)
369 msg_ginfo(" ");
370
371 msg_ginfo("PCI IDs Status\n\n");
372
373 for (c = chipset_enables; c->vendor_name != NULL; c++) {
374 msg_ginfo("%s", c->vendor_name);
375 for (i = 0; i < maxvendorlen - strlen(c->vendor_name); i++)
376 msg_ginfo(" ");
377 msg_ginfo("%s", c->device_name);
378 for (i = 0; i < maxchipsetlen - strlen(c->device_name); i++)
379 msg_ginfo(" ");
380 msg_ginfo("%04x:%04x %s\n", c->vendor_id, c->device_id,
381 test_state_to_text(c->status));
382 }
383 }
384
print_supported_boards_helper(const struct board_info * boards,const char * devicetype)385 static void print_supported_boards_helper(const struct board_info *boards,
386 const char *devicetype)
387 {
388 unsigned int i;
389 unsigned int boardcount_good = 0, boardcount_bad = 0, boardcount_nt = 0;
390 const struct board_match *e = board_matches;
391 const struct board_info *b = boards;
392 size_t maxvendorlen = strlen("Vendor") + 1;
393 size_t maxboardlen = strlen("Board") + 1;
394
395 for (b = boards; b->vendor != NULL; b++) {
396 maxvendorlen = max(maxvendorlen, strlen(b->vendor));
397 maxboardlen = max(maxboardlen, strlen(b->name));
398 if (b->working == OK)
399 boardcount_good++;
400 else if (b->working == NT)
401 boardcount_nt++;
402 else
403 boardcount_bad++;
404 }
405 maxvendorlen++;
406 maxboardlen++;
407
408 msg_ginfo("%d known %s (good: %d, untested: %d, bad: %d):\n\n",
409 boardcount_good + boardcount_nt + boardcount_bad,
410 devicetype, boardcount_good, boardcount_nt, boardcount_bad);
411
412 msg_ginfo("Vendor");
413 for (i = strlen("Vendor"); i < maxvendorlen; i++)
414 msg_ginfo(" ");
415
416 msg_ginfo("Board");
417 for (i = strlen("Board"); i < maxboardlen; i++)
418 msg_ginfo(" ");
419
420 msg_ginfo("Status Required value for\n");
421 for (i = 0; i < maxvendorlen + maxboardlen + strlen("Status "); i++)
422 msg_ginfo(" ");
423 msg_ginfo("-p internal:mainboard=\n");
424
425 for (b = boards; b->vendor != NULL; b++) {
426 msg_ginfo("%s", b->vendor);
427 for (i = 0; i < maxvendorlen - strlen(b->vendor); i++)
428 msg_ginfo(" ");
429 msg_ginfo("%s", b->name);
430 for (i = 0; i < maxboardlen - strlen(b->name); i++)
431 msg_ginfo(" ");
432
433 switch (b->working) {
434 case OK: msg_ginfo("OK "); break;
435 case NT: msg_ginfo("NT "); break;
436 case DEP: msg_ginfo("DEP "); break;
437 case NA: msg_ginfo("N/A "); break;
438 case BAD:
439 default: msg_ginfo("BAD "); break;
440 }
441
442 for (e = board_matches; e->vendor_name != NULL; e++) {
443 if (strcmp(e->vendor_name, b->vendor)
444 || strcmp(e->board_name, b->name))
445 continue;
446 if (e->lb_vendor == NULL)
447 msg_ginfo("(autodetected)");
448 else
449 msg_ginfo("%s:%s", e->lb_vendor,
450 e->lb_part);
451 }
452 msg_ginfo("\n");
453 }
454 }
455 #endif
456
print_supported_devs(const struct programmer_entry * const prog,const char * const type,int * num_devs)457 static void print_supported_devs(const struct programmer_entry *const prog, const char *const type,
458 int* num_devs)
459 {
460 const struct dev_entry *const devs = prog->devs.dev;
461 msg_ginfo("\nSupported %s devices for the %s programmer:\n", type, prog->name);
462 unsigned int maxvendorlen = strlen("Vendor") + 1;
463 unsigned int maxdevlen = strlen("Device") + 1;
464
465 unsigned int i;
466 for (i = 0; devs[i].vendor_name != NULL; i++) {
467 maxvendorlen = max(maxvendorlen, strlen(devs[i].vendor_name));
468 maxdevlen = max(maxdevlen, strlen(devs[i].device_name));
469 }
470 maxvendorlen++;
471 maxdevlen++;
472
473 msg_ginfo("Vendor");
474 for (i = strlen("Vendor"); i < maxvendorlen; i++)
475 msg_ginfo(" ");
476
477 msg_ginfo("Device");
478 for (i = strlen("Device"); i < maxdevlen; i++)
479 msg_ginfo(" ");
480
481 msg_ginfo(" %s IDs Status\n", type);
482
483 for (i = 0; devs[i].vendor_name != NULL; i++) {
484 msg_ginfo("%s", devs[i].vendor_name);
485 unsigned int j;
486 for (j = strlen(devs[i].vendor_name); j < maxvendorlen; j++)
487 msg_ginfo(" ");
488 msg_ginfo("%s", devs[i].device_name);
489 for (j = strlen(devs[i].device_name); j < maxdevlen; j++)
490 msg_ginfo(" ");
491
492 msg_pinfo(" %04x:%04x %s\n", devs[i].vendor_id, devs[i].device_id,
493 test_state_to_text(devs[i].status));
494 if (devs[i].status == OK || devs[i].status == NT || devs[i].status == DEP)
495 *num_devs += 1;
496 }
497 }
498
print_supported(void)499 int print_supported(void)
500 {
501 unsigned int i;
502 int num_pci_devs = 0;
503 int num_usb_devs = 0;
504
505 if (print_supported_chips())
506 return 1;
507
508 msg_ginfo("\nSupported programmers:\n");
509 list_programmers_linebreak(0, 80, 0);
510 msg_ginfo("\n");
511 #if CONFIG_INTERNAL == 1
512 msg_ginfo("\nSupported devices for the internal programmer:\n\n");
513 print_supported_chipsets();
514 msg_ginfo("\n");
515 print_supported_boards_helper(boards_known, "mainboards");
516 msg_ginfo("\n");
517 print_supported_boards_helper(laptops_known, "mobile devices");
518 #endif
519 for (i = 0; i < programmer_table_size; i++) {
520 const struct programmer_entry *const prog = programmer_table[i];
521 switch (prog->type) {
522 case USB:
523 print_supported_devs(prog, "USB", &num_usb_devs);
524 break;
525 case PCI:
526 print_supported_devs(prog, "PCI", &num_pci_devs);
527 break;
528 case OTHER:
529 if (prog->devs.note != NULL) {
530 msg_ginfo("\nSupported devices for the %s programmer:\n", prog->name);
531 msg_ginfo("%s", prog->devs.note);
532 }
533 break;
534 default:
535 msg_gerr("\n%s: %s: Uninitialized programmer type! Please report a bug at "
536 "[email protected]\n", __func__, prog->name);
537 break;
538 }
539 }
540
541 msg_ginfo("\nSupported USB devices, total %d\nSupported PCI devices, total %d\n",
542 num_usb_devs, num_pci_devs);
543
544 return 0;
545 }
546
print_sysinfo(void)547 static void print_sysinfo(void)
548 {
549 #if IS_WINDOWS
550 SYSTEM_INFO si = { 0 };
551 OSVERSIONINFOEX osvi = { 0 };
552
553 msg_ginfo(" on Windows");
554 /* Tell Windows which version of the structure we want. */
555 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
556 if (GetVersionEx((OSVERSIONINFO*) &osvi))
557 msg_ginfo(" %lu.%lu", (unsigned long)osvi.dwMajorVersion,
558 (unsigned long)osvi.dwMinorVersion);
559 else
560 msg_ginfo(" unknown version");
561 GetSystemInfo(&si);
562 switch (si.wProcessorArchitecture) {
563 case PROCESSOR_ARCHITECTURE_AMD64:
564 msg_ginfo(" (x86_64)");
565 break;
566 case PROCESSOR_ARCHITECTURE_INTEL:
567 msg_ginfo(" (x86)");
568 break;
569 default:
570 msg_ginfo(" (unknown arch)");
571 break;
572 }
573 #elif HAVE_UTSNAME == 1
574 struct utsname osinfo;
575
576 uname(&osinfo);
577 msg_ginfo(" on %s %s (%s)", osinfo.sysname, osinfo.release,
578 osinfo.machine);
579 #else
580 msg_ginfo(" on unknown machine");
581 #endif
582 }
583
print_buildinfo(void)584 void print_buildinfo(void)
585 {
586 msg_gdbg("flashrom was built with");
587 #ifdef __clang__
588 msg_gdbg(" LLVM Clang");
589 #ifdef __clang_version__
590 msg_gdbg(" %s,", __clang_version__);
591 #else
592 msg_gdbg(" unknown version (before r102686),");
593 #endif
594 #elif defined(__GNUC__)
595 msg_gdbg(" GCC");
596 #ifdef __VERSION__
597 msg_gdbg(" %s,", __VERSION__);
598 #else
599 msg_gdbg(" unknown version,");
600 #endif
601 #else
602 msg_gdbg(" unknown compiler,");
603 #endif
604 #if defined (__FLASHROM_LITTLE_ENDIAN__)
605 msg_gdbg(" little endian");
606 #elif defined (__FLASHROM_BIG_ENDIAN__)
607 msg_gdbg(" big endian");
608 #else
609 #error Endianness could not be determined
610 #endif
611 msg_gdbg("\n");
612 }
613
print_version(void)614 void print_version(void)
615 {
616 msg_ginfo("flashrom %s", flashrom_version_info());
617 print_sysinfo();
618 msg_ginfo("\n");
619 }
620
print_banner(void)621 void print_banner(void)
622 {
623 msg_ginfo("flashrom is free software, get the source code at "
624 "https://flashrom.org\n");
625 msg_ginfo("\n");
626 }
627