xref: /aosp_15_r20/external/coreboot/util/nvramtool/cli/nvramtool.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <fcntl.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #ifndef __MINGW32__
7 #include <sys/mman.h>
8 #endif
9 #include "common.h"
10 #include "opts.h"
11 #include "lbtable.h"
12 #include "layout.h"
13 #include "accessors/layout-text.h"
14 #include "input_file.h"
15 #include "cmos_ops.h"
16 #include "cmos_lowlevel.h"
17 #include "reg_expr.h"
18 #include "hexdump.h"
19 #include "cbfs.h"
20 #ifdef __MINGW32__
21 #include <windows.h>
22 #endif
23 
24 typedef void (*op_fn_t) (void);
25 
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[]);
52 
53 static const op_fn_t op_fns[] = { op_show_version,
54 	op_show_usage,
55 	op_lbtable_show_info,
56 	op_lbtable_dump,
57 	op_show_param_values,
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,
63 	op_cmos_checksum,
64 	op_show_layout,
65 	op_write_cmos_dump,
66 	op_read_cmos_dump,
67 	op_show_cmos_hex_dump,
68 	op_show_cmos_dumpfile,
69 	op_write_cmos_layout_bin,
70 	op_write_cmos_layout_header
71 };
72 
op_write_cmos_layout_bin(void)73 static void op_write_cmos_layout_bin(void)
74 {
75 	get_layout_from_file();
76 	write_cmos_output_bin(nvramtool_op.param);
77 }
78 
op_write_cmos_layout_header(void)79 static void op_write_cmos_layout_header(void)
80 {
81 	get_layout_from_file();
82 	write_cmos_layout_header(nvramtool_op.param);
83 }
84 
85 static const hexdump_format_t cmos_dump_format =
86     { 16, 2, "", " | ", " ", " | ", '.' };
87 
88 /****************************************************************************
89  * main
90  ****************************************************************************/
main(int argc,char * argv[])91 int main(int argc, char *argv[])
92 {
93 	void *cmos_default = NULL;
94 	cmos_layout_get_fn_t fn = get_layout_from_cmos_table;
95 
96 	parse_nvramtool_args(argc, argv);
97 
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");
106 				exit(1);
107 			}
108 		}
109 		fn = get_layout_from_cbfs_file;
110 	}
111 
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;
119 	}
120 
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) {
124 		struct stat fd_stat;
125 		int fd;
126 
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);
129 			exit(1);
130 		}
131 
132 		if (fstat(fd, &fd_stat) == -1) {
133 			fprintf(stderr, "Couldn't stat '%s'\n", nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param);
134 			exit(1);
135 		}
136 
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);
142 				exit(1);
143 			}
144 #ifndef __MINGW32__
145 			fsync(fd);
146 #else
147 			FlushFileBuffers ((HANDLE) _get_osfhandle (fd));
148 #endif
149 		}
150 
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);
154 			exit(1);
155 		}
156 	}
157 
158 	/* Switch to memory based CMOS access. */
159 	if (cmos_default) {
160 		select_hal(HAL_MEMORY, cmos_default);
161 	}
162 
163 	register_cmos_layout_get_fn(fn);
164 	op_fns[nvramtool_op.op]();
165 
166 	return 0;
167 }
168 
169 /****************************************************************************
170  * op_show_version
171  *
172  * -v
173  *
174  * Show version information for this program.
175  ****************************************************************************/
op_show_version(void)176 static void op_show_version(void)
177 {
178 	printf("This is %s version %s.\n", prog_name, prog_version);
179 }
180 
181 /****************************************************************************
182  * op_show_usage
183  *
184  * -h
185  *
186  * Show a usage message for this program.
187  ****************************************************************************/
op_show_usage(void)188 static void op_show_usage(void)
189 {
190 	usage(stdout);
191 }
192 
193 /****************************************************************************
194  * op_lbtable_show_info
195  *
196  * -l [ARG]
197  *
198  * If ARG is present, show coreboot table information specified by ARG.
199  * Else show all possible values for ARG.
200  ****************************************************************************/
op_lbtable_show_info(void)201 static void op_lbtable_show_info(void)
202 {
203 	if (nvramtool_op.param == NULL)
204 		list_lbtable_choices();
205 	else {
206 		get_lbtable();
207 		list_lbtable_item(nvramtool_op.param);
208 	}
209 }
210 
211 /****************************************************************************
212  * op_lbtable_dump
213  *
214  * -d
215  *
216  * Do low-level dump of coreboot table.
217  ****************************************************************************/
op_lbtable_dump(void)218 static void op_lbtable_dump(void)
219 {
220 	get_lbtable();
221 	dump_lbtable();
222 }
223 
224 /****************************************************************************
225  * op_show_param_values
226  *
227  * -e NAME option
228  *
229  * Show all possible values for parameter NAME.
230  ****************************************************************************/
op_show_param_values(void)231 static void op_show_param_values(void)
232 {
233 	get_cmos_layout();
234 	list_param_enums(nvramtool_op.param);
235 }
236 
237 /****************************************************************************
238  * op_cmos_show_one_param
239  *
240  * [-n] -r NAME
241  *
242  * Show parameter NAME.  If -n is specified, show value only.  Else show name
243  * and value.
244  ****************************************************************************/
op_cmos_show_one_param(void)245 static void op_cmos_show_one_param(void)
246 {
247 	int result;
248 
249 	get_cmos_layout();
250 	result = list_one_param(nvramtool_op.param,
251 				!nvramtool_op_modifiers
252 				[NVRAMTOOL_MOD_SHOW_VALUE_ONLY].found);
253 	cmos_checksum_verify();
254 
255 	if (result)
256 		exit(1);
257 }
258 
259 /****************************************************************************
260  * op_cmos_show_all_params
261  *
262  * -a
263  *
264  * Show names and values for all parameters.
265  ****************************************************************************/
op_cmos_show_all_params(void)266 static void op_cmos_show_all_params(void)
267 {
268 	int result;
269 
270 	get_cmos_layout();
271 	result = list_all_params();
272 	cmos_checksum_verify();
273 
274 	if (result)
275 		exit(1);
276 }
277 
278 /****************************************************************************
279  * op_cmos_set_one_param
280  *
281  * -w NAME=VALUE
282  *
283  * Set parameter NAME to VALUE.
284  ****************************************************************************/
op_cmos_set_one_param(void)285 static void op_cmos_set_one_param(void)
286 {
287 	const char *name, *value;
288 
289 	get_cmos_layout();
290 
291 	/* Separate 'NAME=VALUE' syntax into two strings representing NAME and
292 	 * VALUE.
293 	 */
294 	parse_assignment(nvramtool_op.param, &name, &value);
295 
296 	set_one_param(name, value);
297 }
298 
299 /****************************************************************************
300  * op_cmos_set_params_stdin
301  *
302  * -i
303  *
304  * Set parameters according to standard input.
305  ****************************************************************************/
op_cmos_set_params_stdin(void)306 static void op_cmos_set_params_stdin(void)
307 {
308 	get_cmos_layout();
309 	set_params(stdin);
310 }
311 
312 /****************************************************************************
313  * op_cmos_set_params_file
314  *
315  * -p INPUT_FILE
316  *
317  * Set parameters according to INPUT_FILE.
318  ****************************************************************************/
op_cmos_set_params_file(void)319 static void op_cmos_set_params_file(void)
320 {
321 	FILE *f;
322 
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));
326 		exit(1);
327 	}
328 
329 	get_cmos_layout();
330 	set_params(f);
331 	fclose(f);
332 }
333 
334 /****************************************************************************
335  * op_cmos_checksum
336  *
337  * -c [VALUE]
338  *
339  * If VALUE is present, set coreboot CMOS checksum to VALUE.  Else show
340  * checksum value.
341  ****************************************************************************/
op_cmos_checksum(void)342 static void op_cmos_checksum(void)
343 {
344 	uint16_t checksum;
345 
346 	get_cmos_layout();
347 
348 	if (nvramtool_op.param == NULL) {
349 		set_iopl(3);
350 		checksum = cmos_checksum_read();
351 		set_iopl(0);
352 		printf("0x%x\n", checksum);
353 	} else {
354 		checksum = convert_checksum_value(nvramtool_op.param);
355 		set_iopl(3);
356 		cmos_checksum_write(checksum);
357 		set_iopl(0);
358 	}
359 }
360 
361 /****************************************************************************
362  * op_show_layout
363  *
364  * -Y
365  *
366  * Write CMOS layout information to standard output.
367  ****************************************************************************/
op_show_layout(void)368 static void op_show_layout(void)
369 {
370 	get_cmos_layout();
371 	write_cmos_layout(stdout);
372 }
373 
374 /****************************************************************************
375  * op_write_cmos_dump
376  *
377  * -b OUTPUT_FILE
378  *
379  * Write the contents of CMOS memory to a binary file.
380  ****************************************************************************/
op_write_cmos_dump(void)381 static void op_write_cmos_dump(void)
382 {
383 	unsigned char data[CMOS_SIZE];
384 	FILE *f;
385 
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));
389 		exit(1);
390 	}
391 
392 	set_iopl(3);
393 	cmos_read_all(data);
394 	set_iopl(0);
395 
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));
399 		exit(1);
400 	}
401 
402 	fclose(f);
403 }
404 
405 /****************************************************************************
406  * op_read_cmos_dump
407  *
408  * -B INPUT_FILE
409  *
410  * Read binary data from a file and write the data to CMOS memory.
411  ****************************************************************************/
op_read_cmos_dump(void)412 static void op_read_cmos_dump(void)
413 {
414 	unsigned char data[CMOS_SIZE];
415 	size_t nr_bytes;
416 	FILE *f;
417 
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));
421 		exit(1);
422 	}
423 
424 	if ((nr_bytes = fread(data, 1, CMOS_SIZE, f)) != CMOS_SIZE) {
425 		fprintf(stderr,
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);
429 		exit(1);
430 	}
431 
432 	fclose(f);
433 	set_iopl(3);
434 	cmos_write_all(data);
435 	set_iopl(0);
436 }
437 
438 /****************************************************************************
439  * op_show_cmos_hex_dump
440  *
441  * -x
442  *
443  * Write a hex dump of CMOS memory to standard output.
444  ****************************************************************************/
op_show_cmos_hex_dump(void)445 static void op_show_cmos_hex_dump(void)
446 {
447 	unsigned char data[CMOS_SIZE];
448 
449 	set_iopl(3);
450 	cmos_read_all(data);
451 	set_iopl(0);
452 	hexdump(data, CMOS_SIZE, 0, stdout, &cmos_dump_format);
453 }
454 
455 /****************************************************************************
456  * op_show_cmos_dumpfile
457  *
458  * -X DUMP_FILE
459  *
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  ****************************************************************************/
op_show_cmos_dumpfile(void)463 static void op_show_cmos_dumpfile(void)
464 {
465 	unsigned char data[CMOS_SIZE];
466 	size_t nr_bytes;
467 	FILE *f;
468 
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));
472 		exit(1);
473 	}
474 
475 	nr_bytes = fread(data, 1, CMOS_SIZE, f);
476 	fclose(f);
477 	hexdump(data, nr_bytes, 0, stdout, &cmos_dump_format);
478 }
479 
480 /****************************************************************************
481  * list_one_param
482  *
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  ****************************************************************************/
list_one_param(const char name[],int show_name)487 static int list_one_param(const char name[], int show_name)
488 {
489 	const cmos_entry_t *e;
490 
491 	if (is_checksum_name(name) || ((e = find_cmos_entry(name)) == NULL)) {
492 		fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name,
493 			name);
494 		exit(1);
495 	}
496 
497 	if (e->config == CMOS_ENTRY_RESERVED) {
498 		fprintf(stderr, "%s: Parameter %s is reserved.\n", prog_name,
499 			name);
500 		exit(1);
501 	}
502 
503 	return (list_cmos_entry(e, show_name) != 0);
504 }
505 
506 /****************************************************************************
507  * list_all_params
508  *
509  * Attempt to list all CMOS parameters.  Return 1 if error was encountered.
510  * Else return OK.
511  ****************************************************************************/
list_all_params(void)512 static int list_all_params(void)
513 {
514 	const cmos_entry_t *e;
515 	int result;
516 
517 	result = OK;
518 
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))
522 			continue;
523 
524 		if (list_cmos_entry(e, TRUE))
525 			result = 1;
526 	}
527 
528 	return result;
529 }
530 
531 /****************************************************************************
532  * list_param_enums
533  *
534  * List all possible values for CMOS parameter given by 'name'.
535  ****************************************************************************/
list_param_enums(const char name[])536 static void list_param_enums(const char name[])
537 {
538 	const cmos_entry_t *e;
539 	const cmos_enum_t *p;
540 
541 	if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL) {
542 		fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name,
543 			name);
544 		exit(1);
545 	}
546 
547 	switch (e->config) {
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);
552 
553 		break;
554 
555 	case CMOS_ENTRY_HEX:
556 		printf("Parameter %s requires a %u-bit unsigned integer.\n",
557 		       name, e->length);
558 		break;
559 
560 	case CMOS_ENTRY_STRING:
561 		printf("Parameter %s requires a %u-byte string.\n", name,
562 		       e->length / 8);
563 		break;
564 
565 	case CMOS_ENTRY_RESERVED:
566 		printf("Parameter %s is reserved.\n", name);
567 		break;
568 
569 	default:
570 		BUG();
571 	}
572 }
573 
574 /****************************************************************************
575  * set_one_param
576  *
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  ****************************************************************************/
set_one_param(const char name[],const char value[])584 static void set_one_param(const char name[], const char value[])
585 {
586 	const cmos_entry_t *e;
587 	unsigned long long n;
588 
589 	if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL) {
590 		fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name,
591 			name);
592 		exit(1);
593 	}
594 
595 	switch (prepare_cmos_write(e, value, &n)) {
596 	case OK:
597 		break;
598 
599 	case CMOS_OP_BAD_ENUM_VALUE:
600 		fprintf(stderr, "%s: Bad value for parameter %s.", prog_name,
601 			name);
602 		goto fail;
603 
604 	case CMOS_OP_NEGATIVE_INT:
605 		fprintf(stderr,
606 			"%s: This program does not support assignment of negative "
607 			"numbers to coreboot parameters.", prog_name);
608 		goto fail;
609 
610 	case CMOS_OP_INVALID_INT:
611 		fprintf(stderr, "%s: %s is not a valid integer.", prog_name,
612 			value);
613 		goto fail;
614 
615 	case CMOS_OP_RESERVED:
616 		fprintf(stderr,
617 			"%s: Can not modify reserved coreboot parameter %s.",
618 			prog_name, name);
619 		goto fail;
620 
621 	case CMOS_OP_VALUE_TOO_WIDE:
622 		fprintf(stderr,
623 			"%s: Can not write value %s to CMOS parameter %s that is "
624 			"only %d bits wide.", prog_name, value, name,
625 			e->length);
626 		goto fail;
627 
628 	case CMOS_OP_NO_MATCHING_ENUM:
629 		fprintf(stderr,
630 			"%s: coreboot parameter %s has no matching enums.",
631 			prog_name, name);
632 		goto fail;
633 
634 	case CMOS_AREA_OUT_OF_RANGE:
635 		fprintf(stderr,
636 			"%s: The CMOS area specified by the layout info for "
637 			"coreboot parameter %s is out of range.", prog_name,
638 			name);
639 		goto fail;
640 
641 	case CMOS_AREA_OVERLAPS_RTC:
642 		fprintf(stderr,
643 			"%s: The CMOS area specified by the layout info for "
644 			"coreboot parameter %s overlaps the realtime clock area.",
645 			prog_name, name);
646 		goto fail;
647 
648 	case CMOS_AREA_TOO_WIDE:
649 		fprintf(stderr,
650 			"%s: The CMOS area specified by the layout info for "
651 			"coreboot parameter %s is too wide.", prog_name, name);
652 		goto fail;
653 
654 	default:
655 		fprintf(stderr,
656 			"%s: Unknown error encountered while attempting to modify "
657 			"coreboot parameter %s.", prog_name, name);
658 		goto fail;
659 	}
660 
661 	/* write the value to nonvolatile RAM */
662 	set_iopl(3);
663 	cmos_write(e, n);
664 	cmos_checksum_write(cmos_checksum_compute());
665 	set_iopl(0);
666 	return;
667 
668       fail:
669 	fprintf(stderr, "  CMOS write not performed.\n");
670 	exit(1);
671 }
672 
673 /****************************************************************************
674  * set_params
675  *
676  * Set coreboot parameters according to the contents of file 'f'.
677  ****************************************************************************/
set_params(FILE * f)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.
682 				 */
683 	do_cmos_writes(process_input_file(f));
684 }
685 
686 /****************************************************************************
687  * parse_assignment
688  *
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  ****************************************************************************/
parse_assignment(char arg[],const char ** name,const char ** value)695 static void parse_assignment(char arg[], const char **name, const char **value)
696 {
697 	static const size_t N_MATCHES = 4;
698 	regmatch_t match[N_MATCHES];
699 	regex_t assignment;
700 
701 	compile_reg_expr(REG_EXTENDED | REG_NEWLINE, assignment_regex, &assignment);
702 
703 	/* Does 'arg' conform to proper assignment syntax?  If not, exit with a
704 	 * usage message.
705 	 */
706 	if (regexec(&assignment, arg, N_MATCHES, match, 0))
707 		usage(stderr);
708 
709 	/* Ok, we found a valid assignment.  Break it into two strings
710 	 * representing NAME and VALUE.
711 	 */
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];
716 
717 	regfree(&assignment);
718 }
719 
720 /****************************************************************************
721  * list_cmos_entry
722  *
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  ****************************************************************************/
list_cmos_entry(const cmos_entry_t * e,int show_name)728 static int list_cmos_entry(const cmos_entry_t * e, int show_name)
729 {
730 	const cmos_enum_t *p;
731 	unsigned long long value;
732 	char *w;
733 
734 	/* sanity check CMOS entry */
735 	switch (prepare_cmos_read(e)) {
736 	case OK:
737 		break;
738 
739 	case CMOS_OP_RESERVED:
740 		fprintf(stderr,
741 			"%s: Cannot access reserved CMOS area (for %s).\n",
742 			prog_name, e->name);
743 		return 1;
744 
745 	case CMOS_AREA_OUT_OF_RANGE:
746 		fprintf(stderr,
747 			"%s: Can not read coreboot parameter %s because "
748 			"layout info specifies out of range CMOS area.\n",
749 			prog_name, e->name);
750 		return 1;
751 
752 	case CMOS_AREA_OVERLAPS_RTC:
753 		fprintf(stderr,
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);
757 		return 1;
758 
759 	case CMOS_AREA_TOO_WIDE:
760 		fprintf(stderr,
761 			"%s: Can not read coreboot parameter %s because "
762 			"layout info specifies CMOS area that is too wide.\n",
763 			prog_name, e->name);
764 		return 1;
765 
766 	default:
767 		fprintf(stderr,
768 			"%s: Unknown error encountered while attempting to "
769 			"read coreboot parameter %s\n", prog_name, e->name);
770 		return 1;
771 	}
772 
773 	/* read the value from CMOS */
774 	set_iopl(3);
775 	value = cmos_read(e);
776 	set_iopl(0);
777 
778 	/* display the value */
779 	switch (e->config) {
780 	case CMOS_ENTRY_ENUM:
781 		if ((p = find_cmos_enum(e->config_id, value)) == NULL) {
782 			if (show_name)
783 				printf("# Bad value -> %s = 0x%llx\n", e->name,
784 				       value);
785 			else
786 				printf("Bad value -> 0x%llx\n", value);
787 		} else {
788 			if (show_name)
789 				printf("%s = %s\n", e->name, p->text);
790 			else
791 				printf("%s\n", p->text);
792 		}
793 
794 		break;
795 
796 	case CMOS_ENTRY_HEX:
797 		if (show_name)
798 			printf("%s = 0x%llx\n", e->name, value);
799 		else
800 			printf("0x%llx\n", value);
801 
802 		break;
803 
804 	case CMOS_ENTRY_STRING:
805 		w = (char *)(unsigned long)value;
806 		while (*w) {
807 			if(!isprint((int)(unsigned char)*w)) {
808 				if (show_name)
809 					printf("# Bad value -> %s\n", e->name);
810 				else
811 					printf("Bad value\n");
812 				break;
813 			}
814 			w++;
815 		}
816 
817 		if (!*w) {
818 
819 			if (show_name)
820 				printf("%s = %s\n", e->name,
821 				       (char *)(unsigned long)value);
822 			else
823 				printf("%s\n", (char *)(unsigned long)value);
824 		}
825 
826 		free((void *)(unsigned long)value);
827 
828 		break;
829 
830 	case CMOS_ENTRY_RESERVED:
831 	default:
832 		BUG();
833 	}
834 
835 	return OK;
836 }
837 
838 /****************************************************************************
839  * convert_checksum_value
840  *
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  ****************************************************************************/
convert_checksum_value(const char value[])846 static uint16_t convert_checksum_value(const char value[])
847 {
848 	unsigned long n;
849 	const char *p;
850 	uint16_t result;
851 	int negative;
852 
853 	for (p = value; isspace((int)(unsigned char)*p); p++) ;
854 
855 	negative = (*p == '-');
856 	n = strtoul(value, (char **)&p, 0);
857 
858 	if (*p) {
859 		fprintf(stderr,
860 			"%s: Checksum value %s is not a valid integer.\n",
861 			prog_name, value);
862 		exit(1);
863 	}
864 
865 	if (negative) {
866 		fprintf(stderr,
867 			"%s: Checksum must be an unsigned integer.\n",
868 			prog_name);
869 		exit(1);
870 	}
871 
872 	result = (uint16_t) n;
873 
874 	if (result != n) {
875 		fprintf(stderr,
876 			"%s: Checksum value must fit within 16 bits.\n",
877 			prog_name);
878 		exit(1);
879 	}
880 
881 	return result;
882 }
883