Use more secure HTTPS URLs for coreboot sites
[coreboot.git] / util / nvramtool / accessors / layout-bin.c
blobe545dc51a77e7275457e9b4c7aa02f292833758b
1 /*****************************************************************************\
2 * lbtable.c
3 *****************************************************************************
4 * Copyright (C) 2012, Vikram Narayanan
5 * Unified build_opt_tbl and nvramtool
6 * build_opt_tbl.c
7 * Copyright (C) 2003 Eric Biederman (ebiederm@xmission.com)
8 * Copyright (C) 2007-2010 coresystems GmbH
10 * Copyright (C) 2002-2005 The Regents of the University of California.
11 * Produced at the Lawrence Livermore National Laboratory.
12 * Written by Dave Peterson <dsp@llnl.gov> <dave_peterson@pobox.com>
13 * and Stefan Reinauer <stepan@openbios.org>.
14 * UCRL-CODE-2003-012
15 * All rights reserved.
17 * This file is part of nvramtool, a utility for reading/writing coreboot
18 * parameters and displaying information from the coreboot table.
19 * For details, see https://coreboot.org/nvramtool.
21 * Please also read the file DISCLAIMER which is included in this software
22 * distribution.
24 * This program is free software; you can redistribute it and/or modify it
25 * under the terms of the GNU General Public License (as published by the
26 * Free Software Foundation) version 2, dated June 1991.
28 * This program is distributed in the hope that it will be useful, but
29 * WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
31 * conditions of the GNU General Public License for more details.
32 \*****************************************************************************/
34 #include <string.h>
35 #ifndef __MINGW32__
36 #include <sys/mman.h>
37 #endif
38 #include "common.h"
39 #include "coreboot_tables.h"
40 #include "ip_checksum.h"
41 #include "lbtable.h"
42 #include "layout.h"
43 #include "cmos_lowlevel.h"
44 #include "hexdump.h"
45 #include "cbfs.h"
46 #include "layout-text.h"
48 static void process_cmos_table(void);
49 static void get_cmos_checksum_info(void);
50 static void try_convert_checksum_layout(cmos_checksum_layout_t * layout);
51 static void try_add_cmos_table_enum(cmos_enum_t * cmos_enum);
52 static void try_add_cmos_table_entry(cmos_entry_t * cmos_entry);
53 static const struct cmos_entries *first_cmos_table_entry(void);
54 static const struct cmos_entries *next_cmos_table_entry(const struct
55 cmos_entries *last);
56 static const struct cmos_enums *first_cmos_table_enum(void);
57 static const struct cmos_enums *next_cmos_table_enum
58 (const struct cmos_enums *last);
59 static const struct lb_record *first_cmos_rec(uint32_t tag);
60 static const struct lb_record *next_cmos_rec(const struct lb_record *last,
61 uint32_t tag);
63 /* The CMOS option table is located within the coreboot table. It tells us
64 * where the CMOS parameters are located in the nonvolatile RAM.
66 static const struct cmos_option_table *cmos_table = NULL;
68 #define ROUNDUP4(x) (x += (4 - (x % 4)))
70 void process_layout(void)
72 if ((cmos_table) == NULL) {
73 fprintf(stderr,
74 "%s: CMOS option table not found in coreboot table. "
75 "Apparently, the coreboot installed on this system was "
76 "built without specifying CONFIG_HAVE_OPTION_TABLE.\n",
77 prog_name);
78 exit(1);
81 process_cmos_table();
82 get_cmos_checksum_info();
85 void get_layout_from_cbfs_file(void)
87 uint32_t len;
88 cmos_table = cbfs_find_file("cmos_layout.bin", CBFS_COMPONENT_CMOS_LAYOUT, &len);
89 process_layout();
92 int write_cmos_layout_bin(FILE *f)
94 const cmos_entry_t *cmos_entry;
95 const cmos_enum_t *cmos_enum;
96 cmos_checksum_layout_t layout;
97 struct cmos_option_table table;
98 struct cmos_entries entry;
99 struct cmos_enums cenum;
100 struct cmos_checksum csum;
101 size_t sum = 0;
102 int len;
104 for (cmos_entry = first_cmos_entry(); cmos_entry != NULL;
105 cmos_entry = next_cmos_entry(cmos_entry)) {
107 if (cmos_entry == first_cmos_entry()) {
108 sum += sizeof(table);
109 table.header_length = sizeof(table);
110 table.tag = LB_TAG_CMOS_OPTION_TABLE;
111 table.size = 0;
113 if (fwrite((char *)&table, sizeof(table), 1, f) != 1) {
114 perror("Error writing image file");
115 goto err;
119 memset(&entry, 0, sizeof(entry));
120 entry.tag = LB_TAG_OPTION;
121 entry.config = cmos_entry->config;
122 entry.config_id = (uint32_t)cmos_entry->config_id;
123 entry.bit = cmos_entry->bit;
124 entry.length = cmos_entry->length;
126 if (!is_ident((char *)cmos_entry->name)) {
127 fprintf(stderr,
128 "Error - Name %s is an invalid identifier\n",
129 cmos_entry->name);
130 goto err;
133 memcpy(entry.name, cmos_entry->name, strlen(cmos_entry->name));
134 entry.name[strlen(cmos_entry->name)] = '\0';
135 len = strlen(cmos_entry->name) + 1;
137 if (len % 4)
138 ROUNDUP4(len);
140 entry.size = sizeof(entry) - CMOS_MAX_NAME_LENGTH + len;
141 sum += entry.size;
142 if (fwrite((char *)&entry, entry.size, 1, f) != 1) {
143 perror("Error writing image file");
144 goto err;
148 for (cmos_enum = first_cmos_enum();
149 cmos_enum != NULL; cmos_enum = next_cmos_enum(cmos_enum)) {
150 memset(&cenum, 0, sizeof(cenum));
151 cenum.tag = LB_TAG_OPTION_ENUM;
152 memcpy(cenum.text, cmos_enum->text, strlen(cmos_enum->text));
153 cenum.text[strlen(cmos_enum->text)] = '\0';
154 len = strlen((char *)cenum.text) + 1;
156 if (len % 4)
157 ROUNDUP4(len);
159 cenum.config_id = cmos_enum->config_id;
160 cenum.value = cmos_enum->value;
161 cenum.size = sizeof(cenum) - CMOS_MAX_TEXT_LENGTH + len;
162 sum += cenum.size;
163 if (fwrite((char *)&cenum, cenum.size, 1, f) != 1) {
164 perror("Error writing image file");
165 goto err;
169 layout.summed_area_start = cmos_checksum_start;
170 layout.summed_area_end = cmos_checksum_end;
171 layout.checksum_at = cmos_checksum_index;
172 checksum_layout_to_bits(&layout);
174 csum.tag = LB_TAG_OPTION_CHECKSUM;
175 csum.size = sizeof(csum);
176 csum.range_start = layout.summed_area_start;
177 csum.range_end = layout.summed_area_end;
178 csum.location = layout.checksum_at;
179 csum.type = CHECKSUM_PCBIOS;
180 sum += csum.size;
182 if (fwrite((char *)&csum, csum.size, 1, f) != 1) {
183 perror("Error writing image file");
184 goto err;
187 if (fseek(f, 0, SEEK_SET) != 0) {
188 perror("Error while seeking");
189 goto err;
192 table.size = sum;
193 if (fwrite((char *)&table, sizeof(table), 1, f) != 1) {
194 perror("Error writing image file");
195 goto err;
197 return sum;
199 err:
200 fclose(f);
201 exit(1);
204 void write_cmos_output_bin(const char *binary_filename)
206 FILE *fp;
208 if ((fp = fopen(binary_filename, "wb")) == NULL) {
209 fprintf(stderr,
210 "%s: Can not open file %s for writing: "
211 "%s\n", prog_name, binary_filename, strerror(errno));
212 exit(1);
214 write_cmos_layout_bin(fp);
215 fclose(fp);
218 /****************************************************************************
219 * get_layout_from_cmos_table
221 * Find the CMOS table which is stored within the coreboot table and set the
222 * global variable cmos_table to point to it.
223 ****************************************************************************/
224 void get_layout_from_cmos_table(void)
226 get_lbtable();
227 cmos_table = (const struct cmos_option_table *)
228 find_lbrec(LB_TAG_CMOS_OPTION_TABLE);
229 process_layout();
232 /****************************************************************************
233 * process_cmos_table
235 * Extract layout information from the CMOS option table and store it in our
236 * internal repository.
237 ****************************************************************************/
238 static void process_cmos_table(void)
240 const struct cmos_enums *p;
241 const struct cmos_entries *q;
242 cmos_enum_t cmos_enum;
243 cmos_entry_t cmos_entry;
245 /* First add the enums. */
246 for (p = first_cmos_table_enum(); p != NULL;
247 p = next_cmos_table_enum(p)) {
248 cmos_enum.config_id = p->config_id;
249 cmos_enum.value = p->value;
250 strncpy(cmos_enum.text, (char *)p->text, CMOS_MAX_TEXT_LENGTH);
251 cmos_enum.text[CMOS_MAX_TEXT_LENGTH] = '\0';
252 try_add_cmos_table_enum(&cmos_enum);
255 /* Now add the entries. We must add the entries after the enums because
256 * the entries are sanity checked against the enums as they are added.
258 for (q = first_cmos_table_entry(); q != NULL;
259 q = next_cmos_table_entry(q)) {
260 cmos_entry.bit = q->bit;
261 cmos_entry.length = q->length;
263 switch (q->config) {
264 case 'e':
265 cmos_entry.config = CMOS_ENTRY_ENUM;
266 break;
268 case 'h':
269 cmos_entry.config = CMOS_ENTRY_HEX;
270 break;
272 case 'r':
273 cmos_entry.config = CMOS_ENTRY_RESERVED;
274 break;
276 case 's':
277 cmos_entry.config = CMOS_ENTRY_STRING;
278 break;
280 default:
281 fprintf(stderr,
282 "%s: Entry in CMOS option table has unknown config "
283 "value.\n", prog_name);
284 exit(1);
287 cmos_entry.config_id = q->config_id;
288 strncpy(cmos_entry.name, (char *)q->name, CMOS_MAX_NAME_LENGTH);
289 cmos_entry.name[CMOS_MAX_NAME_LENGTH] = '\0';
290 try_add_cmos_table_entry(&cmos_entry);
294 /****************************************************************************
295 * get_cmos_checksum_info
297 * Get layout information for CMOS checksum.
298 ****************************************************************************/
299 static void get_cmos_checksum_info(void)
301 const cmos_entry_t *e;
302 struct cmos_checksum *checksum;
303 cmos_checksum_layout_t layout;
304 unsigned index, index2;
306 checksum = (struct cmos_checksum *)next_cmos_rec((const struct lb_record *)first_cmos_table_enum(), LB_TAG_OPTION_CHECKSUM);
308 if (checksum != NULL) { /* We are lucky. The coreboot table hints us to the checksum.
309 * We might have to check the type field here though.
311 layout.summed_area_start = checksum->range_start;
312 layout.summed_area_end = checksum->range_end;
313 layout.checksum_at = checksum->location;
314 try_convert_checksum_layout(&layout);
315 cmos_checksum_start = layout.summed_area_start;
316 cmos_checksum_end = layout.summed_area_end;
317 cmos_checksum_index = layout.checksum_at;
318 return;
321 if ((e = find_cmos_entry(checksum_param_name)) == NULL)
322 return;
324 /* If we get here, we are unlucky. The CMOS option table contains the
325 * location of the CMOS checksum. However, there is no information
326 * regarding which bytes of the CMOS area the checksum is computed over.
327 * Thus we have to hope our presets will be fine.
330 if (e->bit % 8) {
331 fprintf(stderr,
332 "%s: Error: CMOS checksum is not byte-aligned.\n",
333 prog_name);
334 exit(1);
337 index = e->bit / 8;
338 index2 = index + 1; /* The CMOS checksum occupies 16 bits. */
340 if (verify_cmos_byte_index(index) || verify_cmos_byte_index(index2)) {
341 fprintf(stderr,
342 "%s: Error: CMOS checksum location out of range.\n",
343 prog_name);
344 exit(1);
347 if (((index >= cmos_checksum_start) && (index <= cmos_checksum_end)) ||
348 (((index2) >= cmos_checksum_start)
349 && ((index2) <= cmos_checksum_end))) {
350 fprintf(stderr,
351 "%s: Error: CMOS checksum overlaps checksummed area.\n",
352 prog_name);
353 exit(1);
356 cmos_checksum_index = index;
359 /****************************************************************************
360 * try_convert_checksum_layout
362 * Perform sanity checking on CMOS checksum layout information and attempt to
363 * convert information from bit positions to byte positions. Return OK on
364 * success or an error code on failure.
365 ****************************************************************************/
366 static void try_convert_checksum_layout(cmos_checksum_layout_t * layout)
368 switch (checksum_layout_to_bytes(layout)) {
369 case OK:
370 return;
372 case LAYOUT_SUMMED_AREA_START_NOT_ALIGNED:
373 fprintf(stderr,
374 "%s: CMOS checksummed area start is not byte-aligned.\n",
375 prog_name);
376 break;
378 case LAYOUT_SUMMED_AREA_END_NOT_ALIGNED:
379 fprintf(stderr,
380 "%s: CMOS checksummed area end is not byte-aligned.\n",
381 prog_name);
382 break;
384 case LAYOUT_CHECKSUM_LOCATION_NOT_ALIGNED:
385 fprintf(stderr,
386 "%s: CMOS checksum location is not byte-aligned.\n",
387 prog_name);
388 break;
390 case LAYOUT_INVALID_SUMMED_AREA:
391 fprintf(stderr,
392 "%s: CMOS checksummed area end must be greater than "
393 "CMOS checksummed area start.\n", prog_name);
394 break;
396 case LAYOUT_CHECKSUM_OVERLAPS_SUMMED_AREA:
397 fprintf(stderr,
398 "%s: CMOS checksum overlaps checksummed area.\n",
399 prog_name);
400 break;
402 case LAYOUT_SUMMED_AREA_OUT_OF_RANGE:
403 fprintf(stderr,
404 "%s: CMOS checksummed area out of range.\n", prog_name);
405 break;
407 case LAYOUT_CHECKSUM_LOCATION_OUT_OF_RANGE:
408 fprintf(stderr,
409 "%s: CMOS checksum location out of range.\n",
410 prog_name);
411 break;
413 default:
414 BUG();
417 exit(1);
420 /****************************************************************************
421 * try_add_cmos_table_enum
423 * Attempt to add a CMOS enum to our internal repository. Exit with an error
424 * message on failure.
425 ****************************************************************************/
426 static void try_add_cmos_table_enum(cmos_enum_t * cmos_enum)
428 switch (add_cmos_enum(cmos_enum)) {
429 case OK:
430 return;
432 case LAYOUT_DUPLICATE_ENUM:
433 fprintf(stderr, "%s: Duplicate enum %s found in CMOS option "
434 "table.\n", prog_name, cmos_enum->text);
435 break;
437 default:
438 BUG();
441 exit(1);
444 /****************************************************************************
445 * try_add_cmos_table_entry
447 * Attempt to add a CMOS entry to our internal repository. Exit with an
448 * error message on failure.
449 ****************************************************************************/
450 static void try_add_cmos_table_entry(cmos_entry_t * cmos_entry)
452 const cmos_entry_t *conflict;
454 switch (add_cmos_entry(cmos_entry, &conflict)) {
455 case OK:
456 return;
458 case CMOS_AREA_OUT_OF_RANGE:
459 fprintf(stderr,
460 "%s: Bad CMOS option layout in CMOS option table entry "
461 "%s.\n", prog_name, cmos_entry->name);
462 break;
464 case CMOS_AREA_TOO_WIDE:
465 fprintf(stderr,
466 "%s: Area too wide for CMOS option table entry %s.\n",
467 prog_name, cmos_entry->name);
468 break;
470 case LAYOUT_ENTRY_OVERLAP:
471 fprintf(stderr,
472 "%s: CMOS option table entries %s and %s have overlapping "
473 "layouts.\n", prog_name, cmos_entry->name,
474 conflict->name);
475 break;
477 case LAYOUT_ENTRY_BAD_LENGTH:
478 /* Silently ignore entries with zero length. Although this should
479 * never happen in practice, we should handle the case in a
480 * reasonable manner just to be safe.
482 return;
484 case LAYOUT_MULTIBYTE_ENTRY_NOT_ALIGNED:
485 fprintf(stderr,
486 "%s: Unaligned CMOS option table entry %s "
487 "spans multiple bytes.\n", prog_name, cmos_entry->name);
488 break;
490 default:
491 BUG();
494 exit(1);
497 /****************************************************************************
498 * first_cmos_table_entry
500 * Return a pointer to the first entry in the CMOS table that represents a
501 * CMOS parameter. Return NULL if CMOS table is empty.
502 ****************************************************************************/
503 static const struct cmos_entries *first_cmos_table_entry(void)
505 return (const struct cmos_entries *)first_cmos_rec(LB_TAG_OPTION);
508 /****************************************************************************
509 * next_cmos_table_entry
511 * Return a pointer to the next entry after 'last' in the CMOS table that
512 * represents a CMOS parameter. Return NULL if there are no more parameters.
513 ****************************************************************************/
514 static const struct cmos_entries *next_cmos_table_entry(const struct
515 cmos_entries *last)
517 return (const struct cmos_entries *)
518 next_cmos_rec((const struct lb_record *)last, LB_TAG_OPTION);
521 /****************************************************************************
522 * first_cmos_table_enum
524 * Return a pointer to the first entry in the CMOS table that represents a
525 * possible CMOS parameter value. Return NULL if the table does not contain
526 * any such entries.
527 ****************************************************************************/
528 static const struct cmos_enums *first_cmos_table_enum(void)
530 return (const struct cmos_enums *)first_cmos_rec(LB_TAG_OPTION_ENUM);
533 /****************************************************************************
534 * next_cmos_table_enum
536 * Return a pointer to the next entry after 'last' in the CMOS table that
537 * represents a possible CMOS parameter value. Return NULL if there are no
538 * more parameter values.
539 ****************************************************************************/
540 static const struct cmos_enums *next_cmos_table_enum
541 (const struct cmos_enums *last) {
542 return (const struct cmos_enums *)
543 next_cmos_rec((const struct lb_record *)last, LB_TAG_OPTION_ENUM);
546 /****************************************************************************
547 * first_cmos_rec
549 * Return a pointer to the first entry in the CMOS table whose type matches
550 * 'tag'. Return NULL if CMOS table contains no such entry.
552 * Possible values for 'tag' are as follows:
554 * LB_TAG_OPTION: The entry represents a CMOS parameter.
555 * LB_TAG_OPTION_ENUM: The entry represents a possible value for a CMOS
556 * parameter of type 'enum'.
558 * The CMOS table tells us where in the nonvolatile RAM to look for CMOS
559 * parameter values and specifies their types as 'enum', 'hex', or
560 * 'reserved'.
561 ****************************************************************************/
562 static const struct lb_record *first_cmos_rec(uint32_t tag)
564 const char *p;
565 uint32_t bytes_processed, bytes_for_entries;
566 const struct lb_record *lbrec;
568 p = ((const char *)cmos_table) + cmos_table->header_length;
569 bytes_for_entries = cmos_table->size - cmos_table->header_length;
571 for (bytes_processed = 0;
572 bytes_processed < bytes_for_entries;
573 bytes_processed += lbrec->size) {
574 lbrec = (const struct lb_record *)&p[bytes_processed];
576 if (lbrec->tag == tag)
577 return lbrec;
580 return NULL;
583 /****************************************************************************
584 * next_cmos_rec
586 * Return a pointer to the next entry after 'last' in the CMOS table whose
587 * type matches 'tag'. Return NULL if the table contains no more entries of
588 * this type.
589 ****************************************************************************/
590 static const struct lb_record *next_cmos_rec(const struct lb_record *last,
591 uint32_t tag)
593 const char *p;
594 uint32_t bytes_processed, bytes_for_entries, last_offset;
595 const struct lb_record *lbrec;
597 p = ((const char *)cmos_table) + cmos_table->header_length;
598 bytes_for_entries = cmos_table->size - cmos_table->header_length;
599 last_offset = ((const char *)last) - p;
601 for (bytes_processed = last_offset + last->size;
602 bytes_processed < bytes_for_entries;
603 bytes_processed += lbrec->size) {
604 lbrec = (const struct lb_record *)&p[bytes_processed];
606 if (lbrec->tag == tag)
607 return lbrec;
610 return NULL;