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