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