/ util / nvramtool / cli / nvramtool.c
nvramtool.c
  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  
 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  
 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   ****************************************************************************/
 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   ****************************************************************************/
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   ****************************************************************************/
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   ****************************************************************************/
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   ****************************************************************************/
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   ****************************************************************************/
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   ****************************************************************************/
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   ****************************************************************************/
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   ****************************************************************************/
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   ****************************************************************************/
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   ****************************************************************************/
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   ****************************************************************************/
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   ****************************************************************************/
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   ****************************************************************************/
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   ****************************************************************************/
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   ****************************************************************************/
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   ****************************************************************************/
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   ****************************************************************************/
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   ****************************************************************************/
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   ****************************************************************************/
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   ****************************************************************************/
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   ****************************************************************************/
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   ****************************************************************************/
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   ****************************************************************************/
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   ****************************************************************************/
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  }