1 /*****************************************************************************\
3 *****************************************************************************
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>.
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.
14 * Please also read the file DISCLAIMER which is included in this software
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.
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.
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 \*****************************************************************************/
35 #include "layout_file.h"
36 #include "input_file.h"
38 #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, const char **value);
67 static int list_cmos_entry(const cmos_entry_t * e, int show_name);
68 static uint16_t convert_checksum_value(const char value[]);
70 static const op_fn_t op_fns[] = { op_show_version,
75 op_cmos_show_one_param,
76 op_cmos_show_all_params,
77 op_cmos_set_one_param,
78 op_cmos_set_params_stdin,
79 op_cmos_set_params_file,
84 op_show_cmos_hex_dump,
88 static const hexdump_format_t cmos_dump_format =
89 { 16, 2, "", " | ", " ", " | ", '.' };
91 /****************************************************************************
93 ****************************************************************************/
94 int main(int argc, char *argv[])
96 cmos_layout_get_fn_t fn = get_layout_from_cmos_table;
98 parse_nvramtool_args(argc, argv);
100 if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_LAYOUT_FILE].found) {
101 set_layout_filename(nvramtool_op_modifiers
102 [NVRAMTOOL_MOD_USE_CMOS_LAYOUT_FILE].param);
103 fn = get_layout_from_file;
104 } else if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_OPT_TABLE].found) {
105 fn = get_layout_from_cmos_table;
106 } else if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CBFS_FILE].found) {
107 open_cbfs(nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CBFS_FILE].param);
108 void *cmosdefault = cbfs_find_file("cmos.default", CBFS_COMPONENT_CMOS_DEFAULT, NULL);
109 if (cmosdefault == NULL) {
110 printf("Need a cmos.default in the CBFS image for now.\n");
113 select_hal(HAL_MEMORY, cmosdefault);
114 fn = get_layout_from_cbfs_file;
117 register_cmos_layout_get_fn(fn);
118 op_fns[nvramtool_op.op] ();
122 /****************************************************************************
127 * Show version information for this program.
128 ****************************************************************************/
129 static void op_show_version(void)
131 printf("This is %s version %s.\n", prog_name, prog_version);
134 /****************************************************************************
139 * Show a usage message for this program.
140 ****************************************************************************/
141 static void op_show_usage(void)
146 /****************************************************************************
147 * op_lbtable_show_info
151 * If ARG is present, show coreboot table information specified by ARG.
152 * Else show all possible values for ARG.
153 ****************************************************************************/
154 static void op_lbtable_show_info(void)
156 if (nvramtool_op.param == NULL)
157 list_lbtable_choices();
160 list_lbtable_item(nvramtool_op.param);
164 /****************************************************************************
169 * Do low-level dump of coreboot table.
170 ****************************************************************************/
171 static void op_lbtable_dump(void)
177 /****************************************************************************
178 * op_show_param_values
182 * Show all possible values for parameter NAME.
183 ****************************************************************************/
184 static void op_show_param_values(void)
187 list_param_enums(nvramtool_op.param);
190 /****************************************************************************
191 * op_cmos_show_one_param
195 * Show parameter NAME. If -n is specified, show value only. Else show name
197 ****************************************************************************/
198 static void op_cmos_show_one_param(void)
203 result = list_one_param(nvramtool_op.param,
204 !nvramtool_op_modifiers
205 [NVRAMTOOL_MOD_SHOW_VALUE_ONLY].found);
206 cmos_checksum_verify();
212 /****************************************************************************
213 * op_cmos_show_all_params
217 * Show names and values for all parameters.
218 ****************************************************************************/
219 static void op_cmos_show_all_params(void)
224 result = list_all_params();
225 cmos_checksum_verify();
231 /****************************************************************************
232 * op_cmos_set_one_param
236 * Set parameter NAME to VALUE.
237 ****************************************************************************/
238 static void op_cmos_set_one_param(void)
240 const char *name, *value;
244 /* Separate 'NAME=VALUE' syntax into two strings representing NAME and
247 parse_assignment(nvramtool_op.param, &name, &value);
249 set_one_param(name, value);
252 /****************************************************************************
253 * op_cmos_set_params_stdin
257 * Set parameters according to standard input.
258 ****************************************************************************/
259 static void op_cmos_set_params_stdin(void)
265 /****************************************************************************
266 * op_cmos_set_params_file
270 * Set parameters according to INPUT_FILE.
271 ****************************************************************************/
272 static void op_cmos_set_params_file(void)
276 if ((f = fopen(nvramtool_op.param, "r")) == NULL) {
277 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
278 prog_name, nvramtool_op.param, strerror(errno));
287 /****************************************************************************
292 * If VALUE is present, set coreboot CMOS checksum to VALUE. Else show
294 ****************************************************************************/
295 static void op_cmos_checksum(void)
301 if (nvramtool_op.param == NULL) {
303 checksum = cmos_checksum_read();
305 printf("0x%x\n", checksum);
307 checksum = convert_checksum_value(nvramtool_op.param);
309 cmos_checksum_write(checksum);
314 /****************************************************************************
319 * Write CMOS layout information to standard output.
320 ****************************************************************************/
321 static void op_show_layout(void)
324 write_cmos_layout(stdout);
327 /****************************************************************************
332 * Write the contents of CMOS memory to a binary file.
333 ****************************************************************************/
334 static void op_write_cmos_dump(void)
336 unsigned char data[CMOS_SIZE];
339 if ((f = fopen(nvramtool_op.param, "w")) == NULL) {
340 fprintf(stderr, "%s: Can not open file %s for writing: %s\n",
341 prog_name, nvramtool_op.param, strerror(errno));
349 if (fwrite(data, 1, CMOS_SIZE, f) != CMOS_SIZE) {
350 fprintf(stderr, "%s: Error writing CMOS data to file %s: %s\n",
351 prog_name, nvramtool_op.param, strerror(errno));
358 /****************************************************************************
363 * Read binary data from a file and write the data to CMOS memory.
364 ****************************************************************************/
365 static void op_read_cmos_dump(void)
367 unsigned char data[CMOS_SIZE];
371 if ((f = fopen(nvramtool_op.param, "r")) == NULL) {
372 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
373 prog_name, nvramtool_op.param, strerror(errno));
377 if ((nr_bytes = fread(data, 1, CMOS_SIZE, f)) != CMOS_SIZE) {
379 "%s: Error: Only able to read %d bytes of CMOS data "
380 "from file %s. CMOS data is unchanged.\n", prog_name,
381 (int)nr_bytes, nvramtool_op.param);
387 cmos_write_all(data);
391 /****************************************************************************
392 * op_show_cmos_hex_dump
396 * Write a hex dump of CMOS memory to standard output.
397 ****************************************************************************/
398 static void op_show_cmos_hex_dump(void)
400 unsigned char data[CMOS_SIZE];
405 hexdump(data, CMOS_SIZE, 0, stdout, &cmos_dump_format);
408 /****************************************************************************
409 * op_show_cmos_dumpfile
413 * Read binary data from a file (presumably a CMOS dump file) and display a
414 * hex dump of the CMOS data from the file.
415 ****************************************************************************/
416 static void op_show_cmos_dumpfile(void)
418 unsigned char data[CMOS_SIZE];
422 if ((f = fopen(nvramtool_op.param, "r")) == NULL) {
423 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
424 prog_name, nvramtool_op.param, strerror(errno));
428 nr_bytes = fread(data, 1, CMOS_SIZE, f);
430 hexdump(data, nr_bytes, 0, stdout, &cmos_dump_format);
433 /****************************************************************************
436 * Attempt to list one CMOS parameter given by 'name'. 'show_name' is a
437 * boolean value indicating whether the parameter name should be displayed
438 * along with its value. Return 1 if error was encountered. Else return OK.
439 ****************************************************************************/
440 static int list_one_param(const char name[], int show_name)
442 const cmos_entry_t *e;
444 if (is_checksum_name(name) || ((e = find_cmos_entry(name)) == NULL)) {
445 fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name,
450 if (e->config == CMOS_ENTRY_RESERVED) {
451 fprintf(stderr, "%s: Parameter %s is reserved.\n", prog_name,
456 return (list_cmos_entry(e, show_name) != 0);
459 /****************************************************************************
462 * Attempt to list all CMOS parameters. Return 1 if error was encountered.
464 ****************************************************************************/
465 static int list_all_params(void)
467 const cmos_entry_t *e;
472 for (e = first_cmos_entry(); e != NULL; e = next_cmos_entry(e)) {
473 if ((e->config == CMOS_ENTRY_RESERVED)
474 || is_checksum_name(e->name))
477 if (list_cmos_entry(e, TRUE))
484 /****************************************************************************
487 * List all possible values for CMOS parameter given by 'name'.
488 ****************************************************************************/
489 static void list_param_enums(const char name[])
491 const cmos_entry_t *e;
492 const cmos_enum_t *p;
494 if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL) {
495 fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name,
501 case CMOS_ENTRY_ENUM:
502 for (p = first_cmos_enum_id(e->config_id);
503 p != NULL; p = next_cmos_enum_id(p))
504 printf("%s\n", p->text);
509 printf("Parameter %s requires a %u-bit unsigned integer.\n",
513 case CMOS_ENTRY_STRING:
514 printf("Parameter %s requires a %u-byte string.\n", name,
518 case CMOS_ENTRY_RESERVED:
519 printf("Parameter %s is reserved.\n", name);
527 /****************************************************************************
530 * Set the CMOS parameter given by 'name' to 'value'. The 'name' parameter
531 * is case-sensitive. If we are setting an enum parameter, then 'value' is
532 * interpreted as a case-sensitive string that must match the option name
533 * exactly. If we are setting a 'hex' parameter, then 'value' is treated as
534 * a string representation of an unsigned integer that may be specified in
535 * decimal, hex, or octal.
536 ****************************************************************************/
537 static void set_one_param(const char name[], const char value[])
539 const cmos_entry_t *e;
540 unsigned long long n;
542 if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL) {
543 fprintf(stderr, "%s: CMOS parameter %s not found.", prog_name,
548 switch (prepare_cmos_write(e, value, &n)) {
552 case CMOS_OP_BAD_ENUM_VALUE:
553 fprintf(stderr, "%s: Bad value for parameter %s.", prog_name,
557 case CMOS_OP_NEGATIVE_INT:
559 "%s: This program does not support assignment of negative "
560 "numbers to coreboot parameters.", prog_name);
563 case CMOS_OP_INVALID_INT:
564 fprintf(stderr, "%s: %s is not a valid integer.", prog_name,
568 case CMOS_OP_RESERVED:
570 "%s: Can not modify reserved coreboot parameter %s.",
574 case CMOS_OP_VALUE_TOO_WIDE:
576 "%s: Can not write value %s to CMOS parameter %s that is "
577 "only %d bits wide.", prog_name, value, name,
581 case CMOS_OP_NO_MATCHING_ENUM:
583 "%s: coreboot parameter %s has no matching enums.",
587 case CMOS_AREA_OUT_OF_RANGE:
589 "%s: The CMOS area specified by the layout info for "
590 "coreboot parameter %s is out of range.", prog_name,
594 case CMOS_AREA_OVERLAPS_RTC:
596 "%s: The CMOS area specified by the layout info for "
597 "coreboot parameter %s overlaps the realtime clock area.",
601 case CMOS_AREA_TOO_WIDE:
603 "%s: The CMOS area specified by the layout info for "
604 "coreboot parameter %s is too wide.", prog_name, name);
609 "%s: Unknown error encountered while attempting to modify "
610 "coreboot parameter %s.", prog_name, name);
614 /* write the value to nonvolatile RAM */
617 cmos_checksum_write(cmos_checksum_compute());
622 fprintf(stderr, " CMOS write not performed.\n");
626 /****************************************************************************
629 * Set coreboot parameters according to the contents of file 'f'.
630 ****************************************************************************/
631 static void set_params(FILE * f)
632 { /* First process the input file. Then perform writes only if there were
633 * no problems processing the input. Either all values will be written
634 * successfully or no values will be written.
636 do_cmos_writes(process_input_file(f));
639 /****************************************************************************
642 * Parse the string 'arg' (which supposedly represents an assignment) into a
643 * NAME and a VALUE. If 'arg' does not conform to the proper assignment
644 * syntax, exit with a usage message. Otherwise, on return, 'arg' is broken
645 * into substrings representing NAME and VALUE, and *name and *value are set
646 * to point to these two substrings.
647 ****************************************************************************/
648 static void parse_assignment(char arg[], const char **name, const char **value)
650 static const size_t N_MATCHES = 4;
651 regmatch_t match[N_MATCHES];
654 compile_reg_exprs(REG_EXTENDED | REG_NEWLINE, 1, assignment_regex,
657 /* Does 'arg' conform to proper assignment syntax? If not, exit with a
660 if (regexec(&assignment, arg, N_MATCHES, match, 0))
663 /* Ok, we found a valid assignment. Break it into two strings
664 * representing NAME and VALUE.
666 arg[match[1].rm_eo] = '\0';
667 arg[match[2].rm_eo] = '\0';
668 *name = &arg[match[1].rm_so];
669 *value = &arg[match[2].rm_so];
671 free_reg_exprs(1, &assignment);
674 /****************************************************************************
677 * Attempt to list the CMOS entry represented by 'e'. 'show_name' is a
678 * boolean value indicating whether the parameter name should be displayed
679 * along with its value. On success, return OK. On error, print an error
680 * message and return 1.
681 ****************************************************************************/
682 static int list_cmos_entry(const cmos_entry_t * e, int show_name)
684 const cmos_enum_t *p;
685 unsigned long long value;
688 /* sanity check CMOS entry */
689 switch (prepare_cmos_read(e)) {
693 case CMOS_OP_RESERVED:
696 case CMOS_AREA_OUT_OF_RANGE:
698 "%s: Can not read coreboot parameter %s because "
699 "layout info specifies out of range CMOS area.\n",
703 case CMOS_AREA_OVERLAPS_RTC:
705 "%s: Can not read coreboot parameter %s because "
706 "layout info specifies CMOS area that overlaps realtime "
707 "clock area.\n", prog_name, e->name);
710 case CMOS_AREA_TOO_WIDE:
712 "%s: Can not read coreboot parameter %s because "
713 "layout info specifies CMOS area that is too wide.\n",
719 "%s: Unknown error encountered while attempting to "
720 "read coreboot parameter %s\n", prog_name, e->name);
724 /* read the value from CMOS */
726 value = cmos_read(e);
729 /* display the value */
731 case CMOS_ENTRY_ENUM:
732 if ((p = find_cmos_enum(e->config_id, value)) == NULL) {
734 printf("# Bad value -> %s = 0x%llx\n", e->name,
737 printf("Bad value -> 0x%llx\n", value);
740 printf("%s = %s\n", e->name, p->text);
742 printf("%s\n", p->text);
749 printf("%s = 0x%llx\n", e->name, value);
751 printf("0x%llx\n", value);
755 case CMOS_ENTRY_STRING:
756 w = (char *)(unsigned long)value;
760 printf("# Bad value -> %s\n", e->name);
762 printf("Bad value\n");
771 printf("%s = %s\n", e->name,
772 (char *)(unsigned long)value);
774 printf("%s\n", (char *)(unsigned long)value);
777 free((void *)(unsigned long)value);
781 case CMOS_ENTRY_RESERVED:
789 /****************************************************************************
790 * convert_checksum_value
792 * 'value' is the string representation of a checksum value that the user
793 * wishes to set using the -c option. Convert the string to a 16-bit
794 * unsigned integer and return the result. Exit with an error message if
795 * 'value' is invalid.
796 ****************************************************************************/
797 static uint16_t convert_checksum_value(const char value[])
804 for (p = value; isspace(*p); p++) ;
806 negative = (*p == '-');
807 n = strtoul(value, (char **)&p, 0);
811 "%s: Checksum value %s is not a valid integer.\n",
818 "%s: Checksum must be an unsigned integer.\n",
823 result = (uint16_t) n;
827 "%s: Checksum value must fit within 16 bits.\n",