blob: 5f7cadea97e4a6b059db1939a11a76fef5672443 [file] [log] [blame]
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001/*****************************************************************************\
Patrick Georgi49a74432011-01-28 07:50:33 +00002 * layout-text.c
Stefan Reinauer6540ae52007-07-12 16:35:42 +00003 *****************************************************************************
4 * Copyright (C) 2002-2005 The Regents of the University of California.
5 * Produced at the Lawrence Livermore National Laboratory.
6 * Written by Dave Peterson <dsp@llnl.gov> <dave_peterson@pobox.com>.
7 * UCRL-CODE-2003-012
8 * All rights reserved.
9 *
Uwe Hermann6e565942008-03-01 19:06:32 +000010 * This file is part of nvramtool, a utility for reading/writing coreboot
Stefan Reinauerf527e702008-01-18 15:33:49 +000011 * parameters and displaying information from the coreboot table.
Uwe Hermann6e565942008-03-01 19:06:32 +000012 * For details, see http://coreboot.org/nvramtool.
Stefan Reinauer6540ae52007-07-12 16:35:42 +000013 *
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.,
Stefan Reinauerac7a2d22009-09-23 21:53:25 +000028 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
Stefan Reinauer6540ae52007-07-12 16:35:42 +000029\*****************************************************************************/
30
31#include "common.h"
Patrick Georgi49a74432011-01-28 07:50:33 +000032#include "layout-text.h"
Stefan Reinauer6540ae52007-07-12 16:35:42 +000033#include "layout.h"
34#include "cmos_lowlevel.h"
35#include "reg_expr.h"
36
Stefan Reinauer90b96b62010-01-13 21:00:23 +000037static void process_layout_file(FILE * f);
38static void skip_past_start(FILE * f);
39static int process_entry(FILE * f, int skip_add);
40static int process_enum(FILE * f, int skip_add);
41static void process_checksum_info(FILE * f);
42static void skip_remaining_lines(FILE * f);
43static 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[]);
47static void try_add_layout_file_entry(const cmos_entry_t * cmos_entry);
48static void create_enum(cmos_enum_t * cmos_enum, const char id_str[],
49 const char value_str[], const char text_str[]);
50static void try_add_cmos_enum(const cmos_enum_t * cmos_enum);
51static void set_checksum_info(const char start_str[], const char end_str[],
52 const char index_str[]);
53static char cmos_entry_char_value(cmos_entry_config_t config);
54static int get_layout_file_line(FILE * f, char line[], int line_buf_size);
55static unsigned string_to_unsigned(const char str[], const char str_name[]);
56static unsigned long string_to_unsigned_long(const char str[],
57 const char str_name[]);
58static unsigned long do_string_to_unsigned_long(const char str[],
59 const char str_name[],
60 const char blurb[]);
Stefan Reinauer6540ae52007-07-12 16:35:42 +000061
62/* matches either a blank line or a comment line */
63static const char blank_or_comment_regex[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +000064 /* 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 "#.*$)";
Stefan Reinauer6540ae52007-07-12 16:35:42 +000070
71static 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 */
76static const char start_entries_regex[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +000077 /* optional whitespace */
78 "^[[:space:]]*"
79 /* followed by "entries" */
80 "entries"
81 /* followed by optional whitespace */
82 "[[:space:]]*$";
Stefan Reinauer6540ae52007-07-12 16:35:42 +000083
84static regex_t start_entries_expr;
85
86/* matches the line in a CMOS layout file indicating the start of the
87 * "enumerations" section
88 */
89static const char start_enums_regex[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +000090 /* optional whitespace */
91 "^[[:space:]]*"
92 /* followed by "enumerations" */
93 "enumerations"
94 /* followed by optional whitespace */
95 "[[:space:]]*$";
Stefan Reinauer6540ae52007-07-12 16:35:42 +000096
97static regex_t start_enums_expr;
98
99/* matches the line in a CMOS layout file indicating the start of the
100 * "checksums" section
101 */
102static const char start_checksums_regex[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000103 /* optional whitespace */
104 "^[[:space:]]*"
105 /* followed by "checksums" */
106 "checksums"
107 /* followed by optional whitespace */
108 "[[:space:]]*$";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000109
110static regex_t start_checksums_expr;
111
112/* matches a line in a CMOS layout file specifying a CMOS entry */
113static const char entries_line_regex[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000114 /* 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:]]*$";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000136
137static regex_t entries_line_expr;
138
139/* matches a line in a CMOS layout file specifying a CMOS enumeration */
140static const char enums_line_regex[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000141 /* 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:]]*$";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000155
156static regex_t enums_line_expr;
157
158/* matches the line in a CMOS layout file specifying CMOS checksum
159 * information
160 */
161static const char checksum_line_regex[] =
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000162 /* 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:]]*$";
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000180
181static regex_t checksum_line_expr;
182
183static const int LINE_BUF_SIZE = 256;
184
185static int line_num;
186
187static 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 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000194void set_layout_filename(const char filename[])
195{
196 layout_filename = filename;
197}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000198
199/****************************************************************************
200 * get_layout_from_file
201 *
202 * Read CMOS layout information from the user-specified CMOS layout file.
203 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000204void get_layout_from_file(void)
205{
206 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000207
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000208 assert(layout_filename != NULL);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000209
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000210 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000216
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000217 process_layout_file(f);
218 fclose(f);
219}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000220
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 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000227void 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000232
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000233 fprintf(f, "entries\n");
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000234
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000235 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);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000241
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000242 fprintf(f, "\nenumerations\n");
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000243
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000244 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);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000248
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000249 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}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000256
257/****************************************************************************
258 * process_layout_file
259 *
260 * Read CMOS layout information from file 'f' and add it to our internal
261 * repository.
262 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000263static void process_layout_file(FILE * f)
264{
Patrick Georgibf649852011-01-28 07:40:08 +0000265 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);
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000272 line_num = 1;
273 skip_past_start(f);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000274
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000275 /* 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)) ;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000279
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000280 /* Process all enums, adding them to our internal repository as
281 * we go. */
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000282
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000283 if (process_enum(f, 0)) {
284 fprintf(stderr, "%s: Error: CMOS layout file contains no "
285 "enumerations.\n", prog_name);
286 exit(1);
287 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000288
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000289 while (!process_enum(f, 0)) ;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000290
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000291 /* Go back to start of file. */
292 line_num = 1;
293 fseek(f, 0, SEEK_SET);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000294
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000295 skip_past_start(f);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000296
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000297 /* 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 */
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000303
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000304 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000310
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000311 while (!process_entry(f, 0)) ;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000312
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000313 /* Skip past all enums. They have already been processed. */
314 while (!process_enum(f, 1)) ;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000315
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000316 /* Process CMOS checksum info. */
317 process_checksum_info(f);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000318
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000319 /* 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);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000323
Patrick Georgibf649852011-01-28 07:40:08 +0000324 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);
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000331}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000332
333/****************************************************************************
334 * skip_past_start
335 *
336 * Skip past the line that marks the start of the "entries" section.
337 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000338static void skip_past_start(FILE * f)
339{
340 char line[LINE_BUF_SIZE];
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000341
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000342 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000349
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000350 if (!regexec(&blank_or_comment_expr, line, 0, NULL, 0))
351 continue;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000352
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000353 if (!regexec(&start_entries_expr, line, 0, NULL, 0))
354 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000355
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000356 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000361
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000362 line_num++;
363}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000364
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 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000372static 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000379
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000380 result = 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000381
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000382 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000389
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000390 if (!regexec(&blank_or_comment_expr, line, 0, NULL, 0))
391 continue;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000392
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000393 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000400
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000401 break; /* start of enumerations reached: no more entries */
402 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000403
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000404 result = 0; /* next layout entry found */
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000405
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000406 if (skip_add)
407 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000408
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000409 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000420
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000421 line_num++;
422 return result;
423}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000424
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 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000432static 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000439
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000440 result = 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000441
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000442 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000450
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000451 if (!regexec(&blank_or_comment_expr, line, 0, NULL, 0))
452 continue;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000453
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000454 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000461
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000462 break; /* start of checksums reached: no more enumerations */
463 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000464
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000465 result = 0; /* next layout enumeration found */
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000466
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000467 if (skip_add)
468 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000469
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000470 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000478
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000479 line_num++;
480 return result;
481}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000482
483/****************************************************************************
484 * process_checksum_info
485 *
486 * Get line conatining CMOS checksum information.
487 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000488static 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];
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000493
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000494 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000501
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000502 if (!regexec(&blank_or_comment_expr, line, 0, NULL, 0))
503 continue;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000504
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000505 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000512
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000513 /* 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}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000522
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 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000529static void skip_remaining_lines(FILE * f)
530{
531 char line[LINE_BUF_SIZE];
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000532
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000533 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}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000544
545/****************************************************************************
546 * create_entry
547 *
548 * Create a CMOS entry structure representing the given information. Perform
549 * sanity checking on input parameters.
550 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000551static 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");
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000558
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000559 if (config_str[1] != '\0')
560 goto bad_config_str;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000561
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000562 switch (config_str[0]) {
563 case 'e':
564 cmos_entry->config = CMOS_ENTRY_ENUM;
565 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000566
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000567 case 'h':
568 cmos_entry->config = CMOS_ENTRY_HEX;
569 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000570
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000571 case 's':
572 cmos_entry->config = CMOS_ENTRY_STRING;
573 break;
Stefan Reinauera67aab72008-09-27 10:08:28 +0000574
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000575 case 'r':
576 cmos_entry->config = CMOS_ENTRY_RESERVED;
577 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000578
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000579 default:
580 goto bad_config_str;
581 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000582
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000583 cmos_entry->config_id = string_to_unsigned(config_id_str, "config-ID");
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000584
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000585 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000592
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000593 strcpy(cmos_entry->name, name_str);
594 return;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000595
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000596 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}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000602
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 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000609static void try_add_layout_file_entry(const cmos_entry_t * cmos_entry)
610{
611 const cmos_entry_t *conflict;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000612
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000613 switch (add_cmos_entry(cmos_entry, &conflict)) {
614 case OK:
615 return;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000616
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000617 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000623
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000624 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000630
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000631 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000637
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000638 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000644
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000645 default:
646 BUG();
647 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000648
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000649 exit(1);
650}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000651
652/****************************************************************************
653 * create_enum
654 *
655 * Create a CMOS enumeration structure representing the given information.
656 * Perform sanity checking on input parameters.
657 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000658static 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");
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000663
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000664 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000671
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000672 strcpy(cmos_enum->text, text_str);
673}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000674
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 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000681static void try_add_cmos_enum(const cmos_enum_t * cmos_enum)
682{
683 switch (add_cmos_enum(cmos_enum)) {
684 case OK:
685 return;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000686
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000687 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000692
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000693 default:
694 BUG();
695 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000696
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000697 exit(1);
698}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000699
700/****************************************************************************
701 * set_checksum_info
702 *
703 * Set CMOS checksum information according to input parameters and perform
704 * sanity checking on input parameters.
705 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000706static void set_checksum_info(const char start_str[], const char end_str[],
707 const char index_str[])
708{
709 cmos_checksum_layout_t layout;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000710
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000711 /* 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");
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000718
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000719 switch (checksum_layout_to_bytes(&layout)) {
720 case OK:
721 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000722
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000723 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000729
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000730 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000736
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000737 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000743
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000744 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000750
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000751 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000757
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000758 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000764
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000765 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000771
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000772 default:
773 BUG();
774 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000775
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000776 cmos_checksum_start = layout.summed_area_start;
777 cmos_checksum_end = layout.summed_area_end;
778 cmos_checksum_index = layout.checksum_at;
779 return;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000780
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000781 fail:
782 exit(1);
783}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000784
785/****************************************************************************
786 * cmos_entry_char_value
787 *
788 * Return the character representation of 'config'.
789 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000790static char cmos_entry_char_value(cmos_entry_config_t config)
791{
792 switch (config) {
793 case CMOS_ENTRY_ENUM:
794 return 'e';
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000795
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000796 case CMOS_ENTRY_HEX:
797 return 'h';
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000798
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000799 case CMOS_ENTRY_RESERVED:
800 return 'r';
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000801
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000802 case CMOS_ENTRY_STRING:
803 return 's';
Stefan Reinauera67aab72008-09-27 10:08:28 +0000804
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000805 default:
806 BUG();
807 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000808
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000809 return 0; /* not reached */
810}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000811
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 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000819static 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000824
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000825 case LINE_EOF:
826 return LINE_EOF;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000827
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000828 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000835
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000836 exit(1);
837 return 1; /* keep compiler happy */
838}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000839
840/****************************************************************************
841 * string_to_unsigned
842 *
843 * Convert the string 'str' to an unsigned and return the result.
844 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000845static unsigned string_to_unsigned(const char str[], const char str_name[])
846{
847 unsigned long n;
848 unsigned z;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000849
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000850 n = do_string_to_unsigned_long(str, str_name, "");
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000851
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000852 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000861
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000862 return z;
863}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000864
865/****************************************************************************
866 * string_to_unsigned_long
867 *
868 * Convert the string 'str' to an unsigned long and return the result.
869 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000870static 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}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000875
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 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000882static 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000888
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000889 n = strtoul(str, &p, 0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000890
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000891 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000898
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000899 return n;
900}