535554f704e0b823c09a4c3dcc50967475aed1c4
[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_expr(REG_EXTENDED | REG_NEWLINE, blank_or_comment_regex, &blank_or_comment_expr);
266         compile_reg_expr(REG_EXTENDED | REG_NEWLINE, start_entries_regex, &start_entries_expr);
267         compile_reg_expr(REG_EXTENDED | REG_NEWLINE, entries_line_regex, &entries_line_expr);
268         compile_reg_expr(REG_EXTENDED | REG_NEWLINE, start_enums_regex, &start_enums_expr);
269         compile_reg_expr(REG_EXTENDED | REG_NEWLINE, enums_line_regex, &enums_line_expr);
270         compile_reg_expr(REG_EXTENDED | REG_NEWLINE, start_checksums_regex, &start_checksums_expr);
271         compile_reg_expr(REG_EXTENDED | REG_NEWLINE, checksum_line_regex, &checksum_line_expr);
272         line_num = 1;
273         skip_past_start(f);
274
275         /* Skip past all entries.  We will process these later when we
276          * make a second pass through the file.
277          */
278         while (!process_entry(f, 1)) ;
279
280         /* Process all enums, adding them to our internal repository as
281          * we go. */
282
283         if (process_enum(f, 0)) {
284                 fprintf(stderr, "%s: Error: CMOS layout file contains no "
285                         "enumerations.\n", prog_name);
286                 exit(1);
287         }
288
289         while (!process_enum(f, 0)) ;
290
291         /* Go back to start of file. */
292         line_num = 1;
293         fseek(f, 0, SEEK_SET);
294
295         skip_past_start(f);
296
297         /* Process all entries, adding them to the repository as we go.
298          * We must add the entries after the enums, even though they
299          * appear in the layout file before the enums.  This is because
300          * the entries are sanity checked against the enums as they are
301          * added.
302          */
303
304         if (process_entry(f, 0)) {
305                 fprintf(stderr,
306                         "%s: Error: CMOS layout file contains no entries.\n",
307                         prog_name);
308                 exit(1);
309         }
310
311         while (!process_entry(f, 0)) ;
312
313         /* Skip past all enums.  They have already been processed. */
314         while (!process_enum(f, 1)) ;
315
316         /* Process CMOS checksum info. */
317         process_checksum_info(f);
318
319         /* See if there are any lines left to process.  If so, verify
320          * that they are all either blank lines or comments.
321          */
322         skip_remaining_lines(f);
323
324         regfree(&blank_or_comment_expr);
325         regfree(&start_entries_expr);
326         regfree(&entries_line_expr);
327         regfree(&start_enums_expr);
328         regfree(&enums_line_expr);
329         regfree(&start_checksums_expr);
330         regfree(&checksum_line_expr);
331 }
332
333 /****************************************************************************
334  * skip_past_start
335  *
336  * Skip past the line that marks the start of the "entries" section.
337  ****************************************************************************/
338 static void skip_past_start(FILE * f)
339 {
340         char line[LINE_BUF_SIZE];
341
342         for (;; line_num++) {
343                 if (get_layout_file_line(f, line, LINE_BUF_SIZE)) {
344                         fprintf(stderr,
345                                 "%s: \"entries\" line not found in CMOS layout file.\n",
346                                 prog_name);
347                         exit(1);
348                 }
349
350                 if (!regexec(&blank_or_comment_expr, line, 0, NULL, 0))
351                         continue;
352
353                 if (!regexec(&start_entries_expr, line, 0, NULL, 0))
354                         break;
355
356                 fprintf(stderr,
357                         "%s: Syntax error on line %d of CMOS layout file.  "
358                         "\"entries\" line expected.\n", prog_name, line_num);
359                 exit(1);
360         }
361
362         line_num++;
363 }
364
365 /****************************************************************************
366  * process_entry
367  *
368  * Get an entry from "entries" section of file and add it to our repository
369  * of layout information.  Return 0 if an entry was found and processed.
370  * Return 1 if there are no more entries.
371  ****************************************************************************/
372 static int process_entry(FILE * f, int skip_add)
373 {
374         static const size_t N_MATCHES = 6;
375         char line[LINE_BUF_SIZE];
376         regmatch_t match[N_MATCHES];
377         cmos_entry_t cmos_entry;
378         int result;
379
380         result = 1;
381
382         for (;; line_num++) {
383                 if (get_layout_file_line(f, line, LINE_BUF_SIZE)) {
384                         fprintf(stderr,
385                                 "%s: Unexpected end of CMOS layout file reached while "
386                                 "reading \"entries\" section.\n", prog_name);
387                         exit(1);
388                 }
389
390                 if (!regexec(&blank_or_comment_expr, line, 0, NULL, 0))
391                         continue;
392
393                 if (regexec(&entries_line_expr, line, N_MATCHES, match, 0)) {
394                         if (regexec(&start_enums_expr, line, 0, NULL, 0)) {
395                                 fprintf(stderr,
396                                         "%s: Syntax error on line %d of CMOS layout "
397                                         "file.\n", prog_name, line_num);
398                                 exit(1);
399                         }
400
401                         break;  /* start of enumerations reached: no more entries */
402                 }
403
404                 result = 0;     /* next layout entry found */
405
406                 if (skip_add)
407                         break;
408
409                 line[match[1].rm_eo] = '\0';
410                 line[match[2].rm_eo] = '\0';
411                 line[match[3].rm_eo] = '\0';
412                 line[match[4].rm_eo] = '\0';
413                 line[match[5].rm_eo] = '\0';
414                 create_entry(&cmos_entry, &line[match[1].rm_so],
415                              &line[match[2].rm_so], &line[match[3].rm_so],
416                              &line[match[4].rm_so], &line[match[5].rm_so]);
417                 try_add_layout_file_entry(&cmos_entry);
418                 break;
419         }
420
421         line_num++;
422         return result;
423 }
424
425 /****************************************************************************
426  * process_enum
427  *
428  * Get an enuneration from "enumerations" section of file and add it to our
429  * repository of layout information.  Return 0 if an enumeration was found
430  * and processed.  Return 1 if there are no more enumerations.
431  ****************************************************************************/
432 static int process_enum(FILE * f, int skip_add)
433 {
434         static const size_t N_MATCHES = 4;
435         char line[LINE_BUF_SIZE];
436         regmatch_t match[N_MATCHES];
437         cmos_enum_t cmos_enum;
438         int result;
439
440         result = 1;
441
442         for (;; line_num++) {
443                 if (get_layout_file_line(f, line, LINE_BUF_SIZE)) {
444                         fprintf(stderr,
445                                 "%s: Unexpected end of CMOS layout file reached while "
446                                 "reading \"enumerations\" section.\n",
447                                 prog_name);
448                         exit(1);
449                 }
450
451                 if (!regexec(&blank_or_comment_expr, line, 0, NULL, 0))
452                         continue;
453
454                 if (regexec(&enums_line_expr, line, N_MATCHES, match, 0)) {
455                         if (regexec(&start_checksums_expr, line, 0, NULL, 0)) {
456                                 fprintf(stderr,
457                                         "%s: Syntax error on line %d of CMOS layout "
458                                         "file.\n", prog_name, line_num);
459                                 exit(1);
460                         }
461
462                         break;  /* start of checksums reached: no more enumerations */
463                 }
464
465                 result = 0;     /* next layout enumeration found */
466
467                 if (skip_add)
468                         break;
469
470                 line[match[1].rm_eo] = '\0';
471                 line[match[2].rm_eo] = '\0';
472                 line[match[3].rm_eo] = '\0';
473                 create_enum(&cmos_enum, &line[match[1].rm_so],
474                             &line[match[2].rm_so], &line[match[3].rm_so]);
475                 try_add_cmos_enum(&cmos_enum);
476                 break;
477         }
478
479         line_num++;
480         return result;
481 }
482
483 /****************************************************************************
484  * process_checksum_info
485  *
486  * Get line conatining CMOS checksum information.
487  ****************************************************************************/
488 static void process_checksum_info(FILE * f)
489 {
490         static const size_t N_MATCHES = 4;
491         char line[LINE_BUF_SIZE];
492         regmatch_t match[N_MATCHES];
493
494         for (;; line_num++) {
495                 if (get_layout_file_line(f, line, LINE_BUF_SIZE)) {
496                         fprintf(stderr,
497                                 "%s: Unexpected end of CMOS layout file reached while "
498                                 "reading \"checksums\" section.\n", prog_name);
499                         exit(1);
500                 }
501
502                 if (!regexec(&blank_or_comment_expr, line, 0, NULL, 0))
503                         continue;
504
505                 if (regexec(&checksum_line_expr, line, N_MATCHES, match, 0)) {
506                         fprintf(stderr,
507                                 "%s: Syntax error on line %d of CMOS layout "
508                                 "file.  \"checksum\" line expected.\n",
509                                 prog_name, line_num);
510                         exit(1);
511                 }
512
513                 /* checksum line found */
514                 line[match[1].rm_eo] = '\0';
515                 line[match[2].rm_eo] = '\0';
516                 line[match[3].rm_eo] = '\0';
517                 set_checksum_info(&line[match[1].rm_so], &line[match[2].rm_so],
518                                   &line[match[3].rm_so]);
519                 break;
520         }
521 }
522
523 /****************************************************************************
524  * skip_remaining_lines
525  *
526  * Get any remaining lines of unprocessed input.  Complain if we find a line
527  * that contains anything other than comments and whitespace.
528  ****************************************************************************/
529 static void skip_remaining_lines(FILE * f)
530 {
531         char line[LINE_BUF_SIZE];
532
533         for (line_num++;
534              get_layout_file_line(f, line, LINE_BUF_SIZE) == OK; line_num++) {
535                 if (regexec(&blank_or_comment_expr, line, 0, NULL, 0)) {
536                         fprintf(stderr,
537                                 "%s: Syntax error on line %d of CMOS layout file: "
538                                 "Only comments and/or whitespace allowed after "
539                                 "\"checksum\" line.\n", prog_name, line_num);
540                         exit(1);
541                 }
542         }
543 }
544
545 /****************************************************************************
546  * create_entry
547  *
548  * Create a CMOS entry structure representing the given information.  Perform
549  * sanity checking on input parameters.
550  ****************************************************************************/
551 static void create_entry(cmos_entry_t * cmos_entry,
552                          const char start_bit_str[], const char length_str[],
553                          const char config_str[], const char config_id_str[],
554                          const char name_str[])
555 {
556         cmos_entry->bit = string_to_unsigned(start_bit_str, "start-bit");
557         cmos_entry->length = string_to_unsigned(length_str, "length");
558
559         if (config_str[1] != '\0')
560                 goto bad_config_str;
561
562         switch (config_str[0]) {
563         case 'e':
564                 cmos_entry->config = CMOS_ENTRY_ENUM;
565                 break;
566
567         case 'h':
568                 cmos_entry->config = CMOS_ENTRY_HEX;
569                 break;
570
571         case 's':
572                 cmos_entry->config = CMOS_ENTRY_STRING;
573                 break;
574
575         case 'r':
576                 cmos_entry->config = CMOS_ENTRY_RESERVED;
577                 break;
578
579         default:
580                 goto bad_config_str;
581         }
582
583         cmos_entry->config_id = string_to_unsigned(config_id_str, "config-ID");
584
585         if (strlen(name_str) >= CMOS_MAX_NAME_LENGTH) {
586                 fprintf(stderr,
587                         "%s: Error on line %d of CMOS layout file: name too "
588                         "long (max length is %d).\n", prog_name, line_num,
589                         CMOS_MAX_NAME_LENGTH - 1);
590                 exit(1);
591         }
592
593         strcpy(cmos_entry->name, name_str);
594         return;
595
596       bad_config_str:
597         fprintf(stderr,
598                 "%s: Error on line %d of CMOS layout file: 'e', 'h', or "
599                 "'r' expected for config value.\n", prog_name, line_num);
600         exit(1);
601 }
602
603 /****************************************************************************
604  * try_add_layout_file_entry
605  *
606  * Attempt to add the given CMOS entry to our internal repository.  Exit with
607  * an error message on failure.
608  ****************************************************************************/
609 static void try_add_layout_file_entry(const cmos_entry_t * cmos_entry)
610 {
611         const cmos_entry_t *conflict;
612
613         switch (add_cmos_entry(cmos_entry, &conflict)) {
614         case OK:
615                 return;
616
617         case CMOS_AREA_OUT_OF_RANGE:
618                 fprintf(stderr,
619                         "%s: Error on line %d of CMOS layout file.  Area "
620                         "covered by entry %s is out of range.\n", prog_name,
621                         line_num, cmos_entry->name);
622                 break;
623
624         case CMOS_AREA_TOO_WIDE:
625                 fprintf(stderr,
626                         "%s: Error on line %d of CMOS layout file.  Area "
627                         "covered by entry %s is too wide.\n", prog_name,
628                         line_num, cmos_entry->name);
629                 break;
630
631         case LAYOUT_ENTRY_OVERLAP:
632                 fprintf(stderr,
633                         "%s: Error on line %d of CMOS layout file.  Layouts "
634                         "overlap for entries %s and %s.\n", prog_name, line_num,
635                         cmos_entry->name, conflict->name);
636                 break;
637
638         case LAYOUT_ENTRY_BAD_LENGTH:
639                 /* Silently ignore entries with zero length.  Although this should
640                  * never happen in practice, we should handle the case in a
641                  * reasonable manner just to be safe.
642                  */
643                 return;
644
645         default:
646                 BUG();
647         }
648
649         exit(1);
650 }
651
652 /****************************************************************************
653  * create_enum
654  *
655  * Create a CMOS enumeration structure representing the given information.
656  * Perform sanity checking on input parameters.
657  ****************************************************************************/
658 static void create_enum(cmos_enum_t * cmos_enum, const char id_str[],
659                         const char value_str[], const char text_str[])
660 {
661         cmos_enum->config_id = string_to_unsigned(id_str, "ID");
662         cmos_enum->value = string_to_unsigned_long(value_str, "value");
663
664         if (strlen(text_str) >= CMOS_MAX_TEXT_LENGTH) {
665                 fprintf(stderr,
666                         "%s: Error on line %d of CMOS layout file: text too "
667                         "long (max length is %d).\n", prog_name, line_num,
668                         CMOS_MAX_TEXT_LENGTH - 1);
669                 exit(1);
670         }
671
672         strcpy(cmos_enum->text, text_str);
673 }
674
675 /****************************************************************************
676  * try_add_cmos_enum
677  *
678  * Attempt to add the given CMOS enum to our internal repository.  Exit with
679  * an error message on failure.
680  ****************************************************************************/
681 static void try_add_cmos_enum(const cmos_enum_t * cmos_enum)
682 {
683         switch (add_cmos_enum(cmos_enum)) {
684         case OK:
685                 return;
686
687         case LAYOUT_DUPLICATE_ENUM:
688                 fprintf(stderr, "%s: Error on line %d of CMOS layout file: "
689                         "Enumeration found with duplicate ID/value combination.\n",
690                         prog_name, line_num);
691                 break;
692
693         default:
694                 BUG();
695         }
696
697         exit(1);
698 }
699
700 /****************************************************************************
701  * set_checksum_info
702  *
703  * Set CMOS checksum information according to input parameters and perform
704  * sanity checking on input parameters.
705  ****************************************************************************/
706 static void set_checksum_info(const char start_str[], const char end_str[],
707                               const char index_str[])
708 {
709         cmos_checksum_layout_t layout;
710
711         /* These are bit positions that we want to convert to byte positions. */
712         layout.summed_area_start =
713             string_to_unsigned(start_str, "CMOS checksummed area start");
714         layout.summed_area_end =
715             string_to_unsigned(end_str, "CMOS checksummed area end");
716         layout.checksum_at =
717             string_to_unsigned(index_str, "CMOS checksum location");
718
719         switch (checksum_layout_to_bytes(&layout)) {
720         case OK:
721                 break;
722
723         case LAYOUT_SUMMED_AREA_START_NOT_ALIGNED:
724                 fprintf(stderr,
725                         "%s: Error on line %d of CMOS layout file.  CMOS "
726                         "checksummed area start is not byte-aligned.\n",
727                         prog_name, line_num);
728                 goto fail;
729
730         case LAYOUT_SUMMED_AREA_END_NOT_ALIGNED:
731                 fprintf(stderr,
732                         "%s: Error on line %d of CMOS layout file.  CMOS "
733                         "checksummed area end is not byte-aligned.\n",
734                         prog_name, line_num);
735                 goto fail;
736
737         case LAYOUT_CHECKSUM_LOCATION_NOT_ALIGNED:
738                 fprintf(stderr,
739                         "%s: Error on line %d of CMOS layout file.  CMOS "
740                         "checksum location is not byte-aligned.\n", prog_name,
741                         line_num);
742                 goto fail;
743
744         case LAYOUT_INVALID_SUMMED_AREA:
745                 fprintf(stderr,
746                         "%s: Error on line %d of CMOS layout file.  CMOS "
747                         "checksummed area end must be greater than CMOS checksummed "
748                         "area start.\n", prog_name, line_num);
749                 goto fail;
750
751         case LAYOUT_CHECKSUM_OVERLAPS_SUMMED_AREA:
752                 fprintf(stderr,
753                         "%s: Error on line %d of CMOS layout file.  CMOS "
754                         "checksum overlaps checksummed area.\n", prog_name,
755                         line_num);
756                 goto fail;
757
758         case LAYOUT_SUMMED_AREA_OUT_OF_RANGE:
759                 fprintf(stderr,
760                         "%s: Error on line %d of CMOS layout file.  CMOS "
761                         "checksummed area out of range.\n", prog_name,
762                         line_num);
763                 goto fail;
764
765         case LAYOUT_CHECKSUM_LOCATION_OUT_OF_RANGE:
766                 fprintf(stderr,
767                         "%s: Error on line %d of CMOS layout file.  CMOS "
768                         "checksum location out of range.\n", prog_name,
769                         line_num);
770                 goto fail;
771
772         default:
773                 BUG();
774         }
775
776         cmos_checksum_start = layout.summed_area_start;
777         cmos_checksum_end = layout.summed_area_end;
778         cmos_checksum_index = layout.checksum_at;
779         return;
780
781       fail:
782         exit(1);
783 }
784
785 /****************************************************************************
786  * cmos_entry_char_value
787  *
788  * Return the character representation of 'config'.
789  ****************************************************************************/
790 static char cmos_entry_char_value(cmos_entry_config_t config)
791 {
792         switch (config) {
793         case CMOS_ENTRY_ENUM:
794                 return 'e';
795
796         case CMOS_ENTRY_HEX:
797                 return 'h';
798
799         case CMOS_ENTRY_RESERVED:
800                 return 'r';
801
802         case CMOS_ENTRY_STRING:
803                 return 's';
804
805         default:
806                 BUG();
807         }
808
809         return 0;               /* not reached */
810 }
811
812 /****************************************************************************
813  * get_layout_file_line
814  *
815  * Get a line of input from file 'f'.  Store result in 'line' which is an
816  * array of 'line_buf_size' bytes.  Return OK on success or an error code on
817  * failure.
818  ****************************************************************************/
819 static int get_layout_file_line(FILE * f, char line[], int line_buf_size)
820 {
821         switch (get_line_from_file(f, line, line_buf_size)) {
822         case OK:
823                 return OK;
824
825         case LINE_EOF:
826                 return LINE_EOF;
827
828         case LINE_TOO_LONG:
829                 fprintf(stderr,
830                         "%s: Error on line %d of CMOS layout file: Maximum "
831                         "line length exceeded.  Max is %d characters.\n",
832                         prog_name, line_num, line_buf_size - 2);
833                 break;
834         }
835
836         exit(1);
837         return 1;               /* keep compiler happy */
838 }
839
840 /****************************************************************************
841  * string_to_unsigned
842  *
843  * Convert the string 'str' to an unsigned and return the result.
844  ****************************************************************************/
845 static unsigned string_to_unsigned(const char str[], const char str_name[])
846 {
847         unsigned long n;
848         unsigned z;
849
850         n = do_string_to_unsigned_long(str, str_name, "");
851
852         if ((z = (unsigned)n) != n) {
853                 /* This could happen on an architecture in which
854                  * sizeof(unsigned) < sizeof(unsigned long).
855                  */
856                 fprintf(stderr,
857                         "%s: Error on line %d of CMOS layout file: %s value is "
858                         "out of range.\n", prog_name, line_num, str_name);
859                 exit(1);
860         }
861
862         return z;
863 }
864
865 /****************************************************************************
866  * string_to_unsigned_long
867  *
868  * Convert the string 'str' to an unsigned long and return the result.
869  ****************************************************************************/
870 static unsigned long string_to_unsigned_long(const char str[],
871                                              const char str_name[])
872 {
873         return do_string_to_unsigned_long(str, str_name, " long");
874 }
875
876 /****************************************************************************
877  * do_string_to_unsigned_long
878  *
879  * Convert the string 'str' to an unsigned long and return the result.  Exit
880  * with an appropriate error message on failure.
881  ****************************************************************************/
882 static unsigned long do_string_to_unsigned_long(const char str[],
883                                                 const char str_name[],
884                                                 const char blurb[])
885 {
886         unsigned long n;
887         char *p;
888
889         n = strtoul(str, &p, 0);
890
891         if (*p != '\0') {
892                 fprintf(stderr,
893                         "%s: Error on line %d of CMOS layout file: %s is not a "
894                         "valid unsigned%s integer.\n", prog_name, line_num,
895                         str_name, blurb);
896                 exit(1);
897         }
898
899         return n;
900 }