Rename lxbios to nvramtool, step 3 (rename directory).
[coreboot.git] / util / nvramtool / input_file.c
1 /*****************************************************************************\
2  * input_file.c
3  * $Id$
4  *****************************************************************************
5  *  Copyright (C) 2002-2005 The Regents of the University of California.
6  *  Produced at the Lawrence Livermore National Laboratory.
7  *  Written by David S. Peterson <dsp@llnl.gov> <dave_peterson@pobox.com>.
8  *  UCRL-CODE-2003-012
9  *  All rights reserved.
10  *
11  *  This file is part of nvramtool, a utility for reading/writing coreboot
12  *  parameters and displaying information from the coreboot table.
13  *  For details, see http://coreboot.org/nvramtool.
14  *
15  *  Please also read the file DISCLAIMER which is included in this software
16  *  distribution.
17  *
18  *  This program is free software; you can redistribute it and/or modify it
19  *  under the terms of the GNU General Public License (as published by the
20  *  Free Software Foundation) version 2, dated June 1991.
21  *
22  *  This program is distributed in the hope that it will be useful, but
23  *  WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
24  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the terms and
25  *  conditions of the GNU General Public License for more details.
26  *
27  *  You should have received a copy of the GNU General Public License along
28  *  with this program; if not, write to the Free Software Foundation, Inc.,
29  *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
30 \*****************************************************************************/
31
32 #include "common.h"
33 #include "input_file.h"
34 #include "layout.h"
35 #include "cmos_ops.h"
36 #include "cmos_lowlevel.h"
37 #include "reg_expr.h"
38
39 static int get_input_file_line (FILE *f, char line[], int line_buf_size);
40 static unsigned long long try_prepare_cmos_write (const cmos_entry_t *e,
41                                                   const char value_str[]);
42
43 /* matches either a blank line or a comment line */
44 static const char blank_or_comment_regex[] =
45    /* a blank line */
46    "(^[[:space:]]+$)"
47
48    "|"  /* or ... */
49
50    /* a line consisting of: optional whitespace followed by */
51    "(^[[:space:]]*"
52    /* a '#' character and optionally, additional characters */
53    "#.*$)";
54
55 /* matches an assignment line */
56 const char assignment_regex[] =
57    /* optional whitespace */
58    "^[[:space:]]*"
59    /* followed by a coreboot parameter name */
60    "([^[:space:]]+)"
61    /* followed by optional whitespace */
62    "[[:space:]]*"
63    /* followed by an '=' character */
64    "="
65    /* followed by optional whitespace */
66    "[[:space:]]*"
67    /* followed by a value that may contain embedded whitespace */
68    "([^[:space:]]+([[:space:]]+[^[:space:]]+)*)+"
69    /* followed by optional whitespace */
70    "[[:space:]]*$";
71
72 static int line_num;
73
74 /****************************************************************************
75  * process_input_file
76  *
77  * Read the contents of file 'f' and return a pointer to a list of pending
78  * write operations.  Perform sanity checking on all write operations and
79  * exit with an error message if there is a problem.
80  ****************************************************************************/
81 cmos_write_t * process_input_file (FILE *f)
82  {
83    static const int LINE_BUF_SIZE = 256;
84    static const size_t N_MATCHES = 4;
85    char line[LINE_BUF_SIZE];
86    const char *name, *value;
87    cmos_write_t *list, *item, **p;
88    regex_t blank_or_comment, assignment;
89    regmatch_t match[N_MATCHES];
90    const cmos_entry_t *e;
91
92    list = NULL;
93    p = &list;
94
95    compile_reg_exprs(REG_EXTENDED | REG_NEWLINE, 2, blank_or_comment_regex,
96                      &blank_or_comment, assignment_regex, &assignment);
97
98    /* each iteration processes one line from input file */
99    for (line_num = 1;
100         get_input_file_line(f, line, LINE_BUF_SIZE) == OK;
101         line_num++)
102     { /* skip comments and blank lines */
103       if (!regexec(&blank_or_comment, line, 0, NULL, 0))
104          continue;
105
106       /* Is this a valid assignment line?  If not, then it's a syntax
107        * error.
108        */
109       if (regexec(&assignment, line, N_MATCHES, match, 0))
110        { fprintf(stderr, "%s: Syntax error on line %d of input file.\n",
111                  prog_name, line_num);
112          exit(1);
113        }
114
115       /* OK, we found an assignment.  Break the line into substrings
116        * representing the lefthand and righthand sides of the assignment.
117        */
118       line[match[1].rm_eo] = '\0';
119       line[match[2].rm_eo] = '\0';
120       name = &line[match[1].rm_so];
121       value = &line[match[2].rm_so];
122
123       /* now look up the coreboot parameter name */
124       if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL)
125        { fprintf(stderr, "%s: Error on line %d of input file: CMOS parameter "
126                  "%s not found.\n", prog_name, line_num, name);
127          exit(1);
128        }
129
130       /* At this point, we figure out what numeric value needs to be written
131        * to which location.  At the same time, we perform sanity checking on
132        * the write operation.
133        */
134
135       if ((item = (cmos_write_t *) malloc(sizeof(*item))) == NULL)
136          out_of_memory();
137
138       item->bit = e->bit;
139       item->length = e->length;
140       item->value = try_prepare_cmos_write(e, value);
141
142       /* Append write operation to pending write list. */
143       item->next = NULL;
144       *p = item;
145       p = &item->next;
146     }
147
148    free_reg_exprs(2, &blank_or_comment, &assignment);
149    return list;
150  }
151
152 /****************************************************************************
153  * do_cmos_writes
154  *
155  * 'list' is a linked list of pending CMOS write operations that have passed
156  * all sanity checks.  Perform all write operations, destroying the list as
157  * we go.
158  ****************************************************************************/
159 void do_cmos_writes (cmos_write_t *list)
160  { cmos_write_t *item;
161
162    set_iopl(3);
163
164    while (list != NULL)
165     { item = list;
166       list = item->next;
167       cmos_write(item->bit, item->length, item->value);
168       free(item);
169     }
170
171    cmos_checksum_write(cmos_checksum_compute());
172    set_iopl(0);
173  }
174
175 /****************************************************************************
176  * get_input_file_line
177  *
178  * Get a line of input from file 'f'.  Store result in 'line' which is an
179  * array of 'line_buf_size' bytes.  Return OK on success or an error code on
180  * error.
181  ****************************************************************************/
182 static int get_input_file_line (FILE *f, char line[], int line_buf_size)
183  { switch (get_line_from_file(f, line, line_buf_size))
184     { case OK:
185          return OK;
186
187       case LINE_EOF:
188          return LINE_EOF;
189
190       case LINE_TOO_LONG:
191          fprintf(stderr, "%s: Error on line %d of input file: Maximum line "
192                  "length exceeded.  Max is %d characters.\n", prog_name,
193                  line_num, line_buf_size - 2);
194          break;
195
196       default:
197          BUG();
198     }
199
200    exit(1);
201    return 1;  /* keep compiler happy */
202  }
203
204 /****************************************************************************
205  * try_prepare_cmos_write
206  *
207  * Attempt to convert 'value_str' to an integer representation for storage in
208  * CMOS memory.  On success, return the converted value.  On error, exit with
209  * an error message.
210  ****************************************************************************/
211 static unsigned long long try_prepare_cmos_write (const cmos_entry_t *e,
212                                                   const char value_str[])
213  { unsigned long long value;
214
215    switch (prepare_cmos_write(e, value_str, &value))
216     { case OK:
217          return value;
218
219       case CMOS_OP_BAD_ENUM_VALUE:
220          fprintf(stderr, "%s: Error on line %d of input file: Bad value for "
221                  "parameter %s.", prog_name, line_num, e->name);
222          break;
223
224       case CMOS_OP_NEGATIVE_INT:
225          fprintf(stderr, "%s: Error on line %d of input file: This program "
226                  "does not support assignment of negative numbers to "
227                  "coreboot parameters.", prog_name, line_num);
228          break;
229
230       case CMOS_OP_INVALID_INT:
231          fprintf(stderr, "%s: Error on line %d of input file: %s is not a "
232                  "valid integer.", prog_name, line_num, value_str);
233          break;
234
235       case CMOS_OP_RESERVED:
236          fprintf(stderr, "%s: Error on line %d of input file: Can not modify "
237                  "reserved coreboot parameter %s.", prog_name, line_num,
238                  e->name);
239          break;
240
241       case CMOS_OP_VALUE_TOO_WIDE:
242          fprintf(stderr, "%s: Error on line %d of input file: Can not write "
243                  "value %s to CMOS parameter %s that is only %d bits wide.",
244                  prog_name, line_num, value_str, e->name, e->length);
245          break;
246
247       case CMOS_OP_NO_MATCHING_ENUM:
248          fprintf(stderr, "%s: coreboot parameter %s has no matching enums.",
249                  prog_name, e->name);
250          break;
251
252       case CMOS_AREA_OUT_OF_RANGE:
253          fprintf(stderr, "%s: The CMOS area specified by the layout info for "
254                  "coreboot parameter %s is out of range.", prog_name,
255                  e->name);
256          break;
257
258       case CMOS_AREA_OVERLAPS_RTC:
259          fprintf(stderr, "%s: The CMOS area specified by the layout info for "
260                  "coreboot parameter %s overlaps the realtime clock area.",
261                  prog_name, e->name);
262          break;
263
264       case CMOS_AREA_TOO_WIDE:
265          fprintf(stderr, "%s: The CMOS area specified by the layout info for "
266                  "coreboot parameter %s is too wide.",
267                  prog_name, e->name);
268          break;
269
270       default:
271          fprintf(stderr,
272                  "%s: Unknown error encountered while attempting to modify "
273                  "coreboot parameter %s.", prog_name, e->name);
274          break;
275     }
276
277    fprintf(stderr, "  No CMOS writes performed.\n");
278    exit(1);
279    return 0;  /* keep compiler happy */
280  }