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