blob: 05d70c2929694d0f863a3980658aea134fdd0526 [file] [log] [blame]
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001/*****************************************************************************\
2 * lbtable.c
Stefan Reinauer6540ae52007-07-12 16:35:42 +00003 *****************************************************************************
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 *
Uwe Hermann6e565942008-03-01 19:06:32 +000011 * This file is part of nvramtool, a utility for reading/writing coreboot
Stefan Reinauerf527e702008-01-18 15:33:49 +000012 * parameters and displaying information from the coreboot table.
Uwe Hermann6e565942008-03-01 19:06:32 +000013 * For details, see http://coreboot.org/nvramtool.
Stefan Reinauer6540ae52007-07-12 16:35:42 +000014 *
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
Stefan Reinauer297b91c2008-09-18 14:49:33 +000032#include <string.h>
Stefan Reinauer6540ae52007-07-12 16:35:42 +000033#include <sys/mman.h>
34#include "common.h"
Stefan Reinauer7223ab72008-01-18 16:17:44 +000035#include "coreboot_tables.h"
Stefan Reinauer6540ae52007-07-12 16:35:42 +000036#include "ip_checksum.h"
37#include "lbtable.h"
38#include "layout.h"
39#include "cmos_lowlevel.h"
40#include "hexdump.h"
41
42typedef void (*lbtable_print_fn_t) (const struct lb_record *rec);
43
Stefan Reinauerf527e702008-01-18 15:33:49 +000044/* This structure represents an item in the coreboot table that may be
Stefan Reinauer6540ae52007-07-12 16:35:42 +000045 * displayed using the -l option.
46 */
47typedef 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 }
54lbtable_choice_t;
55
56typedef struct
57 { unsigned long start; /* address of first byte of memory range */
58 unsigned long end; /* address of last byte of memory range */
59 }
60mem_range_t;
61
62static const struct lb_header * lbtable_scan (unsigned long start,
63 unsigned long end,
64 int *bad_header_count,
65 int *bad_table_count);
66static void process_cmos_table (void);
67static void get_cmos_checksum_info (void);
68static void try_convert_checksum_layout (cmos_checksum_layout_t *layout);
69static void try_add_cmos_table_enum (cmos_enum_t *cmos_enum);
70static void try_add_cmos_table_entry (cmos_entry_t *cmos_entry);
71static const struct lb_record * find_lbrec (uint32_t tag);
72static const char * lbrec_tag_to_str (uint32_t tag);
73static const struct cmos_entries * first_cmos_table_entry (void);
74static const struct cmos_entries *
75 next_cmos_table_entry (const struct cmos_entries *last);
76static const struct cmos_enums * first_cmos_table_enum (void);
77static const struct cmos_enums * next_cmos_table_enum
78 (const struct cmos_enums *last);
79static const struct lb_record * first_cmos_rec (uint32_t tag);
80static const struct lb_record * next_cmos_rec (const struct lb_record *last,
81 uint32_t tag);
82static void memory_print_fn (const struct lb_record *rec);
83static void mainboard_print_fn (const struct lb_record *rec);
84static void cmos_opt_table_print_fn (const struct lb_record *rec);
85static void print_option_record (const struct cmos_entries *cmos_entry);
86static void print_enum_record (const struct cmos_enums *cmos_enum);
87static void print_defaults_record (const struct cmos_defaults *cmos_defaults);
88static void print_unknown_record (const struct lb_record *cmos_item);
89static void option_checksum_print_fn (const struct lb_record *rec);
90static void string_print_fn (const struct lb_record *rec);
91static void uint64_to_hex_string (char str[], uint64_t n);
92
93static const char memory_desc[] =
94" This shows information about system memory.\n";
95
96static const char mainboard_desc[] =
97" This shows information about your mainboard.\n";
98
99static const char version_desc[] =
Stefan Reinauerf527e702008-01-18 15:33:49 +0000100" This shows coreboot version information.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000101
102static const char extra_version_desc[] =
Stefan Reinauerf527e702008-01-18 15:33:49 +0000103" This shows extra coreboot version information.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000104
105static const char build_desc[] =
Stefan Reinauerf527e702008-01-18 15:33:49 +0000106" This shows coreboot build information.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000107
108static const char compile_time_desc[] =
Stefan Reinauerf527e702008-01-18 15:33:49 +0000109" This shows when coreboot was compiled.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000110
111static const char compile_by_desc[] =
Stefan Reinauerf527e702008-01-18 15:33:49 +0000112" This shows who compiled coreboot.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000113
114static const char compile_host_desc[] =
Stefan Reinauerf527e702008-01-18 15:33:49 +0000115" This shows the name of the machine that compiled coreboot.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000116
117static const char compile_domain_desc[] =
Stefan Reinauerf527e702008-01-18 15:33:49 +0000118" This shows the domain name of the machine that compiled coreboot.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000119
120static const char compiler_desc[] =
Stefan Reinauerf527e702008-01-18 15:33:49 +0000121" This shows the name of the compiler used to build coreboot.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000122
123static const char linker_desc[] =
Stefan Reinauerf527e702008-01-18 15:33:49 +0000124" This shows the name of the linker used to build coreboot.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000125
126static const char assembler_desc[] =
Stefan Reinauerf527e702008-01-18 15:33:49 +0000127" This shows the name of the assembler used to build coreboot.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000128
129static const char cmos_opt_table_desc[] =
130" This does a low-level dump of the CMOS option table. The table "
131"contains\n"
Stefan Reinauerf527e702008-01-18 15:33:49 +0000132" information about the layout of the values that coreboot stores in\n"
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000133" nonvolatile RAM.\n";
134
135static 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
140static const char generic_nofound_msg[] =
Stefan Reinauerf527e702008-01-18 15:33:49 +0000141"%s: Item %s not found in coreboot table.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000142
143static const char nofound_msg_cmos_opt_table[] =
Stefan Reinauerf527e702008-01-18 15:33:49 +0000144"%s: Item %s not found in coreboot table. Apparently, the "
145"coreboot installed on this system was built without specifying "
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000146"HAVE_OPTION_TABLE.\n";
147
148static const char nofound_msg_option_checksum[] =
Stefan Reinauerf527e702008-01-18 15:33:49 +0000149"%s: Item %s not found in coreboot table. Apparently, you are "
150"using coreboot v1.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000151
Stefan Reinauerf527e702008-01-18 15:33:49 +0000152/* This is the number of items from the coreboot table that may be displayed
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000153 * using the -l option.
154 */
155#define NUM_LBTABLE_CHOICES 14
156
Stefan Reinauerf527e702008-01-18 15:33:49 +0000157/* These represent the various items from the coreboot table that may be
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000158 * displayed using the -l option.
159 */
160static 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
Stefan Reinauerf527e702008-01-18 15:33:49 +0000219/* The coreboot table resides in low physical memory, which we access using
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000220 * /dev/mem. These are ranges of physical memory that should be scanned for a
Stefan Reinauerf527e702008-01-18 15:33:49 +0000221 * coreboot table.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000222 */
223
224#define NUM_MEM_RANGES 2
225
226static 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
Stefan Reinauerf527e702008-01-18 15:33:49 +0000234 * coreboot table (since the start of the table could potentially occur at
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000235 * the end of the last memory range).
236 */
237static 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 */
242static const void *low_phys_mem;
243
Stefan Reinauerf527e702008-01-18 15:33:49 +0000244/* Pointer to coreboot table. */
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000245static const struct lb_header *lbtable = NULL;
246
Stefan Reinauerf527e702008-01-18 15:33:49 +0000247/* The CMOS option table is located within the coreboot table. It tells us
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000248 * where the CMOS parameters are located in the nonvolatile RAM.
249 */
250static const struct cmos_option_table *cmos_table = NULL;
251
252static 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 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000280 * Find the coreboot table and set global variable lbtable to point to it.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000281 ****************************************************************************/
282void 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
Stefan Reinauerf527e702008-01-18 15:33:49 +0000288 /* The coreboot table is located in low physical memory, which may be
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000289 * 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,
Stefan Reinauerf527e702008-01-18 15:33:49 +0000321 "%s: coreboot table not found. coreboot does not appear to\n"
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000322 " 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 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000336 * Find the CMOS table which is stored within the coreboot table and set the
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000337 * global variable cmos_table to point to it.
338 ****************************************************************************/
339void 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,
Stefan Reinauerf527e702008-01-18 15:33:49 +0000348 "%s: CMOS option table not found in coreboot table. "
349 "Apparently, the coreboot installed on this system was "
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000350 "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 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000362 * Do a low-level dump of the coreboot table.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000363 ****************************************************************************/
364void 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;
Stefan Reinauerf527e702008-01-18 15:33:49 +0000370 printf("Coreboot table at physical address 0x%lx:\n"
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000371 " 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)
Stefan Reinauerf527e702008-01-18 15:33:49 +0000392 { printf("The coreboot table is empty!!!\n");
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000393 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 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000421 * List names and informational blurbs for items from the coreboot table
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000422 * that may be displayed using the -l option.
423 ****************************************************************************/
424void 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 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000441 * Show the coreboot table item specified by 'item'.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000442 ****************************************************************************/
443void 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)
Stefan Reinauerf527e702008-01-18 15:33:49 +0000453 { fprintf(stderr, "%s: Invalid coreboot table item %s.\n", prog_name,
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000454 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 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000470 * Scan the chunk of memory specified by 'start' and 'end' for a coreboot
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000471 * 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 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000479 * If a coreboot table is found, return a pointer to it. Otherwise return
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000480 * 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 ****************************************************************************/
491static 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 ****************************************************************************/
549static 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;
Stefan Reinauer297b91c2008-09-18 14:49:33 +0000559 strncpy(cmos_enum.text, (char *)p->text, CMOS_MAX_TEXT_LENGTH);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000560 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
Stefan Reinauera67aab72008-09-27 10:08:28 +0000584 case 's':
585 cmos_entry.config = CMOS_ENTRY_STRING;
586 break;
587
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000588 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;
Stefan Reinauer297b91c2008-09-18 14:49:33 +0000596 strncpy(cmos_entry.name, (char *)q->name, CMOS_MAX_NAME_LENGTH);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000597 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 ****************************************************************************/
607static 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)
Stefan Reinauerf527e702008-01-18 15:33:49 +0000616 { /* We are lucky. The coreboot table hints us to the checksum.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000617 * 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 ****************************************************************************/
670static 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 ****************************************************************************/
731static 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 ****************************************************************************/
754static 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 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000796 * Find the record in the coreboot table that matches 'tag'. Return pointer
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000797 * to record on success or NULL if record not found.
798 ****************************************************************************/
799static 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 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000821 * Return a pointer to the string representation of the given coreboot table
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000822 * tag.
823 ****************************************************************************/
824static 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 ****************************************************************************/
887static 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 ****************************************************************************/
896static 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 ****************************************************************************/
909static 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 ****************************************************************************/
919static 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 ****************************************************************************/
941static 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 ****************************************************************************/
968static 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 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000993 * Display function for 'memory' item of coreboot table.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000994 ****************************************************************************/
995static 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 *
Stefan Reinauerf527e702008-01-18 15:33:49 +00001053 * Display function for 'mainboard' item of coreboot table.
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001054 ****************************************************************************/
1055static 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 *
Stefan Reinauerf527e702008-01-18 15:33:49 +00001068 * Display function for 'cmos_opt_table' item of coreboot table.
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001069 ****************************************************************************/
1070static 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 ****************************************************************************/
1134static 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 ****************************************************************************/
1176static 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 ****************************************************************************/
1193static 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 ****************************************************************************/
1213static 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 *
Stefan Reinauerf527e702008-01-18 15:33:49 +00001230 * Display function for 'option_checksum' item of coreboot table.
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001231 ****************************************************************************/
1232static 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 *
Stefan Reinauerf527e702008-01-18 15:33:49 +00001245 * Display function for a generic item of coreboot table that simply
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001246 * consists of a string.
1247 ****************************************************************************/
1248static 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 ****************************************************************************/
1264static 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 }