~ubuntu-branches/ubuntu/wily/nvramtool/wily

« back to all changes in this revision

Viewing changes to lbtable.c

  • Committer: Bazaar Package Importer
  • Author(s): Uwe Hermann
  • Date: 2008-10-19 20:43:49 UTC
  • Revision ID: james.westby@ubuntu.com-20081019204349-fahvutx2gcad1ayq
Tags: upstream-0.0+r3669
ImportĀ upstreamĀ versionĀ 0.0+r3669

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 
30
\*****************************************************************************/
 
31
 
 
32
#include <string.h>
 
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, (char *)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
         case 's':
 
585
            cmos_entry.config = CMOS_ENTRY_STRING;
 
586
            break;
 
587
 
 
588
         default:
 
589
            fprintf(stderr,
 
590
                    "%s: Entry in CMOS option table has unknown config "
 
591
                    "value.\n", prog_name);
 
592
            exit(1);
 
593
       }
 
594
 
 
595
      cmos_entry.config_id = q->config_id;
 
596
      strncpy(cmos_entry.name, (char *)q->name, CMOS_MAX_NAME_LENGTH);
 
597
      cmos_entry.name[CMOS_MAX_NAME_LENGTH] = '\0';
 
598
      try_add_cmos_table_entry(&cmos_entry);
 
599
    }
 
600
 }
 
601
 
 
602
/****************************************************************************
 
603
 * get_cmos_checksum_info
 
604
 *
 
605
 * Get layout information for CMOS checksum.
 
606
 ****************************************************************************/
 
607
static void get_cmos_checksum_info (void)
 
608
 { const cmos_entry_t *e;
 
609
   struct cmos_checksum *checksum;
 
610
   cmos_checksum_layout_t layout;
 
611
   unsigned index, index2;
 
612
 
 
613
   checksum = (struct cmos_checksum *) find_lbrec(LB_TAG_OPTION_CHECKSUM);
 
614
 
 
615
   if (checksum != NULL)
 
616
    { /* We are lucky.  The coreboot table hints us to the checksum.
 
617
       * We might have to check the type field here though.
 
618
       */
 
619
      layout.summed_area_start = checksum->range_start;
 
620
      layout.summed_area_end = checksum->range_end;
 
621
      layout.checksum_at = checksum->location;
 
622
      try_convert_checksum_layout(&layout);
 
623
      cmos_checksum_start = layout.summed_area_start;
 
624
      cmos_checksum_end = layout.summed_area_end;
 
625
      cmos_checksum_index = layout.checksum_at;
 
626
      return;
 
627
    }
 
628
 
 
629
   if ((e = find_cmos_entry(checksum_param_name)) == NULL)
 
630
      return;
 
631
 
 
632
   /* If we get here, we are unlucky.  The CMOS option table contains the
 
633
    * location of the CMOS checksum.  However, there is no information
 
634
    * regarding which bytes of the CMOS area the checksum is computed over.
 
635
    * Thus we have to hope our presets will be fine.
 
636
    */
 
637
 
 
638
   if (e->bit % 8)
 
639
    { fprintf(stderr, "%s: Error: CMOS checksum is not byte-aligned.\n",
 
640
              prog_name);
 
641
      exit(1);
 
642
    }
 
643
 
 
644
   index = e->bit / 8;
 
645
   index2 = index + 1;  /* The CMOS checksum occupies 16 bits. */
 
646
 
 
647
   if (verify_cmos_byte_index(index) || verify_cmos_byte_index(index2))
 
648
    { fprintf(stderr, "%s: Error: CMOS checksum location out of range.\n",
 
649
              prog_name);
 
650
      exit(1);
 
651
    }
 
652
 
 
653
   if (((index >= cmos_checksum_start) && (index <= cmos_checksum_end)) ||
 
654
       (((index2) >= cmos_checksum_start) && ((index2) <= cmos_checksum_end)))
 
655
    { fprintf(stderr, "%s: Error: CMOS checksum overlaps checksummed area.\n",
 
656
              prog_name);
 
657
      exit(1);
 
658
    }
 
659
 
 
660
   cmos_checksum_index = index;
 
661
 }
 
662
 
 
663
/****************************************************************************
 
664
 * try_convert_checksum_layout
 
665
 *
 
666
 * Perform sanity checking on CMOS checksum layout information and attempt to
 
667
 * convert information from bit positions to byte positions.  Return OK on
 
668
 * success or an error code on failure.
 
669
 ****************************************************************************/
 
670
static void try_convert_checksum_layout (cmos_checksum_layout_t *layout)
 
671
 { switch (checksum_layout_to_bytes(layout))
 
672
    { case OK:
 
673
         return;
 
674
 
 
675
      case LAYOUT_SUMMED_AREA_START_NOT_ALIGNED:
 
676
         fprintf(stderr,
 
677
                 "%s: CMOS checksummed area start is not byte-aligned.\n",
 
678
                 prog_name);
 
679
         break;
 
680
 
 
681
      case LAYOUT_SUMMED_AREA_END_NOT_ALIGNED:
 
682
         fprintf(stderr,
 
683
                 "%s: CMOS checksummed area end is not byte-aligned.\n",
 
684
                 prog_name);
 
685
         break;
 
686
 
 
687
      case LAYOUT_CHECKSUM_LOCATION_NOT_ALIGNED:
 
688
         fprintf(stderr,
 
689
                 "%s: CMOS checksum location is not byte-aligned.\n",
 
690
                 prog_name);
 
691
         break;
 
692
 
 
693
      case LAYOUT_INVALID_SUMMED_AREA:
 
694
         fprintf(stderr,
 
695
                 "%s: CMOS checksummed area end must be greater than "
 
696
                 "CMOS checksummed area start.\n",
 
697
                 prog_name);
 
698
         break;
 
699
 
 
700
      case LAYOUT_CHECKSUM_OVERLAPS_SUMMED_AREA:
 
701
         fprintf(stderr,
 
702
                 "%s: CMOS checksum overlaps checksummed area.\n",
 
703
                 prog_name);
 
704
         break;
 
705
 
 
706
      case LAYOUT_SUMMED_AREA_OUT_OF_RANGE:
 
707
         fprintf(stderr,
 
708
                 "%s: CMOS checksummed area out of range.\n",
 
709
                 prog_name);
 
710
         break;
 
711
 
 
712
      case LAYOUT_CHECKSUM_LOCATION_OUT_OF_RANGE:
 
713
         fprintf(stderr,
 
714
                 "%s: CMOS checksum location out of range.\n",
 
715
                 prog_name);
 
716
         break;
 
717
 
 
718
      default:
 
719
         BUG();
 
720
    }
 
721
 
 
722
   exit(1);
 
723
 }
 
724
 
 
725
/****************************************************************************
 
726
 * try_add_cmos_table_enum
 
727
 *
 
728
 * Attempt to add a CMOS enum to our internal repository.  Exit with an error
 
729
 * message on failure.
 
730
 ****************************************************************************/
 
731
static void try_add_cmos_table_enum (cmos_enum_t *cmos_enum)
 
732
 { switch (add_cmos_enum(cmos_enum))
 
733
    { case OK:
 
734
         return;
 
735
 
 
736
      case LAYOUT_DUPLICATE_ENUM:
 
737
         fprintf(stderr, "%s: Duplicate enum %s found in CMOS option "
 
738
                 "table.\n", prog_name, cmos_enum->text);
 
739
         break;
 
740
 
 
741
      default:
 
742
         BUG();
 
743
    }
 
744
 
 
745
   exit(1);
 
746
 }
 
747
 
 
748
/****************************************************************************
 
749
 * try_add_cmos_table_entry
 
750
 *
 
751
 * Attempt to add a CMOS entry to our internal repository.  Exit with an
 
752
 * error message on failure.
 
753
 ****************************************************************************/
 
754
static void try_add_cmos_table_entry (cmos_entry_t *cmos_entry)
 
755
 { const cmos_entry_t *conflict;
 
756
 
 
757
   switch (add_cmos_entry(cmos_entry, &conflict))
 
758
    { case OK:
 
759
         return;
 
760
 
 
761
      case CMOS_AREA_OUT_OF_RANGE:
 
762
         fprintf(stderr,
 
763
                 "%s: Bad CMOS option layout in CMOS option table entry "
 
764
                 "%s.\n", prog_name, cmos_entry->name);
 
765
         break;
 
766
 
 
767
      case CMOS_AREA_TOO_WIDE:
 
768
         fprintf(stderr,
 
769
                 "%s: Area too wide for CMOS option table entry %s.\n",
 
770
                 prog_name, cmos_entry->name);
 
771
         break;
 
772
 
 
773
      case LAYOUT_ENTRY_OVERLAP:
 
774
         fprintf(stderr,
 
775
                 "%s: CMOS option table entries %s and %s have overlapping "
 
776
                 "layouts.\n", prog_name, cmos_entry->name, conflict->name);
 
777
         break;
 
778
 
 
779
      case LAYOUT_ENTRY_BAD_LENGTH:
 
780
         /* Silently ignore entries with zero length.  Although this should
 
781
          * never happen in practice, we should handle the case in a
 
782
          * reasonable manner just to be safe.
 
783
          */
 
784
         return;
 
785
 
 
786
      default:
 
787
         BUG();
 
788
    }
 
789
 
 
790
   exit(1);
 
791
 }
 
792
 
 
793
/****************************************************************************
 
794
 * find_lbrec
 
795
 *
 
796
 * Find the record in the coreboot table that matches 'tag'.  Return pointer
 
797
 * to record on success or NULL if record not found.
 
798
 ****************************************************************************/
 
799
static const struct lb_record * find_lbrec (uint32_t tag)
 
800
 { const char *p;
 
801
   uint32_t bytes_processed;
 
802
   const struct lb_record *lbrec;
 
803
 
 
804
   p = ((const char *) lbtable) + lbtable->header_bytes;
 
805
 
 
806
   for (bytes_processed = 0;
 
807
        bytes_processed < lbtable->table_bytes;
 
808
        bytes_processed += lbrec->size)
 
809
    { lbrec = (const struct lb_record *) &p[bytes_processed];
 
810
 
 
811
      if (lbrec->tag == tag)
 
812
         return lbrec;
 
813
    }
 
814
 
 
815
   return NULL;
 
816
 }
 
817
 
 
818
/****************************************************************************
 
819
 * lbrec_tag_to_str
 
820
 *
 
821
 * Return a pointer to the string representation of the given coreboot table
 
822
 * tag.
 
823
 ****************************************************************************/
 
824
static const char * lbrec_tag_to_str (uint32_t tag)
 
825
 { switch (tag)
 
826
    { case LB_TAG_UNUSED:
 
827
         return "UNUSED";
 
828
 
 
829
      case LB_TAG_MEMORY:
 
830
         return "MEMORY";
 
831
 
 
832
      case LB_TAG_HWRPB:
 
833
         return "HWRPB";
 
834
 
 
835
      case LB_TAG_MAINBOARD:
 
836
         return "MAINBOARD";
 
837
 
 
838
      case LB_TAG_VERSION:
 
839
         return "VERSION";
 
840
 
 
841
      case LB_TAG_EXTRA_VERSION:
 
842
         return "EXTRA_VERSION";
 
843
 
 
844
      case LB_TAG_BUILD:
 
845
         return "BUILD";
 
846
 
 
847
      case LB_TAG_COMPILE_TIME:
 
848
         return "COMPILE_TIME";
 
849
 
 
850
      case LB_TAG_COMPILE_BY:
 
851
         return "COMPILE_BY";
 
852
 
 
853
      case LB_TAG_COMPILE_HOST:
 
854
         return "COMPILE_HOST";
 
855
 
 
856
      case LB_TAG_COMPILE_DOMAIN:
 
857
         return "COMPILE_DOMAIN";
 
858
 
 
859
      case LB_TAG_COMPILER:
 
860
         return "COMPILER";
 
861
 
 
862
      case LB_TAG_LINKER:
 
863
         return "LINKER";
 
864
 
 
865
      case LB_TAG_ASSEMBLER:
 
866
         return "ASSEMBLER";
 
867
 
 
868
      case LB_TAG_CMOS_OPTION_TABLE:
 
869
         return "CMOS_OPTION_TABLE";
 
870
 
 
871
      case LB_TAG_OPTION_CHECKSUM:
 
872
         return "OPTION_CHECKSUM";
 
873
 
 
874
      default:
 
875
         break;
 
876
    }
 
877
 
 
878
   return "UNKNOWN";
 
879
 }
 
880
 
 
881
/****************************************************************************
 
882
 * first_cmos_table_entry
 
883
 *
 
884
 * Return a pointer to the first entry in the CMOS table that represents a
 
885
 * CMOS parameter.  Return NULL if CMOS table is empty.
 
886
 ****************************************************************************/
 
887
static const struct cmos_entries * first_cmos_table_entry (void)
 
888
 { return (const struct cmos_entries *) first_cmos_rec(LB_TAG_OPTION); }
 
889
 
 
890
/****************************************************************************
 
891
 * next_cmos_table_entry
 
892
 *
 
893
 * Return a pointer to the next entry after 'last' in the CMOS table that
 
894
 * represents a CMOS parameter.  Return NULL if there are no more parameters.
 
895
 ****************************************************************************/
 
896
static const struct cmos_entries *
 
897
      next_cmos_table_entry (const struct cmos_entries *last)
 
898
 { return (const struct cmos_entries *)
 
899
          next_cmos_rec((const struct lb_record *) last, LB_TAG_OPTION);
 
900
 }
 
901
 
 
902
/****************************************************************************
 
903
 * first_cmos_table_enum
 
904
 *
 
905
 * Return a pointer to the first entry in the CMOS table that represents a
 
906
 * possible CMOS parameter value.  Return NULL if the table does not contain
 
907
 * any such entries.
 
908
 ****************************************************************************/
 
909
static const struct cmos_enums * first_cmos_table_enum (void)
 
910
 { return (const struct cmos_enums *) first_cmos_rec(LB_TAG_OPTION_ENUM); }
 
911
 
 
912
/****************************************************************************
 
913
 * next_cmos_table_enum
 
914
 *
 
915
 * Return a pointer to the next entry after 'last' in the CMOS table that
 
916
 * represents a possible CMOS parameter value.  Return NULL if there are no
 
917
 * more parameter values.
 
918
 ****************************************************************************/
 
919
static const struct cmos_enums * next_cmos_table_enum
 
920
      (const struct cmos_enums *last)
 
921
 { return (const struct cmos_enums *)
 
922
          next_cmos_rec((const struct lb_record *) last, LB_TAG_OPTION_ENUM);
 
923
 }
 
924
 
 
925
/****************************************************************************
 
926
 * first_cmos_rec
 
927
 *
 
928
 * Return a pointer to the first entry in the CMOS table whose type matches
 
929
 * 'tag'.  Return NULL if CMOS table contains no such entry.
 
930
 *
 
931
 * Possible values for 'tag' are as follows:
 
932
 *
 
933
 *     LB_TAG_OPTION:      The entry represents a CMOS parameter.
 
934
 *     LB_TAG_OPTION_ENUM: The entry represents a possible value for a CMOS
 
935
 *                         parameter of type 'enum'.
 
936
 *
 
937
 * The CMOS table tells us where in the nonvolatile RAM to look for CMOS
 
938
 * parameter values and specifies their types as 'enum', 'hex', or
 
939
 * 'reserved'.
 
940
 ****************************************************************************/
 
941
static const struct lb_record * first_cmos_rec (uint32_t tag)
 
942
 { const char             *p;
 
943
   uint32_t               bytes_processed, bytes_for_entries;
 
944
   const struct lb_record *lbrec;
 
945
 
 
946
   p = ((const char *) cmos_table) + cmos_table->header_length;
 
947
   bytes_for_entries = cmos_table->size - cmos_table->header_length;
 
948
 
 
949
   for (bytes_processed = 0;
 
950
        bytes_processed < bytes_for_entries;
 
951
        bytes_processed += lbrec->size)
 
952
    { lbrec = (const struct lb_record *) &p[bytes_processed];
 
953
 
 
954
      if (lbrec->tag == tag)
 
955
         return lbrec;
 
956
    }
 
957
 
 
958
   return NULL;
 
959
 }
 
960
 
 
961
/****************************************************************************
 
962
 * next_cmos_rec
 
963
 *
 
964
 * Return a pointer to the next entry after 'last' in the CMOS table whose
 
965
 * type matches 'tag'.  Return NULL if the table contains no more entries of
 
966
 * this type.
 
967
 ****************************************************************************/
 
968
static const struct lb_record * next_cmos_rec (const struct lb_record *last,
 
969
                                               uint32_t tag)
 
970
 { const char *p;
 
971
   uint32_t bytes_processed, bytes_for_entries, last_offset;
 
972
   const struct lb_record *lbrec;
 
973
 
 
974
   p = ((const char *) cmos_table) + cmos_table->header_length;
 
975
   bytes_for_entries = cmos_table->size - cmos_table->header_length;
 
976
   last_offset = ((const char *) last) - p;
 
977
 
 
978
   for (bytes_processed = last_offset + last->size;
 
979
        bytes_processed < bytes_for_entries;
 
980
        bytes_processed += lbrec->size)
 
981
    { lbrec = (const struct lb_record *) &p[bytes_processed];
 
982
 
 
983
      if (lbrec->tag == tag)
 
984
         return lbrec;
 
985
    }
 
986
 
 
987
   return NULL;
 
988
 }
 
989
 
 
990
/****************************************************************************
 
991
 * memory_print_fn
 
992
 *
 
993
 * Display function for 'memory' item of coreboot table.
 
994
 ****************************************************************************/
 
995
static void memory_print_fn (const struct lb_record *rec)
 
996
 { char start_str[19], end_str[19], size_str[19];
 
997
   const struct lb_memory *p;
 
998
   const char *mem_type;
 
999
   const struct lb_memory_range *ranges;
 
1000
   uint64_t size, start, end;
 
1001
   int i, entries;
 
1002
 
 
1003
   p = (const struct lb_memory *) rec;
 
1004
   entries = (p->size -  sizeof(*p)) / sizeof(p->map[0]);
 
1005
   ranges = p->map;
 
1006
 
 
1007
   if (entries == 0)
 
1008
    { printf("No memory ranges were found.\n");
 
1009
      return;
 
1010
    }
 
1011
 
 
1012
   for (i = 0; ; )
 
1013
    { switch (ranges[i].type)
 
1014
       { case LB_MEM_RAM:
 
1015
            mem_type = "AVAILABLE";
 
1016
            break;
 
1017
 
 
1018
         case LB_MEM_RESERVED:
 
1019
            mem_type = "RESERVED";
 
1020
            break;
 
1021
 
 
1022
         case LB_MEM_TABLE:
 
1023
            mem_type = "CONFIG_TABLE";
 
1024
            break;
 
1025
 
 
1026
         default:
 
1027
            mem_type = "UNKNOWN";
 
1028
            break;
 
1029
       }
 
1030
 
 
1031
      size = unpack_lb64(ranges[i].size);
 
1032
      start = unpack_lb64(ranges[i].start);
 
1033
      end  = start + size - 1;
 
1034
      uint64_to_hex_string(start_str, start);
 
1035
      uint64_to_hex_string(end_str, end);
 
1036
      uint64_to_hex_string(size_str, size);
 
1037
      printf("%s memory:\n"
 
1038
             "    from physical addresses %s to %s\n"
 
1039
             "    size is %s bytes (%lld in decimal)\n",
 
1040
             mem_type, start_str, end_str, size_str,
 
1041
             (unsigned long long) size);
 
1042
 
 
1043
      if (++i >= entries)
 
1044
         break;
 
1045
 
 
1046
      printf("\n");
 
1047
    }
 
1048
 }
 
1049
 
 
1050
/****************************************************************************
 
1051
 * mainboard_print_fn
 
1052
 *
 
1053
 * Display function for 'mainboard' item of coreboot table.
 
1054
 ****************************************************************************/
 
1055
static void mainboard_print_fn (const struct lb_record *rec)
 
1056
 { const struct lb_mainboard *p;
 
1057
 
 
1058
   p = (const struct lb_mainboard *) rec;
 
1059
   printf("Vendor:      %s\n"
 
1060
          "Part number: %s\n",
 
1061
          &p->strings[p->vendor_idx],
 
1062
          &p->strings[p->part_number_idx]);
 
1063
 }
 
1064
 
 
1065
/****************************************************************************
 
1066
 * cmos_opt_table_print_fn
 
1067
 *
 
1068
 * Display function for 'cmos_opt_table' item of coreboot table.
 
1069
 ****************************************************************************/
 
1070
static void cmos_opt_table_print_fn (const struct lb_record *rec)
 
1071
 {
 
1072
   const struct cmos_option_table *p;
 
1073
   const struct lb_record *cmos_item;
 
1074
   uint32_t bytes_processed, bytes_for_entries;
 
1075
   const char *q;
 
1076
 
 
1077
   p = (const struct cmos_option_table *) rec;
 
1078
   q = ((const char *) p) + p->header_length;
 
1079
   bytes_for_entries = p->size - p->header_length;
 
1080
 
 
1081
   printf("CMOS option table at physical address 0x%lx:\n"
 
1082
          "    tag:           0x%x (decimal: %d)\n"
 
1083
          "    size:          0x%x (decimal: %d)\n"
 
1084
          "    header_length: 0x%x (decimal: %d)\n\n",
 
1085
          vtophys(p), p->tag, p->tag, p->size, p->size, p->header_length,
 
1086
          p->header_length);
 
1087
 
 
1088
   if (p->header_length > p->size)
 
1089
    { printf("Header length for CMOS option table is greater than the size "
 
1090
             "of the entire table including header!!!\n");
 
1091
      return;
 
1092
    }
 
1093
 
 
1094
   if (bytes_for_entries == 0)
 
1095
    { printf("The CMOS option table is empty!!!\n");
 
1096
      return;
 
1097
    }
 
1098
 
 
1099
   for (bytes_processed = 0; ; )
 
1100
    { cmos_item = (const struct lb_record *) &q[bytes_processed];
 
1101
 
 
1102
      switch (cmos_item->tag)
 
1103
       { case LB_TAG_OPTION:
 
1104
            print_option_record((const struct cmos_entries *) cmos_item);
 
1105
            break;
 
1106
 
 
1107
         case LB_TAG_OPTION_ENUM:
 
1108
            print_enum_record((const struct cmos_enums *) cmos_item);
 
1109
            break;
 
1110
 
 
1111
         case LB_TAG_OPTION_DEFAULTS:
 
1112
            print_defaults_record((const struct cmos_defaults *) cmos_item);
 
1113
            break;
 
1114
 
 
1115
         default:
 
1116
            print_unknown_record(cmos_item);
 
1117
            break;
 
1118
       }
 
1119
 
 
1120
      bytes_processed += cmos_item->size;
 
1121
 
 
1122
      if (bytes_processed >= bytes_for_entries)
 
1123
         break;
 
1124
 
 
1125
      printf("\n");
 
1126
    }
 
1127
 }
 
1128
 
 
1129
/****************************************************************************
 
1130
 * print_option_record
 
1131
 *
 
1132
 * Display "option" record from CMOS option table.
 
1133
 ****************************************************************************/
 
1134
static void print_option_record (const struct cmos_entries *cmos_entry)
 
1135
 { static const size_t S_BUFSIZE = 80;
 
1136
   char s[S_BUFSIZE];
 
1137
 
 
1138
   switch (cmos_entry->config)
 
1139
    { case 'e':
 
1140
         strcpy(s, "ENUM");
 
1141
         break;
 
1142
 
 
1143
      case 'h':
 
1144
         strcpy(s, "HEX");
 
1145
         break;
 
1146
 
 
1147
      case 'r':
 
1148
         strcpy(s, "RESERVED");
 
1149
         break;
 
1150
 
 
1151
      default:
 
1152
         snprintf(s, S_BUFSIZE, "UNKNOWN: value is 0x%x (decimal: %d)",
 
1153
                  cmos_entry->config, cmos_entry->config);
 
1154
         break;
 
1155
    }
 
1156
 
 
1157
   printf("    OPTION record at physical address 0x%lx:\n"
 
1158
          "        tag:       0x%x (decimal: %d)\n"
 
1159
          "        size:      0x%x (decimal: %d)\n"
 
1160
          "        bit:       0x%x (decimal: %d)\n"
 
1161
          "        length:    0x%x (decimal: %d)\n"
 
1162
          "        config:    %s\n"
 
1163
          "        config_id: 0x%x (decimal: %d)\n"
 
1164
          "        name:      %s\n",
 
1165
          vtophys(cmos_entry), cmos_entry->tag, cmos_entry->tag,
 
1166
          cmos_entry->size, cmos_entry->size, cmos_entry->bit,
 
1167
          cmos_entry->bit, cmos_entry->length, cmos_entry->length, s,
 
1168
          cmos_entry->config_id, cmos_entry->config_id, cmos_entry->name);
 
1169
 }
 
1170
 
 
1171
/****************************************************************************
 
1172
 * print_enum_record
 
1173
 *
 
1174
 * Display "enum" record from CMOS option table.
 
1175
 ****************************************************************************/
 
1176
static void print_enum_record (const struct cmos_enums *cmos_enum)
 
1177
 { printf("    ENUM record at physical address 0x%lx:\n"
 
1178
          "        tag:       0x%x (decimal: %d)\n"
 
1179
          "        size:      0x%x (decimal: %d)\n"
 
1180
          "        config_id: 0x%x (decimal: %d)\n"
 
1181
          "        value:     0x%x (decimal: %d)\n"
 
1182
          "        text:      %s\n",
 
1183
          vtophys(cmos_enum), cmos_enum->tag, cmos_enum->tag, cmos_enum->size,
 
1184
          cmos_enum->size, cmos_enum->config_id, cmos_enum->config_id,
 
1185
          cmos_enum->value, cmos_enum->value, cmos_enum->text);
 
1186
 }
 
1187
 
 
1188
/****************************************************************************
 
1189
 * print_defaults_record
 
1190
 *
 
1191
 * Display "defaults" record from CMOS option table.
 
1192
 ****************************************************************************/
 
1193
static void print_defaults_record (const struct cmos_defaults *cmos_defaults)
 
1194
 { printf("    DEFAULTS record at physical address 0x%lx:\n"
 
1195
          "        tag:         0x%x (decimal: %d)\n"
 
1196
          "        size:        0x%x (decimal: %d)\n"
 
1197
          "        name_length: 0x%x (decimal: %d)\n"
 
1198
          "        name:        %s\n"
 
1199
          "        default_set:\n",
 
1200
          vtophys(cmos_defaults), cmos_defaults->tag, cmos_defaults->tag,
 
1201
          cmos_defaults->size, cmos_defaults->size,
 
1202
          cmos_defaults->name_length, cmos_defaults->name_length,
 
1203
          cmos_defaults->name);
 
1204
   hexdump(cmos_defaults->default_set, CMOS_IMAGE_BUFFER_SIZE,
 
1205
           vtophys(cmos_defaults->default_set), stdout, &format);
 
1206
 }
 
1207
 
 
1208
/****************************************************************************
 
1209
 * print_unknown_record
 
1210
 *
 
1211
 * Display record of unknown type from CMOS option table.
 
1212
 ****************************************************************************/
 
1213
static void print_unknown_record (const struct lb_record *cmos_item)
 
1214
 { const char *data;
 
1215
 
 
1216
   printf("    UNKNOWN record at physical address 0x%lx:\n"
 
1217
          "        tag:  0x%x (decimal: %d)\n"
 
1218
          "        size: 0x%x (decimal: %d)\n"
 
1219
          "        data:\n",
 
1220
          vtophys(cmos_item), cmos_item->tag, cmos_item->tag,
 
1221
          cmos_item->size, cmos_item->size);
 
1222
   data = ((const char *) cmos_item) + sizeof(*cmos_item);
 
1223
   hexdump(data, cmos_item->size - sizeof(*cmos_item), vtophys(data), stdout,
 
1224
           &format);
 
1225
 }
 
1226
 
 
1227
/****************************************************************************
 
1228
 * option_checksum_print_fn
 
1229
 *
 
1230
 * Display function for 'option_checksum' item of coreboot table.
 
1231
 ****************************************************************************/
 
1232
static void option_checksum_print_fn (const struct lb_record *rec)
 
1233
 { struct cmos_checksum *p;
 
1234
 
 
1235
   p = (struct cmos_checksum *) rec;
 
1236
   printf("CMOS checksum from bit %d to bit %d\n"
 
1237
          "at position %d is type %s.\n",
 
1238
          p->range_start, p->range_end, p->location,
 
1239
          (p->type == CHECKSUM_PCBIOS) ? "PC BIOS" : "NONE");
 
1240
 }
 
1241
 
 
1242
/****************************************************************************
 
1243
 * string_print_fn
 
1244
 *
 
1245
 * Display function for a generic item of coreboot table that simply
 
1246
 * consists of a string.
 
1247
 ****************************************************************************/
 
1248
static void string_print_fn (const struct lb_record *rec)
 
1249
 { const struct lb_string *p;
 
1250
 
 
1251
   p = (const struct lb_string *) rec;
 
1252
   printf("%s\n", p->string);
 
1253
 }
 
1254
 
 
1255
/****************************************************************************
 
1256
 * uint64_to_hex_string
 
1257
 *
 
1258
 * Convert the 64-bit integer 'n' to its hexadecimal string representation,
 
1259
 * storing the result in 's'.  's' must point to a buffer at least 19 bytes
 
1260
 * long.  The result is displayed with as many leading zeros as needed to
 
1261
 * make a 16-digit hex number including a 0x prefix (example: the number 1
 
1262
 * will be displayed as "0x0000000000000001").
 
1263
 ****************************************************************************/
 
1264
static void uint64_to_hex_string (char str[], uint64_t n)
 
1265
 { int chars_printed;
 
1266
 
 
1267
   str[0] = '0';
 
1268
   str[1] = 'x';
 
1269
 
 
1270
   /* Print the result right-justified with leading spaces in a
 
1271
    * 16-character field. */
 
1272
   chars_printed = sprintf(&str[2], "%016llx", (unsigned long long) n);
 
1273
   assert(chars_printed == 16);
 
1274
 }