1 /*****************************************************************************\
4 *****************************************************************************
5 * Copyright (C) 2002-2005 The Regents of the University of California.
6 * Produced at the Lawrence Livermore National Laboratory.
7 * Written by Dave Peterson <dsp@llnl.gov> <dave_peterson@pobox.com>.
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.
15 * Please also read the file DISCLAIMER which is included in this software
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.
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.
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 \*****************************************************************************/
36 #include "layout_file.h"
37 #include "input_file.h"
39 #include "cmos_lowlevel.h"
43 typedef void (*op_fn_t) (void);
45 static void op_show_version (void);
46 static void op_show_usage (void);
47 static void op_lbtable_show_info (void);
48 static void op_lbtable_dump (void);
49 static void op_show_param_values (void);
50 static void op_cmos_show_one_param (void);
51 static void op_cmos_show_all_params (void);
52 static void op_cmos_set_one_param (void);
53 static void op_cmos_set_params_stdin (void);
54 static void op_cmos_set_params_file (void);
55 static void op_cmos_checksum (void);
56 static void op_show_layout (void);
57 static void op_write_cmos_dump (void);
58 static void op_read_cmos_dump (void);
59 static void op_show_cmos_hex_dump (void);
60 static void op_show_cmos_dumpfile (void);
61 static int list_one_param (const char name[], int show_name);
62 static int list_all_params (void);
63 static void list_param_enums (const char name[]);
64 static void set_one_param (const char name[], const char value[]);
65 static void set_params (FILE *f);
66 static void parse_assignment (char arg[], const char **name,
68 static int list_cmos_entry (const cmos_entry_t *e, int show_name);
69 static uint16_t convert_checksum_value (const char value[]);
71 static const op_fn_t op_fns[] =
77 op_cmos_show_one_param,
78 op_cmos_show_all_params,
79 op_cmos_set_one_param,
80 op_cmos_set_params_stdin,
81 op_cmos_set_params_file,
86 op_show_cmos_hex_dump,
90 static const hexdump_format_t cmos_dump_format =
91 { 16, 2, "", " | ", " ", " | ", '.', NULL };
93 /****************************************************************************
95 ****************************************************************************/
96 int main (int argc, char *argv[])
97 { cmos_layout_get_fn_t fn;
99 parse_nvramtool_args(argc, argv);
101 if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_LAYOUT_FILE].found)
102 { set_layout_filename(
103 nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_LAYOUT_FILE].param);
104 fn = get_layout_from_file;
107 fn = get_layout_from_cmos_table;
109 register_cmos_layout_get_fn(fn);
110 op_fns[nvramtool_op.op]();
114 /****************************************************************************
119 * Show version information for this program.
120 ****************************************************************************/
121 static void op_show_version (void)
122 { printf("This is %s version %s.\n", prog_name, prog_version); }
124 /****************************************************************************
129 * Show a usage message for this program.
130 ****************************************************************************/
131 static void op_show_usage (void)
134 /****************************************************************************
135 * op_lbtable_show_info
139 * If ARG is present, show coreboot table information specified by ARG.
140 * Else show all possible values for ARG.
141 ****************************************************************************/
142 static void op_lbtable_show_info (void)
143 { if (nvramtool_op.param == NULL)
144 list_lbtable_choices();
147 list_lbtable_item(nvramtool_op.param);
151 /****************************************************************************
156 * Do low-level dump of coreboot table.
157 ****************************************************************************/
158 static void op_lbtable_dump (void)
163 /****************************************************************************
164 * op_show_param_values
168 * Show all possible values for parameter NAME.
169 ****************************************************************************/
170 static void op_show_param_values (void)
172 list_param_enums(nvramtool_op.param);
175 /****************************************************************************
176 * op_cmos_show_one_param
180 * Show parameter NAME. If -n is specified, show value only. Else show name
182 ****************************************************************************/
183 static void op_cmos_show_one_param (void)
187 result = list_one_param(nvramtool_op.param,
188 !nvramtool_op_modifiers[NVRAMTOOL_MOD_SHOW_VALUE_ONLY].found);
189 cmos_checksum_verify();
195 /****************************************************************************
196 * op_cmos_show_all_params
200 * Show names and values for all parameters.
201 ****************************************************************************/
202 static void op_cmos_show_all_params (void)
206 result = list_all_params();
207 cmos_checksum_verify();
213 /****************************************************************************
214 * op_cmos_set_one_param
218 * Set parameter NAME to VALUE.
219 ****************************************************************************/
220 static void op_cmos_set_one_param (void)
221 { const char *name, *value;
225 /* Separate 'NAME=VALUE' syntax into two strings representing NAME and
228 parse_assignment(nvramtool_op.param, &name, &value);
230 set_one_param(name, value);
233 /****************************************************************************
234 * op_cmos_set_params_stdin
238 * Set parameters according to standard input.
239 ****************************************************************************/
240 static void op_cmos_set_params_stdin (void)
245 /****************************************************************************
246 * op_cmos_set_params_file
250 * Set parameters according to INPUT_FILE.
251 ****************************************************************************/
252 static void op_cmos_set_params_file (void)
255 if ((f = fopen(nvramtool_op.param, "r")) == NULL)
256 { fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
257 prog_name, nvramtool_op.param, strerror(errno));
266 /****************************************************************************
271 * If VALUE is present, set coreboot CMOS checksum to VALUE. Else show
273 ****************************************************************************/
274 static void op_cmos_checksum (void)
279 if (nvramtool_op.param == NULL)
281 checksum = cmos_checksum_read();
283 printf("0x%x\n", checksum);
286 { checksum = convert_checksum_value(nvramtool_op.param);
288 cmos_checksum_write(checksum);
293 /****************************************************************************
298 * Write CMOS layout information to standard output.
299 ****************************************************************************/
300 static void op_show_layout (void)
302 write_cmos_layout(stdout);
305 /****************************************************************************
310 * Write the contents of CMOS memory to a binary file.
311 ****************************************************************************/
312 static void op_write_cmos_dump (void)
313 { unsigned char data[CMOS_SIZE];
316 if ((f = fopen(nvramtool_op.param, "w")) == NULL)
317 { fprintf(stderr, "%s: Can not open file %s for writing: %s\n",
318 prog_name, nvramtool_op.param, strerror(errno));
326 if (fwrite(data, 1, CMOS_SIZE, f) != CMOS_SIZE)
327 { fprintf(stderr, "%s: Error writing CMOS data to file %s: %s\n",
328 prog_name, nvramtool_op.param, strerror(errno));
335 /****************************************************************************
340 * Read binary data from a file and write the data to CMOS memory.
341 ****************************************************************************/
342 static void op_read_cmos_dump (void)
343 { unsigned char data[CMOS_SIZE];
347 if ((f = fopen(nvramtool_op.param, "r")) == NULL)
348 { fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
349 prog_name, nvramtool_op.param, strerror(errno));
353 if ((nr_bytes = fread(data, 1, CMOS_SIZE, f)) != CMOS_SIZE)
354 { fprintf(stderr, "%s: Error: Only able to read %d bytes of CMOS data "
355 "from file %s. CMOS data is unchanged.\n", prog_name,
356 (int) nr_bytes, nvramtool_op.param);
362 cmos_write_all(data);
366 /****************************************************************************
367 * op_show_cmos_hex_dump
371 * Write a hex dump of CMOS memory to standard output.
372 ****************************************************************************/
373 static void op_show_cmos_hex_dump (void)
374 { unsigned char data[CMOS_SIZE];
379 hexdump(data, CMOS_SIZE, 0, stdout, &cmos_dump_format);
382 /****************************************************************************
383 * op_show_cmos_dumpfile
387 * Read binary data from a file (presumably a CMOS dump file) and display a
388 * hex dump of the CMOS data from the file.
389 ****************************************************************************/
390 static void op_show_cmos_dumpfile (void)
391 { unsigned char data[CMOS_SIZE];
395 if ((f = fopen(nvramtool_op.param, "r")) == NULL)
396 { fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
397 prog_name, nvramtool_op.param, strerror(errno));
401 nr_bytes = fread(data, 1, CMOS_SIZE, f);
403 hexdump(data, nr_bytes, 0, stdout, &cmos_dump_format);
406 /****************************************************************************
409 * Attempt to list one CMOS parameter given by 'name'. 'show_name' is a
410 * boolean value indicating whether the parameter name should be displayed
411 * along with its value. Return 1 if error was encountered. Else return OK.
412 ****************************************************************************/
413 static int list_one_param (const char name[], int show_name)
414 { const cmos_entry_t *e;
416 if (is_checksum_name(name) || ((e = find_cmos_entry(name)) == NULL))
417 { fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name, name);
421 if (e->config == CMOS_ENTRY_RESERVED)
422 { fprintf(stderr, "%s: Parameter %s is reserved.\n", prog_name, name);
426 return (list_cmos_entry(e, show_name) != 0);
429 /****************************************************************************
432 * Attempt to list all CMOS parameters. Return 1 if error was encountered.
434 ****************************************************************************/
435 static int list_all_params (void)
436 { const cmos_entry_t *e;
441 for (e = first_cmos_entry(); e != NULL; e = next_cmos_entry(e))
442 { if ((e->config == CMOS_ENTRY_RESERVED) || is_checksum_name(e->name))
445 if (list_cmos_entry(e, TRUE))
452 /****************************************************************************
455 * List all possible values for CMOS parameter given by 'name'.
456 ****************************************************************************/
457 static void list_param_enums (const char name[])
458 { const cmos_entry_t *e;
459 const cmos_enum_t *p;
461 if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL)
462 { fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name, name);
467 { case CMOS_ENTRY_ENUM:
468 for (p = first_cmos_enum_id(e->config_id);
470 p = next_cmos_enum_id(p))
471 printf("%s\n", p->text);
476 printf("Parameter %s requires a %u-bit unsigned integer.\n", name,
480 case CMOS_ENTRY_RESERVED:
481 printf("Parameter %s is reserved.\n", name);
489 /****************************************************************************
492 * Set the CMOS parameter given by 'name' to 'value'. The 'name' parameter
493 * is case-sensitive. If we are setting an enum parameter, then 'value' is
494 * interpreted as a case-sensitive string that must match the option name
495 * exactly. If we are setting a 'hex' parameter, then 'value' is treated as
496 * a string representation of an unsigned integer that may be specified in
497 * decimal, hex, or octal.
498 ****************************************************************************/
499 static void set_one_param (const char name[], const char value[])
500 { const cmos_entry_t *e;
501 unsigned long long n;
503 if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL)
504 { fprintf(stderr, "%s: CMOS parameter %s not found.", prog_name, name);
508 switch (prepare_cmos_write(e, value, &n))
512 case CMOS_OP_BAD_ENUM_VALUE:
513 fprintf(stderr, "%s: Bad value for parameter %s.", prog_name, name);
516 case CMOS_OP_NEGATIVE_INT:
518 "%s: This program does not support assignment of negative "
519 "numbers to coreboot parameters.", prog_name);
522 case CMOS_OP_INVALID_INT:
523 fprintf(stderr, "%s: %s is not a valid integer.", prog_name, value);
526 case CMOS_OP_RESERVED:
528 "%s: Can not modify reserved coreboot parameter %s.",
532 case CMOS_OP_VALUE_TOO_WIDE:
534 "%s: Can not write value %s to CMOS parameter %s that is "
535 "only %d bits wide.", prog_name, value, name, e->length);
538 case CMOS_OP_NO_MATCHING_ENUM:
540 "%s: coreboot parameter %s has no matching enums.",
544 case CMOS_AREA_OUT_OF_RANGE:
546 "%s: The CMOS area specified by the layout info for "
547 "coreboot parameter %s is out of range.", prog_name, name);
550 case CMOS_AREA_OVERLAPS_RTC:
552 "%s: The CMOS area specified by the layout info for "
553 "coreboot parameter %s overlaps the realtime clock area.",
557 case CMOS_AREA_TOO_WIDE:
559 "%s: The CMOS area specified by the layout info for "
560 "coreboot parameter %s is too wide.",
566 "%s: Unknown error encountered while attempting to modify "
567 "coreboot parameter %s.", prog_name, name);
571 /* write the value to nonvolatile RAM */
573 cmos_write(e->bit, e->length, n);
574 cmos_checksum_write(cmos_checksum_compute());
579 fprintf(stderr, " CMOS write not performed.\n");
583 /****************************************************************************
586 * Set coreboot parameters according to the contents of file 'f'.
587 ****************************************************************************/
588 static void set_params (FILE *f)
589 { /* First process the input file. Then perform writes only if there were
590 * no problems processing the input. Either all values will be written
591 * successfully or no values will be written.
593 do_cmos_writes(process_input_file(f));
596 /****************************************************************************
599 * Parse the string 'arg' (which supposedly represents an assignment) into a
600 * NAME and a VALUE. If 'arg' does not conform to the proper assignment
601 * syntax, exit with a usage message. Otherwise, on return, 'arg' is broken
602 * into substrings representing NAME and VALUE, and *name and *value are set
603 * to point to these two substrings.
604 ****************************************************************************/
605 static void parse_assignment (char arg[], const char **name,
607 { static const size_t N_MATCHES = 4;
608 regmatch_t match[N_MATCHES];
611 compile_reg_exprs(REG_EXTENDED | REG_NEWLINE, 1, assignment_regex,
614 /* Does 'arg' conform to proper assignment syntax? If not, exit with a
617 if (regexec(&assignment, arg, N_MATCHES, match, 0))
620 /* Ok, we found a valid assignment. Break it into two strings
621 * representing NAME and VALUE.
623 arg[match[1].rm_eo] = '\0';
624 arg[match[2].rm_eo] = '\0';
625 *name = &arg[match[1].rm_so];
626 *value = &arg[match[2].rm_so];
628 free_reg_exprs(1, &assignment);
631 /****************************************************************************
634 * Attempt to list the CMOS entry represented by 'e'. 'show_name' is a
635 * boolean value indicating whether the parameter name should be displayed
636 * along with its value. On success, return OK. On error, print an error
637 * message and return 1.
638 ****************************************************************************/
639 static int list_cmos_entry (const cmos_entry_t *e, int show_name)
640 { const cmos_enum_t *p;
641 unsigned long long value;
643 /* sanity check CMOS entry */
644 switch (prepare_cmos_read(e))
648 case CMOS_OP_RESERVED:
651 case CMOS_AREA_OUT_OF_RANGE:
652 fprintf(stderr, "%s: Can not read coreboot parameter %s because "
653 "layout info specifies out of range CMOS area.\n", prog_name,
657 case CMOS_AREA_OVERLAPS_RTC:
658 fprintf(stderr, "%s: Can not read coreboot parameter %s because "
659 "layout info specifies CMOS area that overlaps realtime "
660 "clock area.\n", prog_name, e->name);
663 case CMOS_AREA_TOO_WIDE:
664 fprintf(stderr, "%s: Can not read coreboot parameter %s because "
665 "layout info specifies CMOS area that is too wide.\n",
670 fprintf(stderr, "%s: Unknown error encountered while attempting to "
671 "read coreboot parameter %s\n", prog_name, e->name);
675 /* read the value from CMOS */
677 value = cmos_read(e->bit, e->length);
680 /* display the value */
682 { case CMOS_ENTRY_ENUM:
683 if ((p = find_cmos_enum(e->config_id, value)) == NULL)
685 printf("# Bad value -> %s = 0x%llx\n", e->name, value);
687 printf("Bad value -> 0x%llx\n", value);
691 printf("%s = %s\n", e->name, p->text);
693 printf("%s\n", p->text);
700 printf("%s = 0x%llx\n", e->name, value);
702 printf("0x%llx\n", value);
706 case CMOS_ENTRY_RESERVED:
714 /****************************************************************************
715 * convert_checksum_value
717 * 'value' is the string representation of a checksum value that the user
718 * wishes to set using the -c option. Convert the string to a 16-bit
719 * unsigned integer and return the result. Exit with an error message if
720 * 'value' is invalid.
721 ****************************************************************************/
722 static uint16_t convert_checksum_value (const char value[])
728 for (p = value; isspace(*p); p++);
730 negative = (*p == '-');
731 n = strtoul(value, (char **) &p, 0);
734 { fprintf(stderr, "%s: Checksum value %s is not a valid integer.\n",
741 "%s: Checksum must be an unsigned integer.\n", prog_name);
745 result = (uint16_t) n;
749 "%s: Checksum value must fit within 16 bits.\n", prog_name);