xref: /aosp_15_r20/external/flashrom/print.c (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
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