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 https://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.
25 \*****************************************************************************/
37 #include "accessors/layout-text.h"
38 #include "input_file.h"
40 #include "cmos_lowlevel.h"
48 typedef void (*op_fn_t
) (void);
50 static void op_show_version(void);
51 static void op_show_usage(void);
52 static void op_lbtable_show_info(void);
53 static void op_lbtable_dump(void);
54 static void op_show_param_values(void);
55 static void op_cmos_show_one_param(void);
56 static void op_cmos_show_all_params(void);
57 static void op_cmos_set_one_param(void);
58 static void op_cmos_set_params_stdin(void);
59 static void op_cmos_set_params_file(void);
60 static void op_cmos_checksum(void);
61 static void op_show_layout(void);
62 static void op_write_cmos_dump(void);
63 static void op_read_cmos_dump(void);
64 static void op_show_cmos_hex_dump(void);
65 static void op_show_cmos_dumpfile(void);
66 static void op_write_cmos_layout_bin(void);
67 static void op_write_cmos_layout_header(void);
68 static int list_one_param(const char name
[], int show_name
);
69 static int list_all_params(void);
70 static void list_param_enums(const char name
[]);
71 static void set_one_param(const char name
[], const char value
[]);
72 static void set_params(FILE * f
);
73 static void parse_assignment(char arg
[], const char **name
, const char **value
);
74 static int list_cmos_entry(const cmos_entry_t
* e
, int show_name
);
75 static uint16_t convert_checksum_value(const char value
[]);
77 static const op_fn_t op_fns
[] = { op_show_version
,
82 op_cmos_show_one_param
,
83 op_cmos_show_all_params
,
84 op_cmos_set_one_param
,
85 op_cmos_set_params_stdin
,
86 op_cmos_set_params_file
,
91 op_show_cmos_hex_dump
,
92 op_show_cmos_dumpfile
,
93 op_write_cmos_layout_bin
,
94 op_write_cmos_layout_header
97 static void op_write_cmos_layout_bin(void)
99 get_layout_from_file();
100 write_cmos_output_bin(nvramtool_op
.param
);
103 static void op_write_cmos_layout_header(void)
105 get_layout_from_file();
106 write_cmos_layout_header(nvramtool_op
.param
);
109 static const hexdump_format_t cmos_dump_format
=
110 { 16, 2, "", " | ", " ", " | ", '.' };
112 /****************************************************************************
114 ****************************************************************************/
115 int main(int argc
, char *argv
[])
117 void *cmos_default
= NULL
;
118 cmos_layout_get_fn_t fn
= get_layout_from_cmos_table
;
120 parse_nvramtool_args(argc
, argv
);
122 /* If we should operate on a CBFS file default to reading the layout
123 * and CMOS contents from it. */
124 if (nvramtool_op_modifiers
[NVRAMTOOL_MOD_USE_CBFS_FILE
].found
) {
125 open_cbfs(nvramtool_op_modifiers
[NVRAMTOOL_MOD_USE_CBFS_FILE
].param
);
126 if (!nvramtool_op_modifiers
[NVRAMTOOL_MOD_USE_CMOS_FILE
].found
) {
127 cmos_default
= cbfs_find_file("cmos.default", CBFS_COMPONENT_CMOS_DEFAULT
, NULL
);
128 if (cmos_default
== NULL
) {
129 fprintf(stderr
, "Need a cmos.default in the CBFS image or separate cmos file (-D).\n");
133 fn
= get_layout_from_cbfs_file
;
136 /* If the user wants to use a specific layout file or explicitly use
137 * the coreboot option table allow him to override previous settings. */
138 if (nvramtool_op_modifiers
[NVRAMTOOL_MOD_USE_CMOS_LAYOUT_FILE
].found
) {
139 set_layout_filename(nvramtool_op_modifiers
[NVRAMTOOL_MOD_USE_CMOS_LAYOUT_FILE
].param
);
140 fn
= get_layout_from_file
;
141 } else if (nvramtool_op_modifiers
[NVRAMTOOL_MOD_USE_CMOS_OPT_TABLE
].found
) {
142 fn
= get_layout_from_cmos_table
;
145 /* Allow the user to use a file for the CMOS contents, possibly
146 * overriding a previously opened "cmos.default" file from the CBFS. */
147 if (nvramtool_op_modifiers
[NVRAMTOOL_MOD_USE_CMOS_FILE
].found
) {
151 if ((fd
= open(nvramtool_op_modifiers
[NVRAMTOOL_MOD_USE_CMOS_FILE
].param
, O_RDWR
| O_CREAT
, 0666)) < 0) {
152 fprintf(stderr
, "Couldn't open '%s'\n", nvramtool_op_modifiers
[NVRAMTOOL_MOD_USE_CMOS_FILE
].param
);
156 if (fstat(fd
, &fd_stat
) == -1) {
157 fprintf(stderr
, "Couldn't stat '%s'\n", nvramtool_op_modifiers
[NVRAMTOOL_MOD_USE_CMOS_FILE
].param
);
161 if (fd_stat
.st_size
< CMOS_SIZE
) {
162 if ((lseek(fd
, CMOS_SIZE
- 1, SEEK_SET
) == -1) ||
163 (write(fd
, "\0", 1) != 1)) {
164 fprintf(stderr
, "Unable to extended '%s' to its full size.\n",
165 nvramtool_op_modifiers
[NVRAMTOOL_MOD_USE_CMOS_FILE
].param
);
171 FlushFileBuffers ((HANDLE
) _get_osfhandle (fd
));
175 cmos_default
= mmap(NULL
, CMOS_SIZE
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, fd
, 0);
176 if (cmos_default
== MAP_FAILED
) {
177 fprintf(stderr
, "Couldn't map '%s'\n", nvramtool_op_modifiers
[NVRAMTOOL_MOD_USE_CMOS_FILE
].param
);
182 /* Switch to memory based CMOS access. */
184 select_hal(HAL_MEMORY
, cmos_default
);
187 register_cmos_layout_get_fn(fn
);
188 op_fns
[nvramtool_op
.op
]();
193 /****************************************************************************
198 * Show version information for this program.
199 ****************************************************************************/
200 static void op_show_version(void)
202 printf("This is %s version %s.\n", prog_name
, prog_version
);
205 /****************************************************************************
210 * Show a usage message for this program.
211 ****************************************************************************/
212 static void op_show_usage(void)
217 /****************************************************************************
218 * op_lbtable_show_info
222 * If ARG is present, show coreboot table information specified by ARG.
223 * Else show all possible values for ARG.
224 ****************************************************************************/
225 static void op_lbtable_show_info(void)
227 if (nvramtool_op
.param
== NULL
)
228 list_lbtable_choices();
231 list_lbtable_item(nvramtool_op
.param
);
235 /****************************************************************************
240 * Do low-level dump of coreboot table.
241 ****************************************************************************/
242 static void op_lbtable_dump(void)
248 /****************************************************************************
249 * op_show_param_values
253 * Show all possible values for parameter NAME.
254 ****************************************************************************/
255 static void op_show_param_values(void)
258 list_param_enums(nvramtool_op
.param
);
261 /****************************************************************************
262 * op_cmos_show_one_param
266 * Show parameter NAME. If -n is specified, show value only. Else show name
268 ****************************************************************************/
269 static void op_cmos_show_one_param(void)
274 result
= list_one_param(nvramtool_op
.param
,
275 !nvramtool_op_modifiers
276 [NVRAMTOOL_MOD_SHOW_VALUE_ONLY
].found
);
277 cmos_checksum_verify();
283 /****************************************************************************
284 * op_cmos_show_all_params
288 * Show names and values for all parameters.
289 ****************************************************************************/
290 static void op_cmos_show_all_params(void)
295 result
= list_all_params();
296 cmos_checksum_verify();
302 /****************************************************************************
303 * op_cmos_set_one_param
307 * Set parameter NAME to VALUE.
308 ****************************************************************************/
309 static void op_cmos_set_one_param(void)
311 const char *name
, *value
;
315 /* Separate 'NAME=VALUE' syntax into two strings representing NAME and
318 parse_assignment(nvramtool_op
.param
, &name
, &value
);
320 set_one_param(name
, value
);
323 /****************************************************************************
324 * op_cmos_set_params_stdin
328 * Set parameters according to standard input.
329 ****************************************************************************/
330 static void op_cmos_set_params_stdin(void)
336 /****************************************************************************
337 * op_cmos_set_params_file
341 * Set parameters according to INPUT_FILE.
342 ****************************************************************************/
343 static void op_cmos_set_params_file(void)
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
));
358 /****************************************************************************
363 * If VALUE is present, set coreboot CMOS checksum to VALUE. Else show
365 ****************************************************************************/
366 static void op_cmos_checksum(void)
372 if (nvramtool_op
.param
== NULL
) {
374 checksum
= cmos_checksum_read();
376 printf("0x%x\n", checksum
);
378 checksum
= convert_checksum_value(nvramtool_op
.param
);
380 cmos_checksum_write(checksum
);
385 /****************************************************************************
390 * Write CMOS layout information to standard output.
391 ****************************************************************************/
392 static void op_show_layout(void)
395 write_cmos_layout(stdout
);
398 /****************************************************************************
403 * Write the contents of CMOS memory to a binary file.
404 ****************************************************************************/
405 static void op_write_cmos_dump(void)
407 unsigned char data
[CMOS_SIZE
];
410 if ((f
= fopen(nvramtool_op
.param
, "wb")) == NULL
) {
411 fprintf(stderr
, "%s: Can not open file %s for writing: %s\n",
412 prog_name
, nvramtool_op
.param
, strerror(errno
));
420 if (fwrite(data
, 1, CMOS_SIZE
, f
) != CMOS_SIZE
) {
421 fprintf(stderr
, "%s: Error writing CMOS data to file %s: %s\n",
422 prog_name
, nvramtool_op
.param
, strerror(errno
));
429 /****************************************************************************
434 * Read binary data from a file and write the data to CMOS memory.
435 ****************************************************************************/
436 static void op_read_cmos_dump(void)
438 unsigned char data
[CMOS_SIZE
];
442 if ((f
= fopen(nvramtool_op
.param
, "rb")) == NULL
) {
443 fprintf(stderr
, "%s: Can not open file %s for reading: %s\n",
444 prog_name
, nvramtool_op
.param
, strerror(errno
));
448 if ((nr_bytes
= fread(data
, 1, CMOS_SIZE
, f
)) != CMOS_SIZE
) {
450 "%s: Error: Only able to read %d bytes of CMOS data "
451 "from file %s. CMOS data is unchanged.\n", prog_name
,
452 (int)nr_bytes
, nvramtool_op
.param
);
458 cmos_write_all(data
);
462 /****************************************************************************
463 * op_show_cmos_hex_dump
467 * Write a hex dump of CMOS memory to standard output.
468 ****************************************************************************/
469 static void op_show_cmos_hex_dump(void)
471 unsigned char data
[CMOS_SIZE
];
476 hexdump(data
, CMOS_SIZE
, 0, stdout
, &cmos_dump_format
);
479 /****************************************************************************
480 * op_show_cmos_dumpfile
484 * Read binary data from a file (presumably a CMOS dump file) and display a
485 * hex dump of the CMOS data from the file.
486 ****************************************************************************/
487 static void op_show_cmos_dumpfile(void)
489 unsigned char data
[CMOS_SIZE
];
493 if ((f
= fopen(nvramtool_op
.param
, "r")) == NULL
) {
494 fprintf(stderr
, "%s: Can not open file %s for reading: %s\n",
495 prog_name
, nvramtool_op
.param
, strerror(errno
));
499 nr_bytes
= fread(data
, 1, CMOS_SIZE
, f
);
501 hexdump(data
, nr_bytes
, 0, stdout
, &cmos_dump_format
);
504 /****************************************************************************
507 * Attempt to list one CMOS parameter given by 'name'. 'show_name' is a
508 * boolean value indicating whether the parameter name should be displayed
509 * along with its value. Return 1 if error was encountered. Else return OK.
510 ****************************************************************************/
511 static int list_one_param(const char name
[], int show_name
)
513 const cmos_entry_t
*e
;
515 if (is_checksum_name(name
) || ((e
= find_cmos_entry(name
)) == NULL
)) {
516 fprintf(stderr
, "%s: CMOS parameter %s not found.\n", prog_name
,
521 if (e
->config
== CMOS_ENTRY_RESERVED
) {
522 fprintf(stderr
, "%s: Parameter %s is reserved.\n", prog_name
,
527 return (list_cmos_entry(e
, show_name
) != 0);
530 /****************************************************************************
533 * Attempt to list all CMOS parameters. Return 1 if error was encountered.
535 ****************************************************************************/
536 static int list_all_params(void)
538 const cmos_entry_t
*e
;
543 for (e
= first_cmos_entry(); e
!= NULL
; e
= next_cmos_entry(e
)) {
544 if ((e
->config
== CMOS_ENTRY_RESERVED
)
545 || is_checksum_name(e
->name
))
548 if (list_cmos_entry(e
, TRUE
))
555 /****************************************************************************
558 * List all possible values for CMOS parameter given by 'name'.
559 ****************************************************************************/
560 static void list_param_enums(const char name
[])
562 const cmos_entry_t
*e
;
563 const cmos_enum_t
*p
;
565 if (is_checksum_name(name
) || (e
= find_cmos_entry(name
)) == NULL
) {
566 fprintf(stderr
, "%s: CMOS parameter %s not found.\n", prog_name
,
572 case CMOS_ENTRY_ENUM
:
573 for (p
= first_cmos_enum_id(e
->config_id
);
574 p
!= NULL
; p
= next_cmos_enum_id(p
))
575 printf("%s\n", p
->text
);
580 printf("Parameter %s requires a %u-bit unsigned integer.\n",
584 case CMOS_ENTRY_STRING
:
585 printf("Parameter %s requires a %u-byte string.\n", name
,
589 case CMOS_ENTRY_RESERVED
:
590 printf("Parameter %s is reserved.\n", name
);
598 /****************************************************************************
601 * Set the CMOS parameter given by 'name' to 'value'. The 'name' parameter
602 * is case-sensitive. If we are setting an enum parameter, then 'value' is
603 * interpreted as a case-sensitive string that must match the option name
604 * exactly. If we are setting a 'hex' parameter, then 'value' is treated as
605 * a string representation of an unsigned integer that may be specified in
606 * decimal, hex, or octal.
607 ****************************************************************************/
608 static void set_one_param(const char name
[], const char value
[])
610 const cmos_entry_t
*e
;
611 unsigned long long n
;
613 if (is_checksum_name(name
) || (e
= find_cmos_entry(name
)) == NULL
) {
614 fprintf(stderr
, "%s: CMOS parameter %s not found.\n", prog_name
,
619 switch (prepare_cmos_write(e
, value
, &n
)) {
623 case CMOS_OP_BAD_ENUM_VALUE
:
624 fprintf(stderr
, "%s: Bad value for parameter %s.", prog_name
,
628 case CMOS_OP_NEGATIVE_INT
:
630 "%s: This program does not support assignment of negative "
631 "numbers to coreboot parameters.", prog_name
);
634 case CMOS_OP_INVALID_INT
:
635 fprintf(stderr
, "%s: %s is not a valid integer.", prog_name
,
639 case CMOS_OP_RESERVED
:
641 "%s: Can not modify reserved coreboot parameter %s.",
645 case CMOS_OP_VALUE_TOO_WIDE
:
647 "%s: Can not write value %s to CMOS parameter %s that is "
648 "only %d bits wide.", prog_name
, value
, name
,
652 case CMOS_OP_NO_MATCHING_ENUM
:
654 "%s: coreboot parameter %s has no matching enums.",
658 case CMOS_AREA_OUT_OF_RANGE
:
660 "%s: The CMOS area specified by the layout info for "
661 "coreboot parameter %s is out of range.", prog_name
,
665 case CMOS_AREA_OVERLAPS_RTC
:
667 "%s: The CMOS area specified by the layout info for "
668 "coreboot parameter %s overlaps the realtime clock area.",
672 case CMOS_AREA_TOO_WIDE
:
674 "%s: The CMOS area specified by the layout info for "
675 "coreboot parameter %s is too wide.", prog_name
, name
);
680 "%s: Unknown error encountered while attempting to modify "
681 "coreboot parameter %s.", prog_name
, name
);
685 /* write the value to nonvolatile RAM */
688 cmos_checksum_write(cmos_checksum_compute());
693 fprintf(stderr
, " CMOS write not performed.\n");
697 /****************************************************************************
700 * Set coreboot parameters according to the contents of file 'f'.
701 ****************************************************************************/
702 static void set_params(FILE * f
)
703 { /* First process the input file. Then perform writes only if there were
704 * no problems processing the input. Either all values will be written
705 * successfully or no values will be written.
707 do_cmos_writes(process_input_file(f
));
710 /****************************************************************************
713 * Parse the string 'arg' (which supposedly represents an assignment) into a
714 * NAME and a VALUE. If 'arg' does not conform to the proper assignment
715 * syntax, exit with a usage message. Otherwise, on return, 'arg' is broken
716 * into substrings representing NAME and VALUE, and *name and *value are set
717 * to point to these two substrings.
718 ****************************************************************************/
719 static void parse_assignment(char arg
[], const char **name
, const char **value
)
721 static const size_t N_MATCHES
= 4;
722 regmatch_t match
[N_MATCHES
];
725 compile_reg_expr(REG_EXTENDED
| REG_NEWLINE
, assignment_regex
, &assignment
);
727 /* Does 'arg' conform to proper assignment syntax? If not, exit with a
730 if (regexec(&assignment
, arg
, N_MATCHES
, match
, 0))
733 /* Ok, we found a valid assignment. Break it into two strings
734 * representing NAME and VALUE.
736 arg
[match
[1].rm_eo
] = '\0';
737 arg
[match
[2].rm_eo
] = '\0';
738 *name
= &arg
[match
[1].rm_so
];
739 *value
= &arg
[match
[2].rm_so
];
741 regfree(&assignment
);
744 /****************************************************************************
747 * Attempt to list the CMOS entry represented by 'e'. 'show_name' is a
748 * boolean value indicating whether the parameter name should be displayed
749 * along with its value. On success, return OK. On error, print an error
750 * message and return 1.
751 ****************************************************************************/
752 static int list_cmos_entry(const cmos_entry_t
* e
, int show_name
)
754 const cmos_enum_t
*p
;
755 unsigned long long value
;
758 /* sanity check CMOS entry */
759 switch (prepare_cmos_read(e
)) {
763 case CMOS_OP_RESERVED
:
765 "%s: Cannot access reserved CMOS area (for %s).\n",
769 case CMOS_AREA_OUT_OF_RANGE
:
771 "%s: Can not read coreboot parameter %s because "
772 "layout info specifies out of range CMOS area.\n",
776 case CMOS_AREA_OVERLAPS_RTC
:
778 "%s: Can not read coreboot parameter %s because "
779 "layout info specifies CMOS area that overlaps realtime "
780 "clock area.\n", prog_name
, e
->name
);
783 case CMOS_AREA_TOO_WIDE
:
785 "%s: Can not read coreboot parameter %s because "
786 "layout info specifies CMOS area that is too wide.\n",
792 "%s: Unknown error encountered while attempting to "
793 "read coreboot parameter %s\n", prog_name
, e
->name
);
797 /* read the value from CMOS */
799 value
= cmos_read(e
);
802 /* display the value */
804 case CMOS_ENTRY_ENUM
:
805 if ((p
= find_cmos_enum(e
->config_id
, value
)) == NULL
) {
807 printf("# Bad value -> %s = 0x%llx\n", e
->name
,
810 printf("Bad value -> 0x%llx\n", value
);
813 printf("%s = %s\n", e
->name
, p
->text
);
815 printf("%s\n", p
->text
);
822 printf("%s = 0x%llx\n", e
->name
, value
);
824 printf("0x%llx\n", value
);
828 case CMOS_ENTRY_STRING
:
829 w
= (char *)(unsigned long)value
;
831 if(!isprint((int)(unsigned char)*w
)) {
833 printf("# Bad value -> %s\n", e
->name
);
835 printf("Bad value\n");
844 printf("%s = %s\n", e
->name
,
845 (char *)(unsigned long)value
);
847 printf("%s\n", (char *)(unsigned long)value
);
850 free((void *)(unsigned long)value
);
854 case CMOS_ENTRY_RESERVED
:
862 /****************************************************************************
863 * convert_checksum_value
865 * 'value' is the string representation of a checksum value that the user
866 * wishes to set using the -c option. Convert the string to a 16-bit
867 * unsigned integer and return the result. Exit with an error message if
868 * 'value' is invalid.
869 ****************************************************************************/
870 static uint16_t convert_checksum_value(const char value
[])
877 for (p
= value
; isspace((int)(unsigned char)*p
); p
++) ;
879 negative
= (*p
== '-');
880 n
= strtoul(value
, (char **)&p
, 0);
884 "%s: Checksum value %s is not a valid integer.\n",
891 "%s: Checksum must be an unsigned integer.\n",
896 result
= (uint16_t) n
;
900 "%s: Checksum value must fit within 16 bits.\n",