blob: 0ec25f83178a5af055ad9b4b65a7df73bf728fdb [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.,
Stefan Reinauerac7a2d22009-09-23 21:53:25 +000029 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
Stefan Reinauer6540ae52007-07-12 16:35:42 +000030\*****************************************************************************/
31
Patrick Georgi269e9322011-01-21 07:24:08 +000032#include <arpa/inet.h>
Stefan Reinauer297b91c2008-09-18 14:49:33 +000033#include <string.h>
Stefan Reinauer6540ae52007-07-12 16:35:42 +000034#include <sys/mman.h>
35#include "common.h"
Stefan Reinauer7223ab72008-01-18 16:17:44 +000036#include "coreboot_tables.h"
Stefan Reinauer6540ae52007-07-12 16:35:42 +000037#include "ip_checksum.h"
38#include "lbtable.h"
39#include "layout.h"
40#include "cmos_lowlevel.h"
41#include "hexdump.h"
Patrick Georgi269e9322011-01-21 07:24:08 +000042#include "cbfs.h"
Stefan Reinauer6540ae52007-07-12 16:35:42 +000043
Stefan Reinauer90b96b62010-01-13 21:00:23 +000044typedef void (*lbtable_print_fn_t) (const struct lb_record * rec);
Stefan Reinauer6540ae52007-07-12 16:35:42 +000045
Stefan Reinauerf527e702008-01-18 15:33:49 +000046/* This structure represents an item in the coreboot table that may be
Stefan Reinauer6540ae52007-07-12 16:35:42 +000047 * displayed using the -l option.
48 */
Stefan Reinauer90b96b62010-01-13 21:00:23 +000049typedef struct {
50 uint32_t tag;
51 const char *name;
52 const char *description;
53 const char *nofound_msg;
54 lbtable_print_fn_t print_fn;
55} lbtable_choice_t;
Stefan Reinauer6540ae52007-07-12 16:35:42 +000056
Stefan Reinauer90b96b62010-01-13 21:00:23 +000057typedef struct {
58 unsigned long start; /* address of first byte of memory range */
59 unsigned long end; /* address of last byte of memory range */
60} mem_range_t;
Stefan Reinauer6540ae52007-07-12 16:35:42 +000061
Stefan Reinauer90b96b62010-01-13 21:00:23 +000062static 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 *next_cmos_table_entry(const struct
75 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);
Stefan Reinauer6540ae52007-07-12 16:35:42 +000091
92static const char memory_desc[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +000093 " This shows information about system memory.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +000094
95static const char mainboard_desc[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +000096 " This shows information about your mainboard.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +000097
98static const char version_desc[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +000099 " This shows coreboot version information.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000100
101static const char extra_version_desc[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000102 " This shows extra coreboot version information.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000103
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000104static const char build_desc[] = " This shows coreboot build information.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000105
106static const char compile_time_desc[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000107 " This shows when coreboot was compiled.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000108
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000109static const char compile_by_desc[] = " This shows who compiled coreboot.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000110
111static const char compile_host_desc[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000112 " This shows the name of the machine that compiled coreboot.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000113
114static const char compile_domain_desc[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000115 " This shows the domain name of the machine that compiled coreboot.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000116
117static const char compiler_desc[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000118 " This shows the name of the compiler used to build coreboot.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000119
120static const char linker_desc[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000121 " This shows the name of the linker used to build coreboot.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000122
123static const char assembler_desc[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000124 " This shows the name of the assembler used to build coreboot.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000125
126static const char cmos_opt_table_desc[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000127 " This does a low-level dump of the CMOS option table. The table "
128 "contains\n"
129 " information about the layout of the values that coreboot stores in\n"
130 " nonvolatile RAM.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000131
132static const char option_checksum_desc[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000133 " This shows the location of the CMOS checksum and the area over which it "
134 "is\n" " calculated.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000135
136static const char generic_nofound_msg[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000137 "%s: Item %s not found in coreboot table.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000138
139static const char nofound_msg_cmos_opt_table[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000140 "%s: Item %s not found in coreboot table. Apparently, the "
141 "coreboot installed on this system was built without specifying "
142 "CONFIG_HAVE_OPTION_TABLE.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000143
144static const char nofound_msg_option_checksum[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000145 "%s: Item %s not found in coreboot table. Apparently, you are "
146 "using coreboot v1.\n";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000147
Stefan Reinauer764fe402009-03-17 14:39:36 +0000148int fd;
149
Stefan Reinauerf527e702008-01-18 15:33:49 +0000150/* This is the number of items from the coreboot table that may be displayed
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000151 * using the -l option.
152 */
153#define NUM_LBTABLE_CHOICES 14
154
Stefan Reinauerf527e702008-01-18 15:33:49 +0000155/* These represent the various items from the coreboot table that may be
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000156 * displayed using the -l option.
157 */
158static const lbtable_choice_t lbtable_choices[NUM_LBTABLE_CHOICES] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000159 { {LB_TAG_MEMORY, "memory",
160 memory_desc, generic_nofound_msg,
161 memory_print_fn},
162{LB_TAG_MAINBOARD, "mainboard",
163 mainboard_desc, generic_nofound_msg,
164 mainboard_print_fn},
165{LB_TAG_VERSION, "version",
166 version_desc, generic_nofound_msg,
167 string_print_fn},
168{LB_TAG_EXTRA_VERSION, "extra_version",
169 extra_version_desc, generic_nofound_msg,
170 string_print_fn},
171{LB_TAG_BUILD, "build",
172 build_desc, generic_nofound_msg,
173 string_print_fn},
174{LB_TAG_COMPILE_TIME, "compile_time",
175 compile_time_desc, generic_nofound_msg,
176 string_print_fn},
177{LB_TAG_COMPILE_BY, "compile_by",
178 compile_by_desc, generic_nofound_msg,
179 string_print_fn},
180{LB_TAG_COMPILE_HOST, "compile_host",
181 compile_host_desc, generic_nofound_msg,
182 string_print_fn},
183{LB_TAG_COMPILE_DOMAIN, "compile_domain",
184 compile_domain_desc, generic_nofound_msg,
185 string_print_fn},
186{LB_TAG_COMPILER, "compiler",
187 compiler_desc, generic_nofound_msg,
188 string_print_fn},
189{LB_TAG_LINKER, "linker",
190 linker_desc, generic_nofound_msg,
191 string_print_fn},
192{LB_TAG_ASSEMBLER, "assembler",
193 assembler_desc, generic_nofound_msg,
194 string_print_fn},
195{LB_TAG_CMOS_OPTION_TABLE, "cmos_opt_table",
196 cmos_opt_table_desc, nofound_msg_cmos_opt_table,
197 cmos_opt_table_print_fn},
198{LB_TAG_OPTION_CHECKSUM, "option_checksum",
199 option_checksum_desc, nofound_msg_option_checksum,
200 option_checksum_print_fn}
201};
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000202
Stefan Reinauerf527e702008-01-18 15:33:49 +0000203/* The coreboot table resides in low physical memory, which we access using
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000204 * /dev/mem. These are ranges of physical memory that should be scanned for a
Stefan Reinauerf527e702008-01-18 15:33:49 +0000205 * coreboot table.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000206 */
207
208#define NUM_MEM_RANGES 2
209
210static const mem_range_t mem_ranges[NUM_MEM_RANGES] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000211 { {0x00000000, 0x00000fff},
212{0x000f0000, 0x000fffff}
213};
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000214
215/* This is the number of bytes of physical memory to map, starting at physical
216 * address 0. This value must be large enough to contain all memory ranges
217 * specified in mem_ranges above plus the maximum possible size of the
Stefan Reinauerf527e702008-01-18 15:33:49 +0000218 * coreboot table (since the start of the table could potentially occur at
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000219 * the end of the last memory range).
220 */
221static const size_t BYTES_TO_MAP = (1024 * 1024);
222
223/* Pointer to low physical memory that we access by calling mmap() on
224 * /dev/mem.
225 */
226static const void *low_phys_mem;
Stefan Reinauer764fe402009-03-17 14:39:36 +0000227static unsigned long low_phys_base = 0;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000228
Stefan Reinauerf527e702008-01-18 15:33:49 +0000229/* Pointer to coreboot table. */
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000230static const struct lb_header *lbtable = NULL;
231
Stefan Reinauerf527e702008-01-18 15:33:49 +0000232/* The CMOS option table is located within the coreboot table. It tells us
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000233 * where the CMOS parameters are located in the nonvolatile RAM.
234 */
235static const struct cmos_option_table *cmos_table = NULL;
236
237static const hexdump_format_t format =
Patrick Georgi024ec852011-01-18 12:14:08 +0000238 { 12, 4, " ", " | ", " ", " | ", '.' };
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000239
240/****************************************************************************
241 * vtophys
242 *
243 * Convert a virtual address to a physical address. 'vaddr' is a virtual
244 * address in the address space of the current process. It points to
245 * somewhere in the chunk of memory that we mapped by calling mmap() on
246 * /dev/mem. This macro converts 'vaddr' to a physical address.
247 ****************************************************************************/
248#define vtophys(vaddr) (((unsigned long) vaddr) - \
Stefan Reinauer764fe402009-03-17 14:39:36 +0000249 ((unsigned long) low_phys_mem) + low_phys_base)
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000250
251/****************************************************************************
252 * phystov
253 *
254 * Convert a physical address to a virtual address. 'paddr' is a physical
255 * address. This macro converts 'paddr' to a virtual address in the address
256 * space of the current process. The virtual to physical mapping was set up
257 * by calling mmap() on /dev/mem.
258 ****************************************************************************/
259#define phystov(paddr) (((unsigned long) low_phys_mem) + \
Stefan Reinauer764fe402009-03-17 14:39:36 +0000260 ((unsigned long) paddr) - low_phys_base)
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000261
262/****************************************************************************
263 * get_lbtable
264 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000265 * Find the coreboot table and set global variable lbtable to point to it.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000266 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000267void get_lbtable(void)
268{
269 int i, bad_header_count, bad_table_count, bad_headers, bad_tables;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000270
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000271 if (lbtable != NULL)
272 return;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000273
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000274 /* The coreboot table is located in low physical memory, which may be
275 * conveniently accessed by calling mmap() on /dev/mem.
276 */
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000277
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000278 if ((fd = open("/dev/mem", O_RDONLY, 0)) < 0) {
279 fprintf(stderr, "%s: Can not open /dev/mem for reading: %s\n",
280 prog_name, strerror(errno));
281 exit(1);
282 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000283
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000284 if ((low_phys_mem =
285 mmap(NULL, BYTES_TO_MAP, PROT_READ, MAP_SHARED, fd, 0))
286 == MAP_FAILED) {
287 fprintf(stderr, "%s: Failed to mmap /dev/mem: %s\n", prog_name,
288 strerror(errno));
289 exit(1);
290 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000291
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000292 bad_header_count = 0;
293 bad_table_count = 0;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000294
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000295 for (i = 0; i < NUM_MEM_RANGES; i++) {
296 lbtable = lbtable_scan(phystov(mem_ranges[i].start),
297 phystov(mem_ranges[i].end),
298 &bad_headers, &bad_tables);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000299
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000300 if (lbtable != NULL)
301 return; /* success: we found it! */
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000302
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000303 bad_header_count += bad_headers;
304 bad_table_count += bad_tables;
305 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000306
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000307 fprintf(stderr,
308 "%s: coreboot table not found. coreboot does not appear to\n"
309 " be installed on this system. Scanning for the table "
310 "produced the\n"
311 " following results:\n\n"
312 " %d valid signatures were found with bad header "
313 "checksums.\n"
314 " %d valid headers were found with bad table "
315 "checksums.\n", prog_name, bad_header_count, bad_table_count);
316 exit(1);
317}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000318
Patrick Georgi269e9322011-01-21 07:24:08 +0000319static void process_layout(void)
320{
321 if ((cmos_table) == NULL) {
322 fprintf(stderr,
323 "%s: CMOS option table not found in coreboot table. "
324 "Apparently, the coreboot installed on this system was "
325 "built without specifying CONFIG_HAVE_OPTION_TABLE.\n",
326 prog_name);
327 exit(1);
328 }
329
330 process_cmos_table();
331 get_cmos_checksum_info();
332}
333
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000334/****************************************************************************
335 * get_layout_from_cmos_table
336 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000337 * Find the CMOS table which is stored within the coreboot table and set the
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000338 * global variable cmos_table to point to it.
339 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000340void get_layout_from_cmos_table(void)
341{
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000342
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000343 get_lbtable();
344 cmos_table = (const struct cmos_option_table *)
345 find_lbrec(LB_TAG_CMOS_OPTION_TABLE);
Patrick Georgi269e9322011-01-21 07:24:08 +0000346 process_layout();
347}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000348
Patrick Georgi269e9322011-01-21 07:24:08 +0000349void get_layout_from_cbfs_file(void)
350{
351 static struct lb_header header;
352 u32 len;
353 cmos_table = cbfs_find_file("cmos_layout.bin", CBFS_COMPONENT_CMOS_LAYOUT, &len);
354 lbtable = &header;
355 header.header_bytes = (u32)cmos_table-(u32)lbtable;
356 header.table_bytes = ntohl(len);
357 process_layout();
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000358}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000359
360/****************************************************************************
361 * dump_lbtable
362 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000363 * Do a low-level dump of the coreboot table.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000364 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000365void dump_lbtable(void)
366{
367 const char *p, *data;
368 uint32_t bytes_processed;
369 const struct lb_record *lbrec;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000370
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000371 p = ((const char *)lbtable) + lbtable->header_bytes;
372 printf("Coreboot table at physical address 0x%lx:\n"
373 " signature: 0x%x (ASCII: %c%c%c%c)\n"
374 " header_bytes: 0x%x (decimal: %d)\n"
375 " header_checksum: 0x%x (decimal: %d)\n"
376 " table_bytes: 0x%x (decimal: %d)\n"
377 " table_checksum: 0x%x (decimal: %d)\n"
378 " table_entries: 0x%x (decimal: %d)\n\n",
Patrick Georgi26016972011-01-18 12:12:47 +0000379 vtophys(lbtable), lbtable->signature32,
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000380 lbtable->signature[0], lbtable->signature[1],
381 lbtable->signature[2], lbtable->signature[3],
382 lbtable->header_bytes, lbtable->header_bytes,
383 lbtable->header_checksum, lbtable->header_checksum,
384 lbtable->table_bytes, lbtable->table_bytes,
385 lbtable->table_checksum, lbtable->table_checksum,
386 lbtable->table_entries, lbtable->table_entries);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000387
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000388 if ((lbtable->table_bytes == 0) != (lbtable->table_entries == 0)) {
389 printf
390 ("Inconsistent values for table_bytes and table_entries!!!\n"
391 "They should be either both 0 or both nonzero.\n");
392 return;
393 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000394
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000395 if (lbtable->table_bytes == 0) {
396 printf("The coreboot table is empty!!!\n");
397 return;
398 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000399
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000400 for (bytes_processed = 0;;) {
401 lbrec = (const struct lb_record *)&p[bytes_processed];
402 printf(" %s record at physical address 0x%lx:\n"
403 " tag: 0x%x (decimal: %d)\n"
404 " size: 0x%x (decimal: %d)\n"
405 " data:\n",
406 lbrec_tag_to_str(lbrec->tag), vtophys(lbrec), lbrec->tag,
407 lbrec->tag, lbrec->size, lbrec->size);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000408
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000409 data = ((const char *)lbrec) + sizeof(*lbrec);
410 hexdump(data, lbrec->size - sizeof(*lbrec), vtophys(data),
411 stdout, &format);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000412
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000413 bytes_processed += lbrec->size;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000414
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000415 if (bytes_processed >= lbtable->table_bytes)
416 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000417
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000418 printf("\n");
419 }
420}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000421
422/****************************************************************************
423 * list_lbtable_choices
424 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000425 * List names and informational blurbs for items from the coreboot table
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000426 * that may be displayed using the -l option.
427 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000428void list_lbtable_choices(void)
429{
430 int i;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000431
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000432 for (i = 0;;) {
433 printf("%s:\n%s",
434 lbtable_choices[i].name, lbtable_choices[i].description);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000435
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000436 if (++i >= NUM_LBTABLE_CHOICES)
437 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000438
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000439 printf("\n");
440 }
441}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000442
443/****************************************************************************
444 * list_lbtable_item
445 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000446 * Show the coreboot table item specified by 'item'.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000447 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000448void list_lbtable_item(const char item[])
449{
450 int i;
451 const struct lb_record *rec;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000452
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000453 for (i = 0; i < NUM_LBTABLE_CHOICES; i++) {
454 if (strcmp(item, lbtable_choices[i].name) == 0)
455 break;
456 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000457
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000458 if (i == NUM_LBTABLE_CHOICES) {
459 fprintf(stderr, "%s: Invalid coreboot table item %s.\n",
460 prog_name, item);
461 exit(1);
462 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000463
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000464 if ((rec = find_lbrec(lbtable_choices[i].tag)) == NULL) {
465 fprintf(stderr, lbtable_choices[i].nofound_msg, prog_name,
466 lbtable_choices[i].name);
467 exit(1);
468 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000469
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000470 lbtable_choices[i].print_fn(rec);
471}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000472
473/****************************************************************************
474 * lbtable_scan
475 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000476 * Scan the chunk of memory specified by 'start' and 'end' for a coreboot
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000477 * table. The first 4 bytes of the table are marked by the signature
478 * { 'L', 'B', 'I', 'O' }. 'start' and 'end' indicate the addresses of the
479 * first and last bytes of the chunk of memory to be scanned. For instance,
480 * values of 0x10000000 and 0x1000ffff for 'start' and 'end' specify a 64k
481 * chunk of memory starting at address 0x10000000. 'start' and 'end' are
482 * virtual addresses in the address space of the current process. They
483 * represent a chunk of memory obtained by calling mmap() on /dev/mem.
484 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000485 * If a coreboot table is found, return a pointer to it. Otherwise return
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000486 * NULL. On return, *bad_header_count and *bad_table_count are set as
487 * follows:
488 *
489 * *bad_header_count:
490 * Indicates the number of times in which a valid signature was found
491 * but the header checksum was invalid.
492 *
493 * *bad_table_count:
494 * Indicates the number of times in which a header with a valid
495 * checksum was found but the table checksum was invalid.
496 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000497static const struct lb_header *lbtable_scan(unsigned long start,
498 unsigned long end,
499 int *bad_header_count,
500 int *bad_table_count)
501{
Patrick Georgi26016972011-01-18 12:12:47 +0000502 static const char signature[4] = { 'L', 'B', 'I', 'O' };
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000503 const struct lb_header *table;
504 const struct lb_forward *forward;
505 const uint32_t *p;
506 uint32_t sig;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000507
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000508 assert(end >= start);
Patrick Georgi26016972011-01-18 12:12:47 +0000509 memcpy(&sig, signature, sizeof(sig));
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000510 table = NULL;
511 *bad_header_count = 0;
512 *bad_table_count = 0;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000513
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000514 /* Look for signature. Table is aligned on 16-byte boundary. Therefore
515 * only check every fourth 32-bit memory word. As the loop is coded below,
516 * this function will behave in a reasonable manner for ALL possible values
517 * for 'start' and 'end': even weird boundary cases like 0x00000000 and
518 * 0xffffffff on a 32-bit architecture.
519 */
520 for (p = (const uint32_t *)start;
521 (((unsigned long)p) <= end) &&
522 ((end - (unsigned long)p) >= (sizeof(uint32_t) - 1)); p += 4) {
523 if (*p != sig)
524 continue;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000525
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000526 /* We found a valid signature. */
527 table = (const struct lb_header *)p;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000528
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000529 /* validate header checksum */
530 if (compute_ip_checksum((void *)table, sizeof(*table))) {
531 (*bad_header_count)++;
532 continue;
533 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000534
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000535 /* validate table checksum */
536 if (table->table_checksum !=
537 compute_ip_checksum(((char *)table) + sizeof(*table),
538 table->table_bytes)) {
539 (*bad_table_count)++;
540 continue;
541 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000542
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000543 /* checksums are ok: we found it! */
544 /* But it may just be a forwarding table, so look if there's a forwarder */
545 lbtable = table;
546 forward = (struct lb_forward *)find_lbrec(LB_TAG_FORWARD);
547 lbtable = NULL;
Stefan Reinauer764fe402009-03-17 14:39:36 +0000548
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000549 if (forward) {
550 uint64_t new_phys = forward->forward;
Stefan Reinauer764fe402009-03-17 14:39:36 +0000551
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000552 new_phys &= ~(getpagesize() - 1);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000553
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000554 munmap((void *)low_phys_mem, BYTES_TO_MAP);
555 if ((low_phys_mem =
556 mmap(NULL, BYTES_TO_MAP, PROT_READ, MAP_SHARED, fd,
557 (off_t) new_phys)) == MAP_FAILED) {
558 fprintf(stderr,
559 "%s: Failed to mmap /dev/mem: %s\n",
560 prog_name, strerror(errno));
561 exit(1);
562 }
563 low_phys_base = new_phys;
564 table =
565 lbtable_scan(phystov(low_phys_base),
566 phystov(low_phys_base + BYTES_TO_MAP),
567 bad_header_count, bad_table_count);
568 }
569 return table;
570 }
571
572 return NULL;
573}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000574
575/****************************************************************************
576 * process_cmos_table
577 *
578 * Extract layout information from the CMOS option table and store it in our
579 * internal repository.
580 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000581static void process_cmos_table(void)
582{
583 const struct cmos_enums *p;
584 const struct cmos_entries *q;
585 cmos_enum_t cmos_enum;
586 cmos_entry_t cmos_entry;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000587
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000588 /* First add the enums. */
589 for (p = first_cmos_table_enum(); p != NULL;
590 p = next_cmos_table_enum(p)) {
591 cmos_enum.config_id = p->config_id;
592 cmos_enum.value = p->value;
593 strncpy(cmos_enum.text, (char *)p->text, CMOS_MAX_TEXT_LENGTH);
594 cmos_enum.text[CMOS_MAX_TEXT_LENGTH] = '\0';
595 try_add_cmos_table_enum(&cmos_enum);
596 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000597
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000598 /* Now add the entries. We must add the entries after the enums because
599 * the entries are sanity checked against the enums as they are added.
600 */
601 for (q = first_cmos_table_entry(); q != NULL;
602 q = next_cmos_table_entry(q)) {
603 cmos_entry.bit = q->bit;
604 cmos_entry.length = q->length;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000605
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000606 switch (q->config) {
607 case 'e':
608 cmos_entry.config = CMOS_ENTRY_ENUM;
609 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000610
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000611 case 'h':
612 cmos_entry.config = CMOS_ENTRY_HEX;
613 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000614
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000615 case 'r':
616 cmos_entry.config = CMOS_ENTRY_RESERVED;
617 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000618
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000619 case 's':
620 cmos_entry.config = CMOS_ENTRY_STRING;
621 break;
Stefan Reinauera67aab72008-09-27 10:08:28 +0000622
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000623 default:
624 fprintf(stderr,
625 "%s: Entry in CMOS option table has unknown config "
626 "value.\n", prog_name);
627 exit(1);
628 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000629
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000630 cmos_entry.config_id = q->config_id;
631 strncpy(cmos_entry.name, (char *)q->name, CMOS_MAX_NAME_LENGTH);
632 cmos_entry.name[CMOS_MAX_NAME_LENGTH] = '\0';
633 try_add_cmos_table_entry(&cmos_entry);
634 }
635}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000636
637/****************************************************************************
638 * get_cmos_checksum_info
639 *
640 * Get layout information for CMOS checksum.
641 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000642static void get_cmos_checksum_info(void)
643{
644 const cmos_entry_t *e;
645 struct cmos_checksum *checksum;
646 cmos_checksum_layout_t layout;
647 unsigned index, index2;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000648
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000649 checksum = (struct cmos_checksum *)find_lbrec(LB_TAG_OPTION_CHECKSUM);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000650
Patrick Georgi0d4f6532011-01-21 07:04:05 +0000651 if (checksum == NULL) {
652 checksum = (struct cmos_checksum *)next_cmos_rec((const struct lb_record *)first_cmos_table_enum(), LB_TAG_OPTION_CHECKSUM);
653 }
654
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000655 if (checksum != NULL) { /* We are lucky. The coreboot table hints us to the checksum.
656 * We might have to check the type field here though.
657 */
658 layout.summed_area_start = checksum->range_start;
659 layout.summed_area_end = checksum->range_end;
660 layout.checksum_at = checksum->location;
661 try_convert_checksum_layout(&layout);
662 cmos_checksum_start = layout.summed_area_start;
663 cmos_checksum_end = layout.summed_area_end;
664 cmos_checksum_index = layout.checksum_at;
665 return;
666 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000667
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000668 if ((e = find_cmos_entry(checksum_param_name)) == NULL)
669 return;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000670
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000671 /* If we get here, we are unlucky. The CMOS option table contains the
672 * location of the CMOS checksum. However, there is no information
673 * regarding which bytes of the CMOS area the checksum is computed over.
674 * Thus we have to hope our presets will be fine.
675 */
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000676
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000677 if (e->bit % 8) {
678 fprintf(stderr,
679 "%s: Error: CMOS checksum is not byte-aligned.\n",
680 prog_name);
681 exit(1);
682 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000683
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000684 index = e->bit / 8;
685 index2 = index + 1; /* The CMOS checksum occupies 16 bits. */
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000686
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000687 if (verify_cmos_byte_index(index) || verify_cmos_byte_index(index2)) {
688 fprintf(stderr,
689 "%s: Error: CMOS checksum location out of range.\n",
690 prog_name);
691 exit(1);
692 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000693
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000694 if (((index >= cmos_checksum_start) && (index <= cmos_checksum_end)) ||
695 (((index2) >= cmos_checksum_start)
696 && ((index2) <= cmos_checksum_end))) {
697 fprintf(stderr,
698 "%s: Error: CMOS checksum overlaps checksummed area.\n",
699 prog_name);
700 exit(1);
701 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000702
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000703 cmos_checksum_index = index;
704}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000705
706/****************************************************************************
707 * try_convert_checksum_layout
708 *
709 * Perform sanity checking on CMOS checksum layout information and attempt to
710 * convert information from bit positions to byte positions. Return OK on
711 * success or an error code on failure.
712 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000713static void try_convert_checksum_layout(cmos_checksum_layout_t * layout)
714{
715 switch (checksum_layout_to_bytes(layout)) {
716 case OK:
717 return;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000718
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000719 case LAYOUT_SUMMED_AREA_START_NOT_ALIGNED:
720 fprintf(stderr,
721 "%s: CMOS checksummed area start is not byte-aligned.\n",
722 prog_name);
723 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000724
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000725 case LAYOUT_SUMMED_AREA_END_NOT_ALIGNED:
726 fprintf(stderr,
727 "%s: CMOS checksummed area end is not byte-aligned.\n",
728 prog_name);
729 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000730
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000731 case LAYOUT_CHECKSUM_LOCATION_NOT_ALIGNED:
732 fprintf(stderr,
733 "%s: CMOS checksum location is not byte-aligned.\n",
734 prog_name);
735 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000736
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000737 case LAYOUT_INVALID_SUMMED_AREA:
738 fprintf(stderr,
739 "%s: CMOS checksummed area end must be greater than "
740 "CMOS checksummed area start.\n", prog_name);
741 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000742
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000743 case LAYOUT_CHECKSUM_OVERLAPS_SUMMED_AREA:
744 fprintf(stderr,
745 "%s: CMOS checksum overlaps checksummed area.\n",
746 prog_name);
747 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000748
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000749 case LAYOUT_SUMMED_AREA_OUT_OF_RANGE:
750 fprintf(stderr,
751 "%s: CMOS checksummed area out of range.\n", prog_name);
752 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000753
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000754 case LAYOUT_CHECKSUM_LOCATION_OUT_OF_RANGE:
755 fprintf(stderr,
756 "%s: CMOS checksum location out of range.\n",
757 prog_name);
758 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000759
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000760 default:
761 BUG();
762 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000763
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000764 exit(1);
765}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000766
767/****************************************************************************
768 * try_add_cmos_table_enum
769 *
770 * Attempt to add a CMOS enum to our internal repository. Exit with an error
771 * message on failure.
772 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000773static void try_add_cmos_table_enum(cmos_enum_t * cmos_enum)
774{
775 switch (add_cmos_enum(cmos_enum)) {
776 case OK:
777 return;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000778
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000779 case LAYOUT_DUPLICATE_ENUM:
780 fprintf(stderr, "%s: Duplicate enum %s found in CMOS option "
781 "table.\n", prog_name, cmos_enum->text);
782 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000783
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000784 default:
785 BUG();
786 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000787
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000788 exit(1);
789}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000790
791/****************************************************************************
792 * try_add_cmos_table_entry
793 *
794 * Attempt to add a CMOS entry to our internal repository. Exit with an
795 * error message on failure.
796 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000797static void try_add_cmos_table_entry(cmos_entry_t * cmos_entry)
798{
799 const cmos_entry_t *conflict;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000800
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000801 switch (add_cmos_entry(cmos_entry, &conflict)) {
802 case OK:
803 return;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000804
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000805 case CMOS_AREA_OUT_OF_RANGE:
806 fprintf(stderr,
807 "%s: Bad CMOS option layout in CMOS option table entry "
808 "%s.\n", prog_name, cmos_entry->name);
809 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000810
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000811 case CMOS_AREA_TOO_WIDE:
812 fprintf(stderr,
813 "%s: Area too wide for CMOS option table entry %s.\n",
814 prog_name, cmos_entry->name);
815 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000816
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000817 case LAYOUT_ENTRY_OVERLAP:
818 fprintf(stderr,
819 "%s: CMOS option table entries %s and %s have overlapping "
820 "layouts.\n", prog_name, cmos_entry->name,
821 conflict->name);
822 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000823
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000824 case LAYOUT_ENTRY_BAD_LENGTH:
825 /* Silently ignore entries with zero length. Although this should
826 * never happen in practice, we should handle the case in a
827 * reasonable manner just to be safe.
828 */
829 return;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000830
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000831 default:
832 BUG();
833 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000834
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000835 exit(1);
836}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000837
838/****************************************************************************
839 * find_lbrec
840 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000841 * Find the record in the coreboot table that matches 'tag'. Return pointer
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000842 * to record on success or NULL if record not found.
843 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000844static const struct lb_record *find_lbrec(uint32_t tag)
845{
846 const char *p;
847 uint32_t bytes_processed;
848 const struct lb_record *lbrec;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000849
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000850 p = ((const char *)lbtable) + lbtable->header_bytes;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000851
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000852 for (bytes_processed = 0;
853 bytes_processed < lbtable->table_bytes;
854 bytes_processed += lbrec->size) {
855 lbrec = (const struct lb_record *)&p[bytes_processed];
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000856
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000857 if (lbrec->tag == tag)
858 return lbrec;
859 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000860
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000861 return NULL;
862}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000863
864/****************************************************************************
865 * lbrec_tag_to_str
866 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000867 * Return a pointer to the string representation of the given coreboot table
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000868 * tag.
869 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000870static const char *lbrec_tag_to_str(uint32_t tag)
871{
872 switch (tag) {
873 case LB_TAG_UNUSED:
874 return "UNUSED";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000875
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000876 case LB_TAG_MEMORY:
877 return "MEMORY";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000878
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000879 case LB_TAG_HWRPB:
880 return "HWRPB";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000881
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000882 case LB_TAG_MAINBOARD:
883 return "MAINBOARD";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000884
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000885 case LB_TAG_VERSION:
886 return "VERSION";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000887
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000888 case LB_TAG_EXTRA_VERSION:
889 return "EXTRA_VERSION";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000890
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000891 case LB_TAG_BUILD:
892 return "BUILD";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000893
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000894 case LB_TAG_COMPILE_TIME:
895 return "COMPILE_TIME";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000896
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000897 case LB_TAG_COMPILE_BY:
898 return "COMPILE_BY";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000899
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000900 case LB_TAG_COMPILE_HOST:
901 return "COMPILE_HOST";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000902
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000903 case LB_TAG_COMPILE_DOMAIN:
904 return "COMPILE_DOMAIN";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000905
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000906 case LB_TAG_COMPILER:
907 return "COMPILER";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000908
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000909 case LB_TAG_LINKER:
910 return "LINKER";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000911
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000912 case LB_TAG_ASSEMBLER:
913 return "ASSEMBLER";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000914
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000915 case LB_TAG_SERIAL:
916 return "SERIAL";
Stefan Reinauer764fe402009-03-17 14:39:36 +0000917
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000918 case LB_TAG_CONSOLE:
919 return "CONSOLE";
Stefan Reinauer764fe402009-03-17 14:39:36 +0000920
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000921 case LB_TAG_FORWARD:
922 return "FORWARD";
Stefan Reinauer764fe402009-03-17 14:39:36 +0000923
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000924 case LB_TAG_CMOS_OPTION_TABLE:
925 return "CMOS_OPTION_TABLE";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000926
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000927 case LB_TAG_OPTION_CHECKSUM:
928 return "OPTION_CHECKSUM";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000929
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000930 default:
931 break;
932 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000933
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000934 return "UNKNOWN";
935}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000936
937/****************************************************************************
938 * first_cmos_table_entry
939 *
940 * Return a pointer to the first entry in the CMOS table that represents a
941 * CMOS parameter. Return NULL if CMOS table is empty.
942 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000943static const struct cmos_entries *first_cmos_table_entry(void)
944{
945 return (const struct cmos_entries *)first_cmos_rec(LB_TAG_OPTION);
946}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000947
948/****************************************************************************
949 * next_cmos_table_entry
950 *
951 * Return a pointer to the next entry after 'last' in the CMOS table that
952 * represents a CMOS parameter. Return NULL if there are no more parameters.
953 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000954static const struct cmos_entries *next_cmos_table_entry(const struct
955 cmos_entries *last)
956{
957 return (const struct cmos_entries *)
958 next_cmos_rec((const struct lb_record *)last, LB_TAG_OPTION);
959}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000960
961/****************************************************************************
962 * first_cmos_table_enum
963 *
964 * Return a pointer to the first entry in the CMOS table that represents a
965 * possible CMOS parameter value. Return NULL if the table does not contain
966 * any such entries.
967 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000968static const struct cmos_enums *first_cmos_table_enum(void)
969{
970 return (const struct cmos_enums *)first_cmos_rec(LB_TAG_OPTION_ENUM);
971}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000972
973/****************************************************************************
974 * next_cmos_table_enum
975 *
976 * Return a pointer to the next entry after 'last' in the CMOS table that
977 * represents a possible CMOS parameter value. Return NULL if there are no
978 * more parameter values.
979 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000980static const struct cmos_enums *next_cmos_table_enum
981 (const struct cmos_enums *last) {
982 return (const struct cmos_enums *)
983 next_cmos_rec((const struct lb_record *)last, LB_TAG_OPTION_ENUM);
984}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000985
986/****************************************************************************
987 * first_cmos_rec
988 *
989 * Return a pointer to the first entry in the CMOS table whose type matches
990 * 'tag'. Return NULL if CMOS table contains no such entry.
991 *
992 * Possible values for 'tag' are as follows:
993 *
994 * LB_TAG_OPTION: The entry represents a CMOS parameter.
995 * LB_TAG_OPTION_ENUM: The entry represents a possible value for a CMOS
996 * parameter of type 'enum'.
997 *
998 * The CMOS table tells us where in the nonvolatile RAM to look for CMOS
999 * parameter values and specifies their types as 'enum', 'hex', or
1000 * 'reserved'.
1001 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001002static const struct lb_record *first_cmos_rec(uint32_t tag)
1003{
1004 const char *p;
1005 uint32_t bytes_processed, bytes_for_entries;
1006 const struct lb_record *lbrec;
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001007
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001008 p = ((const char *)cmos_table) + cmos_table->header_length;
1009 bytes_for_entries = cmos_table->size - cmos_table->header_length;
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001010
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001011 for (bytes_processed = 0;
1012 bytes_processed < bytes_for_entries;
1013 bytes_processed += lbrec->size) {
1014 lbrec = (const struct lb_record *)&p[bytes_processed];
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001015
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001016 if (lbrec->tag == tag)
1017 return lbrec;
1018 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001019
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001020 return NULL;
1021}
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001022
1023/****************************************************************************
1024 * next_cmos_rec
1025 *
1026 * Return a pointer to the next entry after 'last' in the CMOS table whose
1027 * type matches 'tag'. Return NULL if the table contains no more entries of
1028 * this type.
1029 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001030static const struct lb_record *next_cmos_rec(const struct lb_record *last,
1031 uint32_t tag)
1032{
1033 const char *p;
1034 uint32_t bytes_processed, bytes_for_entries, last_offset;
1035 const struct lb_record *lbrec;
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001036
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001037 p = ((const char *)cmos_table) + cmos_table->header_length;
1038 bytes_for_entries = cmos_table->size - cmos_table->header_length;
1039 last_offset = ((const char *)last) - p;
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001040
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001041 for (bytes_processed = last_offset + last->size;
1042 bytes_processed < bytes_for_entries;
1043 bytes_processed += lbrec->size) {
1044 lbrec = (const struct lb_record *)&p[bytes_processed];
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001045
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001046 if (lbrec->tag == tag)
1047 return lbrec;
1048 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001049
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001050 return NULL;
1051}
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001052
1053/****************************************************************************
1054 * memory_print_fn
1055 *
Stefan Reinauerf527e702008-01-18 15:33:49 +00001056 * Display function for 'memory' item of coreboot table.
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001057 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001058static void memory_print_fn(const struct lb_record *rec)
1059{
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001060 const struct lb_memory *p;
1061 const char *mem_type;
1062 const struct lb_memory_range *ranges;
1063 uint64_t size, start, end;
1064 int i, entries;
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001065
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001066 p = (const struct lb_memory *)rec;
1067 entries = (p->size - sizeof(*p)) / sizeof(p->map[0]);
1068 ranges = p->map;
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001069
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001070 if (entries == 0) {
1071 printf("No memory ranges were found.\n");
1072 return;
1073 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001074
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001075 for (i = 0;;) {
1076 switch (ranges[i].type) {
1077 case LB_MEM_RAM:
1078 mem_type = "AVAILABLE";
1079 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001080
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001081 case LB_MEM_RESERVED:
1082 mem_type = "RESERVED";
1083 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001084
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001085 case LB_MEM_TABLE:
1086 mem_type = "CONFIG_TABLE";
1087 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001088
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001089 default:
1090 mem_type = "UNKNOWN";
1091 break;
1092 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001093
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001094 size = unpack_lb64(ranges[i].size);
1095 start = unpack_lb64(ranges[i].start);
1096 end = start + size - 1;
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001097 printf("%s memory:\n"
Patrick Georgic7ca3e52011-01-28 07:41:10 +00001098 " from physical addresses 0x%016llx to 0x%016llx\n"
1099 " size is 0x%016llx bytes (%lld in decimal)\n",
1100 mem_type, start, end, size,
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001101 (unsigned long long)size);
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001102
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001103 if (++i >= entries)
1104 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001105
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001106 printf("\n");
1107 }
1108}
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001109
1110/****************************************************************************
1111 * mainboard_print_fn
1112 *
Stefan Reinauerf527e702008-01-18 15:33:49 +00001113 * Display function for 'mainboard' item of coreboot table.
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001114 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001115static void mainboard_print_fn(const struct lb_record *rec)
1116{
1117 const struct lb_mainboard *p;
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001118
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001119 p = (const struct lb_mainboard *)rec;
1120 printf("Vendor: %s\n"
1121 "Part number: %s\n",
1122 &p->strings[p->vendor_idx], &p->strings[p->part_number_idx]);
1123}
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001124
1125/****************************************************************************
1126 * cmos_opt_table_print_fn
1127 *
Stefan Reinauerf527e702008-01-18 15:33:49 +00001128 * Display function for 'cmos_opt_table' item of coreboot table.
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001129 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001130static void cmos_opt_table_print_fn(const struct lb_record *rec)
1131{
1132 const struct cmos_option_table *p;
1133 const struct lb_record *cmos_item;
1134 uint32_t bytes_processed, bytes_for_entries;
1135 const char *q;
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001136
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001137 p = (const struct cmos_option_table *)rec;
1138 q = ((const char *)p) + p->header_length;
1139 bytes_for_entries = p->size - p->header_length;
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001140
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001141 printf("CMOS option table at physical address 0x%lx:\n"
1142 " tag: 0x%x (decimal: %d)\n"
1143 " size: 0x%x (decimal: %d)\n"
1144 " header_length: 0x%x (decimal: %d)\n\n",
1145 vtophys(p), p->tag, p->tag, p->size, p->size, p->header_length,
1146 p->header_length);
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001147
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001148 if (p->header_length > p->size) {
1149 printf
1150 ("Header length for CMOS option table is greater than the size "
1151 "of the entire table including header!!!\n");
1152 return;
1153 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001154
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001155 if (bytes_for_entries == 0) {
1156 printf("The CMOS option table is empty!!!\n");
1157 return;
1158 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001159
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001160 for (bytes_processed = 0;;) {
1161 cmos_item = (const struct lb_record *)&q[bytes_processed];
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001162
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001163 switch (cmos_item->tag) {
1164 case LB_TAG_OPTION:
1165 print_option_record((const struct cmos_entries *)
1166 cmos_item);
1167 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001168
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001169 case LB_TAG_OPTION_ENUM:
1170 print_enum_record((const struct cmos_enums *)cmos_item);
1171 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001172
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001173 case LB_TAG_OPTION_DEFAULTS:
1174 print_defaults_record((const struct cmos_defaults *)
1175 cmos_item);
1176 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001177
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001178 default:
1179 print_unknown_record(cmos_item);
1180 break;
1181 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001182
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001183 bytes_processed += cmos_item->size;
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001184
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001185 if (bytes_processed >= bytes_for_entries)
1186 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001187
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001188 printf("\n");
1189 }
1190}
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001191
1192/****************************************************************************
1193 * print_option_record
1194 *
1195 * Display "option" record from CMOS option table.
1196 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001197static void print_option_record(const struct cmos_entries *cmos_entry)
1198{
1199 static const size_t S_BUFSIZE = 80;
1200 char s[S_BUFSIZE];
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001201
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001202 switch (cmos_entry->config) {
1203 case 'e':
1204 strcpy(s, "ENUM");
1205 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001206
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001207 case 'h':
1208 strcpy(s, "HEX");
1209 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001210
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001211 case 'r':
1212 strcpy(s, "RESERVED");
1213 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001214
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001215 default:
1216 snprintf(s, S_BUFSIZE, "UNKNOWN: value is 0x%x (decimal: %d)",
1217 cmos_entry->config, cmos_entry->config);
1218 break;
1219 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001220
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001221 printf(" OPTION record at physical address 0x%lx:\n"
1222 " tag: 0x%x (decimal: %d)\n"
1223 " size: 0x%x (decimal: %d)\n"
1224 " bit: 0x%x (decimal: %d)\n"
1225 " length: 0x%x (decimal: %d)\n"
1226 " config: %s\n"
1227 " config_id: 0x%x (decimal: %d)\n"
1228 " name: %s\n",
1229 vtophys(cmos_entry), cmos_entry->tag, cmos_entry->tag,
1230 cmos_entry->size, cmos_entry->size, cmos_entry->bit,
1231 cmos_entry->bit, cmos_entry->length, cmos_entry->length, s,
1232 cmos_entry->config_id, cmos_entry->config_id, cmos_entry->name);
1233}
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001234
1235/****************************************************************************
1236 * print_enum_record
1237 *
1238 * Display "enum" record from CMOS option table.
1239 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001240static void print_enum_record(const struct cmos_enums *cmos_enum)
1241{
1242 printf(" ENUM record at physical address 0x%lx:\n"
1243 " tag: 0x%x (decimal: %d)\n"
1244 " size: 0x%x (decimal: %d)\n"
1245 " config_id: 0x%x (decimal: %d)\n"
1246 " value: 0x%x (decimal: %d)\n"
1247 " text: %s\n",
1248 vtophys(cmos_enum), cmos_enum->tag, cmos_enum->tag,
1249 cmos_enum->size, cmos_enum->size, cmos_enum->config_id,
1250 cmos_enum->config_id, cmos_enum->value, cmos_enum->value,
1251 cmos_enum->text);
1252}
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001253
1254/****************************************************************************
1255 * print_defaults_record
1256 *
1257 * Display "defaults" record from CMOS option table.
1258 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001259static void print_defaults_record(const struct cmos_defaults *cmos_defaults)
1260{
1261 printf(" DEFAULTS record at physical address 0x%lx:\n"
1262 " tag: 0x%x (decimal: %d)\n"
1263 " size: 0x%x (decimal: %d)\n"
1264 " name_length: 0x%x (decimal: %d)\n"
1265 " name: %s\n"
1266 " default_set:\n",
1267 vtophys(cmos_defaults), cmos_defaults->tag, cmos_defaults->tag,
1268 cmos_defaults->size, cmos_defaults->size,
1269 cmos_defaults->name_length, cmos_defaults->name_length,
1270 cmos_defaults->name);
1271 hexdump(cmos_defaults->default_set, CMOS_IMAGE_BUFFER_SIZE,
1272 vtophys(cmos_defaults->default_set), stdout, &format);
1273}
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001274
1275/****************************************************************************
1276 * print_unknown_record
1277 *
1278 * Display record of unknown type from CMOS option table.
1279 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001280static void print_unknown_record(const struct lb_record *cmos_item)
1281{
1282 const char *data;
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001283
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001284 printf(" UNKNOWN record at physical address 0x%lx:\n"
1285 " tag: 0x%x (decimal: %d)\n"
1286 " size: 0x%x (decimal: %d)\n"
1287 " data:\n",
1288 vtophys(cmos_item), cmos_item->tag, cmos_item->tag,
1289 cmos_item->size, cmos_item->size);
1290 data = ((const char *)cmos_item) + sizeof(*cmos_item);
1291 hexdump(data, cmos_item->size - sizeof(*cmos_item), vtophys(data),
1292 stdout, &format);
1293}
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001294
1295/****************************************************************************
1296 * option_checksum_print_fn
1297 *
Stefan Reinauerf527e702008-01-18 15:33:49 +00001298 * Display function for 'option_checksum' item of coreboot table.
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001299 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001300static void option_checksum_print_fn(const struct lb_record *rec)
1301{
1302 struct cmos_checksum *p;
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001303
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001304 p = (struct cmos_checksum *)rec;
1305 printf("CMOS checksum from bit %d to bit %d\n"
1306 "at position %d is type %s.\n",
1307 p->range_start, p->range_end, p->location,
1308 (p->type == CHECKSUM_PCBIOS) ? "PC BIOS" : "NONE");
1309}
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001310
1311/****************************************************************************
1312 * string_print_fn
1313 *
Stefan Reinauerf527e702008-01-18 15:33:49 +00001314 * Display function for a generic item of coreboot table that simply
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001315 * consists of a string.
1316 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001317static void string_print_fn(const struct lb_record *rec)
1318{
1319 const struct lb_string *p;
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001320
Stefan Reinauer90b96b62010-01-13 21:00:23 +00001321 p = (const struct lb_string *)rec;
1322 printf("%s\n", p->string);
1323}
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001324