Add nvramtool -C option that takes a CBFS file as argument.
[coreboot.git] / util / nvramtool / nvramtool.c
1 /*****************************************************************************\
2  * nvramtool.c
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>.
7  *  UCRL-CODE-2003-012
8  *  All rights reserved.
9  *
10  *  This file is part of nvramtool, a utility for reading/writing coreboot
11  *  parameters and displaying information from the coreboot table.
12  *  For details, see http://coreboot.org/nvramtool.
13  *
14  *  Please also read the file DISCLAIMER which is included in this software
15  *  distribution.
16  *
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.
20  *
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  *
26  *  You should have received a copy of the GNU General Public License along
27  *  with this program; if not, write to the Free Software Foundation, Inc.,
28  *  51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
29 \*****************************************************************************/
30
31 #include "common.h"
32 #include "opts.h"
33 #include "lbtable.h"
34 #include "layout.h"
35 #include "layout_file.h"
36 #include "input_file.h"
37 #include "cmos_ops.h"
38 #include "cmos_lowlevel.h"
39 #include "reg_expr.h"
40 #include "hexdump.h"
41 #include "cbfs.h"
42
43 typedef void (*op_fn_t) (void);
44
45 static void op_show_version(void);
46 static void op_show_usage(void);
47 static void op_lbtable_show_info(void);
48 static void op_lbtable_dump(void);
49 static void op_show_param_values(void);
50 static void op_cmos_show_one_param(void);
51 static void op_cmos_show_all_params(void);
52 static void op_cmos_set_one_param(void);
53 static void op_cmos_set_params_stdin(void);
54 static void op_cmos_set_params_file(void);
55 static void op_cmos_checksum(void);
56 static void op_show_layout(void);
57 static void op_write_cmos_dump(void);
58 static void op_read_cmos_dump(void);
59 static void op_show_cmos_hex_dump(void);
60 static void op_show_cmos_dumpfile(void);
61 static int list_one_param(const char name[], int show_name);
62 static int list_all_params(void);
63 static void list_param_enums(const char name[]);
64 static void set_one_param(const char name[], const char value[]);
65 static void set_params(FILE * f);
66 static void parse_assignment(char arg[], const char **name, const char **value);
67 static int list_cmos_entry(const cmos_entry_t * e, int show_name);
68 static uint16_t convert_checksum_value(const char value[]);
69
70 static const op_fn_t op_fns[] = { op_show_version,
71         op_show_usage,
72         op_lbtable_show_info,
73         op_lbtable_dump,
74         op_show_param_values,
75         op_cmos_show_one_param,
76         op_cmos_show_all_params,
77         op_cmos_set_one_param,
78         op_cmos_set_params_stdin,
79         op_cmos_set_params_file,
80         op_cmos_checksum,
81         op_show_layout,
82         op_write_cmos_dump,
83         op_read_cmos_dump,
84         op_show_cmos_hex_dump,
85         op_show_cmos_dumpfile
86 };
87
88 static const hexdump_format_t cmos_dump_format =
89     { 16, 2, "", " | ", " ", " | ", '.' };
90
91 /****************************************************************************
92  * main
93  ****************************************************************************/
94 int main(int argc, char *argv[])
95 {
96         cmos_layout_get_fn_t fn = get_layout_from_cmos_table;
97
98         parse_nvramtool_args(argc, argv);
99
100         if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_LAYOUT_FILE].found) {
101                 set_layout_filename(nvramtool_op_modifiers
102                                     [NVRAMTOOL_MOD_USE_CMOS_LAYOUT_FILE].param);
103                 fn = get_layout_from_file;
104         } else if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_OPT_TABLE].found) {
105                 fn = get_layout_from_cmos_table;
106         } else if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CBFS_FILE].found) {
107                 open_cbfs(nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CBFS_FILE].param);
108                 void *cmosdefault = cbfs_find_file("cmos.default", CBFS_COMPONENT_CMOS_DEFAULT, NULL);
109                 if (cmosdefault == NULL) {
110                         printf("Need a cmos.default in the CBFS image for now.\n");
111                         exit(1);
112                 }
113                 select_hal(HAL_MEMORY, cmosdefault);
114                 fn = get_layout_from_cbfs_file;
115         }
116
117         register_cmos_layout_get_fn(fn);
118         op_fns[nvramtool_op.op] ();
119         return 0;
120 }
121
122 /****************************************************************************
123  * op_show_version
124  *
125  * -v
126  *
127  * Show version information for this program.
128  ****************************************************************************/
129 static void op_show_version(void)
130 {
131         printf("This is %s version %s.\n", prog_name, prog_version);
132 }
133
134 /****************************************************************************
135  * op_show_usage
136  *
137  * -h
138  *
139  * Show a usage message for this program.
140  ****************************************************************************/
141 static void op_show_usage(void)
142 {
143         usage(stdout);
144 }
145
146 /****************************************************************************
147  * op_lbtable_show_info
148  *
149  * -l [ARG]
150  *
151  * If ARG is present, show coreboot table information specified by ARG.
152  * Else show all possible values for ARG.
153  ****************************************************************************/
154 static void op_lbtable_show_info(void)
155 {
156         if (nvramtool_op.param == NULL)
157                 list_lbtable_choices();
158         else {
159                 get_lbtable();
160                 list_lbtable_item(nvramtool_op.param);
161         }
162 }
163
164 /****************************************************************************
165  * op_lbtable_dump
166  *
167  * -d
168  *
169  * Do low-level dump of coreboot table.
170  ****************************************************************************/
171 static void op_lbtable_dump(void)
172 {
173         get_lbtable();
174         dump_lbtable();
175 }
176
177 /****************************************************************************
178  * op_show_param_values
179  *
180  * -e NAME option
181  *
182  * Show all possible values for parameter NAME.
183  ****************************************************************************/
184 static void op_show_param_values(void)
185 {
186         get_cmos_layout();
187         list_param_enums(nvramtool_op.param);
188 }
189
190 /****************************************************************************
191  * op_cmos_show_one_param
192  *
193  * [-n] -r NAME
194  *
195  * Show parameter NAME.  If -n is specified, show value only.  Else show name
196  * and value.
197  ****************************************************************************/
198 static void op_cmos_show_one_param(void)
199 {
200         int result;
201
202         get_cmos_layout();
203         result = list_one_param(nvramtool_op.param,
204                                 !nvramtool_op_modifiers
205                                 [NVRAMTOOL_MOD_SHOW_VALUE_ONLY].found);
206         cmos_checksum_verify();
207
208         if (result)
209                 exit(1);
210 }
211
212 /****************************************************************************
213  * op_cmos_show_all_params
214  *
215  * -a
216  *
217  * Show names and values for all parameters.
218  ****************************************************************************/
219 static void op_cmos_show_all_params(void)
220 {
221         int result;
222
223         get_cmos_layout();
224         result = list_all_params();
225         cmos_checksum_verify();
226
227         if (result)
228                 exit(1);
229 }
230
231 /****************************************************************************
232  * op_cmos_set_one_param
233  *
234  * -w NAME=VALUE
235  *
236  * Set parameter NAME to VALUE.
237  ****************************************************************************/
238 static void op_cmos_set_one_param(void)
239 {
240         const char *name, *value;
241
242         get_cmos_layout();
243
244         /* Separate 'NAME=VALUE' syntax into two strings representing NAME and
245          * VALUE.
246          */
247         parse_assignment(nvramtool_op.param, &name, &value);
248
249         set_one_param(name, value);
250 }
251
252 /****************************************************************************
253  * op_cmos_set_params_stdin
254  *
255  * -i
256  *
257  * Set parameters according to standard input.
258  ****************************************************************************/
259 static void op_cmos_set_params_stdin(void)
260 {
261         get_cmos_layout();
262         set_params(stdin);
263 }
264
265 /****************************************************************************
266  * op_cmos_set_params_file
267  *
268  * -p INPUT_FILE
269  *
270  * Set parameters according to INPUT_FILE.
271  ****************************************************************************/
272 static void op_cmos_set_params_file(void)
273 {
274         FILE *f;
275
276         if ((f = fopen(nvramtool_op.param, "r")) == NULL) {
277                 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
278                         prog_name, nvramtool_op.param, strerror(errno));
279                 exit(1);
280         }
281
282         get_cmos_layout();
283         set_params(f);
284         fclose(f);
285 }
286
287 /****************************************************************************
288  * op_cmos_checksum
289  *
290  * -c [VALUE]
291  *
292  * If VALUE is present, set coreboot CMOS checksum to VALUE.  Else show
293  * checksum value.
294  ****************************************************************************/
295 static void op_cmos_checksum(void)
296 {
297         uint16_t checksum;
298
299         get_cmos_layout();
300
301         if (nvramtool_op.param == NULL) {
302                 set_iopl(3);
303                 checksum = cmos_checksum_read();
304                 set_iopl(0);
305                 printf("0x%x\n", checksum);
306         } else {
307                 checksum = convert_checksum_value(nvramtool_op.param);
308                 set_iopl(3);
309                 cmos_checksum_write(checksum);
310                 set_iopl(0);
311         }
312 }
313
314 /****************************************************************************
315  * op_show_layout
316  *
317  * -Y
318  *
319  * Write CMOS layout information to standard output.
320  ****************************************************************************/
321 static void op_show_layout(void)
322 {
323         get_cmos_layout();
324         write_cmos_layout(stdout);
325 }
326
327 /****************************************************************************
328  * op_write_cmos_dump
329  *
330  * -b OUTPUT_FILE
331  *
332  * Write the contents of CMOS memory to a binary file.
333  ****************************************************************************/
334 static void op_write_cmos_dump(void)
335 {
336         unsigned char data[CMOS_SIZE];
337         FILE *f;
338
339         if ((f = fopen(nvramtool_op.param, "w")) == NULL) {
340                 fprintf(stderr, "%s: Can not open file %s for writing: %s\n",
341                         prog_name, nvramtool_op.param, strerror(errno));
342                 exit(1);
343         }
344
345         set_iopl(3);
346         cmos_read_all(data);
347         set_iopl(0);
348
349         if (fwrite(data, 1, CMOS_SIZE, f) != CMOS_SIZE) {
350                 fprintf(stderr, "%s: Error writing CMOS data to file %s: %s\n",
351                         prog_name, nvramtool_op.param, strerror(errno));
352                 exit(1);
353         }
354
355         fclose(f);
356 }
357
358 /****************************************************************************
359  * op_read_cmos_dump
360  *
361  * -B INPUT_FILE
362  *
363  * Read binary data from a file and write the data to CMOS memory.
364  ****************************************************************************/
365 static void op_read_cmos_dump(void)
366 {
367         unsigned char data[CMOS_SIZE];
368         size_t nr_bytes;
369         FILE *f;
370
371         if ((f = fopen(nvramtool_op.param, "r")) == NULL) {
372                 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
373                         prog_name, nvramtool_op.param, strerror(errno));
374                 exit(1);
375         }
376
377         if ((nr_bytes = fread(data, 1, CMOS_SIZE, f)) != CMOS_SIZE) {
378                 fprintf(stderr,
379                         "%s: Error: Only able to read %d bytes of CMOS data "
380                         "from file %s.  CMOS data is unchanged.\n", prog_name,
381                         (int)nr_bytes, nvramtool_op.param);
382                 exit(1);
383         }
384
385         fclose(f);
386         set_iopl(3);
387         cmos_write_all(data);
388         set_iopl(0);
389 }
390
391 /****************************************************************************
392  * op_show_cmos_hex_dump
393  *
394  * -x
395  *
396  * Write a hex dump of CMOS memory to standard output.
397  ****************************************************************************/
398 static void op_show_cmos_hex_dump(void)
399 {
400         unsigned char data[CMOS_SIZE];
401
402         set_iopl(3);
403         cmos_read_all(data);
404         set_iopl(0);
405         hexdump(data, CMOS_SIZE, 0, stdout, &cmos_dump_format);
406 }
407
408 /****************************************************************************
409  * op_show_cmos_dumpfile
410  *
411  * -X DUMP_FILE
412  *
413  * Read binary data from a file (presumably a CMOS dump file) and display a
414  * hex dump of the CMOS data from the file.
415  ****************************************************************************/
416 static void op_show_cmos_dumpfile(void)
417 {
418         unsigned char data[CMOS_SIZE];
419         size_t nr_bytes;
420         FILE *f;
421
422         if ((f = fopen(nvramtool_op.param, "r")) == NULL) {
423                 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
424                         prog_name, nvramtool_op.param, strerror(errno));
425                 exit(1);
426         }
427
428         nr_bytes = fread(data, 1, CMOS_SIZE, f);
429         fclose(f);
430         hexdump(data, nr_bytes, 0, stdout, &cmos_dump_format);
431 }
432
433 /****************************************************************************
434  * list_one_param
435  *
436  * Attempt to list one CMOS parameter given by 'name'.  'show_name' is a
437  * boolean value indicating whether the parameter name should be displayed
438  * along with its value.  Return 1 if error was encountered.  Else return OK.
439  ****************************************************************************/
440 static int list_one_param(const char name[], int show_name)
441 {
442         const cmos_entry_t *e;
443
444         if (is_checksum_name(name) || ((e = find_cmos_entry(name)) == NULL)) {
445                 fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name,
446                         name);
447                 exit(1);
448         }
449
450         if (e->config == CMOS_ENTRY_RESERVED) {
451                 fprintf(stderr, "%s: Parameter %s is reserved.\n", prog_name,
452                         name);
453                 exit(1);
454         }
455
456         return (list_cmos_entry(e, show_name) != 0);
457 }
458
459 /****************************************************************************
460  * list_all_params
461  *
462  * Attempt to list all CMOS parameters.  Return 1 if error was encountered.
463  * Else return OK.
464  ****************************************************************************/
465 static int list_all_params(void)
466 {
467         const cmos_entry_t *e;
468         int result;
469
470         result = OK;
471
472         for (e = first_cmos_entry(); e != NULL; e = next_cmos_entry(e)) {
473                 if ((e->config == CMOS_ENTRY_RESERVED)
474                     || is_checksum_name(e->name))
475                         continue;
476
477                 if (list_cmos_entry(e, TRUE))
478                         result = 1;
479         }
480
481         return result;
482 }
483
484 /****************************************************************************
485  * list_param_enums
486  *
487  * List all possible values for CMOS parameter given by 'name'.
488  ****************************************************************************/
489 static void list_param_enums(const char name[])
490 {
491         const cmos_entry_t *e;
492         const cmos_enum_t *p;
493
494         if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL) {
495                 fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name,
496                         name);
497                 exit(1);
498         }
499
500         switch (e->config) {
501         case CMOS_ENTRY_ENUM:
502                 for (p = first_cmos_enum_id(e->config_id);
503                      p != NULL; p = next_cmos_enum_id(p))
504                         printf("%s\n", p->text);
505
506                 break;
507
508         case CMOS_ENTRY_HEX:
509                 printf("Parameter %s requires a %u-bit unsigned integer.\n",
510                        name, e->length);
511                 break;
512
513         case CMOS_ENTRY_STRING:
514                 printf("Parameter %s requires a %u-byte string.\n", name,
515                        e->length / 8);
516                 break;
517
518         case CMOS_ENTRY_RESERVED:
519                 printf("Parameter %s is reserved.\n", name);
520                 break;
521
522         default:
523                 BUG();
524         }
525 }
526
527 /****************************************************************************
528  * set_one_param
529  *
530  * Set the CMOS parameter given by 'name' to 'value'.  The 'name' parameter
531  * is case-sensitive.  If we are setting an enum parameter, then 'value' is
532  * interpreted as a case-sensitive string that must match the option name
533  * exactly.  If we are setting a 'hex' parameter, then 'value' is treated as
534  * a string representation of an unsigned integer that may be specified in
535  * decimal, hex, or octal.
536  ****************************************************************************/
537 static void set_one_param(const char name[], const char value[])
538 {
539         const cmos_entry_t *e;
540         unsigned long long n;
541
542         if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL) {
543                 fprintf(stderr, "%s: CMOS parameter %s not found.", prog_name,
544                         name);
545                 exit(1);
546         }
547
548         switch (prepare_cmos_write(e, value, &n)) {
549         case OK:
550                 break;
551
552         case CMOS_OP_BAD_ENUM_VALUE:
553                 fprintf(stderr, "%s: Bad value for parameter %s.", prog_name,
554                         name);
555                 goto fail;
556
557         case CMOS_OP_NEGATIVE_INT:
558                 fprintf(stderr,
559                         "%s: This program does not support assignment of negative "
560                         "numbers to coreboot parameters.", prog_name);
561                 goto fail;
562
563         case CMOS_OP_INVALID_INT:
564                 fprintf(stderr, "%s: %s is not a valid integer.", prog_name,
565                         value);
566                 goto fail;
567
568         case CMOS_OP_RESERVED:
569                 fprintf(stderr,
570                         "%s: Can not modify reserved coreboot parameter %s.",
571                         prog_name, name);
572                 goto fail;
573
574         case CMOS_OP_VALUE_TOO_WIDE:
575                 fprintf(stderr,
576                         "%s: Can not write value %s to CMOS parameter %s that is "
577                         "only %d bits wide.", prog_name, value, name,
578                         e->length);
579                 goto fail;
580
581         case CMOS_OP_NO_MATCHING_ENUM:
582                 fprintf(stderr,
583                         "%s: coreboot parameter %s has no matching enums.",
584                         prog_name, name);
585                 goto fail;
586
587         case CMOS_AREA_OUT_OF_RANGE:
588                 fprintf(stderr,
589                         "%s: The CMOS area specified by the layout info for "
590                         "coreboot parameter %s is out of range.", prog_name,
591                         name);
592                 goto fail;
593
594         case CMOS_AREA_OVERLAPS_RTC:
595                 fprintf(stderr,
596                         "%s: The CMOS area specified by the layout info for "
597                         "coreboot parameter %s overlaps the realtime clock area.",
598                         prog_name, name);
599                 goto fail;
600
601         case CMOS_AREA_TOO_WIDE:
602                 fprintf(stderr,
603                         "%s: The CMOS area specified by the layout info for "
604                         "coreboot parameter %s is too wide.", prog_name, name);
605                 goto fail;
606
607         default:
608                 fprintf(stderr,
609                         "%s: Unknown error encountered while attempting to modify "
610                         "coreboot parameter %s.", prog_name, name);
611                 goto fail;
612         }
613
614         /* write the value to nonvolatile RAM */
615         set_iopl(3);
616         cmos_write(e, n);
617         cmos_checksum_write(cmos_checksum_compute());
618         set_iopl(0);
619         return;
620
621       fail:
622         fprintf(stderr, "  CMOS write not performed.\n");
623         exit(1);
624 }
625
626 /****************************************************************************
627  * set_params
628  *
629  * Set coreboot parameters according to the contents of file 'f'.
630  ****************************************************************************/
631 static void set_params(FILE * f)
632 {                               /* First process the input file.  Then perform writes only if there were
633                                  * no problems processing the input.  Either all values will be written
634                                  * successfully or no values will be written.
635                                  */
636         do_cmos_writes(process_input_file(f));
637 }
638
639 /****************************************************************************
640  * parse_assignment
641  *
642  * Parse the string 'arg' (which supposedly represents an assignment) into a
643  * NAME and a VALUE.  If 'arg' does not conform to the proper assignment
644  * syntax, exit with a usage message.  Otherwise, on return, 'arg' is broken
645  * into substrings representing NAME and VALUE, and *name and *value are set
646  * to point to these two substrings.
647  ****************************************************************************/
648 static void parse_assignment(char arg[], const char **name, const char **value)
649 {
650         static const size_t N_MATCHES = 4;
651         regmatch_t match[N_MATCHES];
652         regex_t assignment;
653
654         compile_reg_exprs(REG_EXTENDED | REG_NEWLINE, 1, assignment_regex,
655                           &assignment);
656
657         /* Does 'arg' conform to proper assignment syntax?  If not, exit with a
658          * usage message.
659          */
660         if (regexec(&assignment, arg, N_MATCHES, match, 0))
661                 usage(stderr);
662
663         /* Ok, we found a valid assignment.  Break it into two strings
664          * representing NAME and VALUE.
665          */
666         arg[match[1].rm_eo] = '\0';
667         arg[match[2].rm_eo] = '\0';
668         *name = &arg[match[1].rm_so];
669         *value = &arg[match[2].rm_so];
670
671         free_reg_exprs(1, &assignment);
672 }
673
674 /****************************************************************************
675  * list_cmos_entry
676  *
677  * Attempt to list the CMOS entry represented by 'e'.  'show_name' is a
678  * boolean value indicating whether the parameter name should be displayed
679  * along with its value.  On success, return OK.  On error, print an error
680  * message and return 1.
681  ****************************************************************************/
682 static int list_cmos_entry(const cmos_entry_t * e, int show_name)
683 {
684         const cmos_enum_t *p;
685         unsigned long long value;
686         char *w;
687
688         /* sanity check CMOS entry */
689         switch (prepare_cmos_read(e)) {
690         case OK:
691                 break;
692
693         case CMOS_OP_RESERVED:
694                 BUG();
695
696         case CMOS_AREA_OUT_OF_RANGE:
697                 fprintf(stderr,
698                         "%s: Can not read coreboot parameter %s because "
699                         "layout info specifies out of range CMOS area.\n",
700                         prog_name, e->name);
701                 return 1;
702
703         case CMOS_AREA_OVERLAPS_RTC:
704                 fprintf(stderr,
705                         "%s: Can not read coreboot parameter %s because "
706                         "layout info specifies CMOS area that overlaps realtime "
707                         "clock area.\n", prog_name, e->name);
708                 return 1;
709
710         case CMOS_AREA_TOO_WIDE:
711                 fprintf(stderr,
712                         "%s: Can not read coreboot parameter %s because "
713                         "layout info specifies CMOS area that is too wide.\n",
714                         prog_name, e->name);
715                 return 1;
716
717         default:
718                 fprintf(stderr,
719                         "%s: Unknown error encountered while attempting to "
720                         "read coreboot parameter %s\n", prog_name, e->name);
721                 return 1;
722         }
723
724         /* read the value from CMOS */
725         set_iopl(3);
726         value = cmos_read(e);
727         set_iopl(0);
728
729         /* display the value */
730         switch (e->config) {
731         case CMOS_ENTRY_ENUM:
732                 if ((p = find_cmos_enum(e->config_id, value)) == NULL) {
733                         if (show_name)
734                                 printf("# Bad value -> %s = 0x%llx\n", e->name,
735                                        value);
736                         else
737                                 printf("Bad value -> 0x%llx\n", value);
738                 } else {
739                         if (show_name)
740                                 printf("%s = %s\n", e->name, p->text);
741                         else
742                                 printf("%s\n", p->text);
743                 }
744
745                 break;
746
747         case CMOS_ENTRY_HEX:
748                 if (show_name)
749                         printf("%s = 0x%llx\n", e->name, value);
750                 else
751                         printf("0x%llx\n", value);
752
753                 break;
754
755         case CMOS_ENTRY_STRING:
756                 w = (char *)(unsigned long)value;
757                 while (*w) {
758                         if(!isprint(*w)) {
759                                 if (show_name)
760                                         printf("# Bad value -> %s\n", e->name);
761                                 else
762                                         printf("Bad value\n");
763                                 break;
764                         }
765                         w++;
766                 }
767
768                 if (!*w) {
769
770                         if (show_name)
771                                 printf("%s = %s\n", e->name,
772                                        (char *)(unsigned long)value);
773                         else
774                                 printf("%s\n", (char *)(unsigned long)value);
775                 }
776
777                 free((void *)(unsigned long)value);
778
779                 break;
780
781         case CMOS_ENTRY_RESERVED:
782         default:
783                 BUG();
784         }
785
786         return OK;
787 }
788
789 /****************************************************************************
790  * convert_checksum_value
791  *
792  * 'value' is the string representation of a checksum value that the user
793  * wishes to set using the -c option.  Convert the string to a 16-bit
794  * unsigned integer and return the result.  Exit with an error message if
795  * 'value' is invalid.
796  ****************************************************************************/
797 static uint16_t convert_checksum_value(const char value[])
798 {
799         unsigned long n;
800         const char *p;
801         uint16_t result;
802         int negative;
803
804         for (p = value; isspace(*p); p++) ;
805
806         negative = (*p == '-');
807         n = strtoul(value, (char **)&p, 0);
808
809         if (*p) {
810                 fprintf(stderr,
811                         "%s: Checksum value %s is not a valid integer.\n",
812                         prog_name, value);
813                 exit(1);
814         }
815
816         if (negative) {
817                 fprintf(stderr,
818                         "%s: Checksum must be an unsigned integer.\n",
819                         prog_name);
820                 exit(1);
821         }
822
823         result = (uint16_t) n;
824
825         if (result != n) {
826                 fprintf(stderr,
827                         "%s: Checksum value must fit within 16 bits.\n",
828                         prog_name);
829                 exit(1);
830         }
831
832         return result;
833 }