1 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include "input_file.h"
7 #include "cmos_lowlevel.h"
10 static int get_input_file_line(FILE * f
, char line
[], int line_buf_size
);
11 static unsigned long long try_prepare_cmos_write(const cmos_entry_t
* e
,
12 const char value_str
[]);
14 /* matches either a blank line or a comment line */
15 static const char blank_or_comment_regex
[] =
17 "(^[[:space:]]+$)" "|" /* or ... */
18 /* a line consisting of: optional whitespace followed by */
20 /* a '#' character and optionally, additional characters */
23 /* matches an assignment line */
24 const char assignment_regex
[] =
25 /* optional whitespace */
27 /* followed by a coreboot parameter name */
29 /* followed by optional whitespace */
31 /* followed by an '=' character */
33 /* followed by optional whitespace */
35 /* followed by a value that may contain embedded whitespace */
36 "([^[:space:]]+([[:space:]]+[^[:space:]]+)*)+"
37 /* followed by optional whitespace */
42 /****************************************************************************
45 * Read the contents of file 'f' and return a pointer to a list of pending
46 * write operations. Perform sanity checking on all write operations and
47 * exit with an error message if there is a problem.
48 ****************************************************************************/
49 cmos_write_t
*process_input_file(FILE * f
)
51 static const int LINE_BUF_SIZE
= 256;
52 static const size_t N_MATCHES
= 4;
53 char line
[LINE_BUF_SIZE
];
54 const char *name
, *value
;
55 cmos_write_t
*list
, *item
, **p
;
56 regex_t blank_or_comment
, assignment
;
57 regmatch_t match
[N_MATCHES
];
58 const cmos_entry_t
*e
;
63 compile_reg_expr(REG_EXTENDED
| REG_NEWLINE
, blank_or_comment_regex
, &blank_or_comment
);
64 compile_reg_expr(REG_EXTENDED
| REG_NEWLINE
, assignment_regex
, &assignment
);
66 /* each iteration processes one line from input file */
67 for (line_num
= 1; get_input_file_line(f
, line
, LINE_BUF_SIZE
) == OK
; line_num
++) { /* skip comments and blank lines */
68 if (!regexec(&blank_or_comment
, line
, 0, NULL
, 0))
71 /* Is this a valid assignment line? If not, then it's a syntax
74 if (regexec(&assignment
, line
, N_MATCHES
, match
, 0)) {
76 "%s: Syntax error on line %d of input file.\n",
81 /* OK, we found an assignment. Break the line into substrings
82 * representing the lefthand and righthand sides of the assignment.
84 line
[match
[1].rm_eo
] = '\0';
85 line
[match
[2].rm_eo
] = '\0';
86 name
= &line
[match
[1].rm_so
];
87 value
= &line
[match
[2].rm_so
];
89 /* now look up the coreboot parameter name */
90 if (is_checksum_name(name
)
91 || (e
= find_cmos_entry(name
)) == NULL
) {
93 "%s: Error on line %d of input file: CMOS parameter "
94 "%s not found.\n", prog_name
, line_num
, name
);
98 /* At this point, we figure out what numeric value needs to be written
99 * to which location. At the same time, we perform sanity checking on
100 * the write operation.
103 if ((item
= (cmos_write_t
*) malloc(sizeof(*item
))) == NULL
)
107 item
->length
= e
->length
;
108 item
->config
= e
->config
;
109 item
->value
= try_prepare_cmos_write(e
, value
);
111 /* Append write operation to pending write list. */
117 regfree(&blank_or_comment
);
118 regfree(&assignment
);
122 /****************************************************************************
125 * 'list' is a linked list of pending CMOS write operations that have passed
126 * all sanity checks. Perform all write operations, destroying the list as
128 ****************************************************************************/
129 void do_cmos_writes(cmos_write_t
* list
)
135 while (list
!= NULL
) {
139 e
.length
= item
->length
;
140 e
.config
= item
->config
;
142 cmos_write(&e
, item
->value
);
146 cmos_checksum_write(cmos_checksum_compute());
150 /****************************************************************************
151 * get_input_file_line
153 * Get a line of input from file 'f'. Store result in 'line' which is an
154 * array of 'line_buf_size' bytes. Return OK on success or an error code on
156 ****************************************************************************/
157 static int get_input_file_line(FILE * f
, char line
[], int line_buf_size
)
159 switch (get_line_from_file(f
, line
, line_buf_size
)) {
168 "%s: Error on line %d of input file: Maximum line "
169 "length exceeded. Max is %d characters.\n", prog_name
,
170 line_num
, line_buf_size
- 2);
178 return 1; /* keep compiler happy */
181 /****************************************************************************
182 * try_prepare_cmos_write
184 * Attempt to convert 'value_str' to an integer representation for storage in
185 * CMOS memory. On success, return the converted value. On error, exit with
187 ****************************************************************************/
188 static unsigned long long try_prepare_cmos_write(const cmos_entry_t
* e
,
189 const char value_str
[])
191 unsigned long long value
;
193 switch (prepare_cmos_write(e
, value_str
, &value
)) {
197 case CMOS_OP_BAD_ENUM_VALUE
:
199 "%s: Error on line %d of input file: Bad value for "
200 "parameter %s.", prog_name
, line_num
, e
->name
);
203 case CMOS_OP_NEGATIVE_INT
:
205 "%s: Error on line %d of input file: This program "
206 "does not support assignment of negative numbers to "
207 "coreboot parameters.", prog_name
, line_num
);
210 case CMOS_OP_INVALID_INT
:
212 "%s: Error on line %d of input file: %s is not a "
213 "valid integer.", prog_name
, line_num
, value_str
);
216 case CMOS_OP_RESERVED
:
218 "%s: Error on line %d of input file: Can not modify "
219 "reserved coreboot parameter %s.", prog_name
, line_num
,
223 case CMOS_OP_VALUE_TOO_WIDE
:
225 "%s: Error on line %d of input file: Can not write "
226 "value %s to CMOS parameter %s that is only %d bits wide.",
227 prog_name
, line_num
, value_str
, e
->name
, e
->length
);
230 case CMOS_OP_NO_MATCHING_ENUM
:
232 "%s: coreboot parameter %s has no matching enums.",
236 case CMOS_AREA_OUT_OF_RANGE
:
238 "%s: The CMOS area specified by the layout info for "
239 "coreboot parameter %s is out of range.", prog_name
,
243 case CMOS_AREA_OVERLAPS_RTC
:
245 "%s: The CMOS area specified by the layout info for "
246 "coreboot parameter %s overlaps the realtime clock area.",
250 case CMOS_AREA_TOO_WIDE
:
252 "%s: The CMOS area specified by the layout info for "
253 "coreboot parameter %s is too wide.", prog_name
,
259 "%s: Unknown error encountered while attempting to modify "
260 "coreboot parameter %s.", prog_name
, e
->name
);
264 fprintf(stderr
, " No CMOS writes performed.\n");
266 return 0; /* keep compiler happy */