1 /* SPDX-License-Identifier: GPL-2.0-only */
13 #include "accessors/layout-text.h"
14 #include "input_file.h"
16 #include "cmos_lowlevel.h"
24 typedef void (*op_fn_t
) (void);
26 static void op_show_version(void);
27 static void op_show_usage(void);
28 static void op_lbtable_show_info(void);
29 static void op_lbtable_dump(void);
30 static void op_show_param_values(void);
31 static void op_cmos_show_one_param(void);
32 static void op_cmos_show_all_params(void);
33 static void op_cmos_set_one_param(void);
34 static void op_cmos_set_params_stdin(void);
35 static void op_cmos_set_params_file(void);
36 static void op_cmos_checksum(void);
37 static void op_show_layout(void);
38 static void op_write_cmos_dump(void);
39 static void op_read_cmos_dump(void);
40 static void op_show_cmos_hex_dump(void);
41 static void op_show_cmos_dumpfile(void);
42 static void op_write_cmos_layout_bin(void);
43 static void op_write_cmos_layout_header(void);
44 static int list_one_param(const char name
[], int show_name
);
45 static int list_all_params(void);
46 static void list_param_enums(const char name
[]);
47 static void set_one_param(const char name
[], const char value
[]);
48 static void set_params(FILE * f
);
49 static void parse_assignment(char arg
[], const char **name
, const char **value
);
50 static int list_cmos_entry(const cmos_entry_t
* e
, int show_name
);
51 static uint16_t convert_checksum_value(const char value
[]);
53 static const op_fn_t op_fns
[] = { op_show_version
,
58 op_cmos_show_one_param
,
59 op_cmos_show_all_params
,
60 op_cmos_set_one_param
,
61 op_cmos_set_params_stdin
,
62 op_cmos_set_params_file
,
67 op_show_cmos_hex_dump
,
68 op_show_cmos_dumpfile
,
69 op_write_cmos_layout_bin
,
70 op_write_cmos_layout_header
73 static void op_write_cmos_layout_bin(void)
75 get_layout_from_file();
76 write_cmos_output_bin(nvramtool_op
.param
);
79 static void op_write_cmos_layout_header(void)
81 get_layout_from_file();
82 write_cmos_layout_header(nvramtool_op
.param
);
85 static const hexdump_format_t cmos_dump_format
=
86 { 16, 2, "", " | ", " ", " | ", '.' };
88 /****************************************************************************
90 ****************************************************************************/
91 int main(int argc
, char *argv
[])
93 void *cmos_default
= NULL
;
94 cmos_layout_get_fn_t fn
= get_layout_from_cmos_table
;
96 parse_nvramtool_args(argc
, argv
);
98 /* If we should operate on a CBFS file default to reading the layout
99 * and CMOS contents from it. */
100 if (nvramtool_op_modifiers
[NVRAMTOOL_MOD_USE_CBFS_FILE
].found
) {
101 open_cbfs(nvramtool_op_modifiers
[NVRAMTOOL_MOD_USE_CBFS_FILE
].param
);
102 if (!nvramtool_op_modifiers
[NVRAMTOOL_MOD_USE_CMOS_FILE
].found
) {
103 cmos_default
= cbfs_find_file("cmos.default", CBFS_COMPONENT_CMOS_DEFAULT
, NULL
);
104 if (cmos_default
== NULL
) {
105 fprintf(stderr
, "Need a cmos.default in the CBFS image or separate CMOS file (-D).\n");
109 fn
= get_layout_from_cbfs_file
;
112 /* If the user wants to use a specific layout file or explicitly use
113 * the coreboot option table allow him to override previous settings. */
114 if (nvramtool_op_modifiers
[NVRAMTOOL_MOD_USE_CMOS_LAYOUT_FILE
].found
) {
115 set_layout_filename(nvramtool_op_modifiers
[NVRAMTOOL_MOD_USE_CMOS_LAYOUT_FILE
].param
);
116 fn
= get_layout_from_file
;
117 } else if (nvramtool_op_modifiers
[NVRAMTOOL_MOD_USE_CMOS_OPT_TABLE
].found
) {
118 fn
= get_layout_from_cmos_table
;
121 /* Allow the user to use a file for the CMOS contents, possibly
122 * overriding a previously opened "cmos.default" file from the CBFS. */
123 if (nvramtool_op_modifiers
[NVRAMTOOL_MOD_USE_CMOS_FILE
].found
) {
127 if ((fd
= open(nvramtool_op_modifiers
[NVRAMTOOL_MOD_USE_CMOS_FILE
].param
, O_RDWR
| O_CREAT
, 0666)) < 0) {
128 fprintf(stderr
, "Couldn't open '%s'\n", nvramtool_op_modifiers
[NVRAMTOOL_MOD_USE_CMOS_FILE
].param
);
132 if (fstat(fd
, &fd_stat
) == -1) {
133 fprintf(stderr
, "Couldn't stat '%s'\n", nvramtool_op_modifiers
[NVRAMTOOL_MOD_USE_CMOS_FILE
].param
);
137 if (fd_stat
.st_size
< CMOS_SIZE
) {
138 if ((lseek(fd
, CMOS_SIZE
- 1, SEEK_SET
) == -1) ||
139 (write(fd
, "\0", 1) != 1)) {
140 fprintf(stderr
, "Unable to extended '%s' to its full size.\n",
141 nvramtool_op_modifiers
[NVRAMTOOL_MOD_USE_CMOS_FILE
].param
);
147 FlushFileBuffers ((HANDLE
) _get_osfhandle (fd
));
151 cmos_default
= mmap(NULL
, CMOS_SIZE
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, fd
, 0);
152 if (cmos_default
== MAP_FAILED
) {
153 fprintf(stderr
, "Couldn't map '%s'\n", nvramtool_op_modifiers
[NVRAMTOOL_MOD_USE_CMOS_FILE
].param
);
158 /* Switch to memory based CMOS access. */
160 select_hal(HAL_MEMORY
, cmos_default
);
163 register_cmos_layout_get_fn(fn
);
164 op_fns
[nvramtool_op
.op
]();
169 /****************************************************************************
174 * Show version information for this program.
175 ****************************************************************************/
176 static void op_show_version(void)
178 printf("This is %s version %s.\n", prog_name
, prog_version
);
181 /****************************************************************************
186 * Show a usage message for this program.
187 ****************************************************************************/
188 static void op_show_usage(void)
193 /****************************************************************************
194 * op_lbtable_show_info
198 * If ARG is present, show coreboot table information specified by ARG.
199 * Else show all possible values for ARG.
200 ****************************************************************************/
201 static void op_lbtable_show_info(void)
203 if (nvramtool_op
.param
== NULL
)
204 list_lbtable_choices();
207 list_lbtable_item(nvramtool_op
.param
);
211 /****************************************************************************
216 * Do low-level dump of coreboot table.
217 ****************************************************************************/
218 static void op_lbtable_dump(void)
224 /****************************************************************************
225 * op_show_param_values
229 * Show all possible values for parameter NAME.
230 ****************************************************************************/
231 static void op_show_param_values(void)
234 list_param_enums(nvramtool_op
.param
);
237 /****************************************************************************
238 * op_cmos_show_one_param
242 * Show parameter NAME. If -n is specified, show value only. Else show name
244 ****************************************************************************/
245 static void op_cmos_show_one_param(void)
250 result
= list_one_param(nvramtool_op
.param
,
251 !nvramtool_op_modifiers
252 [NVRAMTOOL_MOD_SHOW_VALUE_ONLY
].found
);
253 cmos_checksum_verify();
259 /****************************************************************************
260 * op_cmos_show_all_params
264 * Show names and values for all parameters.
265 ****************************************************************************/
266 static void op_cmos_show_all_params(void)
271 result
= list_all_params();
272 cmos_checksum_verify();
278 /****************************************************************************
279 * op_cmos_set_one_param
283 * Set parameter NAME to VALUE.
284 ****************************************************************************/
285 static void op_cmos_set_one_param(void)
287 const char *name
, *value
;
291 /* Separate 'NAME=VALUE' syntax into two strings representing NAME and
294 parse_assignment(nvramtool_op
.param
, &name
, &value
);
296 set_one_param(name
, value
);
299 /****************************************************************************
300 * op_cmos_set_params_stdin
304 * Set parameters according to standard input.
305 ****************************************************************************/
306 static void op_cmos_set_params_stdin(void)
312 /****************************************************************************
313 * op_cmos_set_params_file
317 * Set parameters according to INPUT_FILE.
318 ****************************************************************************/
319 static void op_cmos_set_params_file(void)
323 if ((f
= fopen(nvramtool_op
.param
, "r")) == NULL
) {
324 fprintf(stderr
, "%s: Can not open file %s for reading: %s\n",
325 prog_name
, nvramtool_op
.param
, strerror(errno
));
334 /****************************************************************************
339 * If VALUE is present, set coreboot CMOS checksum to VALUE. Else show
341 ****************************************************************************/
342 static void op_cmos_checksum(void)
348 if (nvramtool_op
.param
== NULL
) {
350 checksum
= cmos_checksum_read();
352 printf("0x%x\n", checksum
);
354 checksum
= convert_checksum_value(nvramtool_op
.param
);
356 cmos_checksum_write(checksum
);
361 /****************************************************************************
366 * Write CMOS layout information to standard output.
367 ****************************************************************************/
368 static void op_show_layout(void)
371 write_cmos_layout(stdout
);
374 /****************************************************************************
379 * Write the contents of CMOS memory to a binary file.
380 ****************************************************************************/
381 static void op_write_cmos_dump(void)
383 unsigned char data
[CMOS_SIZE
];
386 if ((f
= fopen(nvramtool_op
.param
, "wb")) == NULL
) {
387 fprintf(stderr
, "%s: Can not open file %s for writing: %s\n",
388 prog_name
, nvramtool_op
.param
, strerror(errno
));
396 if (fwrite(data
, 1, CMOS_SIZE
, f
) != CMOS_SIZE
) {
397 fprintf(stderr
, "%s: Error writing CMOS data to file %s: %s\n",
398 prog_name
, nvramtool_op
.param
, strerror(errno
));
405 /****************************************************************************
410 * Read binary data from a file and write the data to CMOS memory.
411 ****************************************************************************/
412 static void op_read_cmos_dump(void)
414 unsigned char data
[CMOS_SIZE
];
418 if ((f
= fopen(nvramtool_op
.param
, "rb")) == NULL
) {
419 fprintf(stderr
, "%s: Can not open file %s for reading: %s\n",
420 prog_name
, nvramtool_op
.param
, strerror(errno
));
424 if ((nr_bytes
= fread(data
, 1, CMOS_SIZE
, f
)) != CMOS_SIZE
) {
426 "%s: Error: Only able to read %d bytes of CMOS data "
427 "from file %s. CMOS data is unchanged.\n", prog_name
,
428 (int)nr_bytes
, nvramtool_op
.param
);
434 cmos_write_all(data
);
438 /****************************************************************************
439 * op_show_cmos_hex_dump
443 * Write a hex dump of CMOS memory to standard output.
444 ****************************************************************************/
445 static void op_show_cmos_hex_dump(void)
447 unsigned char data
[CMOS_SIZE
];
452 hexdump(data
, CMOS_SIZE
, 0, stdout
, &cmos_dump_format
);
455 /****************************************************************************
456 * op_show_cmos_dumpfile
460 * Read binary data from a file (presumably a CMOS dump file) and display a
461 * hex dump of the CMOS data from the file.
462 ****************************************************************************/
463 static void op_show_cmos_dumpfile(void)
465 unsigned char data
[CMOS_SIZE
];
469 if ((f
= fopen(nvramtool_op
.param
, "r")) == NULL
) {
470 fprintf(stderr
, "%s: Can not open file %s for reading: %s\n",
471 prog_name
, nvramtool_op
.param
, strerror(errno
));
475 nr_bytes
= fread(data
, 1, CMOS_SIZE
, f
);
477 hexdump(data
, nr_bytes
, 0, stdout
, &cmos_dump_format
);
480 /****************************************************************************
483 * Attempt to list one CMOS parameter given by 'name'. 'show_name' is a
484 * boolean value indicating whether the parameter name should be displayed
485 * along with its value. Return 1 if error was encountered. Else return OK.
486 ****************************************************************************/
487 static int list_one_param(const char name
[], int show_name
)
489 const cmos_entry_t
*e
;
491 if (is_checksum_name(name
) || ((e
= find_cmos_entry(name
)) == NULL
)) {
492 fprintf(stderr
, "%s: CMOS parameter %s not found.\n", prog_name
,
497 if (e
->config
== CMOS_ENTRY_RESERVED
) {
498 fprintf(stderr
, "%s: Parameter %s is reserved.\n", prog_name
,
503 return (list_cmos_entry(e
, show_name
) != 0);
506 /****************************************************************************
509 * Attempt to list all CMOS parameters. Return 1 if error was encountered.
511 ****************************************************************************/
512 static int list_all_params(void)
514 const cmos_entry_t
*e
;
519 for (e
= first_cmos_entry(); e
!= NULL
; e
= next_cmos_entry(e
)) {
520 if ((e
->config
== CMOS_ENTRY_RESERVED
)
521 || is_checksum_name(e
->name
))
524 if (list_cmos_entry(e
, TRUE
))
531 /****************************************************************************
534 * List all possible values for CMOS parameter given by 'name'.
535 ****************************************************************************/
536 static void list_param_enums(const char name
[])
538 const cmos_entry_t
*e
;
539 const cmos_enum_t
*p
;
541 if (is_checksum_name(name
) || (e
= find_cmos_entry(name
)) == NULL
) {
542 fprintf(stderr
, "%s: CMOS parameter %s not found.\n", prog_name
,
548 case CMOS_ENTRY_ENUM
:
549 for (p
= first_cmos_enum_id(e
->config_id
);
550 p
!= NULL
; p
= next_cmos_enum_id(p
))
551 printf("%s\n", p
->text
);
556 printf("Parameter %s requires a %u-bit unsigned integer.\n",
560 case CMOS_ENTRY_STRING
:
561 printf("Parameter %s requires a %u-byte string.\n", name
,
565 case CMOS_ENTRY_RESERVED
:
566 printf("Parameter %s is reserved.\n", name
);
574 /****************************************************************************
577 * Set the CMOS parameter given by 'name' to 'value'. The 'name' parameter
578 * is case-sensitive. If we are setting an enum parameter, then 'value' is
579 * interpreted as a case-sensitive string that must match the option name
580 * exactly. If we are setting a 'hex' parameter, then 'value' is treated as
581 * a string representation of an unsigned integer that may be specified in
582 * decimal, hex, or octal.
583 ****************************************************************************/
584 static void set_one_param(const char name
[], const char value
[])
586 const cmos_entry_t
*e
;
587 unsigned long long n
;
589 if (is_checksum_name(name
) || (e
= find_cmos_entry(name
)) == NULL
) {
590 fprintf(stderr
, "%s: CMOS parameter %s not found.\n", prog_name
,
595 switch (prepare_cmos_write(e
, value
, &n
)) {
599 case CMOS_OP_BAD_ENUM_VALUE
:
600 fprintf(stderr
, "%s: Bad value for parameter %s.", prog_name
,
604 case CMOS_OP_NEGATIVE_INT
:
606 "%s: This program does not support assignment of negative "
607 "numbers to coreboot parameters.", prog_name
);
610 case CMOS_OP_INVALID_INT
:
611 fprintf(stderr
, "%s: %s is not a valid integer.", prog_name
,
615 case CMOS_OP_RESERVED
:
617 "%s: Can not modify reserved coreboot parameter %s.",
621 case CMOS_OP_VALUE_TOO_WIDE
:
623 "%s: Can not write value %s to CMOS parameter %s that is "
624 "only %d bits wide.", prog_name
, value
, name
,
628 case CMOS_OP_NO_MATCHING_ENUM
:
630 "%s: coreboot parameter %s has no matching enums.",
634 case CMOS_AREA_OUT_OF_RANGE
:
636 "%s: The CMOS area specified by the layout info for "
637 "coreboot parameter %s is out of range.", prog_name
,
641 case CMOS_AREA_OVERLAPS_RTC
:
643 "%s: The CMOS area specified by the layout info for "
644 "coreboot parameter %s overlaps the realtime clock area.",
648 case CMOS_AREA_TOO_WIDE
:
650 "%s: The CMOS area specified by the layout info for "
651 "coreboot parameter %s is too wide.", prog_name
, name
);
656 "%s: Unknown error encountered while attempting to modify "
657 "coreboot parameter %s.", prog_name
, name
);
661 /* write the value to nonvolatile RAM */
664 cmos_checksum_write(cmos_checksum_compute());
669 fprintf(stderr
, " CMOS write not performed.\n");
673 /****************************************************************************
676 * Set coreboot parameters according to the contents of file 'f'.
677 ****************************************************************************/
678 static void set_params(FILE * f
)
679 { /* First process the input file. Then perform writes only if there were
680 * no problems processing the input. Either all values will be written
681 * successfully or no values will be written.
683 do_cmos_writes(process_input_file(f
));
686 /****************************************************************************
689 * Parse the string 'arg' (which supposedly represents an assignment) into a
690 * NAME and a VALUE. If 'arg' does not conform to the proper assignment
691 * syntax, exit with a usage message. Otherwise, on return, 'arg' is broken
692 * into substrings representing NAME and VALUE, and *name and *value are set
693 * to point to these two substrings.
694 ****************************************************************************/
695 static void parse_assignment(char arg
[], const char **name
, const char **value
)
697 static const size_t N_MATCHES
= 4;
698 regmatch_t match
[N_MATCHES
];
701 compile_reg_expr(REG_EXTENDED
| REG_NEWLINE
, assignment_regex
, &assignment
);
703 /* Does 'arg' conform to proper assignment syntax? If not, exit with a
706 if (regexec(&assignment
, arg
, N_MATCHES
, match
, 0))
709 /* Ok, we found a valid assignment. Break it into two strings
710 * representing NAME and VALUE.
712 arg
[match
[1].rm_eo
] = '\0';
713 arg
[match
[2].rm_eo
] = '\0';
714 *name
= &arg
[match
[1].rm_so
];
715 *value
= &arg
[match
[2].rm_so
];
717 regfree(&assignment
);
720 /****************************************************************************
723 * Attempt to list the CMOS entry represented by 'e'. 'show_name' is a
724 * boolean value indicating whether the parameter name should be displayed
725 * along with its value. On success, return OK. On error, print an error
726 * message and return 1.
727 ****************************************************************************/
728 static int list_cmos_entry(const cmos_entry_t
* e
, int show_name
)
730 const cmos_enum_t
*p
;
731 unsigned long long value
;
734 /* sanity check CMOS entry */
735 switch (prepare_cmos_read(e
)) {
739 case CMOS_OP_RESERVED
:
741 "%s: Cannot access reserved CMOS area (for %s).\n",
745 case CMOS_AREA_OUT_OF_RANGE
:
747 "%s: Can not read coreboot parameter %s because "
748 "layout info specifies out of range CMOS area.\n",
752 case CMOS_AREA_OVERLAPS_RTC
:
754 "%s: Can not read coreboot parameter %s because "
755 "layout info specifies CMOS area that overlaps realtime "
756 "clock area.\n", prog_name
, e
->name
);
759 case CMOS_AREA_TOO_WIDE
:
761 "%s: Can not read coreboot parameter %s because "
762 "layout info specifies CMOS area that is too wide.\n",
768 "%s: Unknown error encountered while attempting to "
769 "read coreboot parameter %s\n", prog_name
, e
->name
);
773 /* read the value from CMOS */
775 value
= cmos_read(e
);
778 /* display the value */
780 case CMOS_ENTRY_ENUM
:
781 if ((p
= find_cmos_enum(e
->config_id
, value
)) == NULL
) {
783 printf("# Bad value -> %s = 0x%llx\n", e
->name
,
786 printf("Bad value -> 0x%llx\n", value
);
789 printf("%s = %s\n", e
->name
, p
->text
);
791 printf("%s\n", p
->text
);
798 printf("%s = 0x%llx\n", e
->name
, value
);
800 printf("0x%llx\n", value
);
804 case CMOS_ENTRY_STRING
:
805 w
= (char *)(unsigned long)value
;
807 if(!isprint((int)(unsigned char)*w
)) {
809 printf("# Bad value -> %s\n", e
->name
);
811 printf("Bad value\n");
820 printf("%s = %s\n", e
->name
,
821 (char *)(unsigned long)value
);
823 printf("%s\n", (char *)(unsigned long)value
);
826 free((void *)(unsigned long)value
);
830 case CMOS_ENTRY_RESERVED
:
838 /****************************************************************************
839 * convert_checksum_value
841 * 'value' is the string representation of a checksum value that the user
842 * wishes to set using the -c option. Convert the string to a 16-bit
843 * unsigned integer and return the result. Exit with an error message if
844 * 'value' is invalid.
845 ****************************************************************************/
846 static uint16_t convert_checksum_value(const char value
[])
853 for (p
= value
; isspace((int)(unsigned char)*p
); p
++) ;
855 negative
= (*p
== '-');
856 n
= strtoul(value
, (char **)&p
, 0);
860 "%s: Checksum value %s is not a valid integer.\n",
867 "%s: Checksum must be an unsigned integer.\n",
872 result
= (uint16_t) n
;
876 "%s: Checksum value must fit within 16 bits.\n",