soc/intel/cmn/cse: Deprecate CONFIG_SOC_INTEL_CSE_RW_VERSION
[coreboot2.git] / util / nvramtool / accessors / layout-text.c
blobacbe7f8b39799c199a079116f6a85cb649289ca0
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include "common.h"
4 #include "layout-text.h"
5 #include "layout.h"
6 #include "cmos_lowlevel.h"
7 #include "reg_expr.h"
9 static void process_layout_file(FILE * f);
10 static void skip_past_start(FILE * f);
11 static int process_entry(FILE * f, int skip_add);
12 static int process_enum(FILE * f, int skip_add);
13 static void process_checksum_info(FILE * f);
14 static void skip_remaining_lines(FILE * f);
15 static void create_entry(cmos_entry_t * cmos_entry,
16 const char start_bit_str[], const char length_str[],
17 const char config_str[], const char config_id_str[],
18 const char name_str[]);
19 static void try_add_layout_file_entry(const cmos_entry_t * cmos_entry);
20 static void create_enum(cmos_enum_t * cmos_enum, const char id_str[],
21 const char value_str[], const char text_str[]);
22 static void try_add_cmos_enum(const cmos_enum_t * cmos_enum);
23 static void set_checksum_info(const char start_str[], const char end_str[],
24 const char index_str[]);
25 static char cmos_entry_char_value(cmos_entry_config_t config);
26 static int get_layout_file_line(FILE * f, char line[], int line_buf_size);
27 static unsigned string_to_unsigned(const char str[], const char str_name[]);
28 static unsigned long string_to_unsigned_long(const char str[],
29 const char str_name[]);
30 static unsigned long do_string_to_unsigned_long(const char str[],
31 const char str_name[],
32 const char blurb[]);
34 /* matches either a blank line or a comment line */
35 static const char blank_or_comment_regex[] =
36 /* a blank line */
37 "(^[[:space:]]+$)" "|" /* or ... */
38 /* a line consisting of: optional whitespace followed by */
39 "(^[[:space:]]*"
40 /* a '#' character and optionally, additional characters */
41 "#.*$)";
43 static regex_t blank_or_comment_expr;
45 /* matches the line in a CMOS layout file indicating the start of the
46 * "entries" section.
48 static const char start_entries_regex[] =
49 /* optional whitespace */
50 "^[[:space:]]*"
51 /* followed by "entries" */
52 "entries"
53 /* followed by optional whitespace */
54 "[[:space:]]*$";
56 static regex_t start_entries_expr;
58 /* matches the line in a CMOS layout file indicating the start of the
59 * "enumerations" section
61 static const char start_enums_regex[] =
62 /* optional whitespace */
63 "^[[:space:]]*"
64 /* followed by "enumerations" */
65 "enumerations"
66 /* followed by optional whitespace */
67 "[[:space:]]*$";
69 static regex_t start_enums_expr;
71 /* matches the line in a CMOS layout file indicating the start of the
72 * "checksums" section
74 static const char start_checksums_regex[] =
75 /* optional whitespace */
76 "^[[:space:]]*"
77 /* followed by "checksums" */
78 "checksums"
79 /* followed by optional whitespace */
80 "[[:space:]]*$";
82 static regex_t start_checksums_expr;
84 /* matches a line in a CMOS layout file specifying a CMOS entry */
85 static const char entries_line_regex[] =
86 /* optional whitespace */
87 "^[[:space:]]*"
88 /* followed by a chunk of nonwhitespace for start-bit field */
89 "([^[:space:]]+)"
90 /* followed by one or more whitespace characters */
91 "[[:space:]]+"
92 /* followed by a chunk of nonwhitespace for length field */
93 "([^[:space:]]+)"
94 /* followed by one or more whitespace characters */
95 "[[:space:]]+"
96 /* followed by a chunk of nonwhitespace for config field */
97 "([^[:space:]]+)"
98 /* followed by one or more whitespace characters */
99 "[[:space:]]+"
100 /* followed by a chunk of nonwhitespace for config-ID field */
101 "([^[:space:]]+)"
102 /* followed by one or more whitespace characters */
103 "[[:space:]]+"
104 /* followed by a chunk of nonwhitespace for name field */
105 "([^[:space:]]+)"
106 /* followed by optional whitespace */
107 "[[:space:]]*$";
109 static regex_t entries_line_expr;
111 /* matches a line in a CMOS layout file specifying a CMOS enumeration */
112 static const char enums_line_regex[] =
113 /* optional whitespace */
114 "^[[:space:]]*"
115 /* followed by a chunk of nonwhitespace for ID field */
116 "([^[:space:]]+)"
117 /* followed by one or more whitespace characters */
118 "[[:space:]]+"
119 /* followed by a chunk of nonwhitespace for value field */
120 "([^[:space:]]+)"
121 /* followed by one or more whitespace characters */
122 "[[:space:]]+"
123 /* followed by a chunk of nonwhitespace for text field */
124 "([[:print:]]*[^[:space:]])"
125 /* followed by optional whitespace */
126 "[[:space:]]*$";
128 static regex_t enums_line_expr;
130 /* matches the line in a CMOS layout file specifying CMOS checksum
131 * information
133 static const char checksum_line_regex[] =
134 /* optional whitespace */
135 "^[[:space:]]*"
136 /* followed by "checksum" */
137 "checksum"
138 /* followed by one or more whitespace characters */
139 "[[:space:]]+"
140 /* followed by a chunk of nonwhitespace for first bit of summed area */
141 "([^[:space:]]+)"
142 /* followed by one or more whitespace characters */
143 "[[:space:]]+"
144 /* followed by a chunk of nonwhitespace for last bit of summed area */
145 "([^[:space:]]+)"
146 /* followed by one or more whitespace characters */
147 "[[:space:]]+"
148 /* followed by a chunk of nonwhitespace for checksum location bit */
149 "([^[:space:]]+)"
150 /* followed by optional whitespace */
151 "[[:space:]]*$";
153 static regex_t checksum_line_expr;
155 static const int LINE_BUF_SIZE = 256;
157 static int line_num;
159 static const char *layout_filename = NULL;
161 /****************************************************************************
162 * set_layout_filename
164 * Set the name of the file we will obtain CMOS layout information from.
165 ****************************************************************************/
166 void set_layout_filename(const char filename[])
168 layout_filename = filename;
171 /****************************************************************************
172 * get_layout_from_file
174 * Read CMOS layout information from the user-specified CMOS layout file.
175 ****************************************************************************/
176 void get_layout_from_file(void)
178 FILE *f;
180 assert(layout_filename != NULL);
182 if ((f = fopen(layout_filename, "r")) == NULL) {
183 fprintf(stderr,
184 "%s: Can not open CMOS layout file %s for reading: "
185 "%s\n", prog_name, layout_filename, strerror(errno));
186 exit(1);
189 process_layout_file(f);
190 fclose(f);
193 void write_cmos_layout_header(const char *header_filename)
195 FILE *fp;
196 const cmos_entry_t *cmos_entry;
197 cmos_checksum_layout_t layout;
199 if ((fp = fopen(header_filename, "w+")) == NULL) {
200 fprintf(stderr,
201 "%s: Can't open file %s for writing: %s\n",
202 prog_name, header_filename, strerror(errno));
203 exit(1);
206 fprintf(fp, "/**\n * This is an autogenerated file. Do not EDIT.\n"
207 " * All changes made to this file will be lost.\n"
208 " * See mainboard's cmos.layout file.\n */\n"
209 "\n#ifndef __OPTION_TABLE_H\n"
210 "#define __OPTION_TABLE_H\n\n");
212 for (cmos_entry = first_cmos_entry(); cmos_entry != NULL;
213 cmos_entry = next_cmos_entry(cmos_entry)) {
215 if (!is_ident((char *)cmos_entry->name)) {
216 fprintf(stderr,
217 "Error - Name %s is an invalid identifier\n",
218 cmos_entry->name);
219 fclose(fp);
220 exit(1);
223 fprintf(fp, "#define CMOS_VSTART_%s\t%d\n",
224 cmos_entry->name, cmos_entry->bit);
225 fprintf(fp, "#define CMOS_VLEN_%s\t%d\n",
226 cmos_entry->name, cmos_entry->length);
229 layout.summed_area_start = cmos_checksum_start;
230 layout.summed_area_end = cmos_checksum_end;
231 layout.checksum_at = cmos_checksum_index;
232 checksum_layout_to_bits(&layout);
234 fprintf(fp, "\n#define LB_CKS_RANGE_START %d\n",
235 layout.summed_area_start / 8);
236 fprintf(fp, "#define LB_CKS_RANGE_END %d\n",
237 layout.summed_area_end / 8);
238 fprintf(fp, "#define LB_CKS_LOC %d\n",
239 layout.checksum_at / 8);
240 fprintf(fp, "\n#endif /* __OPTION_TABLE_H */\n");
242 fclose(fp);
244 /****************************************************************************
245 * write_cmos_layout
247 * Write CMOS layout information to file 'f'. The output is written in the
248 * format that CMOS layout files adhere to.
249 ****************************************************************************/
250 void write_cmos_layout(FILE * f)
252 const cmos_entry_t *cmos_entry;
253 const cmos_enum_t *cmos_enum;
254 cmos_checksum_layout_t layout;
256 fprintf(f, "entries\n");
258 for (cmos_entry = first_cmos_entry();
259 cmos_entry != NULL; cmos_entry = next_cmos_entry(cmos_entry))
260 fprintf(f, "%u %u %c %u %s\n", cmos_entry->bit,
261 cmos_entry->length,
262 cmos_entry_char_value(cmos_entry->config),
263 cmos_entry->config_id, cmos_entry->name);
265 fprintf(f, "\nenumerations\n");
267 for (cmos_enum = first_cmos_enum();
268 cmos_enum != NULL; cmos_enum = next_cmos_enum(cmos_enum))
269 fprintf(f, "%u %llu %s\n", cmos_enum->config_id,
270 cmos_enum->value, cmos_enum->text);
272 layout.summed_area_start = cmos_checksum_start;
273 layout.summed_area_end = cmos_checksum_end;
274 layout.checksum_at = cmos_checksum_index;
275 checksum_layout_to_bits(&layout);
276 fprintf(f, "\nchecksums\nchecksum %u %u %u\n", layout.summed_area_start,
277 layout.summed_area_end, layout.checksum_at);
280 /****************************************************************************
281 * process_layout_file
283 * Read CMOS layout information from file 'f' and add it to our internal
284 * repository.
285 ****************************************************************************/
286 static void process_layout_file(FILE * f)
288 compile_reg_expr(REG_EXTENDED | REG_NEWLINE, blank_or_comment_regex, &blank_or_comment_expr);
289 compile_reg_expr(REG_EXTENDED | REG_NEWLINE, start_entries_regex, &start_entries_expr);
290 compile_reg_expr(REG_EXTENDED | REG_NEWLINE, entries_line_regex, &entries_line_expr);
291 compile_reg_expr(REG_EXTENDED | REG_NEWLINE, start_enums_regex, &start_enums_expr);
292 compile_reg_expr(REG_EXTENDED | REG_NEWLINE, enums_line_regex, &enums_line_expr);
293 compile_reg_expr(REG_EXTENDED | REG_NEWLINE, start_checksums_regex, &start_checksums_expr);
294 compile_reg_expr(REG_EXTENDED | REG_NEWLINE, checksum_line_regex, &checksum_line_expr);
295 line_num = 1;
296 skip_past_start(f);
298 /* Skip past all entries. We will process these later when we
299 * make a second pass through the file.
301 while (!process_entry(f, 1)) ;
303 /* Process all enums, adding them to our internal repository as
304 * we go. */
306 if (process_enum(f, 0)) {
307 fprintf(stderr, "%s: Error: CMOS layout file contains no "
308 "enumerations.\n", prog_name);
309 exit(1);
312 while (!process_enum(f, 0)) ;
314 /* Go back to start of file. */
315 line_num = 1;
316 fseek(f, 0, SEEK_SET);
318 skip_past_start(f);
320 /* Process all entries, adding them to the repository as we go.
321 * We must add the entries after the enums, even though they
322 * appear in the layout file before the enums. This is because
323 * the entries are sanity checked against the enums as they are
324 * added.
327 if (process_entry(f, 0)) {
328 fprintf(stderr,
329 "%s: Error: CMOS layout file contains no entries.\n",
330 prog_name);
331 exit(1);
334 while (!process_entry(f, 0)) ;
336 /* Skip past all enums. They have already been processed. */
337 while (!process_enum(f, 1)) ;
339 /* Process CMOS checksum info. */
340 process_checksum_info(f);
342 /* See if there are any lines left to process. If so, verify
343 * that they are all either blank lines or comments.
345 skip_remaining_lines(f);
347 regfree(&blank_or_comment_expr);
348 regfree(&start_entries_expr);
349 regfree(&entries_line_expr);
350 regfree(&start_enums_expr);
351 regfree(&enums_line_expr);
352 regfree(&start_checksums_expr);
353 regfree(&checksum_line_expr);
356 /****************************************************************************
357 * skip_past_start
359 * Skip past the line that marks the start of the "entries" section.
360 ****************************************************************************/
361 static void skip_past_start(FILE * f)
363 char line[LINE_BUF_SIZE];
365 for (;; line_num++) {
366 if (get_layout_file_line(f, line, LINE_BUF_SIZE)) {
367 fprintf(stderr,
368 "%s: \"entries\" line not found in CMOS layout file.\n",
369 prog_name);
370 exit(1);
373 if (!regexec(&blank_or_comment_expr, line, 0, NULL, 0))
374 continue;
376 if (!regexec(&start_entries_expr, line, 0, NULL, 0))
377 break;
379 fprintf(stderr,
380 "%s: Syntax error on line %d of CMOS layout file. "
381 "\"entries\" line expected.\n", prog_name, line_num);
382 exit(1);
385 line_num++;
388 /****************************************************************************
389 * process_entry
391 * Get an entry from "entries" section of file and add it to our repository
392 * of layout information. Return 0 if an entry was found and processed.
393 * Return 1 if there are no more entries.
394 ****************************************************************************/
395 static int process_entry(FILE * f, int skip_add)
397 static const size_t N_MATCHES = 6;
398 char line[LINE_BUF_SIZE];
399 regmatch_t match[N_MATCHES];
400 cmos_entry_t cmos_entry;
401 int result;
403 result = 1;
405 for (;; line_num++) {
406 if (get_layout_file_line(f, line, LINE_BUF_SIZE)) {
407 fprintf(stderr,
408 "%s: Unexpected end of CMOS layout file reached while "
409 "reading \"entries\" section.\n", prog_name);
410 exit(1);
413 if (!regexec(&blank_or_comment_expr, line, 0, NULL, 0))
414 continue;
416 if (regexec(&entries_line_expr, line, N_MATCHES, match, 0)) {
417 if (regexec(&start_enums_expr, line, 0, NULL, 0)) {
418 fprintf(stderr,
419 "%s: Syntax error on line %d of CMOS layout "
420 "file.\n", prog_name, line_num);
421 exit(1);
424 break; /* start of enumerations reached: no more entries */
427 result = 0; /* next layout entry found */
429 if (skip_add)
430 break;
432 line[match[1].rm_eo] = '\0';
433 line[match[2].rm_eo] = '\0';
434 line[match[3].rm_eo] = '\0';
435 line[match[4].rm_eo] = '\0';
436 line[match[5].rm_eo] = '\0';
437 create_entry(&cmos_entry, &line[match[1].rm_so],
438 &line[match[2].rm_so], &line[match[3].rm_so],
439 &line[match[4].rm_so], &line[match[5].rm_so]);
440 try_add_layout_file_entry(&cmos_entry);
441 break;
444 line_num++;
445 return result;
448 /****************************************************************************
449 * process_enum
451 * Get an enuneration from "enumerations" section of file and add it to our
452 * repository of layout information. Return 0 if an enumeration was found
453 * and processed. Return 1 if there are no more enumerations.
454 ****************************************************************************/
455 static int process_enum(FILE * f, int skip_add)
457 static const size_t N_MATCHES = 4;
458 char line[LINE_BUF_SIZE];
459 regmatch_t match[N_MATCHES];
460 cmos_enum_t cmos_enum;
461 int result;
463 result = 1;
465 for (;; line_num++) {
466 if (get_layout_file_line(f, line, LINE_BUF_SIZE)) {
467 fprintf(stderr,
468 "%s: Unexpected end of CMOS layout file reached while "
469 "reading \"enumerations\" section.\n",
470 prog_name);
471 exit(1);
474 if (!regexec(&blank_or_comment_expr, line, 0, NULL, 0))
475 continue;
477 if (regexec(&enums_line_expr, line, N_MATCHES, match, 0)) {
478 if (regexec(&start_checksums_expr, line, 0, NULL, 0)) {
479 fprintf(stderr,
480 "%s: Syntax error on line %d of CMOS layout "
481 "file.\n", prog_name, line_num);
482 exit(1);
485 break; /* start of checksums reached: no more enumerations */
488 result = 0; /* next layout enumeration found */
490 if (skip_add)
491 break;
493 line[match[1].rm_eo] = '\0';
494 line[match[2].rm_eo] = '\0';
495 line[match[3].rm_eo] = '\0';
496 create_enum(&cmos_enum, &line[match[1].rm_so],
497 &line[match[2].rm_so], &line[match[3].rm_so]);
498 try_add_cmos_enum(&cmos_enum);
499 break;
502 line_num++;
503 return result;
506 /****************************************************************************
507 * process_checksum_info
509 * Get line containing CMOS checksum information.
510 ****************************************************************************/
511 static void process_checksum_info(FILE * f)
513 static const size_t N_MATCHES = 4;
514 char line[LINE_BUF_SIZE];
515 regmatch_t match[N_MATCHES];
517 for (;; line_num++) {
518 if (get_layout_file_line(f, line, LINE_BUF_SIZE)) {
519 fprintf(stderr,
520 "%s: Unexpected end of CMOS layout file reached while "
521 "reading \"checksums\" section.\n", prog_name);
522 exit(1);
525 if (!regexec(&blank_or_comment_expr, line, 0, NULL, 0))
526 continue;
528 if (regexec(&checksum_line_expr, line, N_MATCHES, match, 0)) {
529 fprintf(stderr,
530 "%s: Syntax error on line %d of CMOS layout "
531 "file. \"checksum\" line expected.\n",
532 prog_name, line_num);
533 exit(1);
536 /* checksum line found */
537 line[match[1].rm_eo] = '\0';
538 line[match[2].rm_eo] = '\0';
539 line[match[3].rm_eo] = '\0';
540 set_checksum_info(&line[match[1].rm_so], &line[match[2].rm_so],
541 &line[match[3].rm_so]);
542 break;
546 /****************************************************************************
547 * skip_remaining_lines
549 * Get any remaining lines of unprocessed input. Complain if we find a line
550 * that contains anything other than comments and whitespace.
551 ****************************************************************************/
552 static void skip_remaining_lines(FILE * f)
554 char line[LINE_BUF_SIZE];
556 for (line_num++;
557 get_layout_file_line(f, line, LINE_BUF_SIZE) == OK; line_num++) {
558 if (regexec(&blank_or_comment_expr, line, 0, NULL, 0)) {
559 fprintf(stderr,
560 "%s: Syntax error on line %d of CMOS layout file: "
561 "Only comments and/or whitespace allowed after "
562 "\"checksum\" line.\n", prog_name, line_num);
563 exit(1);
568 /****************************************************************************
569 * create_entry
571 * Create a CMOS entry structure representing the given information. Perform
572 * sanity checking on input parameters.
573 ****************************************************************************/
574 static void create_entry(cmos_entry_t * cmos_entry,
575 const char start_bit_str[], const char length_str[],
576 const char config_str[], const char config_id_str[],
577 const char name_str[])
579 cmos_entry->bit = string_to_unsigned(start_bit_str, "start-bit");
580 cmos_entry->length = string_to_unsigned(length_str, "length");
582 if (config_str[1] != '\0')
583 goto bad_config_str;
585 switch (config_str[0]) {
586 case 'e':
587 cmos_entry->config = CMOS_ENTRY_ENUM;
588 break;
590 case 'h':
591 cmos_entry->config = CMOS_ENTRY_HEX;
592 break;
594 case 's':
595 cmos_entry->config = CMOS_ENTRY_STRING;
596 break;
598 case 'r':
599 cmos_entry->config = CMOS_ENTRY_RESERVED;
600 break;
602 default:
603 goto bad_config_str;
606 cmos_entry->config_id = string_to_unsigned(config_id_str, "config-ID");
608 if (strlen(name_str) >= CMOS_MAX_NAME_LENGTH) {
609 fprintf(stderr,
610 "%s: Error on line %d of CMOS layout file: name too "
611 "long (max length is %d).\n", prog_name, line_num,
612 CMOS_MAX_NAME_LENGTH - 1);
613 exit(1);
616 strcpy(cmos_entry->name, name_str);
617 return;
619 bad_config_str:
620 fprintf(stderr,
621 "%s: Error on line %d of CMOS layout file: 'e', 'h', or "
622 "'r' expected for config value.\n", prog_name, line_num);
623 exit(1);
626 /****************************************************************************
627 * try_add_layout_file_entry
629 * Attempt to add the given CMOS entry to our internal repository. Exit with
630 * an error message on failure.
631 ****************************************************************************/
632 static void try_add_layout_file_entry(const cmos_entry_t * cmos_entry)
634 const cmos_entry_t *conflict;
636 switch (add_cmos_entry(cmos_entry, &conflict)) {
637 case OK:
638 return;
640 case CMOS_AREA_OUT_OF_RANGE:
641 fprintf(stderr,
642 "%s: Error on line %d of CMOS layout file. Area "
643 "covered by entry %s is out of range.\n", prog_name,
644 line_num, cmos_entry->name);
645 break;
647 case CMOS_AREA_TOO_WIDE:
648 fprintf(stderr,
649 "%s: Error on line %d of CMOS layout file. Area "
650 "covered by entry %s is too wide.\n", prog_name,
651 line_num, cmos_entry->name);
652 break;
654 case LAYOUT_ENTRY_OVERLAP:
655 fprintf(stderr,
656 "%s: Error on line %d of CMOS layout file. Layouts "
657 "overlap for entries %s and %s.\n", prog_name, line_num,
658 cmos_entry->name, conflict->name);
659 break;
661 case LAYOUT_ENTRY_BAD_LENGTH:
662 /* Silently ignore entries with zero length. Although this should
663 * never happen in practice, we should handle the case in a
664 * reasonable manner just to be safe.
666 return;
668 case LAYOUT_MULTIBYTE_ENTRY_NOT_ALIGNED:
669 fprintf(stderr,
670 "%s: Unaligned CMOS option table entry %s "
671 "spans multiple bytes.\n", prog_name, cmos_entry->name);
672 break;
674 default:
675 BUG();
678 exit(1);
681 /****************************************************************************
682 * create_enum
684 * Create a CMOS enumeration structure representing the given information.
685 * Perform sanity checking on input parameters.
686 ****************************************************************************/
687 static void create_enum(cmos_enum_t * cmos_enum, const char id_str[],
688 const char value_str[], const char text_str[])
690 cmos_enum->config_id = string_to_unsigned(id_str, "ID");
691 cmos_enum->value = string_to_unsigned_long(value_str, "value");
693 if (strlen(text_str) >= CMOS_MAX_TEXT_LENGTH) {
694 fprintf(stderr,
695 "%s: Error on line %d of CMOS layout file: text too "
696 "long (max length is %d).\n", prog_name, line_num,
697 CMOS_MAX_TEXT_LENGTH - 1);
698 exit(1);
701 strcpy(cmos_enum->text, text_str);
704 /****************************************************************************
705 * try_add_cmos_enum
707 * Attempt to add the given CMOS enum to our internal repository. Exit with
708 * an error message on failure.
709 ****************************************************************************/
710 static void try_add_cmos_enum(const cmos_enum_t * cmos_enum)
712 switch (add_cmos_enum(cmos_enum)) {
713 case OK:
714 return;
716 case LAYOUT_DUPLICATE_ENUM:
717 fprintf(stderr, "%s: Error on line %d of CMOS layout file: "
718 "Enumeration found with duplicate ID/value combination.\n",
719 prog_name, line_num);
720 break;
722 default:
723 BUG();
726 exit(1);
729 /****************************************************************************
730 * set_checksum_info
732 * Set CMOS checksum information according to input parameters and perform
733 * sanity checking on input parameters.
734 ****************************************************************************/
735 static void set_checksum_info(const char start_str[], const char end_str[],
736 const char index_str[])
738 cmos_checksum_layout_t layout;
740 /* These are bit positions that we want to convert to byte positions. */
741 layout.summed_area_start =
742 string_to_unsigned(start_str, "CMOS checksummed area start");
743 layout.summed_area_end =
744 string_to_unsigned(end_str, "CMOS checksummed area end");
745 layout.checksum_at =
746 string_to_unsigned(index_str, "CMOS checksum location");
748 switch (checksum_layout_to_bytes(&layout)) {
749 case OK:
750 break;
752 case LAYOUT_SUMMED_AREA_START_NOT_ALIGNED:
753 fprintf(stderr,
754 "%s: Error on line %d of CMOS layout file. CMOS "
755 "checksummed area start is not byte-aligned.\n",
756 prog_name, line_num);
757 goto fail;
759 case LAYOUT_SUMMED_AREA_END_NOT_ALIGNED:
760 fprintf(stderr,
761 "%s: Error on line %d of CMOS layout file. CMOS "
762 "checksummed area end is not byte-aligned.\n",
763 prog_name, line_num);
764 goto fail;
766 case LAYOUT_CHECKSUM_LOCATION_NOT_ALIGNED:
767 fprintf(stderr,
768 "%s: Error on line %d of CMOS layout file. CMOS "
769 "checksum location is not byte-aligned.\n", prog_name,
770 line_num);
771 goto fail;
773 case LAYOUT_INVALID_SUMMED_AREA:
774 fprintf(stderr,
775 "%s: Error on line %d of CMOS layout file. CMOS "
776 "checksummed area end must be greater than CMOS checksummed "
777 "area start.\n", prog_name, line_num);
778 goto fail;
780 case LAYOUT_CHECKSUM_OVERLAPS_SUMMED_AREA:
781 fprintf(stderr,
782 "%s: Error on line %d of CMOS layout file. CMOS "
783 "checksum overlaps checksummed area.\n", prog_name,
784 line_num);
785 goto fail;
787 case LAYOUT_SUMMED_AREA_OUT_OF_RANGE:
788 fprintf(stderr,
789 "%s: Error on line %d of CMOS layout file. CMOS "
790 "checksummed area out of range.\n", prog_name,
791 line_num);
792 goto fail;
794 case LAYOUT_CHECKSUM_LOCATION_OUT_OF_RANGE:
795 fprintf(stderr,
796 "%s: Error on line %d of CMOS layout file. CMOS "
797 "checksum location out of range.\n", prog_name,
798 line_num);
799 goto fail;
801 default:
802 BUG();
805 cmos_checksum_start = layout.summed_area_start;
806 cmos_checksum_end = layout.summed_area_end;
807 cmos_checksum_index = layout.checksum_at;
808 return;
810 fail:
811 exit(1);
814 /****************************************************************************
815 * cmos_entry_char_value
817 * Return the character representation of 'config'.
818 ****************************************************************************/
819 static char cmos_entry_char_value(cmos_entry_config_t config)
821 switch (config) {
822 case CMOS_ENTRY_ENUM:
823 return 'e';
825 case CMOS_ENTRY_HEX:
826 return 'h';
828 case CMOS_ENTRY_RESERVED:
829 return 'r';
831 case CMOS_ENTRY_STRING:
832 return 's';
834 default:
835 BUG();
838 return 0; /* not reached */
841 /****************************************************************************
842 * get_layout_file_line
844 * Get a line of input from file 'f'. Store result in 'line' which is an
845 * array of 'line_buf_size' bytes. Return OK on success or an error code on
846 * failure.
847 ****************************************************************************/
848 static int get_layout_file_line(FILE * f, char line[], int line_buf_size)
850 switch (get_line_from_file(f, line, line_buf_size)) {
851 case OK:
852 return OK;
854 case LINE_EOF:
855 return LINE_EOF;
857 case LINE_TOO_LONG:
858 fprintf(stderr,
859 "%s: Error on line %d of CMOS layout file: Maximum "
860 "line length exceeded. Max is %d characters.\n",
861 prog_name, line_num, line_buf_size - 2);
862 break;
865 exit(1);
866 return 1; /* keep compiler happy */
869 /****************************************************************************
870 * string_to_unsigned
872 * Convert the string 'str' to an unsigned and return the result.
873 ****************************************************************************/
874 static unsigned string_to_unsigned(const char str[], const char str_name[])
876 unsigned long n;
877 unsigned z;
879 n = do_string_to_unsigned_long(str, str_name, "");
881 if ((z = (unsigned)n) != n) {
882 /* This could happen on an architecture in which
883 * sizeof(unsigned) < sizeof(unsigned long).
885 fprintf(stderr,
886 "%s: Error on line %d of CMOS layout file: %s value is "
887 "out of range.\n", prog_name, line_num, str_name);
888 exit(1);
891 return z;
894 /****************************************************************************
895 * string_to_unsigned_long
897 * Convert the string 'str' to an unsigned long and return the result.
898 ****************************************************************************/
899 static unsigned long string_to_unsigned_long(const char str[],
900 const char str_name[])
902 return do_string_to_unsigned_long(str, str_name, " long");
905 /****************************************************************************
906 * do_string_to_unsigned_long
908 * Convert the string 'str' to an unsigned long and return the result. Exit
909 * with an appropriate error message on failure.
910 ****************************************************************************/
911 static unsigned long do_string_to_unsigned_long(const char str[],
912 const char str_name[],
913 const char blurb[])
915 unsigned long n;
916 char *p;
918 n = strtoul(str, &p, 0);
920 if (*p != '\0') {
921 fprintf(stderr,
922 "%s: Error on line %d of CMOS layout file: %s is not a "
923 "valid unsigned%s integer.\n", prog_name, line_num,
924 str_name, blurb);
925 exit(1);
928 return n;