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