blob: 89ddf31d71a45fc3685b26565ddc132ce5fd7994 [file] [log] [blame]
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001/*****************************************************************************\
Uwe Hermann6e565942008-03-01 19:06:32 +00002 * nvramtool.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"
32#include "opts.h"
33#include "lbtable.h"
34#include "layout.h"
35#include "layout_file.h"
36#include "input_file.h"
37#include "cmos_ops.h"
38#include "cmos_lowlevel.h"
39#include "reg_expr.h"
40#include "hexdump.h"
41
42typedef void (*op_fn_t) (void);
43
Stefan Reinauer90b96b62010-01-13 21:00:23 +000044static void op_show_version(void);
45static void op_show_usage(void);
46static void op_lbtable_show_info(void);
47static void op_lbtable_dump(void);
48static void op_show_param_values(void);
49static void op_cmos_show_one_param(void);
50static void op_cmos_show_all_params(void);
51static void op_cmos_set_one_param(void);
52static void op_cmos_set_params_stdin(void);
53static void op_cmos_set_params_file(void);
54static void op_cmos_checksum(void);
55static void op_show_layout(void);
56static void op_write_cmos_dump(void);
57static void op_read_cmos_dump(void);
58static void op_show_cmos_hex_dump(void);
59static void op_show_cmos_dumpfile(void);
60static int list_one_param(const char name[], int show_name);
61static int list_all_params(void);
62static void list_param_enums(const char name[]);
63static void set_one_param(const char name[], const char value[]);
64static void set_params(FILE * f);
65static void parse_assignment(char arg[], const char **name, const char **value);
66static int list_cmos_entry(const cmos_entry_t * e, int show_name);
67static uint16_t convert_checksum_value(const char value[]);
Stefan Reinauer6540ae52007-07-12 16:35:42 +000068
Stefan Reinauer90b96b62010-01-13 21:00:23 +000069static const op_fn_t op_fns[] = { op_show_version,
70 op_show_usage,
71 op_lbtable_show_info,
72 op_lbtable_dump,
73 op_show_param_values,
74 op_cmos_show_one_param,
75 op_cmos_show_all_params,
76 op_cmos_set_one_param,
77 op_cmos_set_params_stdin,
78 op_cmos_set_params_file,
79 op_cmos_checksum,
80 op_show_layout,
81 op_write_cmos_dump,
82 op_read_cmos_dump,
83 op_show_cmos_hex_dump,
84 op_show_cmos_dumpfile
85};
Stefan Reinauer6540ae52007-07-12 16:35:42 +000086
87static const hexdump_format_t cmos_dump_format =
Stefan Reinauer90b96b62010-01-13 21:00:23 +000088 { 16, 2, "", " | ", " ", " | ", '.', NULL };
Stefan Reinauer6540ae52007-07-12 16:35:42 +000089
90/****************************************************************************
91 * main
92 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +000093int main(int argc, char *argv[])
94{
95 cmos_layout_get_fn_t fn;
Stefan Reinauer6540ae52007-07-12 16:35:42 +000096
Stefan Reinauer90b96b62010-01-13 21:00:23 +000097 parse_nvramtool_args(argc, argv);
Stefan Reinauer6540ae52007-07-12 16:35:42 +000098
Stefan Reinauer90b96b62010-01-13 21:00:23 +000099 if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_LAYOUT_FILE].found) {
100 set_layout_filename(nvramtool_op_modifiers
101 [NVRAMTOOL_MOD_USE_CMOS_LAYOUT_FILE].param);
102 fn = get_layout_from_file;
103 } else
104 fn = get_layout_from_cmos_table;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000105
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000106 register_cmos_layout_get_fn(fn);
107 op_fns[nvramtool_op.op] ();
108 return 0;
109}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000110
111/****************************************************************************
112 * op_show_version
113 *
114 * -v
115 *
116 * Show version information for this program.
117 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000118static void op_show_version(void)
119{
120 printf("This is %s version %s.\n", prog_name, prog_version);
121}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000122
123/****************************************************************************
124 * op_show_usage
125 *
126 * -h
127 *
128 * Show a usage message for this program.
129 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000130static void op_show_usage(void)
131{
132 usage(stdout);
133}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000134
135/****************************************************************************
136 * op_lbtable_show_info
137 *
138 * -l [ARG]
139 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000140 * If ARG is present, show coreboot table information specified by ARG.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000141 * Else show all possible values for ARG.
142 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000143static void op_lbtable_show_info(void)
144{
145 if (nvramtool_op.param == NULL)
146 list_lbtable_choices();
147 else {
148 get_lbtable();
149 list_lbtable_item(nvramtool_op.param);
150 }
151}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000152
153/****************************************************************************
154 * op_lbtable_dump
155 *
156 * -d
157 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000158 * Do low-level dump of coreboot table.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000159 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000160static void op_lbtable_dump(void)
161{
162 get_lbtable();
163 dump_lbtable();
164}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000165
166/****************************************************************************
167 * op_show_param_values
168 *
169 * -e NAME option
170 *
171 * Show all possible values for parameter NAME.
172 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000173static void op_show_param_values(void)
174{
175 get_cmos_layout();
176 list_param_enums(nvramtool_op.param);
177}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000178
179/****************************************************************************
180 * op_cmos_show_one_param
181 *
182 * [-n] -r NAME
183 *
184 * Show parameter NAME. If -n is specified, show value only. Else show name
185 * and value.
186 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000187static void op_cmos_show_one_param(void)
188{
189 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000190
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000191 get_cmos_layout();
192 result = list_one_param(nvramtool_op.param,
193 !nvramtool_op_modifiers
194 [NVRAMTOOL_MOD_SHOW_VALUE_ONLY].found);
195 cmos_checksum_verify();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000196
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000197 if (result)
198 exit(1);
199}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000200
201/****************************************************************************
202 * op_cmos_show_all_params
203 *
204 * -a
205 *
206 * Show names and values for all parameters.
207 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000208static void op_cmos_show_all_params(void)
209{
210 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000211
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000212 get_cmos_layout();
213 result = list_all_params();
214 cmos_checksum_verify();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000215
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000216 if (result)
217 exit(1);
218}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000219
220/****************************************************************************
221 * op_cmos_set_one_param
222 *
223 * -w NAME=VALUE
224 *
225 * Set parameter NAME to VALUE.
226 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000227static void op_cmos_set_one_param(void)
228{
229 const char *name, *value;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000230
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000231 get_cmos_layout();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000232
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000233 /* Separate 'NAME=VALUE' syntax into two strings representing NAME and
234 * VALUE.
235 */
236 parse_assignment(nvramtool_op.param, &name, &value);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000237
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000238 set_one_param(name, value);
239}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000240
241/****************************************************************************
242 * op_cmos_set_params_stdin
243 *
244 * -i
245 *
246 * Set parameters according to standard input.
247 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000248static void op_cmos_set_params_stdin(void)
249{
250 get_cmos_layout();
251 set_params(stdin);
252}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000253
254/****************************************************************************
255 * op_cmos_set_params_file
256 *
257 * -p INPUT_FILE
258 *
259 * Set parameters according to INPUT_FILE.
260 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000261static void op_cmos_set_params_file(void)
262{
263 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000264
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000265 if ((f = fopen(nvramtool_op.param, "r")) == NULL) {
266 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
267 prog_name, nvramtool_op.param, strerror(errno));
268 exit(1);
269 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000270
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000271 get_cmos_layout();
272 set_params(f);
273 fclose(f);
274}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000275
276/****************************************************************************
277 * op_cmos_checksum
278 *
279 * -c [VALUE]
280 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000281 * If VALUE is present, set coreboot CMOS checksum to VALUE. Else show
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000282 * checksum value.
283 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000284static void op_cmos_checksum(void)
285{
286 uint16_t checksum;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000287
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000288 get_cmos_layout();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000289
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000290 if (nvramtool_op.param == NULL) {
291 set_iopl(3);
292 checksum = cmos_checksum_read();
293 set_iopl(0);
294 printf("0x%x\n", checksum);
295 } else {
296 checksum = convert_checksum_value(nvramtool_op.param);
297 set_iopl(3);
298 cmos_checksum_write(checksum);
299 set_iopl(0);
300 }
301}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000302
303/****************************************************************************
304 * op_show_layout
305 *
306 * -Y
307 *
308 * Write CMOS layout information to standard output.
309 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000310static void op_show_layout(void)
311{
312 get_cmos_layout();
313 write_cmos_layout(stdout);
314}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000315
316/****************************************************************************
317 * op_write_cmos_dump
318 *
319 * -b OUTPUT_FILE
320 *
321 * Write the contents of CMOS memory to a binary file.
322 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000323static void op_write_cmos_dump(void)
324{
325 unsigned char data[CMOS_SIZE];
326 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000327
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000328 if ((f = fopen(nvramtool_op.param, "w")) == NULL) {
329 fprintf(stderr, "%s: Can not open file %s for writing: %s\n",
330 prog_name, nvramtool_op.param, strerror(errno));
331 exit(1);
332 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000333
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000334 set_iopl(3);
335 cmos_read_all(data);
336 set_iopl(0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000337
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000338 if (fwrite(data, 1, CMOS_SIZE, f) != CMOS_SIZE) {
339 fprintf(stderr, "%s: Error writing CMOS data to file %s: %s\n",
340 prog_name, nvramtool_op.param, strerror(errno));
341 exit(1);
342 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000343
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000344 fclose(f);
345}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000346
347/****************************************************************************
348 * op_read_cmos_dump
349 *
350 * -B INPUT_FILE
351 *
352 * Read binary data from a file and write the data to CMOS memory.
353 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000354static void op_read_cmos_dump(void)
355{
356 unsigned char data[CMOS_SIZE];
357 size_t nr_bytes;
358 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000359
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000360 if ((f = fopen(nvramtool_op.param, "r")) == NULL) {
361 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
362 prog_name, nvramtool_op.param, strerror(errno));
363 exit(1);
364 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000365
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000366 if ((nr_bytes = fread(data, 1, CMOS_SIZE, f)) != CMOS_SIZE) {
367 fprintf(stderr,
368 "%s: Error: Only able to read %d bytes of CMOS data "
369 "from file %s. CMOS data is unchanged.\n", prog_name,
370 (int)nr_bytes, nvramtool_op.param);
371 exit(1);
372 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000373
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000374 fclose(f);
375 set_iopl(3);
376 cmos_write_all(data);
377 set_iopl(0);
378}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000379
380/****************************************************************************
381 * op_show_cmos_hex_dump
382 *
383 * -x
384 *
385 * Write a hex dump of CMOS memory to standard output.
386 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000387static void op_show_cmos_hex_dump(void)
388{
389 unsigned char data[CMOS_SIZE];
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000390
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000391 set_iopl(3);
392 cmos_read_all(data);
393 set_iopl(0);
394 hexdump(data, CMOS_SIZE, 0, stdout, &cmos_dump_format);
395}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000396
397/****************************************************************************
398 * op_show_cmos_dumpfile
399 *
400 * -X DUMP_FILE
401 *
402 * Read binary data from a file (presumably a CMOS dump file) and display a
403 * hex dump of the CMOS data from the file.
404 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000405static void op_show_cmos_dumpfile(void)
406{
407 unsigned char data[CMOS_SIZE];
408 size_t nr_bytes;
409 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000410
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000411 if ((f = fopen(nvramtool_op.param, "r")) == NULL) {
412 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
413 prog_name, nvramtool_op.param, strerror(errno));
414 exit(1);
415 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000416
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000417 nr_bytes = fread(data, 1, CMOS_SIZE, f);
418 fclose(f);
419 hexdump(data, nr_bytes, 0, stdout, &cmos_dump_format);
420}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000421
422/****************************************************************************
423 * list_one_param
424 *
425 * Attempt to list one CMOS parameter given by 'name'. 'show_name' is a
426 * boolean value indicating whether the parameter name should be displayed
427 * along with its value. Return 1 if error was encountered. Else return OK.
428 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000429static int list_one_param(const char name[], int show_name)
430{
431 const cmos_entry_t *e;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000432
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000433 if (is_checksum_name(name) || ((e = find_cmos_entry(name)) == NULL)) {
434 fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name,
435 name);
436 exit(1);
437 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000438
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000439 if (e->config == CMOS_ENTRY_RESERVED) {
440 fprintf(stderr, "%s: Parameter %s is reserved.\n", prog_name,
441 name);
442 exit(1);
443 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000444
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000445 return (list_cmos_entry(e, show_name) != 0);
446}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000447
448/****************************************************************************
449 * list_all_params
450 *
451 * Attempt to list all CMOS parameters. Return 1 if error was encountered.
452 * Else return OK.
453 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000454static int list_all_params(void)
455{
456 const cmos_entry_t *e;
457 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000458
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000459 result = OK;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000460
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000461 for (e = first_cmos_entry(); e != NULL; e = next_cmos_entry(e)) {
462 if ((e->config == CMOS_ENTRY_RESERVED)
463 || is_checksum_name(e->name))
464 continue;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000465
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000466 if (list_cmos_entry(e, TRUE))
467 result = 1;
468 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000469
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000470 return result;
471}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000472
473/****************************************************************************
474 * list_param_enums
475 *
476 * List all possible values for CMOS parameter given by 'name'.
477 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000478static void list_param_enums(const char name[])
479{
480 const cmos_entry_t *e;
481 const cmos_enum_t *p;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000482
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000483 if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL) {
484 fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name,
485 name);
486 exit(1);
487 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000488
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000489 switch (e->config) {
490 case CMOS_ENTRY_ENUM:
491 for (p = first_cmos_enum_id(e->config_id);
492 p != NULL; p = next_cmos_enum_id(p))
493 printf("%s\n", p->text);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000494
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000495 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000496
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000497 case CMOS_ENTRY_HEX:
498 printf("Parameter %s requires a %u-bit unsigned integer.\n",
499 name, e->length);
500 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000501
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000502 case CMOS_ENTRY_STRING:
503 printf("Parameter %s requires a %u-byte string.\n", name,
504 e->length / 8);
505 break;
Stefan Reinauera67aab72008-09-27 10:08:28 +0000506
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000507 case CMOS_ENTRY_RESERVED:
508 printf("Parameter %s is reserved.\n", name);
509 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000510
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000511 default:
512 BUG();
513 }
514}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000515
516/****************************************************************************
517 * set_one_param
518 *
519 * Set the CMOS parameter given by 'name' to 'value'. The 'name' parameter
520 * is case-sensitive. If we are setting an enum parameter, then 'value' is
521 * interpreted as a case-sensitive string that must match the option name
522 * exactly. If we are setting a 'hex' parameter, then 'value' is treated as
523 * a string representation of an unsigned integer that may be specified in
524 * decimal, hex, or octal.
525 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000526static void set_one_param(const char name[], const char value[])
527{
528 const cmos_entry_t *e;
529 unsigned long long n;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000530
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000531 if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL) {
532 fprintf(stderr, "%s: CMOS parameter %s not found.", prog_name,
533 name);
534 exit(1);
535 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000536
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000537 switch (prepare_cmos_write(e, value, &n)) {
538 case OK:
539 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000540
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000541 case CMOS_OP_BAD_ENUM_VALUE:
542 fprintf(stderr, "%s: Bad value for parameter %s.", prog_name,
543 name);
544 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000545
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000546 case CMOS_OP_NEGATIVE_INT:
547 fprintf(stderr,
548 "%s: This program does not support assignment of negative "
549 "numbers to coreboot parameters.", prog_name);
550 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000551
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000552 case CMOS_OP_INVALID_INT:
553 fprintf(stderr, "%s: %s is not a valid integer.", prog_name,
554 value);
555 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000556
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000557 case CMOS_OP_RESERVED:
558 fprintf(stderr,
559 "%s: Can not modify reserved coreboot parameter %s.",
560 prog_name, name);
561 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000562
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000563 case CMOS_OP_VALUE_TOO_WIDE:
564 fprintf(stderr,
565 "%s: Can not write value %s to CMOS parameter %s that is "
566 "only %d bits wide.", prog_name, value, name,
567 e->length);
568 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000569
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000570 case CMOS_OP_NO_MATCHING_ENUM:
571 fprintf(stderr,
572 "%s: coreboot parameter %s has no matching enums.",
573 prog_name, name);
574 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000575
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000576 case CMOS_AREA_OUT_OF_RANGE:
577 fprintf(stderr,
578 "%s: The CMOS area specified by the layout info for "
579 "coreboot parameter %s is out of range.", prog_name,
580 name);
581 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000582
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000583 case CMOS_AREA_OVERLAPS_RTC:
584 fprintf(stderr,
585 "%s: The CMOS area specified by the layout info for "
586 "coreboot parameter %s overlaps the realtime clock area.",
587 prog_name, name);
588 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000589
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000590 case CMOS_AREA_TOO_WIDE:
591 fprintf(stderr,
592 "%s: The CMOS area specified by the layout info for "
593 "coreboot parameter %s is too wide.", prog_name, name);
594 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000595
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000596 default:
597 fprintf(stderr,
598 "%s: Unknown error encountered while attempting to modify "
599 "coreboot parameter %s.", prog_name, name);
600 goto fail;
601 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000602
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000603 /* write the value to nonvolatile RAM */
604 set_iopl(3);
605 cmos_write(e, n);
606 cmos_checksum_write(cmos_checksum_compute());
607 set_iopl(0);
608 return;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000609
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000610 fail:
611 fprintf(stderr, " CMOS write not performed.\n");
612 exit(1);
613}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000614
615/****************************************************************************
616 * set_params
617 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000618 * Set coreboot parameters according to the contents of file 'f'.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000619 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000620static void set_params(FILE * f)
621{ /* First process the input file. Then perform writes only if there were
622 * no problems processing the input. Either all values will be written
623 * successfully or no values will be written.
624 */
625 do_cmos_writes(process_input_file(f));
626}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000627
628/****************************************************************************
629 * parse_assignment
630 *
631 * Parse the string 'arg' (which supposedly represents an assignment) into a
632 * NAME and a VALUE. If 'arg' does not conform to the proper assignment
633 * syntax, exit with a usage message. Otherwise, on return, 'arg' is broken
634 * into substrings representing NAME and VALUE, and *name and *value are set
635 * to point to these two substrings.
636 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000637static void parse_assignment(char arg[], const char **name, const char **value)
638{
639 static const size_t N_MATCHES = 4;
640 regmatch_t match[N_MATCHES];
641 regex_t assignment;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000642
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000643 compile_reg_exprs(REG_EXTENDED | REG_NEWLINE, 1, assignment_regex,
644 &assignment);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000645
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000646 /* Does 'arg' conform to proper assignment syntax? If not, exit with a
647 * usage message.
648 */
649 if (regexec(&assignment, arg, N_MATCHES, match, 0))
650 usage(stderr);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000651
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000652 /* Ok, we found a valid assignment. Break it into two strings
653 * representing NAME and VALUE.
654 */
655 arg[match[1].rm_eo] = '\0';
656 arg[match[2].rm_eo] = '\0';
657 *name = &arg[match[1].rm_so];
658 *value = &arg[match[2].rm_so];
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000659
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000660 free_reg_exprs(1, &assignment);
661}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000662
663/****************************************************************************
664 * list_cmos_entry
665 *
666 * Attempt to list the CMOS entry represented by 'e'. 'show_name' is a
667 * boolean value indicating whether the parameter name should be displayed
668 * along with its value. On success, return OK. On error, print an error
669 * message and return 1.
670 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000671static int list_cmos_entry(const cmos_entry_t * e, int show_name)
672{
673 const cmos_enum_t *p;
674 unsigned long long value;
Stefan Reinauer42944c32010-01-16 14:57:32 +0000675 char *w;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000676
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000677 /* sanity check CMOS entry */
678 switch (prepare_cmos_read(e)) {
679 case OK:
680 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000681
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000682 case CMOS_OP_RESERVED:
683 BUG();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000684
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000685 case CMOS_AREA_OUT_OF_RANGE:
686 fprintf(stderr,
687 "%s: Can not read coreboot parameter %s because "
688 "layout info specifies out of range CMOS area.\n",
689 prog_name, e->name);
690 return 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000691
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000692 case CMOS_AREA_OVERLAPS_RTC:
693 fprintf(stderr,
694 "%s: Can not read coreboot parameter %s because "
695 "layout info specifies CMOS area that overlaps realtime "
696 "clock area.\n", prog_name, e->name);
697 return 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000698
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000699 case CMOS_AREA_TOO_WIDE:
700 fprintf(stderr,
701 "%s: Can not read coreboot parameter %s because "
702 "layout info specifies CMOS area that is too wide.\n",
703 prog_name, e->name);
704 return 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000705
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000706 default:
707 fprintf(stderr,
708 "%s: Unknown error encountered while attempting to "
709 "read coreboot parameter %s\n", prog_name, e->name);
710 return 1;
711 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000712
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000713 /* read the value from CMOS */
714 set_iopl(3);
715 value = cmos_read(e);
716 set_iopl(0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000717
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000718 /* display the value */
719 switch (e->config) {
720 case CMOS_ENTRY_ENUM:
721 if ((p = find_cmos_enum(e->config_id, value)) == NULL) {
722 if (show_name)
723 printf("# Bad value -> %s = 0x%llx\n", e->name,
724 value);
725 else
726 printf("Bad value -> 0x%llx\n", value);
727 } else {
728 if (show_name)
729 printf("%s = %s\n", e->name, p->text);
730 else
731 printf("%s\n", p->text);
732 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000733
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000734 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000735
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000736 case CMOS_ENTRY_HEX:
737 if (show_name)
738 printf("%s = 0x%llx\n", e->name, value);
739 else
740 printf("0x%llx\n", value);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000741
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000742 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000743
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000744 case CMOS_ENTRY_STRING:
Stefan Reinauer42944c32010-01-16 14:57:32 +0000745 w = (char *)(unsigned long)value;
746 while (*w) {
747 if(!isprint(*w)) {
748 if (show_name)
749 printf("# Bad value -> %s\n", e->name);
750 else
751 printf("Bad value\n");
752 break;
753 }
754 w++;
755 }
756
757 if (!*w) {
758
759 if (show_name)
760 printf("%s = %s\n", e->name,
761 (char *)(unsigned long)value);
762 else
763 printf("%s\n", (char *)(unsigned long)value);
764 }
Stefan Reinauera67aab72008-09-27 10:08:28 +0000765
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000766 free((void *)(unsigned long)value);
Stefan Reinauera67aab72008-09-27 10:08:28 +0000767
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000768 break;
Stefan Reinauera67aab72008-09-27 10:08:28 +0000769
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000770 case CMOS_ENTRY_RESERVED:
771 default:
772 BUG();
773 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000774
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000775 return OK;
776}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000777
778/****************************************************************************
779 * convert_checksum_value
780 *
781 * 'value' is the string representation of a checksum value that the user
782 * wishes to set using the -c option. Convert the string to a 16-bit
783 * unsigned integer and return the result. Exit with an error message if
784 * 'value' is invalid.
785 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000786static uint16_t convert_checksum_value(const char value[])
787{
788 unsigned long n;
789 const char *p;
790 uint16_t result;
791 int negative;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000792
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000793 for (p = value; isspace(*p); p++) ;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000794
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000795 negative = (*p == '-');
796 n = strtoul(value, (char **)&p, 0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000797
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000798 if (*p) {
799 fprintf(stderr,
800 "%s: Checksum value %s is not a valid integer.\n",
801 prog_name, value);
802 exit(1);
803 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000804
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000805 if (negative) {
806 fprintf(stderr,
807 "%s: Checksum must be an unsigned integer.\n",
808 prog_name);
809 exit(1);
810 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000811
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000812 result = (uint16_t) n;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000813
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000814 if (result != n) {
815 fprintf(stderr,
816 "%s: Checksum value must fit within 16 bits.\n",
817 prog_name);
818 exit(1);
819 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000820
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000821 return result;
822}