Clean up comments, whitespace, and copyright date in the AMD HT code.
[coreboot.git] / util / nvramtool / lbtable.c
1 /*****************************************************************************\
2  * lbtable.c
3  * $Id$
4  *****************************************************************************
5  *  Copyright (C) 2002-2005 The Regents of the University of California.
6  *  Produced at the Lawrence Livermore National Laboratory.
7  *  Written by Dave Peterson <dsp@llnl.gov> <dave_peterson@pobox.com>
8  *  and Stefan Reinauer <stepan@openbios.org>.
9  *  UCRL-CODE-2003-012
10  *  All rights reserved.
11  *
12  *  This file is part of nvramtool, a utility for reading/writing coreboot
13  *  parameters and displaying information from the coreboot table.
14  *  For details, see http://coreboot.org/nvramtool.
15  *
16  *  Please also read the file DISCLAIMER which is included in this software
17  *  distribution.
18  *
19  *  This program is free software; you can redistribute it and/or modify it
20  *  under the terms of the GNU General Public License (as published by the
21  *  Free Software Foundation) version 2, dated June 1991.
22  *
23  *  This program is distributed in the hope that it will be useful, but
24  *  WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
25  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the terms and
26  *  conditions of the GNU General Public License for more details.
27  *
28  *  You should have received a copy of the GNU General Public License along
29  *  with this program; if not, write to the Free Software Foundation, Inc.,
30  *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
31 \*****************************************************************************/
32
33 #include <sys/mman.h>
34 #include "common.h"
35 #include "coreboot_tables.h"
36 #include "ip_checksum.h"
37 #include "lbtable.h"
38 #include "layout.h"
39 #include "cmos_lowlevel.h"
40 #include "hexdump.h"
41
42 typedef void (*lbtable_print_fn_t) (const struct lb_record *rec);
43
44 /* This structure represents an item in the coreboot table that may be
45  * displayed using the -l option.
46  */
47 typedef struct
48  { uint32_t tag;
49    const char *name;
50    const char *description;
51    const char *nofound_msg;
52    lbtable_print_fn_t print_fn;
53  }
54 lbtable_choice_t;
55
56 typedef struct
57  { unsigned long start;  /* address of first byte of memory range */
58    unsigned long end;  /* address of last byte of memory range */
59  }
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 void process_cmos_table (void);
67 static void get_cmos_checksum_info (void);
68 static void try_convert_checksum_layout (cmos_checksum_layout_t *layout);
69 static void try_add_cmos_table_enum (cmos_enum_t *cmos_enum);
70 static void try_add_cmos_table_entry (cmos_entry_t *cmos_entry);
71 static const struct lb_record * find_lbrec (uint32_t tag);
72 static const char * lbrec_tag_to_str (uint32_t tag);
73 static const struct cmos_entries * first_cmos_table_entry (void);
74 static const struct cmos_entries *
75       next_cmos_table_entry (const struct cmos_entries *last);
76 static const struct cmos_enums * first_cmos_table_enum (void);
77 static const struct cmos_enums * next_cmos_table_enum
78       (const struct cmos_enums *last);
79 static const struct lb_record * first_cmos_rec (uint32_t tag);
80 static const struct lb_record * next_cmos_rec (const struct lb_record *last,
81                                                uint32_t tag);
82 static void memory_print_fn (const struct lb_record *rec);
83 static void mainboard_print_fn (const struct lb_record *rec);
84 static void cmos_opt_table_print_fn (const struct lb_record *rec);
85 static void print_option_record (const struct cmos_entries *cmos_entry);
86 static void print_enum_record (const struct cmos_enums *cmos_enum);
87 static void print_defaults_record (const struct cmos_defaults *cmos_defaults);
88 static void print_unknown_record (const struct lb_record *cmos_item);
89 static void option_checksum_print_fn (const struct lb_record *rec);
90 static void string_print_fn (const struct lb_record *rec);
91 static void uint64_to_hex_string (char str[], uint64_t n);
92
93 static const char memory_desc[] =
94 "    This shows information about system memory.\n";
95
96 static const char mainboard_desc[] =
97 "    This shows information about your mainboard.\n";
98
99 static const char version_desc[] =
100 "    This shows coreboot version information.\n";
101
102 static const char extra_version_desc[] =
103 "    This shows extra coreboot version information.\n";
104
105 static const char build_desc[] =
106 "    This shows coreboot build information.\n";
107
108 static const char compile_time_desc[] =
109 "    This shows when coreboot was compiled.\n";
110
111 static const char compile_by_desc[] =
112 "    This shows who compiled coreboot.\n";
113
114 static const char compile_host_desc[] =
115 "    This shows the name of the machine that compiled coreboot.\n";
116
117 static const char compile_domain_desc[] =
118 "    This shows the domain name of the machine that compiled coreboot.\n";
119
120 static const char compiler_desc[] =
121 "    This shows the name of the compiler used to build coreboot.\n";
122
123 static const char linker_desc[] =
124 "    This shows the name of the linker used to build coreboot.\n";
125
126 static const char assembler_desc[] =
127 "    This shows the name of the assembler used to build coreboot.\n";
128
129 static const char cmos_opt_table_desc[] =
130 "    This does a low-level dump of the CMOS option table.  The table "
131 "contains\n"
132 "    information about the layout of the values that coreboot stores in\n"
133 "    nonvolatile RAM.\n";
134
135 static const char option_checksum_desc[] =
136 "    This shows the location of the CMOS checksum and the area over which it "
137 "is\n"
138 "    calculated.\n";
139
140 static const char generic_nofound_msg[] =
141 "%s: Item %s not found in coreboot table.\n";
142
143 static const char nofound_msg_cmos_opt_table[] =
144 "%s: Item %s not found in coreboot table.  Apparently, the "
145 "coreboot installed on this system was built without specifying "
146 "HAVE_OPTION_TABLE.\n";
147
148 static const char nofound_msg_option_checksum[] =
149 "%s: Item %s not found in coreboot table. Apparently, you are "
150 "using coreboot v1.\n";
151
152 /* This is the number of items from the coreboot table that may be displayed
153  * using the -l option.
154  */
155 #define NUM_LBTABLE_CHOICES 14
156
157 /* These represent the various items from the coreboot table that may be
158  * displayed using the -l option.
159  */
160 static const lbtable_choice_t lbtable_choices[NUM_LBTABLE_CHOICES] =
161  { { LB_TAG_MEMORY,            "memory",
162      memory_desc,              generic_nofound_msg,
163      memory_print_fn
164    },
165    { LB_TAG_MAINBOARD,         "mainboard",
166      mainboard_desc,           generic_nofound_msg,
167      mainboard_print_fn
168    },
169    { LB_TAG_VERSION,           "version",
170      version_desc,             generic_nofound_msg,
171      string_print_fn
172    },
173    { LB_TAG_EXTRA_VERSION,     "extra_version",
174      extra_version_desc,       generic_nofound_msg,
175      string_print_fn
176    },
177    { LB_TAG_BUILD,             "build",
178      build_desc,               generic_nofound_msg,
179      string_print_fn
180    },
181    { LB_TAG_COMPILE_TIME,      "compile_time",
182      compile_time_desc,        generic_nofound_msg,
183      string_print_fn
184    },
185    { LB_TAG_COMPILE_BY,        "compile_by",
186      compile_by_desc,          generic_nofound_msg,
187      string_print_fn
188    },
189    { LB_TAG_COMPILE_HOST,      "compile_host",
190      compile_host_desc,        generic_nofound_msg,
191      string_print_fn
192    },
193    { LB_TAG_COMPILE_DOMAIN,    "compile_domain",
194      compile_domain_desc,      generic_nofound_msg,
195      string_print_fn
196    },
197    { LB_TAG_COMPILER,          "compiler",
198      compiler_desc,            generic_nofound_msg,
199      string_print_fn
200    },
201    { LB_TAG_LINKER,            "linker",
202      linker_desc,              generic_nofound_msg,
203      string_print_fn
204    },
205    { LB_TAG_ASSEMBLER,         "assembler",
206      assembler_desc,           generic_nofound_msg,
207      string_print_fn
208    },
209    { LB_TAG_CMOS_OPTION_TABLE, "cmos_opt_table",
210      cmos_opt_table_desc,      nofound_msg_cmos_opt_table,
211      cmos_opt_table_print_fn
212    },
213    { LB_TAG_OPTION_CHECKSUM, "option_checksum",
214      option_checksum_desc,     nofound_msg_option_checksum,
215      option_checksum_print_fn
216    }
217  };
218
219 /* The coreboot table resides in low physical memory, which we access using
220  * /dev/mem.  These are ranges of physical memory that should be scanned for a
221  * coreboot table.
222  */
223
224 #define NUM_MEM_RANGES 2
225
226 static const mem_range_t mem_ranges[NUM_MEM_RANGES] =
227  { { 0x00000000, 0x00000fff },
228    { 0x000f0000, 0x000fffff }
229  };
230
231 /* This is the number of bytes of physical memory to map, starting at physical
232  * address 0.  This value must be large enough to contain all memory ranges
233  * specified in mem_ranges above plus the maximum possible size of the
234  * coreboot table (since the start of the table could potentially occur at
235  * the end of the last memory range).
236  */
237 static const size_t BYTES_TO_MAP = (1024 * 1024);
238
239 /* Pointer to low physical memory that we access by calling mmap() on
240  * /dev/mem.
241  */
242 static const void *low_phys_mem;
243
244 /* Pointer to coreboot table. */
245 static const struct lb_header *lbtable = NULL;
246
247 /* The CMOS option table is located within the coreboot table.  It tells us
248  * where the CMOS parameters are located in the nonvolatile RAM.
249  */
250 static const struct cmos_option_table *cmos_table = NULL;
251
252 static const hexdump_format_t format =
253  { 12, 4, "            ", " | ", " ", " | ", '.', NULL };
254
255 /****************************************************************************
256  * vtophys
257  *
258  * Convert a virtual address to a physical address.  'vaddr' is a virtual
259  * address in the address space of the current process.  It points to
260  * somewhere in the chunk of memory that we mapped by calling mmap() on
261  * /dev/mem.  This macro converts 'vaddr' to a physical address.
262  ****************************************************************************/
263 #define vtophys(vaddr) (((unsigned long) vaddr) -       \
264                         ((unsigned long) low_phys_mem))
265
266 /****************************************************************************
267  * phystov
268  *
269  * Convert a physical address to a virtual address.  'paddr' is a physical
270  * address.  This macro converts 'paddr' to a virtual address in the address
271  * space of the current process.  The virtual to physical mapping was set up
272  * by calling mmap() on /dev/mem.
273  ****************************************************************************/
274 #define phystov(paddr) (((unsigned long) low_phys_mem) + \
275                         ((unsigned long) paddr))
276
277 /****************************************************************************
278  * get_lbtable
279  *
280  * Find the coreboot table and set global variable lbtable to point to it.
281  ****************************************************************************/
282 void get_lbtable (void)
283  { int fd, i, bad_header_count, bad_table_count, bad_headers, bad_tables;
284
285    if (lbtable != NULL)
286       return;
287
288    /* The coreboot table is located in low physical memory, which may be
289     * conveniently accessed by calling mmap() on /dev/mem.
290     */
291
292    if ((fd = open("/dev/mem", O_RDONLY, 0)) < 0)
293     { fprintf(stderr, "%s: Can not open /dev/mem for reading: %s\n",
294               prog_name, strerror(errno));
295       exit(1);
296     }
297
298    if ((low_phys_mem = mmap(NULL, BYTES_TO_MAP, PROT_READ, MAP_SHARED, fd, 0))
299        == MAP_FAILED)
300     { fprintf(stderr, "%s: Failed to mmap /dev/mem: %s\n", prog_name,
301               strerror(errno));
302       exit(1);
303     }
304
305    bad_header_count = 0;
306    bad_table_count = 0;
307
308    for (i = 0; i < NUM_MEM_RANGES; i++)
309     { lbtable = lbtable_scan(phystov(mem_ranges[i].start),
310                              phystov(mem_ranges[i].end),
311                              &bad_headers, &bad_tables);
312
313       if (lbtable != NULL)
314          return; /* success: we found it! */
315
316       bad_header_count += bad_headers;
317       bad_table_count += bad_tables;
318     }
319
320    fprintf(stderr,
321            "%s: coreboot table not found.  coreboot does not appear to\n"
322            "        be installed on this system.  Scanning for the table "
323            "produced the\n"
324            "        following results:\n\n"
325            "            %d valid signatures were found with bad header "
326            "checksums.\n"
327            "            %d valid headers were found with bad table "
328            "checksums.\n",
329            prog_name, bad_header_count, bad_table_count);
330    exit(1);
331  }
332
333 /****************************************************************************
334  * get_layout_from_cmos_table
335  *
336  * Find the CMOS table which is stored within the coreboot table and set the
337  * global variable cmos_table to point to it.
338  ****************************************************************************/
339 void get_layout_from_cmos_table (void)
340  {
341
342    get_lbtable();
343    cmos_table = (const struct cmos_option_table *)
344                 find_lbrec(LB_TAG_CMOS_OPTION_TABLE);
345
346    if ((cmos_table) == NULL)
347     { fprintf(stderr,
348               "%s: CMOS option table not found in coreboot table.  "
349               "Apparently, the coreboot installed on this system was "
350               "built without specifying HAVE_OPTION_TABLE.\n",
351               prog_name);
352       exit(1);
353     }
354
355    process_cmos_table();
356    get_cmos_checksum_info();
357  }
358
359 /****************************************************************************
360  * dump_lbtable
361  *
362  * Do a low-level dump of the coreboot table.
363  ****************************************************************************/
364 void dump_lbtable (void)
365  { const char *p, *data;
366    uint32_t bytes_processed;
367    const struct lb_record *lbrec;
368
369    p = ((const char *) lbtable) + lbtable->header_bytes;
370    printf("Coreboot table at physical address 0x%lx:\n"
371           "    signature:       0x%x (ASCII: %c%c%c%c)\n"
372           "    header_bytes:    0x%x (decimal: %d)\n"
373           "    header_checksum: 0x%x (decimal: %d)\n"
374           "    table_bytes:     0x%x (decimal: %d)\n"
375           "    table_checksum:  0x%x (decimal: %d)\n"
376           "    table_entries:   0x%x (decimal: %d)\n\n",
377           vtophys(lbtable), *((uint32_t *) lbtable->signature),
378           lbtable->signature[0], lbtable->signature[1],lbtable->signature[2],
379           lbtable->signature[3], lbtable->header_bytes, lbtable->header_bytes,
380           lbtable->header_checksum, lbtable->header_checksum,
381           lbtable->table_bytes, lbtable->table_bytes, lbtable->table_checksum,
382           lbtable->table_checksum, lbtable->table_entries,
383           lbtable->table_entries);
384
385    if ((lbtable->table_bytes == 0) != (lbtable->table_entries == 0))
386     { printf("Inconsistent values for table_bytes and table_entries!!!\n"
387              "They should be either both 0 or both nonzero.\n");
388       return;
389     }
390
391    if (lbtable->table_bytes == 0)
392     { printf("The coreboot table is empty!!!\n");
393       return;
394     }
395
396    for (bytes_processed = 0; ; )
397     { lbrec = (const struct lb_record *) &p[bytes_processed];
398       printf("    %s record at physical address 0x%lx:\n"
399              "        tag:  0x%x (decimal: %d)\n"
400              "        size: 0x%x (decimal: %d)\n"
401              "        data:\n",
402              lbrec_tag_to_str(lbrec->tag), vtophys(lbrec), lbrec->tag,
403              lbrec->tag, lbrec->size, lbrec->size);
404
405       data = ((const char *) lbrec) + sizeof(*lbrec);
406       hexdump(data, lbrec->size - sizeof(*lbrec), vtophys(data), stdout,
407               &format);
408
409       bytes_processed += lbrec->size;
410
411       if (bytes_processed >= lbtable->table_bytes)
412          break;
413
414       printf("\n");
415     }
416  }
417
418 /****************************************************************************
419  * list_lbtable_choices
420  *
421  * List names and informational blurbs for items from the coreboot table
422  * that may be displayed using the -l option.
423  ****************************************************************************/
424 void list_lbtable_choices (void)
425  { int i;
426
427    for (i = 0; ; )
428     { printf("%s:\n%s",
429              lbtable_choices[i].name, lbtable_choices[i].description);
430
431       if (++i >= NUM_LBTABLE_CHOICES)
432          break;
433
434       printf("\n");
435     }
436  }
437
438 /****************************************************************************
439  * list_lbtable_item
440  *
441  * Show the coreboot table item specified by 'item'.
442  ****************************************************************************/
443 void list_lbtable_item (const char item[])
444  { int i;
445    const struct lb_record *rec;
446
447    for (i = 0; i < NUM_LBTABLE_CHOICES; i++)
448     { if (strcmp(item, lbtable_choices[i].name) == 0)
449          break;
450     }
451
452    if (i == NUM_LBTABLE_CHOICES)
453     { fprintf(stderr, "%s: Invalid coreboot table item %s.\n", prog_name,
454               item);
455       exit(1);
456     }
457
458    if ((rec = find_lbrec(lbtable_choices[i].tag)) == NULL)
459     { fprintf(stderr, lbtable_choices[i].nofound_msg, prog_name,
460               lbtable_choices[i].name);
461       exit(1);
462     }
463
464    lbtable_choices[i].print_fn(rec);
465  }
466
467 /****************************************************************************
468  * lbtable_scan
469  *
470  * Scan the chunk of memory specified by 'start' and 'end' for a coreboot
471  * table.  The first 4 bytes of the table are marked by the signature
472  * { 'L', 'B', 'I', 'O' }.  'start' and 'end' indicate the addresses of the
473  * first and last bytes of the chunk of memory to be scanned.  For instance,
474  * values of 0x10000000 and 0x1000ffff for 'start' and 'end' specify a 64k
475  * chunk of memory starting at address 0x10000000.  'start' and 'end' are
476  * virtual addresses in the address space of the current process.  They
477  * represent a chunk of memory obtained by calling mmap() on /dev/mem.
478  *
479  * If a coreboot table is found, return a pointer to it.  Otherwise return
480  * NULL.  On return, *bad_header_count and *bad_table_count are set as
481  * follows:
482  *
483  *     *bad_header_count:
484  *         Indicates the number of times in which a valid signature was found
485  *         but the header checksum was invalid.
486  *
487  *     *bad_table_count:
488  *         Indicates the number of times in which a header with a valid
489  *         checksum was found but the table checksum was invalid.
490  ****************************************************************************/
491 static const struct lb_header * lbtable_scan (unsigned long start,
492                                               unsigned long end,
493                                               int *bad_header_count,
494                                               int *bad_table_count)
495  { static const char signature[] = { 'L', 'B', 'I', 'O' };
496    const struct lb_header *table;
497    const uint32_t *p;
498    uint32_t sig;
499
500    assert(end >= start);
501    sig = (*((const uint32_t *) signature));
502    table = NULL;
503    *bad_header_count = 0;
504    *bad_table_count = 0;
505
506    /* Look for signature.  Table is aligned on 16-byte boundary.  Therefore
507     * only check every fourth 32-bit memory word.  As the loop is coded below,
508     * this function will behave in a reasonable manner for ALL possible values
509     * for 'start' and 'end': even weird boundary cases like 0x00000000 and
510     * 0xffffffff on a 32-bit architecture.
511     */
512    for (p = (const uint32_t *) start;
513         (((unsigned long) p) <= end) &&
514         ((end - (unsigned long) p) >= (sizeof(uint32_t) - 1));
515         p += 4)
516     { if (*p != sig)
517          continue;
518
519       /* We found a valid signature. */
520       table = (const struct lb_header *) p;
521
522       /* validate header checksum */
523       if (compute_ip_checksum((void *) table, sizeof(*table)))
524        { (*bad_header_count)++;
525          continue;
526        }
527
528       /* validate table checksum */
529       if (table->table_checksum !=
530           compute_ip_checksum(((char *) table) + sizeof(*table),
531                               table->table_bytes))
532        { (*bad_table_count)++;
533          continue;
534        }
535
536       /* checksums are ok: we found it! */
537       return table;
538     }
539
540    return NULL;
541  }
542
543 /****************************************************************************
544  * process_cmos_table
545  *
546  * Extract layout information from the CMOS option table and store it in our
547  * internal repository.
548  ****************************************************************************/
549 static void process_cmos_table (void)
550  { const struct cmos_enums *p;
551    const struct cmos_entries *q;
552    cmos_enum_t cmos_enum;
553    cmos_entry_t cmos_entry;
554
555    /* First add the enums. */
556    for (p = first_cmos_table_enum(); p != NULL; p = next_cmos_table_enum(p))
557     { cmos_enum.config_id = p->config_id;
558       cmos_enum.value = p->value;
559       strncpy(cmos_enum.text, p->text, CMOS_MAX_TEXT_LENGTH);
560       cmos_enum.text[CMOS_MAX_TEXT_LENGTH] = '\0';
561       try_add_cmos_table_enum(&cmos_enum);
562     }
563
564    /* Now add the entries.  We must add the entries after the enums because
565     * the entries are sanity checked against the enums as they are added.
566     */
567    for (q = first_cmos_table_entry(); q != NULL; q = next_cmos_table_entry(q))
568     { cmos_entry.bit = q->bit;
569       cmos_entry.length = q->length;
570
571       switch (q->config)
572        { case 'e':
573             cmos_entry.config = CMOS_ENTRY_ENUM;
574             break;
575
576          case 'h':
577             cmos_entry.config = CMOS_ENTRY_HEX;
578             break;
579
580          case 'r':
581             cmos_entry.config = CMOS_ENTRY_RESERVED;
582             break;
583
584          default:
585             fprintf(stderr,
586                     "%s: Entry in CMOS option table has unknown config "
587                     "value.\n", prog_name);
588             exit(1);
589        }
590
591       cmos_entry.config_id = q->config_id;
592       strncpy(cmos_entry.name, q->name, CMOS_MAX_NAME_LENGTH);
593       cmos_entry.name[CMOS_MAX_NAME_LENGTH] = '\0';
594       try_add_cmos_table_entry(&cmos_entry);
595     }
596  }
597
598 /****************************************************************************
599  * get_cmos_checksum_info
600  *
601  * Get layout information for CMOS checksum.
602  ****************************************************************************/
603 static void get_cmos_checksum_info (void)
604  { const cmos_entry_t *e;
605    struct cmos_checksum *checksum;
606    cmos_checksum_layout_t layout;
607    unsigned index, index2;
608
609    checksum = (struct cmos_checksum *) find_lbrec(LB_TAG_OPTION_CHECKSUM);
610
611    if (checksum != NULL)
612     { /* We are lucky.  The coreboot table hints us to the checksum.
613        * We might have to check the type field here though.
614        */
615       layout.summed_area_start = checksum->range_start;
616       layout.summed_area_end = checksum->range_end;
617       layout.checksum_at = checksum->location;
618       try_convert_checksum_layout(&layout);
619       cmos_checksum_start = layout.summed_area_start;
620       cmos_checksum_end = layout.summed_area_end;
621       cmos_checksum_index = layout.checksum_at;
622       return;
623     }
624
625    if ((e = find_cmos_entry(checksum_param_name)) == NULL)
626       return;
627
628    /* If we get here, we are unlucky.  The CMOS option table contains the
629     * location of the CMOS checksum.  However, there is no information
630     * regarding which bytes of the CMOS area the checksum is computed over.
631     * Thus we have to hope our presets will be fine.
632     */
633
634    if (e->bit % 8)
635     { fprintf(stderr, "%s: Error: CMOS checksum is not byte-aligned.\n",
636               prog_name);
637       exit(1);
638     }
639
640    index = e->bit / 8;
641    index2 = index + 1;  /* The CMOS checksum occupies 16 bits. */
642
643    if (verify_cmos_byte_index(index) || verify_cmos_byte_index(index2))
644     { fprintf(stderr, "%s: Error: CMOS checksum location out of range.\n",
645               prog_name);
646       exit(1);
647     }
648
649    if (((index >= cmos_checksum_start) && (index <= cmos_checksum_end)) ||
650        (((index2) >= cmos_checksum_start) && ((index2) <= cmos_checksum_end)))
651     { fprintf(stderr, "%s: Error: CMOS checksum overlaps checksummed area.\n",
652               prog_name);
653       exit(1);
654     }
655
656    cmos_checksum_index = index;
657  }
658
659 /****************************************************************************
660  * try_convert_checksum_layout
661  *
662  * Perform sanity checking on CMOS checksum layout information and attempt to
663  * convert information from bit positions to byte positions.  Return OK on
664  * success or an error code on failure.
665  ****************************************************************************/
666 static void try_convert_checksum_layout (cmos_checksum_layout_t *layout)
667  { switch (checksum_layout_to_bytes(layout))
668     { case OK:
669          return;
670
671       case LAYOUT_SUMMED_AREA_START_NOT_ALIGNED:
672          fprintf(stderr,
673                  "%s: CMOS checksummed area start is not byte-aligned.\n",
674                  prog_name);
675          break;
676
677       case LAYOUT_SUMMED_AREA_END_NOT_ALIGNED:
678          fprintf(stderr,
679                  "%s: CMOS checksummed area end is not byte-aligned.\n",
680                  prog_name);
681          break;
682
683       case LAYOUT_CHECKSUM_LOCATION_NOT_ALIGNED:
684          fprintf(stderr,
685                  "%s: CMOS checksum location is not byte-aligned.\n",
686                  prog_name);
687          break;
688
689       case LAYOUT_INVALID_SUMMED_AREA:
690          fprintf(stderr,
691                  "%s: CMOS checksummed area end must be greater than "
692                  "CMOS checksummed area start.\n",
693                  prog_name);
694          break;
695
696       case LAYOUT_CHECKSUM_OVERLAPS_SUMMED_AREA:
697          fprintf(stderr,
698                  "%s: CMOS checksum overlaps checksummed area.\n",
699                  prog_name);
700          break;
701
702       case LAYOUT_SUMMED_AREA_OUT_OF_RANGE:
703          fprintf(stderr,
704                  "%s: CMOS checksummed area out of range.\n",
705                  prog_name);
706          break;
707
708       case LAYOUT_CHECKSUM_LOCATION_OUT_OF_RANGE:
709          fprintf(stderr,
710                  "%s: CMOS checksum location out of range.\n",
711                  prog_name);
712          break;
713
714       default:
715          BUG();
716     }
717
718    exit(1);
719  }
720
721 /****************************************************************************
722  * try_add_cmos_table_enum
723  *
724  * Attempt to add a CMOS enum to our internal repository.  Exit with an error
725  * message on failure.
726  ****************************************************************************/
727 static void try_add_cmos_table_enum (cmos_enum_t *cmos_enum)
728  { switch (add_cmos_enum(cmos_enum))
729     { case OK:
730          return;
731
732       case LAYOUT_DUPLICATE_ENUM:
733          fprintf(stderr, "%s: Duplicate enum %s found in CMOS option "
734                  "table.\n", prog_name, cmos_enum->text);
735          break;
736
737       default:
738          BUG();
739     }
740
741    exit(1);
742  }
743
744 /****************************************************************************
745  * try_add_cmos_table_entry
746  *
747  * Attempt to add a CMOS entry to our internal repository.  Exit with an
748  * error message on failure.
749  ****************************************************************************/
750 static void try_add_cmos_table_entry (cmos_entry_t *cmos_entry)
751  { const cmos_entry_t *conflict;
752
753    switch (add_cmos_entry(cmos_entry, &conflict))
754     { case OK:
755          return;
756
757       case CMOS_AREA_OUT_OF_RANGE:
758          fprintf(stderr,
759                  "%s: Bad CMOS option layout in CMOS option table entry "
760                  "%s.\n", prog_name, cmos_entry->name);
761          break;
762
763       case CMOS_AREA_TOO_WIDE:
764          fprintf(stderr,
765                  "%s: Area too wide for CMOS option table entry %s.\n",
766                  prog_name, cmos_entry->name);
767          break;
768
769       case LAYOUT_ENTRY_OVERLAP:
770          fprintf(stderr,
771                  "%s: CMOS option table entries %s and %s have overlapping "
772                  "layouts.\n", prog_name, cmos_entry->name, conflict->name);
773          break;
774
775       case LAYOUT_ENTRY_BAD_LENGTH:
776          /* Silently ignore entries with zero length.  Although this should
777           * never happen in practice, we should handle the case in a
778           * reasonable manner just to be safe.
779           */
780          return;
781
782       default:
783          BUG();
784     }
785
786    exit(1);
787  }
788
789 /****************************************************************************
790  * find_lbrec
791  *
792  * Find the record in the coreboot table that matches 'tag'.  Return pointer
793  * to record on success or NULL if record not found.
794  ****************************************************************************/
795 static const struct lb_record * find_lbrec (uint32_t tag)
796  { const char *p;
797    uint32_t bytes_processed;
798    const struct lb_record *lbrec;
799
800    p = ((const char *) lbtable) + lbtable->header_bytes;
801
802    for (bytes_processed = 0;
803         bytes_processed < lbtable->table_bytes;
804         bytes_processed += lbrec->size)
805     { lbrec = (const struct lb_record *) &p[bytes_processed];
806
807       if (lbrec->tag == tag)
808          return lbrec;
809     }
810
811    return NULL;
812  }
813
814 /****************************************************************************
815  * lbrec_tag_to_str
816  *
817  * Return a pointer to the string representation of the given coreboot table
818  * tag.
819  ****************************************************************************/
820 static const char * lbrec_tag_to_str (uint32_t tag)
821  { switch (tag)
822     { case LB_TAG_UNUSED:
823          return "UNUSED";
824
825       case LB_TAG_MEMORY:
826          return "MEMORY";
827
828       case LB_TAG_HWRPB:
829          return "HWRPB";
830
831       case LB_TAG_MAINBOARD:
832          return "MAINBOARD";
833
834       case LB_TAG_VERSION:
835          return "VERSION";
836
837       case LB_TAG_EXTRA_VERSION:
838          return "EXTRA_VERSION";
839
840       case LB_TAG_BUILD:
841          return "BUILD";
842
843       case LB_TAG_COMPILE_TIME:
844          return "COMPILE_TIME";
845
846       case LB_TAG_COMPILE_BY:
847          return "COMPILE_BY";
848
849       case LB_TAG_COMPILE_HOST:
850          return "COMPILE_HOST";
851
852       case LB_TAG_COMPILE_DOMAIN:
853          return "COMPILE_DOMAIN";
854
855       case LB_TAG_COMPILER:
856          return "COMPILER";
857
858       case LB_TAG_LINKER:
859          return "LINKER";
860
861       case LB_TAG_ASSEMBLER:
862          return "ASSEMBLER";
863
864       case LB_TAG_CMOS_OPTION_TABLE:
865          return "CMOS_OPTION_TABLE";
866
867       case LB_TAG_OPTION_CHECKSUM:
868          return "OPTION_CHECKSUM";
869
870       default:
871          break;
872     }
873
874    return "UNKNOWN";
875  }
876
877 /****************************************************************************
878  * first_cmos_table_entry
879  *
880  * Return a pointer to the first entry in the CMOS table that represents a
881  * CMOS parameter.  Return NULL if CMOS table is empty.
882  ****************************************************************************/
883 static const struct cmos_entries * first_cmos_table_entry (void)
884  { return (const struct cmos_entries *) first_cmos_rec(LB_TAG_OPTION); }
885
886 /****************************************************************************
887  * next_cmos_table_entry
888  *
889  * Return a pointer to the next entry after 'last' in the CMOS table that
890  * represents a CMOS parameter.  Return NULL if there are no more parameters.
891  ****************************************************************************/
892 static const struct cmos_entries *
893       next_cmos_table_entry (const struct cmos_entries *last)
894  { return (const struct cmos_entries *)
895           next_cmos_rec((const struct lb_record *) last, LB_TAG_OPTION);
896  }
897
898 /****************************************************************************
899  * first_cmos_table_enum
900  *
901  * Return a pointer to the first entry in the CMOS table that represents a
902  * possible CMOS parameter value.  Return NULL if the table does not contain
903  * any such entries.
904  ****************************************************************************/
905 static const struct cmos_enums * first_cmos_table_enum (void)
906  { return (const struct cmos_enums *) first_cmos_rec(LB_TAG_OPTION_ENUM); }
907
908 /****************************************************************************
909  * next_cmos_table_enum
910  *
911  * Return a pointer to the next entry after 'last' in the CMOS table that
912  * represents a possible CMOS parameter value.  Return NULL if there are no
913  * more parameter values.
914  ****************************************************************************/
915 static const struct cmos_enums * next_cmos_table_enum
916       (const struct cmos_enums *last)
917  { return (const struct cmos_enums *)
918           next_cmos_rec((const struct lb_record *) last, LB_TAG_OPTION_ENUM);
919  }
920
921 /****************************************************************************
922  * first_cmos_rec
923  *
924  * Return a pointer to the first entry in the CMOS table whose type matches
925  * 'tag'.  Return NULL if CMOS table contains no such entry.
926  *
927  * Possible values for 'tag' are as follows:
928  *
929  *     LB_TAG_OPTION:      The entry represents a CMOS parameter.
930  *     LB_TAG_OPTION_ENUM: The entry represents a possible value for a CMOS
931  *                         parameter of type 'enum'.
932  *
933  * The CMOS table tells us where in the nonvolatile RAM to look for CMOS
934  * parameter values and specifies their types as 'enum', 'hex', or
935  * 'reserved'.
936  ****************************************************************************/
937 static const struct lb_record * first_cmos_rec (uint32_t tag)
938  { const char             *p;
939    uint32_t               bytes_processed, bytes_for_entries;
940    const struct lb_record *lbrec;
941
942    p = ((const char *) cmos_table) + cmos_table->header_length;
943    bytes_for_entries = cmos_table->size - cmos_table->header_length;
944
945    for (bytes_processed = 0;
946         bytes_processed < bytes_for_entries;
947         bytes_processed += lbrec->size)
948     { lbrec = (const struct lb_record *) &p[bytes_processed];
949
950       if (lbrec->tag == tag)
951          return lbrec;
952     }
953
954    return NULL;
955  }
956
957 /****************************************************************************
958  * next_cmos_rec
959  *
960  * Return a pointer to the next entry after 'last' in the CMOS table whose
961  * type matches 'tag'.  Return NULL if the table contains no more entries of
962  * this type.
963  ****************************************************************************/
964 static const struct lb_record * next_cmos_rec (const struct lb_record *last,
965                                                uint32_t tag)
966  { const char *p;
967    uint32_t bytes_processed, bytes_for_entries, last_offset;
968    const struct lb_record *lbrec;
969
970    p = ((const char *) cmos_table) + cmos_table->header_length;
971    bytes_for_entries = cmos_table->size - cmos_table->header_length;
972    last_offset = ((const char *) last) - p;
973
974    for (bytes_processed = last_offset + last->size;
975         bytes_processed < bytes_for_entries;
976         bytes_processed += lbrec->size)
977     { lbrec = (const struct lb_record *) &p[bytes_processed];
978
979       if (lbrec->tag == tag)
980          return lbrec;
981     }
982
983    return NULL;
984  }
985
986 /****************************************************************************
987  * memory_print_fn
988  *
989  * Display function for 'memory' item of coreboot table.
990  ****************************************************************************/
991 static void memory_print_fn (const struct lb_record *rec)
992  { char start_str[19], end_str[19], size_str[19];
993    const struct lb_memory *p;
994    const char *mem_type;
995    const struct lb_memory_range *ranges;
996    uint64_t size, start, end;
997    int i, entries;
998
999    p = (const struct lb_memory *) rec;
1000    entries = (p->size -  sizeof(*p)) / sizeof(p->map[0]);
1001    ranges = p->map;
1002
1003    if (entries == 0)
1004     { printf("No memory ranges were found.\n");
1005       return;
1006     }
1007
1008    for (i = 0; ; )
1009     { switch (ranges[i].type)
1010        { case LB_MEM_RAM:
1011             mem_type = "AVAILABLE";
1012             break;
1013
1014          case LB_MEM_RESERVED:
1015             mem_type = "RESERVED";
1016             break;
1017
1018          case LB_MEM_TABLE:
1019             mem_type = "CONFIG_TABLE";
1020             break;
1021
1022          default:
1023             mem_type = "UNKNOWN";
1024             break;
1025        }
1026
1027       size = unpack_lb64(ranges[i].size);
1028       start = unpack_lb64(ranges[i].start);
1029       end  = start + size - 1;
1030       uint64_to_hex_string(start_str, start);
1031       uint64_to_hex_string(end_str, end);
1032       uint64_to_hex_string(size_str, size);
1033       printf("%s memory:\n"
1034              "    from physical addresses %s to %s\n"
1035              "    size is %s bytes (%lld in decimal)\n",
1036              mem_type, start_str, end_str, size_str,
1037              (unsigned long long) size);
1038
1039       if (++i >= entries)
1040          break;
1041
1042       printf("\n");
1043     }
1044  }
1045
1046 /****************************************************************************
1047  * mainboard_print_fn
1048  *
1049  * Display function for 'mainboard' item of coreboot table.
1050  ****************************************************************************/
1051 static void mainboard_print_fn (const struct lb_record *rec)
1052  { const struct lb_mainboard *p;
1053
1054    p = (const struct lb_mainboard *) rec;
1055    printf("Vendor:      %s\n"
1056           "Part number: %s\n",
1057           &p->strings[p->vendor_idx],
1058           &p->strings[p->part_number_idx]);
1059  }
1060
1061 /****************************************************************************
1062  * cmos_opt_table_print_fn
1063  *
1064  * Display function for 'cmos_opt_table' item of coreboot table.
1065  ****************************************************************************/
1066 static void cmos_opt_table_print_fn (const struct lb_record *rec)
1067  {
1068    const struct cmos_option_table *p;
1069    const struct lb_record *cmos_item;
1070    uint32_t bytes_processed, bytes_for_entries;
1071    const char *q;
1072
1073    p = (const struct cmos_option_table *) rec;
1074    q = ((const char *) p) + p->header_length;
1075    bytes_for_entries = p->size - p->header_length;
1076
1077    printf("CMOS option table at physical address 0x%lx:\n"
1078           "    tag:           0x%x (decimal: %d)\n"
1079           "    size:          0x%x (decimal: %d)\n"
1080           "    header_length: 0x%x (decimal: %d)\n\n",
1081           vtophys(p), p->tag, p->tag, p->size, p->size, p->header_length,
1082           p->header_length);
1083
1084    if (p->header_length > p->size)
1085     { printf("Header length for CMOS option table is greater than the size "
1086              "of the entire table including header!!!\n");
1087       return;
1088     }
1089
1090    if (bytes_for_entries == 0)
1091     { printf("The CMOS option table is empty!!!\n");
1092       return;
1093     }
1094
1095    for (bytes_processed = 0; ; )
1096     { cmos_item = (const struct lb_record *) &q[bytes_processed];
1097
1098       switch (cmos_item->tag)
1099        { case LB_TAG_OPTION:
1100             print_option_record((const struct cmos_entries *) cmos_item);
1101             break;
1102
1103          case LB_TAG_OPTION_ENUM:
1104             print_enum_record((const struct cmos_enums *) cmos_item);
1105             break;
1106
1107          case LB_TAG_OPTION_DEFAULTS:
1108             print_defaults_record((const struct cmos_defaults *) cmos_item);
1109             break;
1110
1111          default:
1112             print_unknown_record(cmos_item);
1113             break;
1114        }
1115
1116       bytes_processed += cmos_item->size;
1117
1118       if (bytes_processed >= bytes_for_entries)
1119          break;
1120
1121       printf("\n");
1122     }
1123  }
1124
1125 /****************************************************************************
1126  * print_option_record
1127  *
1128  * Display "option" record from CMOS option table.
1129  ****************************************************************************/
1130 static void print_option_record (const struct cmos_entries *cmos_entry)
1131  { static const size_t S_BUFSIZE = 80;
1132    char s[S_BUFSIZE];
1133
1134    switch (cmos_entry->config)
1135     { case 'e':
1136          strcpy(s, "ENUM");
1137          break;
1138
1139       case 'h':
1140          strcpy(s, "HEX");
1141          break;
1142
1143       case 'r':
1144          strcpy(s, "RESERVED");
1145          break;
1146
1147       default:
1148          snprintf(s, S_BUFSIZE, "UNKNOWN: value is 0x%x (decimal: %d)",
1149                   cmos_entry->config, cmos_entry->config);
1150          break;
1151     }
1152
1153    printf("    OPTION record at physical address 0x%lx:\n"
1154           "        tag:       0x%x (decimal: %d)\n"
1155           "        size:      0x%x (decimal: %d)\n"
1156           "        bit:       0x%x (decimal: %d)\n"
1157           "        length:    0x%x (decimal: %d)\n"
1158           "        config:    %s\n"
1159           "        config_id: 0x%x (decimal: %d)\n"
1160           "        name:      %s\n",
1161           vtophys(cmos_entry), cmos_entry->tag, cmos_entry->tag,
1162           cmos_entry->size, cmos_entry->size, cmos_entry->bit,
1163           cmos_entry->bit, cmos_entry->length, cmos_entry->length, s,
1164           cmos_entry->config_id, cmos_entry->config_id, cmos_entry->name);
1165  }
1166
1167 /****************************************************************************
1168  * print_enum_record
1169  *
1170  * Display "enum" record from CMOS option table.
1171  ****************************************************************************/
1172 static void print_enum_record (const struct cmos_enums *cmos_enum)
1173  { printf("    ENUM record at physical address 0x%lx:\n"
1174           "        tag:       0x%x (decimal: %d)\n"
1175           "        size:      0x%x (decimal: %d)\n"
1176           "        config_id: 0x%x (decimal: %d)\n"
1177           "        value:     0x%x (decimal: %d)\n"
1178           "        text:      %s\n",
1179           vtophys(cmos_enum), cmos_enum->tag, cmos_enum->tag, cmos_enum->size,
1180           cmos_enum->size, cmos_enum->config_id, cmos_enum->config_id,
1181           cmos_enum->value, cmos_enum->value, cmos_enum->text);
1182  }
1183
1184 /****************************************************************************
1185  * print_defaults_record
1186  *
1187  * Display "defaults" record from CMOS option table.
1188  ****************************************************************************/
1189 static void print_defaults_record (const struct cmos_defaults *cmos_defaults)
1190  { printf("    DEFAULTS record at physical address 0x%lx:\n"
1191           "        tag:         0x%x (decimal: %d)\n"
1192           "        size:        0x%x (decimal: %d)\n"
1193           "        name_length: 0x%x (decimal: %d)\n"
1194           "        name:        %s\n"
1195           "        default_set:\n",
1196           vtophys(cmos_defaults), cmos_defaults->tag, cmos_defaults->tag,
1197           cmos_defaults->size, cmos_defaults->size,
1198           cmos_defaults->name_length, cmos_defaults->name_length,
1199           cmos_defaults->name);
1200    hexdump(cmos_defaults->default_set, CMOS_IMAGE_BUFFER_SIZE,
1201            vtophys(cmos_defaults->default_set), stdout, &format);
1202  }
1203
1204 /****************************************************************************
1205  * print_unknown_record
1206  *
1207  * Display record of unknown type from CMOS option table.
1208  ****************************************************************************/
1209 static void print_unknown_record (const struct lb_record *cmos_item)
1210  { const char *data;
1211
1212    printf("    UNKNOWN record at physical address 0x%lx:\n"
1213           "        tag:  0x%x (decimal: %d)\n"
1214           "        size: 0x%x (decimal: %d)\n"
1215           "        data:\n",
1216           vtophys(cmos_item), cmos_item->tag, cmos_item->tag,
1217           cmos_item->size, cmos_item->size);
1218    data = ((const char *) cmos_item) + sizeof(*cmos_item);
1219    hexdump(data, cmos_item->size - sizeof(*cmos_item), vtophys(data), stdout,
1220            &format);
1221  }
1222
1223 /****************************************************************************
1224  * option_checksum_print_fn
1225  *
1226  * Display function for 'option_checksum' item of coreboot table.
1227  ****************************************************************************/
1228 static void option_checksum_print_fn (const struct lb_record *rec)
1229  { struct cmos_checksum *p;
1230
1231    p = (struct cmos_checksum *) rec;
1232    printf("CMOS checksum from bit %d to bit %d\n"
1233           "at position %d is type %s.\n",
1234           p->range_start, p->range_end, p->location,
1235           (p->type == CHECKSUM_PCBIOS) ? "PC BIOS" : "NONE");
1236  }
1237
1238 /****************************************************************************
1239  * string_print_fn
1240  *
1241  * Display function for a generic item of coreboot table that simply
1242  * consists of a string.
1243  ****************************************************************************/
1244 static void string_print_fn (const struct lb_record *rec)
1245  { const struct lb_string *p;
1246
1247    p = (const struct lb_string *) rec;
1248    printf("%s\n", p->string);
1249  }
1250
1251 /****************************************************************************
1252  * uint64_to_hex_string
1253  *
1254  * Convert the 64-bit integer 'n' to its hexadecimal string representation,
1255  * storing the result in 's'.  's' must point to a buffer at least 19 bytes
1256  * long.  The result is displayed with as many leading zeros as needed to
1257  * make a 16-digit hex number including a 0x prefix (example: the number 1
1258  * will be displayed as "0x0000000000000001").
1259  ****************************************************************************/
1260 static void uint64_to_hex_string (char str[], uint64_t n)
1261  { int chars_printed;
1262
1263    str[0] = '0';
1264    str[1] = 'x';
1265
1266    /* Print the result right-justified with leading spaces in a
1267     * 16-character field. */
1268    chars_printed = sprintf(&str[2], "%016llx", (unsigned long long) n);
1269    assert(chars_printed == 16);
1270  }