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