/ util / nvramtool / lbtable.c
lbtable.c
  1  /* SPDX-License-Identifier: GPL-2.0-only */
  2  
  3  #include <stdint.h>
  4  #include <inttypes.h>
  5  #include <string.h>
  6  #ifndef __MINGW32__
  7  #include <sys/mman.h>
  8  #endif
  9  #include "common.h"
 10  #include "coreboot_tables.h"
 11  #include "ip_checksum.h"
 12  #include "lbtable.h"
 13  #include "layout.h"
 14  #include "cmos_lowlevel.h"
 15  #include "hexdump.h"
 16  #include "cbfs.h"
 17  
 18  typedef void (*lbtable_print_fn_t) (const struct lb_record * rec);
 19  
 20  /* This structure represents an item in the coreboot table that may be
 21   * displayed using the -l option.
 22   */
 23  typedef struct {
 24  	uint32_t tag;
 25  	const char *name;
 26  	const char *description;
 27  	const char *nofound_msg;
 28  	lbtable_print_fn_t print_fn;
 29  } lbtable_choice_t;
 30  
 31  typedef struct {
 32  	unsigned long start;	/* address of first byte of memory range */
 33  	unsigned long end;	/* address of last byte of memory range */
 34  } mem_range_t;
 35  
 36  static const struct lb_header *lbtable_scan(unsigned long start,
 37  					    unsigned long end,
 38  					    int *bad_header_count,
 39  					    int *bad_table_count);
 40  static const char *lbrec_tag_to_str(uint32_t tag);
 41  static void memory_print_fn(const struct lb_record *rec);
 42  static void mainboard_print_fn(const struct lb_record *rec);
 43  static void cmos_opt_table_print_fn(const struct lb_record *rec);
 44  static void print_option_record(const struct cmos_entries *cmos_entry);
 45  static void print_enum_record(const struct cmos_enums *cmos_enum);
 46  static void print_defaults_record(const struct cmos_defaults *cmos_defaults);
 47  static void print_unknown_record(const struct lb_record *cmos_item);
 48  static void option_checksum_print_fn(const struct lb_record *rec);
 49  static void string_print_fn(const struct lb_record *rec);
 50  
 51  static const char memory_desc[] =
 52      "    This shows information about system memory.\n";
 53  
 54  static const char mainboard_desc[] =
 55      "    This shows information about your mainboard.\n";
 56  
 57  static const char version_desc[] =
 58      "    This shows coreboot version information.\n";
 59  
 60  static const char extra_version_desc[] =
 61      "    This shows extra coreboot version information.\n";
 62  
 63  static const char build_desc[] = "    This shows coreboot build information.\n";
 64  
 65  static const char compile_time_desc[] =
 66      "    This shows when coreboot was compiled.\n";
 67  
 68  static const char compile_by_desc[] = "    This shows who compiled coreboot.\n";
 69  
 70  static const char compile_host_desc[] =
 71      "    This shows the name of the machine that compiled coreboot.\n";
 72  
 73  static const char compile_domain_desc[] =
 74      "    This shows the domain name of the machine that compiled coreboot.\n";
 75  
 76  static const char compiler_desc[] =
 77      "    This shows the name of the compiler used to build coreboot.\n";
 78  
 79  static const char linker_desc[] =
 80      "    This shows the name of the linker used to build coreboot.\n";
 81  
 82  static const char assembler_desc[] =
 83      "    This shows the name of the assembler used to build coreboot.\n";
 84  
 85  static const char cmos_opt_table_desc[] =
 86      "    This does a low-level dump of the CMOS option table.  The table "
 87      "contains\n"
 88      "    information about the layout of the values that coreboot stores in\n"
 89      "    nonvolatile RAM.\n";
 90  
 91  static const char option_checksum_desc[] =
 92      "    This shows the location of the CMOS checksum and the area over which it "
 93      "is\n" "    calculated.\n";
 94  
 95  static const char generic_nofound_msg[] =
 96      "%s: Item %s not found in coreboot table.\n";
 97  
 98  static const char nofound_msg_cmos_opt_table[] =
 99      "%s: Item %s not found in coreboot table.  Apparently, the "
100      "coreboot installed on this system was built without specifying "
101      "CONFIG_HAVE_OPTION_TABLE.\n";
102  
103  static const char nofound_msg_option_checksum[] =
104      "%s: Item %s not found in coreboot table. Apparently, you are "
105      "using coreboot v1.\n";
106  
107  int fd;
108  
109  /* This is the number of items from the coreboot table that may be displayed
110   * using the -l option.
111   */
112  #define NUM_LBTABLE_CHOICES 14
113  
114  /* These represent the various items from the coreboot table that may be
115   * displayed using the -l option.
116   */
117  static const lbtable_choice_t lbtable_choices[NUM_LBTABLE_CHOICES] =
118      { {LB_TAG_MEMORY, "memory",
119         memory_desc, generic_nofound_msg,
120         memory_print_fn},
121  {LB_TAG_MAINBOARD, "mainboard",
122   mainboard_desc, generic_nofound_msg,
123   mainboard_print_fn},
124  {LB_TAG_VERSION, "version",
125   version_desc, generic_nofound_msg,
126   string_print_fn},
127  {LB_TAG_EXTRA_VERSION, "extra_version",
128   extra_version_desc, generic_nofound_msg,
129   string_print_fn},
130  {LB_TAG_BUILD, "build",
131   build_desc, generic_nofound_msg,
132   string_print_fn},
133  {LB_TAG_COMPILE_TIME, "compile_time",
134   compile_time_desc, generic_nofound_msg,
135   string_print_fn},
136  {LB_TAG_COMPILE_BY, "compile_by",
137   compile_by_desc, generic_nofound_msg,
138   string_print_fn},
139  {LB_TAG_COMPILE_HOST, "compile_host",
140   compile_host_desc, generic_nofound_msg,
141   string_print_fn},
142  {LB_TAG_COMPILE_DOMAIN, "compile_domain",
143   compile_domain_desc, generic_nofound_msg,
144   string_print_fn},
145  {LB_TAG_COMPILER, "compiler",
146   compiler_desc, generic_nofound_msg,
147   string_print_fn},
148  {LB_TAG_LINKER, "linker",
149   linker_desc, generic_nofound_msg,
150   string_print_fn},
151  {LB_TAG_ASSEMBLER, "assembler",
152   assembler_desc, generic_nofound_msg,
153   string_print_fn},
154  {LB_TAG_CMOS_OPTION_TABLE, "cmos_opt_table",
155   cmos_opt_table_desc, nofound_msg_cmos_opt_table,
156   cmos_opt_table_print_fn},
157  {LB_TAG_OPTION_CHECKSUM, "option_checksum",
158   option_checksum_desc, nofound_msg_option_checksum,
159   option_checksum_print_fn}
160  };
161  
162  /* The coreboot table resides in low physical memory, which we access using
163   * /dev/mem.  These are ranges of physical memory that should be scanned for a
164   * coreboot table.
165   */
166  
167  #define NUM_MEM_RANGES 2
168  
169  static const mem_range_t mem_ranges[NUM_MEM_RANGES] =
170      { {0x00000000, 0x00000fff},
171  {0x000f0000, 0x000fffff}
172  };
173  
174  /* Pointer to low physical memory that we access by calling mmap() on
175   * /dev/mem.
176   */
177  static const void *low_phys_mem;
178  /* impossible value since not page aligned: first map request will happen */
179  static unsigned long low_phys_base = 0x1;
180  
181  /* count of mapped pages */
182  static unsigned long mapped_pages = 0;
183  
184  /* Pointer to coreboot table. */
185  static const struct lb_header *lbtable = NULL;
186  
187  static const hexdump_format_t format =
188      { 12, 4, "            ", " | ", " ", " | ", '.' };
189  
190  /****************************************************************************
191   * vtophys
192   *
193   * Convert a virtual address to a physical address.  'vaddr' is a virtual
194   * address in the address space of the current process.  It points to
195   * somewhere in the chunk of memory that we mapped by calling mmap() on
196   * /dev/mem.  This macro converts 'vaddr' to a physical address.
197   ****************************************************************************/
198  #define vtophys(vaddr) (((unsigned long) vaddr) -       \
199                          ((unsigned long) low_phys_mem) + low_phys_base)
200  
201  /****************************************************************************
202   * phystov
203   *
204   * Convert a physical address to a virtual address.  'paddr' is a physical
205   * address.  This macro converts 'paddr' to a virtual address in the address
206   * space of the current process.  The virtual to physical mapping was set up
207   * by calling mmap() on /dev/mem.
208   ****************************************************************************/
209  #define phystov(paddr) (((unsigned long) low_phys_mem) + \
210                          ((unsigned long) paddr) - low_phys_base)
211  
212  /****************************************************************************
213   * map_pages
214   *
215   * Maps just enough pages to cover base_address + length
216   * and updates affected variables
217   ****************************************************************************/
218  static void map_pages(unsigned long base_address, unsigned long length)
219  {
220  	unsigned long num_pages = (length +
221  			(base_address & (getpagesize() - 1)) +
222  			getpagesize() - 1) >> 12;
223  	base_address &= ~(getpagesize() - 1);
224  
225  	/* no need to do anything */
226  	if ((low_phys_base == base_address) && (mapped_pages == num_pages)) {
227  		return;
228  	}
229  
230  	if (low_phys_mem) {
231  		munmap((void *)low_phys_mem, mapped_pages << 12);
232  	}
233  	if ((low_phys_mem = mmap(NULL, num_pages << 12, PROT_READ, MAP_SHARED, fd,
234  		  (off_t) base_address)) == MAP_FAILED) {
235  		fprintf(stderr,
236  			"%s: Failed to mmap /dev/mem at %lx: %s\n",
237  			prog_name, base_address, strerror(errno));
238  		exit(1);
239  	}
240  	low_phys_base = base_address;
241  }
242  
243  /****************************************************************************
244   * get_lbtable
245   *
246   * Find the coreboot table and set global variable lbtable to point to it.
247   ****************************************************************************/
248  void get_lbtable(void)
249  {
250  	int i, bad_header_count, bad_table_count, bad_headers, bad_tables;
251  
252  	if (lbtable != NULL)
253  		return;
254  
255  	/* The coreboot table is located in low physical memory, which may be
256  	 * conveniently accessed by calling mmap() on /dev/mem.
257  	 */
258  
259  	if ((fd = open("/dev/mem", O_RDONLY, 0)) < 0) {
260  		fprintf(stderr, "%s: Can not open /dev/mem for reading: %s\n",
261  			prog_name, strerror(errno));
262  		exit(1);
263  	}
264  
265  	bad_header_count = 0;
266  	bad_table_count = 0;
267  
268  	for (i = 0; i < NUM_MEM_RANGES; i++) {
269  		lbtable = lbtable_scan(mem_ranges[i].start, mem_ranges[i].end,
270  				       &bad_headers, &bad_tables);
271  
272  		if (lbtable != NULL)
273  			return;	/* success: we found it! */
274  
275  		bad_header_count += bad_headers;
276  		bad_table_count += bad_tables;
277  	}
278  
279  	fprintf(stderr,
280  		"%s: coreboot table not found.  coreboot does not appear to\n"
281  		"        be installed on this system.  Scanning for the table "
282  		"produced the\n"
283  		"        following results:\n\n"
284  		"            %d valid signatures were found with bad header "
285  		"checksums.\n"
286  		"            %d valid headers were found with bad table "
287  		"checksums.\n", prog_name, bad_header_count, bad_table_count);
288  	exit(1);
289  }
290  
291  /****************************************************************************
292   * dump_lbtable
293   *
294   * Do a low-level dump of the coreboot table.
295   ****************************************************************************/
296  void dump_lbtable(void)
297  {
298  	const char *p, *data;
299  	uint32_t bytes_processed;
300  	const struct lb_record *lbrec;
301  
302  	p = ((const char *)lbtable) + lbtable->header_bytes;
303  	printf("coreboot table at physical address 0x%lx:\n"
304  	       "    signature:       0x%x (ASCII: %c%c%c%c)\n"
305  	       "    header_bytes:    0x%x (decimal: %d)\n"
306  	       "    header_checksum: 0x%x (decimal: %d)\n"
307  	       "    table_bytes:     0x%x (decimal: %d)\n"
308  	       "    table_checksum:  0x%x (decimal: %d)\n"
309  	       "    table_entries:   0x%x (decimal: %d)\n\n",
310  	       vtophys(lbtable), lbtable->signature32,
311  	       lbtable->signature[0], lbtable->signature[1],
312  	       lbtable->signature[2], lbtable->signature[3],
313  	       lbtable->header_bytes, lbtable->header_bytes,
314  	       lbtable->header_checksum, lbtable->header_checksum,
315  	       lbtable->table_bytes, lbtable->table_bytes,
316  	       lbtable->table_checksum, lbtable->table_checksum,
317  	       lbtable->table_entries, lbtable->table_entries);
318  
319  	if ((lbtable->table_bytes == 0) != (lbtable->table_entries == 0)) {
320  		printf
321  		    ("Inconsistent values for table_bytes and table_entries!!!\n"
322  		     "They should be either both 0 or both nonzero.\n");
323  		return;
324  	}
325  
326  	if (lbtable->table_bytes == 0) {
327  		printf("The coreboot table is empty!!!\n");
328  		return;
329  	}
330  
331  	for (bytes_processed = 0;;) {
332  		lbrec = (const struct lb_record *)&p[bytes_processed];
333  		printf("    %s record at physical address 0x%lx:\n"
334  		       "        tag:  0x%x (decimal: %d)\n"
335  		       "        size: 0x%x (decimal: %d)\n"
336  		       "        data:\n",
337  		       lbrec_tag_to_str(lbrec->tag), vtophys(lbrec), lbrec->tag,
338  		       lbrec->tag, lbrec->size, lbrec->size);
339  
340  		data = ((const char *)lbrec) + sizeof(*lbrec);
341  		hexdump(data, lbrec->size - sizeof(*lbrec), vtophys(data),
342  			stdout, &format);
343  
344  		bytes_processed += lbrec->size;
345  
346  		if (bytes_processed >= lbtable->table_bytes)
347  			break;
348  
349  		printf("\n");
350  	}
351  }
352  
353  /****************************************************************************
354   * list_lbtable_choices
355   *
356   * List names and informational blurbs for items from the coreboot table
357   * that may be displayed using the -l option.
358   ****************************************************************************/
359  void list_lbtable_choices(void)
360  {
361  	int i;
362  
363  	for (i = 0;;) {
364  		printf("%s:\n%s",
365  		       lbtable_choices[i].name, lbtable_choices[i].description);
366  
367  		if (++i >= NUM_LBTABLE_CHOICES)
368  			break;
369  
370  		printf("\n");
371  	}
372  }
373  
374  /****************************************************************************
375   * list_lbtable_item
376   *
377   * Show the coreboot table item specified by 'item'.
378   ****************************************************************************/
379  void list_lbtable_item(const char item[])
380  {
381  	int i;
382  	const struct lb_record *rec;
383  
384  	for (i = 0; i < NUM_LBTABLE_CHOICES; i++) {
385  		if (strcmp(item, lbtable_choices[i].name) == 0)
386  			break;
387  	}
388  
389  	if (i == NUM_LBTABLE_CHOICES) {
390  		fprintf(stderr, "%s: Invalid coreboot table item %s.\n",
391  			prog_name, item);
392  		exit(1);
393  	}
394  
395  	if ((rec = find_lbrec(lbtable_choices[i].tag)) == NULL) {
396  		fprintf(stderr, lbtable_choices[i].nofound_msg, prog_name,
397  			lbtable_choices[i].name);
398  		exit(1);
399  	}
400  
401  	lbtable_choices[i].print_fn(rec);
402  }
403  
404  /****************************************************************************
405   * lbtable_scan
406   *
407   * Scan the chunk of memory specified by 'start' and 'end' for a coreboot
408   * table.  The first 4 bytes of the table are marked by the signature
409   * { 'L', 'B', 'I', 'O' }.  'start' and 'end' indicate the addresses of the
410   * first and last bytes of the chunk of memory to be scanned.  For instance,
411   * values of 0x10000000 and 0x1000ffff for 'start' and 'end' specify a 64k
412   * chunk of memory starting at address 0x10000000.  'start' and 'end' are
413   * physical addresses.
414   *
415   * If a coreboot table is found, return a pointer to it.  Otherwise return
416   * NULL.  On return, *bad_header_count and *bad_table_count are set as
417   * follows:
418   *
419   *     *bad_header_count:
420   *         Indicates the number of times in which a valid signature was found
421   *         but the header checksum was invalid.
422   *
423   *     *bad_table_count:
424   *         Indicates the number of times in which a header with a valid
425   *         checksum was found but the table checksum was invalid.
426   ****************************************************************************/
427  static const struct lb_header *lbtable_scan(unsigned long start,
428  					    unsigned long end,
429  					    int *bad_header_count,
430  					    int *bad_table_count)
431  {
432  	static const char signature[4] = { 'L', 'B', 'I', 'O' };
433  	const struct lb_header *table;
434  	const struct lb_forward *forward;
435  	unsigned long p;
436  	uint32_t sig;
437  
438  	assert(end >= start);
439  	memcpy(&sig, signature, sizeof(sig));
440  	table = NULL;
441  	*bad_header_count = 0;
442  	*bad_table_count = 0;
443  
444  	/* Look for signature.  Table is aligned on 16-byte boundary.  Therefore
445  	 * only check every fourth 32-bit memory word.  As the loop is coded below,
446  	 * this function will behave in a reasonable manner for ALL possible values
447  	 * for 'start' and 'end': even weird boundary cases like 0x00000000 and
448  	 * 0xffffffff on a 32-bit architecture.
449  	 */
450  	map_pages(start, end - start);
451  	for (p = start;
452  	     (p <= end) &&
453  	     (end - p >= (sizeof(uint32_t) - 1)); p += 4) {
454  		if (*(uint32_t*)phystov(p) != sig)
455  			continue;
456  
457  		/* We found a valid signature. */
458  		table = (const struct lb_header *)phystov(p);
459  
460  		/* validate header checksum */
461  		if (compute_ip_checksum((void *)table, sizeof(*table))) {
462  			(*bad_header_count)++;
463  			continue;
464  		}
465  
466  		map_pages(p, table->table_bytes + sizeof(*table));
467  
468  		table = (const struct lb_header *)phystov(p);
469  
470  		/* validate table checksum */
471  		if (table->table_checksum !=
472  		    compute_ip_checksum(((char *)table) + sizeof(*table),
473  					table->table_bytes)) {
474  			(*bad_table_count)++;
475  			continue;
476  		}
477  
478  		/* checksums are ok: we found it! */
479  		/* But it may just be a forwarding table, so look if there's a forwarder */
480  		lbtable = table;
481  		forward = (struct lb_forward *)find_lbrec(LB_TAG_FORWARD);
482  		lbtable = NULL;
483  
484  		if (forward) {
485  			uint64_t new_phys = forward->forward;
486  			table = lbtable_scan(new_phys, new_phys + getpagesize(),
487  					 bad_header_count, bad_table_count);
488  		}
489  		return table;
490  	}
491  
492  	return NULL;
493  }
494  
495  /****************************************************************************
496   * find_lbrec
497   *
498   * Find the record in the coreboot table that matches 'tag'.  Return pointer
499   * to record on success or NULL if record not found.
500   ****************************************************************************/
501  const struct lb_record *find_lbrec(uint32_t tag)
502  {
503  	const char *p;
504  	uint32_t bytes_processed;
505  	const struct lb_record *lbrec;
506  
507  	p = ((const char *)lbtable) + lbtable->header_bytes;
508  
509  	for (bytes_processed = 0;
510  	     bytes_processed < lbtable->table_bytes;
511  	     bytes_processed += lbrec->size) {
512  		lbrec = (const struct lb_record *)&p[bytes_processed];
513  
514  		if (lbrec->tag == tag)
515  			return lbrec;
516  	}
517  
518  	return NULL;
519  }
520  
521  /****************************************************************************
522   * lbrec_tag_to_str
523   *
524   * Return a pointer to the string representation of the given coreboot table
525   * tag.
526   ****************************************************************************/
527  static const char *lbrec_tag_to_str(uint32_t tag)
528  {
529  	switch (tag) {
530  	case LB_TAG_UNUSED:
531  		return "UNUSED";
532  
533  	case LB_TAG_MEMORY:
534  		return "MEMORY";
535  
536  	case LB_TAG_HWRPB:
537  		return "HWRPB";
538  
539  	case LB_TAG_MAINBOARD:
540  		return "MAINBOARD";
541  
542  	case LB_TAG_VERSION:
543  		return "VERSION";
544  
545  	case LB_TAG_EXTRA_VERSION:
546  		return "EXTRA_VERSION";
547  
548  	case LB_TAG_BUILD:
549  		return "BUILD";
550  
551  	case LB_TAG_COMPILE_TIME:
552  		return "COMPILE_TIME";
553  
554  	case LB_TAG_COMPILE_BY:
555  		return "COMPILE_BY";
556  
557  	case LB_TAG_COMPILE_HOST:
558  		return "COMPILE_HOST";
559  
560  	case LB_TAG_COMPILE_DOMAIN:
561  		return "COMPILE_DOMAIN";
562  
563  	case LB_TAG_COMPILER:
564  		return "COMPILER";
565  
566  	case LB_TAG_LINKER:
567  		return "LINKER";
568  
569  	case LB_TAG_ASSEMBLER:
570  		return "ASSEMBLER";
571  
572  	case LB_TAG_SERIAL:
573  		return "SERIAL";
574  
575  	case LB_TAG_CONSOLE:
576  		return "CONSOLE";
577  
578  	case LB_TAG_FORWARD:
579  		return "FORWARD";
580  
581  	case LB_TAG_CMOS_OPTION_TABLE:
582  		return "CMOS_OPTION_TABLE";
583  
584  	case LB_TAG_OPTION_CHECKSUM:
585  		return "OPTION_CHECKSUM";
586  
587  	default:
588  		break;
589  	}
590  
591  	return "UNKNOWN";
592  }
593  
594  /****************************************************************************
595   * memory_print_fn
596   *
597   * Display function for 'memory' item of coreboot table.
598   ****************************************************************************/
599  static void memory_print_fn(const struct lb_record *rec)
600  {
601  	const struct lb_memory *p;
602  	const char *mem_type;
603  	const struct lb_memory_range *ranges;
604  	uint64_t size, start, end;
605  	int i, entries;
606  
607  	p = (const struct lb_memory *)rec;
608  	entries = (p->size - sizeof(*p)) / sizeof(p->map[0]);
609  	ranges = p->map;
610  
611  	if (entries == 0) {
612  		printf("No memory ranges were found.\n");
613  		return;
614  	}
615  
616  	for (i = 0;;) {
617  		switch (ranges[i].type) {
618  		case LB_MEM_RAM:
619  			mem_type = "AVAILABLE";
620  			break;
621  
622  		case LB_MEM_RESERVED:
623  			mem_type = "RESERVED";
624  			break;
625  
626  		case LB_MEM_TABLE:
627  			mem_type = "CONFIG_TABLE";
628  			break;
629  
630  		default:
631  			mem_type = "UNKNOWN";
632  			break;
633  		}
634  
635  		size = ranges[i].size;
636  		start = ranges[i].start;
637  		end = start + size - 1;
638  		printf("%s memory:\n"
639  		       "    from physical addresses 0x%016" PRIx64
640  		       " to 0x%016" PRIx64 "\n    size is 0x%016" PRIx64
641  		       " bytes (%" PRId64 " in decimal)\n",
642  		       mem_type, start, end, size, size);
643  
644  		if (++i >= entries)
645  			break;
646  
647  		printf("\n");
648  	}
649  }
650  
651  /****************************************************************************
652   * mainboard_print_fn
653   *
654   * Display function for 'mainboard' item of coreboot table.
655   ****************************************************************************/
656  static void mainboard_print_fn(const struct lb_record *rec)
657  {
658  	const struct lb_mainboard *p;
659  
660  	p = (const struct lb_mainboard *)rec;
661  	printf("Vendor:      %s\n"
662  	       "Part number: %s\n",
663  	       &p->strings[p->vendor_idx], &p->strings[p->part_number_idx]);
664  }
665  
666  /****************************************************************************
667   * cmos_opt_table_print_fn
668   *
669   * Display function for 'cmos_opt_table' item of coreboot table.
670   ****************************************************************************/
671  static void cmos_opt_table_print_fn(const struct lb_record *rec)
672  {
673  	const struct cmos_option_table *p;
674  	const struct lb_record *cmos_item;
675  	uint32_t bytes_processed, bytes_for_entries;
676  	const char *q;
677  
678  	p = (const struct cmos_option_table *)rec;
679  	q = ((const char *)p) + p->header_length;
680  	bytes_for_entries = p->size - p->header_length;
681  
682  	printf("CMOS option table at physical address 0x%lx:\n"
683  	       "    tag:           0x%x (decimal: %d)\n"
684  	       "    size:          0x%x (decimal: %d)\n"
685  	       "    header_length: 0x%x (decimal: %d)\n\n",
686  	       vtophys(p), p->tag, p->tag, p->size, p->size, p->header_length,
687  	       p->header_length);
688  
689  	if (p->header_length > p->size) {
690  		printf
691  		    ("Header length for CMOS option table is greater than the size "
692  		     "of the entire table including header!!!\n");
693  		return;
694  	}
695  
696  	if (bytes_for_entries == 0) {
697  		printf("The CMOS option table is empty!!!\n");
698  		return;
699  	}
700  
701  	for (bytes_processed = 0;;) {
702  		cmos_item = (const struct lb_record *)&q[bytes_processed];
703  
704  		switch (cmos_item->tag) {
705  		case LB_TAG_OPTION:
706  			print_option_record((const struct cmos_entries *)
707  					    cmos_item);
708  			break;
709  
710  		case LB_TAG_OPTION_ENUM:
711  			print_enum_record((const struct cmos_enums *)cmos_item);
712  			break;
713  
714  		case LB_TAG_OPTION_DEFAULTS:
715  			print_defaults_record((const struct cmos_defaults *)
716  					      cmos_item);
717  			break;
718  
719  		default:
720  			print_unknown_record(cmos_item);
721  			break;
722  		}
723  
724  		bytes_processed += cmos_item->size;
725  
726  		if (bytes_processed >= bytes_for_entries)
727  			break;
728  
729  		printf("\n");
730  	}
731  }
732  
733  /****************************************************************************
734   * print_option_record
735   *
736   * Display "option" record from CMOS option table.
737   ****************************************************************************/
738  static void print_option_record(const struct cmos_entries *cmos_entry)
739  {
740  	static const size_t S_BUFSIZE = 80;
741  	char s[S_BUFSIZE];
742  
743  	switch (cmos_entry->config) {
744  	case 'e':
745  		strcpy(s, "ENUM");
746  		break;
747  
748  	case 'h':
749  		strcpy(s, "HEX");
750  		break;
751  
752  	case 'r':
753  		strcpy(s, "RESERVED");
754  		break;
755  
756  	default:
757  		snprintf(s, S_BUFSIZE, "UNKNOWN: value is 0x%x (decimal: %d)",
758  			 cmos_entry->config, cmos_entry->config);
759  		break;
760  	}
761  
762  	printf("    OPTION record at physical address 0x%lx:\n"
763  	       "        tag:       0x%x (decimal: %d)\n"
764  	       "        size:      0x%x (decimal: %d)\n"
765  	       "        bit:       0x%x (decimal: %d)\n"
766  	       "        length:    0x%x (decimal: %d)\n"
767  	       "        config:    %s\n"
768  	       "        config_id: 0x%x (decimal: %d)\n"
769  	       "        name:      %s\n",
770  	       vtophys(cmos_entry), cmos_entry->tag, cmos_entry->tag,
771  	       cmos_entry->size, cmos_entry->size, cmos_entry->bit,
772  	       cmos_entry->bit, cmos_entry->length, cmos_entry->length, s,
773  	       cmos_entry->config_id, cmos_entry->config_id, cmos_entry->name);
774  }
775  
776  /****************************************************************************
777   * print_enum_record
778   *
779   * Display "enum" record from CMOS option table.
780   ****************************************************************************/
781  static void print_enum_record(const struct cmos_enums *cmos_enum)
782  {
783  	printf("    ENUM record at physical address 0x%lx:\n"
784  	       "        tag:       0x%x (decimal: %d)\n"
785  	       "        size:      0x%x (decimal: %d)\n"
786  	       "        config_id: 0x%x (decimal: %d)\n"
787  	       "        value:     0x%x (decimal: %d)\n"
788  	       "        text:      %s\n",
789  	       vtophys(cmos_enum), cmos_enum->tag, cmos_enum->tag,
790  	       cmos_enum->size, cmos_enum->size, cmos_enum->config_id,
791  	       cmos_enum->config_id, cmos_enum->value, cmos_enum->value,
792  	       cmos_enum->text);
793  }
794  
795  /****************************************************************************
796   * print_defaults_record
797   *
798   * Display "defaults" record from CMOS option table.
799   ****************************************************************************/
800  static void print_defaults_record(const struct cmos_defaults *cmos_defaults)
801  {
802  	printf("    DEFAULTS record at physical address 0x%lx:\n"
803  	       "        tag:         0x%x (decimal: %d)\n"
804  	       "        size:        0x%x (decimal: %d)\n"
805  	       "        name_length: 0x%x (decimal: %d)\n"
806  	       "        name:        %s\n"
807  	       "        default_set:\n",
808  	       vtophys(cmos_defaults), cmos_defaults->tag, cmos_defaults->tag,
809  	       cmos_defaults->size, cmos_defaults->size,
810  	       cmos_defaults->name_length, cmos_defaults->name_length,
811  	       cmos_defaults->name);
812  	hexdump(cmos_defaults->default_set, CMOS_IMAGE_BUFFER_SIZE,
813  		vtophys(cmos_defaults->default_set), stdout, &format);
814  }
815  
816  /****************************************************************************
817   * print_unknown_record
818   *
819   * Display record of unknown type from CMOS option table.
820   ****************************************************************************/
821  static void print_unknown_record(const struct lb_record *cmos_item)
822  {
823  	const char *data;
824  
825  	printf("    UNKNOWN record at physical address 0x%lx:\n"
826  	       "        tag:  0x%x (decimal: %d)\n"
827  	       "        size: 0x%x (decimal: %d)\n"
828  	       "        data:\n",
829  	       vtophys(cmos_item), cmos_item->tag, cmos_item->tag,
830  	       cmos_item->size, cmos_item->size);
831  	data = ((const char *)cmos_item) + sizeof(*cmos_item);
832  	hexdump(data, cmos_item->size - sizeof(*cmos_item), vtophys(data),
833  		stdout, &format);
834  }
835  
836  /****************************************************************************
837   * option_checksum_print_fn
838   *
839   * Display function for 'option_checksum' item of coreboot table.
840   ****************************************************************************/
841  static void option_checksum_print_fn(const struct lb_record *rec)
842  {
843  	struct cmos_checksum *p;
844  
845  	p = (struct cmos_checksum *)rec;
846  	printf("CMOS checksum from bit %d to bit %d\n"
847  	       "at position %d is type %s.\n",
848  	       p->range_start, p->range_end, p->location,
849  	       (p->type == CHECKSUM_PCBIOS) ? "PC BIOS" : "NONE");
850  }
851  
852  /****************************************************************************
853   * string_print_fn
854   *
855   * Display function for a generic item of coreboot table that simply
856   * consists of a string.
857   ****************************************************************************/
858  static void string_print_fn(const struct lb_record *rec)
859  {
860  	const struct lb_string *p;
861  
862  	p = (const struct lb_string *)rec;
863  	printf("%s\n", p->string);
864  }