38214d90c0c0e1503cf5c0fdfafd4b30e1712041
[coreboot.git] / util / nvramtool / input_file.c
1 /*****************************************************************************\
2  * input_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 David S. 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 "input_file.h"
33 #include "layout.h"
34 #include "cmos_ops.h"
35 #include "cmos_lowlevel.h"
36 #include "reg_expr.h"
37
38 static int get_input_file_line(FILE * f, char line[], int line_buf_size);
39 static unsigned long long try_prepare_cmos_write(const cmos_entry_t * e,
40                                                  const char value_str[]);
41
42 /* matches either a blank line or a comment line */
43 static const char blank_or_comment_regex[] =
44     /* a blank line */
45     "(^[[:space:]]+$)" "|"      /* or ... */
46     /* a line consisting of: optional whitespace followed by */
47     "(^[[:space:]]*"
48     /* a '#' character and optionally, additional characters */
49     "#.*$)";
50
51 /* matches an assignment line */
52 const char assignment_regex[] =
53     /* optional whitespace */
54     "^[[:space:]]*"
55     /* followed by a coreboot parameter name */
56     "([^[:space:]]+)"
57     /* followed by optional whitespace */
58     "[[:space:]]*"
59     /* followed by an '=' character */
60     "="
61     /* followed by optional whitespace */
62     "[[:space:]]*"
63     /* followed by a value that may contain embedded whitespace */
64     "([^[:space:]]+([[:space:]]+[^[:space:]]+)*)+"
65     /* followed by optional whitespace */
66     "[[:space:]]*$";
67
68 static int line_num;
69
70 /****************************************************************************
71  * process_input_file
72  *
73  * Read the contents of file 'f' and return a pointer to a list of pending
74  * write operations.  Perform sanity checking on all write operations and
75  * exit with an error message if there is a problem.
76  ****************************************************************************/
77 cmos_write_t *process_input_file(FILE * f)
78 {
79         static const int LINE_BUF_SIZE = 256;
80         static const size_t N_MATCHES = 4;
81         char line[LINE_BUF_SIZE];
82         const char *name, *value;
83         cmos_write_t *list, *item, **p;
84         regex_t blank_or_comment, assignment;
85         regmatch_t match[N_MATCHES];
86         const cmos_entry_t *e;
87
88         list = NULL;
89         p = &list;
90
91         compile_reg_exprs(REG_EXTENDED | REG_NEWLINE, 2, blank_or_comment_regex,
92                           &blank_or_comment, assignment_regex, &assignment);
93
94         /* each iteration processes one line from input file */
95         for (line_num = 1; get_input_file_line(f, line, LINE_BUF_SIZE) == OK; line_num++) {     /* skip comments and blank lines */
96                 if (!regexec(&blank_or_comment, line, 0, NULL, 0))
97                         continue;
98
99                 /* Is this a valid assignment line?  If not, then it's a syntax
100                  * error.
101                  */
102                 if (regexec(&assignment, line, N_MATCHES, match, 0)) {
103                         fprintf(stderr,
104                                 "%s: Syntax error on line %d of input file.\n",
105                                 prog_name, line_num);
106                         exit(1);
107                 }
108
109                 /* OK, we found an assignment.  Break the line into substrings
110                  * representing the lefthand and righthand sides of the assignment.
111                  */
112                 line[match[1].rm_eo] = '\0';
113                 line[match[2].rm_eo] = '\0';
114                 name = &line[match[1].rm_so];
115                 value = &line[match[2].rm_so];
116
117                 /* now look up the coreboot parameter name */
118                 if (is_checksum_name(name)
119                     || (e = find_cmos_entry(name)) == NULL) {
120                         fprintf(stderr,
121                                 "%s: Error on line %d of input file: CMOS parameter "
122                                 "%s not found.\n", prog_name, line_num, name);
123                         exit(1);
124                 }
125
126                 /* At this point, we figure out what numeric value needs to be written
127                  * to which location.  At the same time, we perform sanity checking on
128                  * the write operation.
129                  */
130
131                 if ((item = (cmos_write_t *) malloc(sizeof(*item))) == NULL)
132                         out_of_memory();
133
134                 item->bit = e->bit;
135                 item->length = e->length;
136                 item->config = e->config;
137                 item->value = try_prepare_cmos_write(e, value);
138
139                 /* Append write operation to pending write list. */
140                 item->next = NULL;
141                 *p = item;
142                 p = &item->next;
143         }
144
145         free_reg_exprs(2, &blank_or_comment, &assignment);
146         return list;
147 }
148
149 /****************************************************************************
150  * do_cmos_writes
151  *
152  * 'list' is a linked list of pending CMOS write operations that have passed
153  * all sanity checks.  Perform all write operations, destroying the list as
154  * we go.
155  ****************************************************************************/
156 void do_cmos_writes(cmos_write_t * list)
157 {
158         cmos_write_t *item;
159
160         set_iopl(3);
161
162         while (list != NULL) {
163                 cmos_entry_t e;
164                 item = list;
165                 e.bit = item->bit;
166                 e.length = item->length;
167                 e.config = item->config;
168                 list = item->next;
169                 cmos_write(&e, item->value);
170                 free(item);
171         }
172
173         cmos_checksum_write(cmos_checksum_compute());
174         set_iopl(0);
175 }
176
177 /****************************************************************************
178  * get_input_file_line
179  *
180  * Get a line of input from file 'f'.  Store result in 'line' which is an
181  * array of 'line_buf_size' bytes.  Return OK on success or an error code on
182  * error.
183  ****************************************************************************/
184 static int get_input_file_line(FILE * f, char line[], int line_buf_size)
185 {
186         switch (get_line_from_file(f, line, line_buf_size)) {
187         case OK:
188                 return OK;
189
190         case LINE_EOF:
191                 return LINE_EOF;
192
193         case LINE_TOO_LONG:
194                 fprintf(stderr,
195                         "%s: Error on line %d of input file: Maximum line "
196                         "length exceeded.  Max is %d characters.\n", prog_name,
197                         line_num, line_buf_size - 2);
198                 break;
199
200         default:
201                 BUG();
202         }
203
204         exit(1);
205         return 1;               /* keep compiler happy */
206 }
207
208 /****************************************************************************
209  * try_prepare_cmos_write
210  *
211  * Attempt to convert 'value_str' to an integer representation for storage in
212  * CMOS memory.  On success, return the converted value.  On error, exit with
213  * an error message.
214  ****************************************************************************/
215 static unsigned long long try_prepare_cmos_write(const cmos_entry_t * e,
216                                                  const char value_str[])
217 {
218         unsigned long long value;
219
220         switch (prepare_cmos_write(e, value_str, &value)) {
221         case OK:
222                 return value;
223
224         case CMOS_OP_BAD_ENUM_VALUE:
225                 fprintf(stderr,
226                         "%s: Error on line %d of input file: Bad value for "
227                         "parameter %s.", prog_name, line_num, e->name);
228                 break;
229
230         case CMOS_OP_NEGATIVE_INT:
231                 fprintf(stderr,
232                         "%s: Error on line %d of input file: This program "
233                         "does not support assignment of negative numbers to "
234                         "coreboot parameters.", prog_name, line_num);
235                 break;
236
237         case CMOS_OP_INVALID_INT:
238                 fprintf(stderr,
239                         "%s: Error on line %d of input file: %s is not a "
240                         "valid integer.", prog_name, line_num, value_str);
241                 break;
242
243         case CMOS_OP_RESERVED:
244                 fprintf(stderr,
245                         "%s: Error on line %d of input file: Can not modify "
246                         "reserved coreboot parameter %s.", prog_name, line_num,
247                         e->name);
248                 break;
249
250         case CMOS_OP_VALUE_TOO_WIDE:
251                 fprintf(stderr,
252                         "%s: Error on line %d of input file: Can not write "
253                         "value %s to CMOS parameter %s that is only %d bits wide.",
254                         prog_name, line_num, value_str, e->name, e->length);
255                 break;
256
257         case CMOS_OP_NO_MATCHING_ENUM:
258                 fprintf(stderr,
259                         "%s: coreboot parameter %s has no matching enums.",
260                         prog_name, e->name);
261                 break;
262
263         case CMOS_AREA_OUT_OF_RANGE:
264                 fprintf(stderr,
265                         "%s: The CMOS area specified by the layout info for "
266                         "coreboot parameter %s is out of range.", prog_name,
267                         e->name);
268                 break;
269
270         case CMOS_AREA_OVERLAPS_RTC:
271                 fprintf(stderr,
272                         "%s: The CMOS area specified by the layout info for "
273                         "coreboot parameter %s overlaps the realtime clock area.",
274                         prog_name, e->name);
275                 break;
276
277         case CMOS_AREA_TOO_WIDE:
278                 fprintf(stderr,
279                         "%s: The CMOS area specified by the layout info for "
280                         "coreboot parameter %s is too wide.", prog_name,
281                         e->name);
282                 break;
283
284         default:
285                 fprintf(stderr,
286                         "%s: Unknown error encountered while attempting to modify "
287                         "coreboot parameter %s.", prog_name, e->name);
288                 break;
289         }
290
291         fprintf(stderr, "  No CMOS writes performed.\n");
292         exit(1);
293         return 0;               /* keep compiler happy */
294 }