Add nvramtool -C option that takes a CBFS file as argument.
[coreboot.git] / util / nvramtool / layout_file.c
1 /*****************************************************************************\
2  * layout_file.c
3  *****************************************************************************
4  *  Copyright (C) 2002-2005 The Regents of the University of California.
5  *  Produced at the Lawrence Livermore National Laboratory.
6  *  Written by Dave Peterson <dsp@llnl.gov> <dave_peterson@pobox.com>.
7  *  UCRL-CODE-2003-012
8  *  All rights reserved.
9  *
10  *  This file is part of nvramtool, a utility for reading/writing coreboot
11  *  parameters and displaying information from the coreboot table.
12  *  For details, see http://coreboot.org/nvramtool.
13  *
14  *  Please also read the file DISCLAIMER which is included in this software
15  *  distribution.
16  *
17  *  This program is free software; you can redistribute it and/or modify it
18  *  under the terms of the GNU General Public License (as published by the
19  *  Free Software Foundation) version 2, dated June 1991.
20  *
21  *  This program is distributed in the hope that it will be useful, but
22  *  WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
23  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the terms and
24  *  conditions of the GNU General Public License for more details.
25  *
26  *  You should have received a copy of the GNU General Public License along
27  *  with this program; if not, write to the Free Software Foundation, Inc.,
28  *  51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
29 \*****************************************************************************/
30
31 #include "common.h"
32 #include "layout_file.h"
33 #include "layout.h"
34 #include "cmos_lowlevel.h"
35 #include "reg_expr.h"
36
37 static void process_layout_file(FILE * f);
38 static void skip_past_start(FILE * f);
39 static int process_entry(FILE * f, int skip_add);
40 static int process_enum(FILE * f, int skip_add);
41 static void process_checksum_info(FILE * f);
42 static void skip_remaining_lines(FILE * f);
43 static void create_entry(cmos_entry_t * cmos_entry,
44                          const char start_bit_str[], const char length_str[],
45                          const char config_str[], const char config_id_str[],
46                          const char name_str[]);
47 static void try_add_layout_file_entry(const cmos_entry_t * cmos_entry);
48 static void create_enum(cmos_enum_t * cmos_enum, const char id_str[],
49                         const char value_str[], const char text_str[]);
50 static void try_add_cmos_enum(const cmos_enum_t * cmos_enum);
51 static void set_checksum_info(const char start_str[], const char end_str[],
52                               const char index_str[]);
53 static char cmos_entry_char_value(cmos_entry_config_t config);
54 static int get_layout_file_line(FILE * f, char line[], int line_buf_size);
55 static unsigned string_to_unsigned(const char str[], const char str_name[]);
56 static unsigned long string_to_unsigned_long(const char str[],
57                                              const char str_name[]);
58 static unsigned long do_string_to_unsigned_long(const char str[],
59                                                 const char str_name[],
60                                                 const char blurb[]);
61
62 /* matches either a blank line or a comment line */
63 static const char blank_or_comment_regex[] =
64     /* a blank line */
65     "(^[[:space:]]+$)" "|"      /* or ... */
66     /* a line consisting of: optional whitespace followed by */
67     "(^[[:space:]]*"
68     /* a '#' character and optionally, additional characters */
69     "#.*$)";
70
71 static regex_t blank_or_comment_expr;
72
73 /* matches the line in a CMOS layout file indicating the start of the
74  * "entries" section.
75  */
76 static const char start_entries_regex[] =
77     /* optional whitespace */
78     "^[[:space:]]*"
79     /* followed by "entries" */
80     "entries"
81     /* followed by optional whitespace */
82     "[[:space:]]*$";
83
84 static regex_t start_entries_expr;
85
86 /* matches the line in a CMOS layout file indicating the start of the
87  * "enumerations" section
88  */
89 static const char start_enums_regex[] =
90     /* optional whitespace */
91     "^[[:space:]]*"
92     /* followed by "enumerations" */
93     "enumerations"
94     /* followed by optional whitespace */
95     "[[:space:]]*$";
96
97 static regex_t start_enums_expr;
98
99 /* matches the line in a CMOS layout file indicating the start of the
100  * "checksums" section
101  */
102 static const char start_checksums_regex[] =
103     /* optional whitespace */
104     "^[[:space:]]*"
105     /* followed by "checksums" */
106     "checksums"
107     /* followed by optional whitespace */
108     "[[:space:]]*$";
109
110 static regex_t start_checksums_expr;
111
112 /* matches a line in a CMOS layout file specifying a CMOS entry */
113 static const char entries_line_regex[] =
114     /* optional whitespace */
115     "^[[:space:]]*"
116     /* followed by a chunk of nonwhitespace for start-bit field */
117     "([^[:space:]]+)"
118     /* followed by one or more whitespace characters */
119     "[[:space:]]+"
120     /* followed by a chunk of nonwhitespace for length field */
121     "([^[:space:]]+)"
122     /* followed by one or more whitespace characters */
123     "[[:space:]]+"
124     /* followed by a chunk of nonwhitespace for config field */
125     "([^[:space:]]+)"
126     /* followed by one or more whitespace characters */
127     "[[:space:]]+"
128     /* followed by a chunk of nonwhitespace for config-ID field */
129     "([^[:space:]]+)"
130     /* followed by one or more whitespace characters */
131     "[[:space:]]+"
132     /* followed by a chunk of nonwhitespace for name field */
133     "([^[:space:]]+)"
134     /* followed by optional whitespace */
135     "[[:space:]]*$";
136
137 static regex_t entries_line_expr;
138
139 /* matches a line in a CMOS layout file specifying a CMOS enumeration */
140 static const char enums_line_regex[] =
141     /* optional whitespace */
142     "^[[:space:]]*"
143     /* followed by a chunk of nonwhitespace for ID field */
144     "([^[:space:]]+)"
145     /* followed by one or more whitespace characters */
146     "[[:space:]]+"
147     /* followed by a chunk of nonwhitespace for value field */
148     "([^[:space:]]+)"
149     /* followed by one or more whitespace characters */
150     "[[:space:]]+"
151     /* followed by a chunk of nonwhitespace for text field */
152     "([^[:space:]]+)"
153     /* followed by optional whitespace */
154     "[[:space:]]*$";
155
156 static regex_t enums_line_expr;
157
158 /* matches the line in a CMOS layout file specifying CMOS checksum
159  * information
160  */
161 static const char checksum_line_regex[] =
162     /* optional whitespace */
163     "^[[:space:]]*"
164     /* followed by "checksum" */
165     "checksum"
166     /* followed by one or more whitespace characters */
167     "[[:space:]]+"
168     /* followed by a chunk of nonwhitespace for first bit of summed area */
169     "([^[:space:]]+)"
170     /* followed by one or more whitespace characters */
171     "[[:space:]]+"
172     /* followed by a chunk of nonwhitespace for last bit of summed area */
173     "([^[:space:]]+)"
174     /* followed by one or more whitespace characters */
175     "[[:space:]]+"
176     /* followed by a chunk of nonwhitespace for checksum location bit */
177     "([^[:space:]]+)"
178     /* followed by optional whitespace */
179     "[[:space:]]*$";
180
181 static regex_t checksum_line_expr;
182
183 static const int LINE_BUF_SIZE = 256;
184
185 static int line_num;
186
187 static const char *layout_filename = NULL;
188
189 /****************************************************************************
190  * set_layout_filename
191  *
192  * Set the name of the file we will obtain CMOS layout information from.
193  ****************************************************************************/
194 void set_layout_filename(const char filename[])
195 {
196         layout_filename = filename;
197 }
198
199 /****************************************************************************
200  * get_layout_from_file
201  *
202  * Read CMOS layout information from the user-specified CMOS layout file.
203  ****************************************************************************/
204 void get_layout_from_file(void)
205 {
206         FILE *f;
207
208         assert(layout_filename != NULL);
209
210         if ((f = fopen(layout_filename, "r")) == NULL) {
211                 fprintf(stderr,
212                         "%s: Can not open CMOS layout file %s for reading: "
213                         "%s\n", prog_name, layout_filename, strerror(errno));
214                 exit(1);
215         }
216
217         process_layout_file(f);
218         fclose(f);
219 }
220
221 /****************************************************************************
222  * write_cmos_layout
223  *
224  * Write CMOS layout information to file 'f'.  The output is written in the
225  * format that CMOS layout files adhere to.
226  ****************************************************************************/
227 void write_cmos_layout(FILE * f)
228 {
229         const cmos_entry_t *cmos_entry;
230         const cmos_enum_t *cmos_enum;
231         cmos_checksum_layout_t layout;
232
233         fprintf(f, "entries\n");
234
235         for (cmos_entry = first_cmos_entry();
236              cmos_entry != NULL; cmos_entry = next_cmos_entry(cmos_entry))
237                 fprintf(f, "%u %u %c %u %s\n", cmos_entry->bit,
238                         cmos_entry->length,
239                         cmos_entry_char_value(cmos_entry->config),
240                         cmos_entry->config_id, cmos_entry->name);
241
242         fprintf(f, "\nenumerations\n");
243
244         for (cmos_enum = first_cmos_enum();
245              cmos_enum != NULL; cmos_enum = next_cmos_enum(cmos_enum))
246                 fprintf(f, "%u %llu %s\n", cmos_enum->config_id,
247                         cmos_enum->value, cmos_enum->text);
248
249         layout.summed_area_start = cmos_checksum_start;
250         layout.summed_area_end = cmos_checksum_end;
251         layout.checksum_at = cmos_checksum_index;
252         checksum_layout_to_bits(&layout);
253         fprintf(f, "\nchecksums\nchecksum %u %u %u\n", layout.summed_area_start,
254                 layout.summed_area_end, layout.checksum_at);
255 }
256
257 /****************************************************************************
258  * process_layout_file
259  *
260  * Read CMOS layout information from file 'f' and add it to our internal
261  * repository.
262  ****************************************************************************/
263 static void process_layout_file(FILE * f)
264 {
265         compile_reg_exprs(REG_EXTENDED | REG_NEWLINE, 7,
266                           blank_or_comment_regex, &blank_or_comment_expr,
267                           start_entries_regex, &start_entries_expr,
268                           entries_line_regex, &entries_line_expr,
269                           start_enums_regex, &start_enums_expr,
270                           enums_line_regex, &enums_line_expr,
271                           start_checksums_regex, &start_checksums_expr,
272                           checksum_line_regex, &checksum_line_expr);
273         line_num = 1;
274         skip_past_start(f);
275
276         /* Skip past all entries.  We will process these later when we
277          * make a second pass through the file.
278          */
279         while (!process_entry(f, 1)) ;
280
281         /* Process all enums, adding them to our internal repository as
282          * we go. */
283
284         if (process_enum(f, 0)) {
285                 fprintf(stderr, "%s: Error: CMOS layout file contains no "
286                         "enumerations.\n", prog_name);
287                 exit(1);
288         }
289
290         while (!process_enum(f, 0)) ;
291
292         /* Go back to start of file. */
293         line_num = 1;
294         fseek(f, 0, SEEK_SET);
295
296         skip_past_start(f);
297
298         /* Process all entries, adding them to the repository as we go.
299          * We must add the entries after the enums, even though they
300          * appear in the layout file before the enums.  This is because
301          * the entries are sanity checked against the enums as they are
302          * added.
303          */
304
305         if (process_entry(f, 0)) {
306                 fprintf(stderr,
307                         "%s: Error: CMOS layout file contains no entries.\n",
308                         prog_name);
309                 exit(1);
310         }
311
312         while (!process_entry(f, 0)) ;
313
314         /* Skip past all enums.  They have already been processed. */
315         while (!process_enum(f, 1)) ;
316
317         /* Process CMOS checksum info. */
318         process_checksum_info(f);
319
320         /* See if there are any lines left to process.  If so, verify
321          * that they are all either blank lines or comments.
322          */
323         skip_remaining_lines(f);
324
325         free_reg_exprs(7, &blank_or_comment_expr, &start_entries_expr,
326                        &entries_line_expr, &start_enums_expr,
327                        &enums_line_expr, &start_checksums_expr,
328                        &checksum_line_expr);
329 }
330
331 /****************************************************************************
332  * skip_past_start
333  *
334  * Skip past the line that marks the start of the "entries" section.
335  ****************************************************************************/
336 static void skip_past_start(FILE * f)
337 {
338         char line[LINE_BUF_SIZE];
339
340         for (;; line_num++) {
341                 if (get_layout_file_line(f, line, LINE_BUF_SIZE)) {
342                         fprintf(stderr,
343                                 "%s: \"entries\" line not found in CMOS layout file.\n",
344                                 prog_name);
345                         exit(1);
346                 }
347
348                 if (!regexec(&blank_or_comment_expr, line, 0, NULL, 0))
349                         continue;
350
351                 if (!regexec(&start_entries_expr, line, 0, NULL, 0))
352                         break;
353
354                 fprintf(stderr,
355                         "%s: Syntax error on line %d of CMOS layout file.  "
356                         "\"entries\" line expected.\n", prog_name, line_num);
357                 exit(1);
358         }
359
360         line_num++;
361 }
362
363 /****************************************************************************
364  * process_entry
365  *
366  * Get an entry from "entries" section of file and add it to our repository
367  * of layout information.  Return 0 if an entry was found and processed.
368  * Return 1 if there are no more entries.
369  ****************************************************************************/
370 static int process_entry(FILE * f, int skip_add)
371 {
372         static const size_t N_MATCHES = 6;
373         char line[LINE_BUF_SIZE];
374         regmatch_t match[N_MATCHES];
375         cmos_entry_t cmos_entry;
376         int result;
377
378         result = 1;
379
380         for (;; line_num++) {
381                 if (get_layout_file_line(f, line, LINE_BUF_SIZE)) {
382                         fprintf(stderr,
383                                 "%s: Unexpected end of CMOS layout file reached while "
384                                 "reading \"entries\" section.\n", prog_name);
385                         exit(1);
386                 }
387
388                 if (!regexec(&blank_or_comment_expr, line, 0, NULL, 0))
389                         continue;
390
391                 if (regexec(&entries_line_expr, line, N_MATCHES, match, 0)) {
392                         if (regexec(&start_enums_expr, line, 0, NULL, 0)) {
393                                 fprintf(stderr,
394                                         "%s: Syntax error on line %d of CMOS layout "
395                                         "file.\n", prog_name, line_num);
396                                 exit(1);
397                         }
398
399                         break;  /* start of enumerations reached: no more entries */
400                 }
401
402                 result = 0;     /* next layout entry found */
403
404                 if (skip_add)
405                         break;
406
407                 line[match[1].rm_eo] = '\0';
408                 line[match[2].rm_eo] = '\0';
409                 line[match[3].rm_eo] = '\0';
410                 line[match[4].rm_eo] = '\0';
411                 line[match[5].rm_eo] = '\0';
412                 create_entry(&cmos_entry, &line[match[1].rm_so],
413                              &line[match[2].rm_so], &line[match[3].rm_so],
414                              &line[match[4].rm_so], &line[match[5].rm_so]);
415                 try_add_layout_file_entry(&cmos_entry);
416                 break;
417         }
418
419         line_num++;
420         return result;
421 }
422
423 /****************************************************************************
424  * process_enum
425  *
426  * Get an enuneration from "enumerations" section of file and add it to our
427  * repository of layout information.  Return 0 if an enumeration was found
428  * and processed.  Return 1 if there are no more enumerations.
429  ****************************************************************************/
430 static int process_enum(FILE * f, int skip_add)
431 {
432         static const size_t N_MATCHES = 4;
433         char line[LINE_BUF_SIZE];
434         regmatch_t match[N_MATCHES];
435         cmos_enum_t cmos_enum;
436         int result;
437
438         result = 1;
439
440         for (;; line_num++) {
441                 if (get_layout_file_line(f, line, LINE_BUF_SIZE)) {
442                         fprintf(stderr,
443                                 "%s: Unexpected end of CMOS layout file reached while "
444                                 "reading \"enumerations\" section.\n",
445                                 prog_name);
446                         exit(1);
447                 }
448
449                 if (!regexec(&blank_or_comment_expr, line, 0, NULL, 0))
450                         continue;
451
452                 if (regexec(&enums_line_expr, line, N_MATCHES, match, 0)) {
453                         if (regexec(&start_checksums_expr, line, 0, NULL, 0)) {
454                                 fprintf(stderr,
455                                         "%s: Syntax error on line %d of CMOS layout "
456                                         "file.\n", prog_name, line_num);
457                                 exit(1);
458                         }
459
460                         break;  /* start of checksums reached: no more enumerations */
461                 }
462
463                 result = 0;     /* next layout enumeration found */
464
465                 if (skip_add)
466                         break;
467
468                 line[match[1].rm_eo] = '\0';
469                 line[match[2].rm_eo] = '\0';
470                 line[match[3].rm_eo] = '\0';
471                 create_enum(&cmos_enum, &line[match[1].rm_so],
472                             &line[match[2].rm_so], &line[match[3].rm_so]);
473                 try_add_cmos_enum(&cmos_enum);
474                 break;
475         }
476
477         line_num++;
478         return result;
479 }
480
481 /****************************************************************************
482  * process_checksum_info
483  *
484  * Get line conatining CMOS checksum information.
485  ****************************************************************************/
486 static void process_checksum_info(FILE * f)
487 {
488         static const size_t N_MATCHES = 4;
489         char line[LINE_BUF_SIZE];
490         regmatch_t match[N_MATCHES];
491
492         for (;; line_num++) {
493                 if (get_layout_file_line(f, line, LINE_BUF_SIZE)) {
494                         fprintf(stderr,
495                                 "%s: Unexpected end of CMOS layout file reached while "
496                                 "reading \"checksums\" section.\n", prog_name);
497                         exit(1);
498                 }
499
500                 if (!regexec(&blank_or_comment_expr, line, 0, NULL, 0))
501                         continue;
502
503                 if (regexec(&checksum_line_expr, line, N_MATCHES, match, 0)) {
504                         fprintf(stderr,
505                                 "%s: Syntax error on line %d of CMOS layout "
506                                 "file.  \"checksum\" line expected.\n",
507                                 prog_name, line_num);
508                         exit(1);
509                 }
510
511                 /* checksum line found */
512                 line[match[1].rm_eo] = '\0';
513                 line[match[2].rm_eo] = '\0';
514                 line[match[3].rm_eo] = '\0';
515                 set_checksum_info(&line[match[1].rm_so], &line[match[2].rm_so],
516                                   &line[match[3].rm_so]);
517                 break;
518         }
519 }
520
521 /****************************************************************************
522  * skip_remaining_lines
523  *
524  * Get any remaining lines of unprocessed input.  Complain if we find a line
525  * that contains anything other than comments and whitespace.
526  ****************************************************************************/
527 static void skip_remaining_lines(FILE * f)
528 {
529         char line[LINE_BUF_SIZE];
530
531         for (line_num++;
532              get_layout_file_line(f, line, LINE_BUF_SIZE) == OK; line_num++) {
533                 if (regexec(&blank_or_comment_expr, line, 0, NULL, 0)) {
534                         fprintf(stderr,
535                                 "%s: Syntax error on line %d of CMOS layout file: "
536                                 "Only comments and/or whitespace allowed after "
537                                 "\"checksum\" line.\n", prog_name, line_num);
538                         exit(1);
539                 }
540         }
541 }
542
543 /****************************************************************************
544  * create_entry
545  *
546  * Create a CMOS entry structure representing the given information.  Perform
547  * sanity checking on input parameters.
548  ****************************************************************************/
549 static void create_entry(cmos_entry_t * cmos_entry,
550                          const char start_bit_str[], const char length_str[],
551                          const char config_str[], const char config_id_str[],
552                          const char name_str[])
553 {
554         cmos_entry->bit = string_to_unsigned(start_bit_str, "start-bit");
555         cmos_entry->length = string_to_unsigned(length_str, "length");
556
557         if (config_str[1] != '\0')
558                 goto bad_config_str;
559
560         switch (config_str[0]) {
561         case 'e':
562                 cmos_entry->config = CMOS_ENTRY_ENUM;
563                 break;
564
565         case 'h':
566                 cmos_entry->config = CMOS_ENTRY_HEX;
567                 break;
568
569         case 's':
570                 cmos_entry->config = CMOS_ENTRY_STRING;
571                 break;
572
573         case 'r':
574                 cmos_entry->config = CMOS_ENTRY_RESERVED;
575                 break;
576
577         default:
578                 goto bad_config_str;
579         }
580
581         cmos_entry->config_id = string_to_unsigned(config_id_str, "config-ID");
582
583         if (strlen(name_str) >= CMOS_MAX_NAME_LENGTH) {
584                 fprintf(stderr,
585                         "%s: Error on line %d of CMOS layout file: name too "
586                         "long (max length is %d).\n", prog_name, line_num,
587                         CMOS_MAX_NAME_LENGTH - 1);
588                 exit(1);
589         }
590
591         strcpy(cmos_entry->name, name_str);
592         return;
593
594       bad_config_str:
595         fprintf(stderr,
596                 "%s: Error on line %d of CMOS layout file: 'e', 'h', or "
597                 "'r' expected for config value.\n", prog_name, line_num);
598         exit(1);
599 }
600
601 /****************************************************************************
602  * try_add_layout_file_entry
603  *
604  * Attempt to add the given CMOS entry to our internal repository.  Exit with
605  * an error message on failure.
606  ****************************************************************************/
607 static void try_add_layout_file_entry(const cmos_entry_t * cmos_entry)
608 {
609         const cmos_entry_t *conflict;
610
611         switch (add_cmos_entry(cmos_entry, &conflict)) {
612         case OK:
613                 return;
614
615         case CMOS_AREA_OUT_OF_RANGE:
616                 fprintf(stderr,
617                         "%s: Error on line %d of CMOS layout file.  Area "
618                         "covered by entry %s is out of range.\n", prog_name,
619                         line_num, cmos_entry->name);
620                 break;
621
622         case CMOS_AREA_TOO_WIDE:
623                 fprintf(stderr,
624                         "%s: Error on line %d of CMOS layout file.  Area "
625                         "covered by entry %s is too wide.\n", prog_name,
626                         line_num, cmos_entry->name);
627                 break;
628
629         case LAYOUT_ENTRY_OVERLAP:
630                 fprintf(stderr,
631                         "%s: Error on line %d of CMOS layout file.  Layouts "
632                         "overlap for entries %s and %s.\n", prog_name, line_num,
633                         cmos_entry->name, conflict->name);
634                 break;
635
636         case LAYOUT_ENTRY_BAD_LENGTH:
637                 /* Silently ignore entries with zero length.  Although this should
638                  * never happen in practice, we should handle the case in a
639                  * reasonable manner just to be safe.
640                  */
641                 return;
642
643         default:
644                 BUG();
645         }
646
647         exit(1);
648 }
649
650 /****************************************************************************
651  * create_enum
652  *
653  * Create a CMOS enumeration structure representing the given information.
654  * Perform sanity checking on input parameters.
655  ****************************************************************************/
656 static void create_enum(cmos_enum_t * cmos_enum, const char id_str[],
657                         const char value_str[], const char text_str[])
658 {
659         cmos_enum->config_id = string_to_unsigned(id_str, "ID");
660         cmos_enum->value = string_to_unsigned_long(value_str, "value");
661
662         if (strlen(text_str) >= CMOS_MAX_TEXT_LENGTH) {
663                 fprintf(stderr,
664                         "%s: Error on line %d of CMOS layout file: text too "
665                         "long (max length is %d).\n", prog_name, line_num,
666                         CMOS_MAX_TEXT_LENGTH - 1);
667                 exit(1);
668         }
669
670         strcpy(cmos_enum->text, text_str);
671 }
672
673 /****************************************************************************
674  * try_add_cmos_enum
675  *
676  * Attempt to add the given CMOS enum to our internal repository.  Exit with
677  * an error message on failure.
678  ****************************************************************************/
679 static void try_add_cmos_enum(const cmos_enum_t * cmos_enum)
680 {
681         switch (add_cmos_enum(cmos_enum)) {
682         case OK:
683                 return;
684
685         case LAYOUT_DUPLICATE_ENUM:
686                 fprintf(stderr, "%s: Error on line %d of CMOS layout file: "
687                         "Enumeration found with duplicate ID/value combination.\n",
688                         prog_name, line_num);
689                 break;
690
691         default:
692                 BUG();
693         }
694
695         exit(1);
696 }
697
698 /****************************************************************************
699  * set_checksum_info
700  *
701  * Set CMOS checksum information according to input parameters and perform
702  * sanity checking on input parameters.
703  ****************************************************************************/
704 static void set_checksum_info(const char start_str[], const char end_str[],
705                               const char index_str[])
706 {
707         cmos_checksum_layout_t layout;
708
709         /* These are bit positions that we want to convert to byte positions. */
710         layout.summed_area_start =
711             string_to_unsigned(start_str, "CMOS checksummed area start");
712         layout.summed_area_end =
713             string_to_unsigned(end_str, "CMOS checksummed area end");
714         layout.checksum_at =
715             string_to_unsigned(index_str, "CMOS checksum location");
716
717         switch (checksum_layout_to_bytes(&layout)) {
718         case OK:
719                 break;
720
721         case LAYOUT_SUMMED_AREA_START_NOT_ALIGNED:
722                 fprintf(stderr,
723                         "%s: Error on line %d of CMOS layout file.  CMOS "
724                         "checksummed area start is not byte-aligned.\n",
725                         prog_name, line_num);
726                 goto fail;
727
728         case LAYOUT_SUMMED_AREA_END_NOT_ALIGNED:
729                 fprintf(stderr,
730                         "%s: Error on line %d of CMOS layout file.  CMOS "
731                         "checksummed area end is not byte-aligned.\n",
732                         prog_name, line_num);
733                 goto fail;
734
735         case LAYOUT_CHECKSUM_LOCATION_NOT_ALIGNED:
736                 fprintf(stderr,
737                         "%s: Error on line %d of CMOS layout file.  CMOS "
738                         "checksum location is not byte-aligned.\n", prog_name,
739                         line_num);
740                 goto fail;
741
742         case LAYOUT_INVALID_SUMMED_AREA:
743                 fprintf(stderr,
744                         "%s: Error on line %d of CMOS layout file.  CMOS "
745                         "checksummed area end must be greater than CMOS checksummed "
746                         "area start.\n", prog_name, line_num);
747                 goto fail;
748
749         case LAYOUT_CHECKSUM_OVERLAPS_SUMMED_AREA:
750                 fprintf(stderr,
751                         "%s: Error on line %d of CMOS layout file.  CMOS "
752                         "checksum overlaps checksummed area.\n", prog_name,
753                         line_num);
754                 goto fail;
755
756         case LAYOUT_SUMMED_AREA_OUT_OF_RANGE:
757                 fprintf(stderr,
758                         "%s: Error on line %d of CMOS layout file.  CMOS "
759                         "checksummed area out of range.\n", prog_name,
760                         line_num);
761                 goto fail;
762
763         case LAYOUT_CHECKSUM_LOCATION_OUT_OF_RANGE:
764                 fprintf(stderr,
765                         "%s: Error on line %d of CMOS layout file.  CMOS "
766                         "checksum location out of range.\n", prog_name,
767                         line_num);
768                 goto fail;
769
770         default:
771                 BUG();
772         }
773
774         cmos_checksum_start = layout.summed_area_start;
775         cmos_checksum_end = layout.summed_area_end;
776         cmos_checksum_index = layout.checksum_at;
777         return;
778
779       fail:
780         exit(1);
781 }
782
783 /****************************************************************************
784  * cmos_entry_char_value
785  *
786  * Return the character representation of 'config'.
787  ****************************************************************************/
788 static char cmos_entry_char_value(cmos_entry_config_t config)
789 {
790         switch (config) {
791         case CMOS_ENTRY_ENUM:
792                 return 'e';
793
794         case CMOS_ENTRY_HEX:
795                 return 'h';
796
797         case CMOS_ENTRY_RESERVED:
798                 return 'r';
799
800         case CMOS_ENTRY_STRING:
801                 return 's';
802
803         default:
804                 BUG();
805         }
806
807         return 0;               /* not reached */
808 }
809
810 /****************************************************************************
811  * get_layout_file_line
812  *
813  * Get a line of input from file 'f'.  Store result in 'line' which is an
814  * array of 'line_buf_size' bytes.  Return OK on success or an error code on
815  * failure.
816  ****************************************************************************/
817 static int get_layout_file_line(FILE * f, char line[], int line_buf_size)
818 {
819         switch (get_line_from_file(f, line, line_buf_size)) {
820         case OK:
821                 return OK;
822
823         case LINE_EOF:
824                 return LINE_EOF;
825
826         case LINE_TOO_LONG:
827                 fprintf(stderr,
828                         "%s: Error on line %d of CMOS layout file: Maximum "
829                         "line length exceeded.  Max is %d characters.\n",
830                         prog_name, line_num, line_buf_size - 2);
831                 break;
832         }
833
834         exit(1);
835         return 1;               /* keep compiler happy */
836 }
837
838 /****************************************************************************
839  * string_to_unsigned
840  *
841  * Convert the string 'str' to an unsigned and return the result.
842  ****************************************************************************/
843 static unsigned string_to_unsigned(const char str[], const char str_name[])
844 {
845         unsigned long n;
846         unsigned z;
847
848         n = do_string_to_unsigned_long(str, str_name, "");
849
850         if ((z = (unsigned)n) != n) {
851                 /* This could happen on an architecture in which
852                  * sizeof(unsigned) < sizeof(unsigned long).
853                  */
854                 fprintf(stderr,
855                         "%s: Error on line %d of CMOS layout file: %s value is "
856                         "out of range.\n", prog_name, line_num, str_name);
857                 exit(1);
858         }
859
860         return z;
861 }
862
863 /****************************************************************************
864  * string_to_unsigned_long
865  *
866  * Convert the string 'str' to an unsigned long and return the result.
867  ****************************************************************************/
868 static unsigned long string_to_unsigned_long(const char str[],
869                                              const char str_name[])
870 {
871         return do_string_to_unsigned_long(str, str_name, " long");
872 }
873
874 /****************************************************************************
875  * do_string_to_unsigned_long
876  *
877  * Convert the string 'str' to an unsigned long and return the result.  Exit
878  * with an appropriate error message on failure.
879  ****************************************************************************/
880 static unsigned long do_string_to_unsigned_long(const char str[],
881                                                 const char str_name[],
882                                                 const char blurb[])
883 {
884         unsigned long n;
885         char *p;
886
887         n = strtoul(str, &p, 0);
888
889         if (*p != '\0') {
890                 fprintf(stderr,
891                         "%s: Error on line %d of CMOS layout file: %s is not a "
892                         "valid unsigned%s integer.\n", prog_name, line_num,
893                         str_name, blurb);
894                 exit(1);
895         }
896
897         return n;
898 }