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