blob: cb717513aed5a8eeff476bd74ed637abeb03d942 [file] [log] [blame]
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001/*****************************************************************************\
Uwe Hermann6e565942008-03-01 19:06:32 +00002 * nvramtool.c
Stefan Reinauer6540ae52007-07-12 16:35:42 +00003 *****************************************************************************
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 *
Uwe Hermann6e565942008-03-01 19:06:32 +000010 * This file is part of nvramtool, a utility for reading/writing coreboot
Stefan Reinauerf527e702008-01-18 15:33:49 +000011 * parameters and displaying information from the coreboot table.
Uwe Hermann6e565942008-03-01 19:06:32 +000012 * For details, see http://coreboot.org/nvramtool.
Stefan Reinauer6540ae52007-07-12 16:35:42 +000013 *
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.,
Stefan Reinauerac7a2d22009-09-23 21:53:25 +000028 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
Stefan Reinauer6540ae52007-07-12 16:35:42 +000029\*****************************************************************************/
30
Patrick Georgi202be7b2011-01-21 07:29:40 +000031#include <fcntl.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <sys/mman.h>
Stefan Reinauer6540ae52007-07-12 16:35:42 +000035#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"
Patrick Georgi269e9322011-01-21 07:24:08 +000045#include "cbfs.h"
Stefan Reinauer6540ae52007-07-12 16:35:42 +000046
47typedef void (*op_fn_t) (void);
48
Stefan Reinauer90b96b62010-01-13 21:00:23 +000049static void op_show_version(void);
50static void op_show_usage(void);
51static void op_lbtable_show_info(void);
52static void op_lbtable_dump(void);
53static void op_show_param_values(void);
54static void op_cmos_show_one_param(void);
55static void op_cmos_show_all_params(void);
56static void op_cmos_set_one_param(void);
57static void op_cmos_set_params_stdin(void);
58static void op_cmos_set_params_file(void);
59static void op_cmos_checksum(void);
60static void op_show_layout(void);
61static void op_write_cmos_dump(void);
62static void op_read_cmos_dump(void);
63static void op_show_cmos_hex_dump(void);
64static void op_show_cmos_dumpfile(void);
65static int list_one_param(const char name[], int show_name);
66static int list_all_params(void);
67static void list_param_enums(const char name[]);
68static void set_one_param(const char name[], const char value[]);
69static void set_params(FILE * f);
70static void parse_assignment(char arg[], const char **name, const char **value);
71static int list_cmos_entry(const cmos_entry_t * e, int show_name);
72static uint16_t convert_checksum_value(const char value[]);
Stefan Reinauer6540ae52007-07-12 16:35:42 +000073
Stefan Reinauer90b96b62010-01-13 21:00:23 +000074static 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};
Stefan Reinauer6540ae52007-07-12 16:35:42 +000091
92static const hexdump_format_t cmos_dump_format =
Patrick Georgi024ec852011-01-18 12:14:08 +000093 { 16, 2, "", " | ", " ", " | ", '.' };
Stefan Reinauer6540ae52007-07-12 16:35:42 +000094
95/****************************************************************************
96 * main
97 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +000098int main(int argc, char *argv[])
99{
Patrick Georgi202be7b2011-01-21 07:29:40 +0000100 void *cmos_default = NULL;
Patrick Georgi269e9322011-01-21 07:24:08 +0000101 cmos_layout_get_fn_t fn = get_layout_from_cmos_table;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000102
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000103 parse_nvramtool_args(argc, argv);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000104
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000105 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;
Patrick Georgi269e9322011-01-21 07:24:08 +0000109 } else if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_OPT_TABLE].found) {
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000110 fn = get_layout_from_cmos_table;
Patrick Georgi269e9322011-01-21 07:24:08 +0000111 } else if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CBFS_FILE].found) {
112 open_cbfs(nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CBFS_FILE].param);
Patrick Georgi202be7b2011-01-21 07:29:40 +0000113 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);
Patrick Georgi269e9322011-01-21 07:24:08 +0000126 exit(1);
127 }
Patrick Georgi202be7b2011-01-21 07:29:40 +0000128 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);
Patrick Georgi269e9322011-01-21 07:24:08 +0000145 fn = get_layout_from_cbfs_file;
146 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000147
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000148 register_cmos_layout_get_fn(fn);
149 op_fns[nvramtool_op.op] ();
150 return 0;
151}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000152
153/****************************************************************************
154 * op_show_version
155 *
156 * -v
157 *
158 * Show version information for this program.
159 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000160static void op_show_version(void)
161{
162 printf("This is %s version %s.\n", prog_name, prog_version);
163}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000164
165/****************************************************************************
166 * op_show_usage
167 *
168 * -h
169 *
170 * Show a usage message for this program.
171 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000172static void op_show_usage(void)
173{
174 usage(stdout);
175}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000176
177/****************************************************************************
178 * op_lbtable_show_info
179 *
180 * -l [ARG]
181 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000182 * If ARG is present, show coreboot table information specified by ARG.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000183 * Else show all possible values for ARG.
184 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000185static 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}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000194
195/****************************************************************************
196 * op_lbtable_dump
197 *
198 * -d
199 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000200 * Do low-level dump of coreboot table.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000201 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000202static void op_lbtable_dump(void)
203{
204 get_lbtable();
205 dump_lbtable();
206}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000207
208/****************************************************************************
209 * op_show_param_values
210 *
211 * -e NAME option
212 *
213 * Show all possible values for parameter NAME.
214 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000215static void op_show_param_values(void)
216{
217 get_cmos_layout();
218 list_param_enums(nvramtool_op.param);
219}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000220
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 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000229static void op_cmos_show_one_param(void)
230{
231 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000232
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000233 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();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000238
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000239 if (result)
240 exit(1);
241}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000242
243/****************************************************************************
244 * op_cmos_show_all_params
245 *
246 * -a
247 *
248 * Show names and values for all parameters.
249 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000250static void op_cmos_show_all_params(void)
251{
252 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000253
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000254 get_cmos_layout();
255 result = list_all_params();
256 cmos_checksum_verify();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000257
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000258 if (result)
259 exit(1);
260}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000261
262/****************************************************************************
263 * op_cmos_set_one_param
264 *
265 * -w NAME=VALUE
266 *
267 * Set parameter NAME to VALUE.
268 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000269static void op_cmos_set_one_param(void)
270{
271 const char *name, *value;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000272
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000273 get_cmos_layout();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000274
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000275 /* Separate 'NAME=VALUE' syntax into two strings representing NAME and
276 * VALUE.
277 */
278 parse_assignment(nvramtool_op.param, &name, &value);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000279
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000280 set_one_param(name, value);
281}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000282
283/****************************************************************************
284 * op_cmos_set_params_stdin
285 *
286 * -i
287 *
288 * Set parameters according to standard input.
289 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000290static void op_cmos_set_params_stdin(void)
291{
292 get_cmos_layout();
293 set_params(stdin);
294}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000295
296/****************************************************************************
297 * op_cmos_set_params_file
298 *
299 * -p INPUT_FILE
300 *
301 * Set parameters according to INPUT_FILE.
302 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000303static void op_cmos_set_params_file(void)
304{
305 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000306
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000307 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000312
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000313 get_cmos_layout();
314 set_params(f);
315 fclose(f);
316}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000317
318/****************************************************************************
319 * op_cmos_checksum
320 *
321 * -c [VALUE]
322 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000323 * If VALUE is present, set coreboot CMOS checksum to VALUE. Else show
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000324 * checksum value.
325 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000326static void op_cmos_checksum(void)
327{
328 uint16_t checksum;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000329
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000330 get_cmos_layout();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000331
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000332 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}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000344
345/****************************************************************************
346 * op_show_layout
347 *
348 * -Y
349 *
350 * Write CMOS layout information to standard output.
351 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000352static void op_show_layout(void)
353{
354 get_cmos_layout();
355 write_cmos_layout(stdout);
356}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000357
358/****************************************************************************
359 * op_write_cmos_dump
360 *
361 * -b OUTPUT_FILE
362 *
363 * Write the contents of CMOS memory to a binary file.
364 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000365static void op_write_cmos_dump(void)
366{
367 unsigned char data[CMOS_SIZE];
368 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000369
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000370 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000375
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000376 set_iopl(3);
377 cmos_read_all(data);
378 set_iopl(0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000379
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000380 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000385
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000386 fclose(f);
387}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000388
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 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000396static void op_read_cmos_dump(void)
397{
398 unsigned char data[CMOS_SIZE];
399 size_t nr_bytes;
400 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000401
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000402 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000407
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000408 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000415
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000416 fclose(f);
417 set_iopl(3);
418 cmos_write_all(data);
419 set_iopl(0);
420}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000421
422/****************************************************************************
423 * op_show_cmos_hex_dump
424 *
425 * -x
426 *
427 * Write a hex dump of CMOS memory to standard output.
428 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000429static void op_show_cmos_hex_dump(void)
430{
431 unsigned char data[CMOS_SIZE];
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000432
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000433 set_iopl(3);
434 cmos_read_all(data);
435 set_iopl(0);
436 hexdump(data, CMOS_SIZE, 0, stdout, &cmos_dump_format);
437}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000438
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 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000447static void op_show_cmos_dumpfile(void)
448{
449 unsigned char data[CMOS_SIZE];
450 size_t nr_bytes;
451 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000452
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000453 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000458
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000459 nr_bytes = fread(data, 1, CMOS_SIZE, f);
460 fclose(f);
461 hexdump(data, nr_bytes, 0, stdout, &cmos_dump_format);
462}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000463
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 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000471static int list_one_param(const char name[], int show_name)
472{
473 const cmos_entry_t *e;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000474
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000475 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000480
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000481 if (e->config == CMOS_ENTRY_RESERVED) {
482 fprintf(stderr, "%s: Parameter %s is reserved.\n", prog_name,
483 name);
484 exit(1);
485 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000486
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000487 return (list_cmos_entry(e, show_name) != 0);
488}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000489
490/****************************************************************************
491 * list_all_params
492 *
493 * Attempt to list all CMOS parameters. Return 1 if error was encountered.
494 * Else return OK.
495 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000496static int list_all_params(void)
497{
498 const cmos_entry_t *e;
499 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000500
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000501 result = OK;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000502
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000503 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000507
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000508 if (list_cmos_entry(e, TRUE))
509 result = 1;
510 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000511
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000512 return result;
513}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000514
515/****************************************************************************
516 * list_param_enums
517 *
518 * List all possible values for CMOS parameter given by 'name'.
519 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000520static void list_param_enums(const char name[])
521{
522 const cmos_entry_t *e;
523 const cmos_enum_t *p;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000524
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000525 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000530
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000531 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);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000536
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000537 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000538
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000539 case CMOS_ENTRY_HEX:
540 printf("Parameter %s requires a %u-bit unsigned integer.\n",
541 name, e->length);
542 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000543
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000544 case CMOS_ENTRY_STRING:
545 printf("Parameter %s requires a %u-byte string.\n", name,
546 e->length / 8);
547 break;
Stefan Reinauera67aab72008-09-27 10:08:28 +0000548
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000549 case CMOS_ENTRY_RESERVED:
550 printf("Parameter %s is reserved.\n", name);
551 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000552
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000553 default:
554 BUG();
555 }
556}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000557
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 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000568static void set_one_param(const char name[], const char value[])
569{
570 const cmos_entry_t *e;
571 unsigned long long n;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000572
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000573 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 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000578
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000579 switch (prepare_cmos_write(e, value, &n)) {
580 case OK:
581 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000582
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000583 case CMOS_OP_BAD_ENUM_VALUE:
584 fprintf(stderr, "%s: Bad value for parameter %s.", prog_name,
585 name);
586 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000587
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000588 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000593
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000594 case CMOS_OP_INVALID_INT:
595 fprintf(stderr, "%s: %s is not a valid integer.", prog_name,
596 value);
597 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000598
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000599 case CMOS_OP_RESERVED:
600 fprintf(stderr,
601 "%s: Can not modify reserved coreboot parameter %s.",
602 prog_name, name);
603 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000604
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000605 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000611
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000612 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000617
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000618 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000624
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000625 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000631
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000632 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000637
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000638 default:
639 fprintf(stderr,
640 "%s: Unknown error encountered while attempting to modify "
641 "coreboot parameter %s.", prog_name, name);
642 goto fail;
643 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000644
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000645 /* 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000651
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000652 fail:
653 fprintf(stderr, " CMOS write not performed.\n");
654 exit(1);
655}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000656
657/****************************************************************************
658 * set_params
659 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000660 * Set coreboot parameters according to the contents of file 'f'.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000661 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000662static 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}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000669
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 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000679static 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;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000684
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000685 compile_reg_exprs(REG_EXTENDED | REG_NEWLINE, 1, assignment_regex,
686 &assignment);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000687
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000688 /* Does 'arg' conform to proper assignment syntax? If not, exit with a
689 * usage message.
690 */
691 if (regexec(&assignment, arg, N_MATCHES, match, 0))
692 usage(stderr);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000693
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000694 /* Ok, we found a valid assignment. Break it into two strings
695 * representing NAME and VALUE.
696 */
697 arg[match[1].rm_eo] = '\0';
698 arg[match[2].rm_eo] = '\0';
699 *name = &arg[match[1].rm_so];
700 *value = &arg[match[2].rm_so];
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000701
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000702 free_reg_exprs(1, &assignment);
703}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000704
705/****************************************************************************
706 * list_cmos_entry
707 *
708 * Attempt to list the CMOS entry represented by 'e'. 'show_name' is a
709 * boolean value indicating whether the parameter name should be displayed
710 * along with its value. On success, return OK. On error, print an error
711 * message and return 1.
712 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000713static int list_cmos_entry(const cmos_entry_t * e, int show_name)
714{
715 const cmos_enum_t *p;
716 unsigned long long value;
Stefan Reinauer42944c32010-01-16 14:57:32 +0000717 char *w;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000718
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000719 /* sanity check CMOS entry */
720 switch (prepare_cmos_read(e)) {
721 case OK:
722 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000723
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000724 case CMOS_OP_RESERVED:
725 BUG();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000726
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000727 case CMOS_AREA_OUT_OF_RANGE:
728 fprintf(stderr,
729 "%s: Can not read coreboot parameter %s because "
730 "layout info specifies out of range CMOS area.\n",
731 prog_name, e->name);
732 return 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000733
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000734 case CMOS_AREA_OVERLAPS_RTC:
735 fprintf(stderr,
736 "%s: Can not read coreboot parameter %s because "
737 "layout info specifies CMOS area that overlaps realtime "
738 "clock area.\n", prog_name, e->name);
739 return 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000740
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000741 case CMOS_AREA_TOO_WIDE:
742 fprintf(stderr,
743 "%s: Can not read coreboot parameter %s because "
744 "layout info specifies CMOS area that is too wide.\n",
745 prog_name, e->name);
746 return 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000747
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000748 default:
749 fprintf(stderr,
750 "%s: Unknown error encountered while attempting to "
751 "read coreboot parameter %s\n", prog_name, e->name);
752 return 1;
753 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000754
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000755 /* read the value from CMOS */
756 set_iopl(3);
757 value = cmos_read(e);
758 set_iopl(0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000759
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000760 /* display the value */
761 switch (e->config) {
762 case CMOS_ENTRY_ENUM:
763 if ((p = find_cmos_enum(e->config_id, value)) == NULL) {
764 if (show_name)
765 printf("# Bad value -> %s = 0x%llx\n", e->name,
766 value);
767 else
768 printf("Bad value -> 0x%llx\n", value);
769 } else {
770 if (show_name)
771 printf("%s = %s\n", e->name, p->text);
772 else
773 printf("%s\n", p->text);
774 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000775
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000776 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000777
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000778 case CMOS_ENTRY_HEX:
779 if (show_name)
780 printf("%s = 0x%llx\n", e->name, value);
781 else
782 printf("0x%llx\n", value);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000783
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000784 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000785
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000786 case CMOS_ENTRY_STRING:
Stefan Reinauer42944c32010-01-16 14:57:32 +0000787 w = (char *)(unsigned long)value;
788 while (*w) {
789 if(!isprint(*w)) {
790 if (show_name)
791 printf("# Bad value -> %s\n", e->name);
792 else
793 printf("Bad value\n");
794 break;
795 }
796 w++;
797 }
798
799 if (!*w) {
800
801 if (show_name)
802 printf("%s = %s\n", e->name,
803 (char *)(unsigned long)value);
804 else
805 printf("%s\n", (char *)(unsigned long)value);
806 }
Stefan Reinauera67aab72008-09-27 10:08:28 +0000807
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000808 free((void *)(unsigned long)value);
Stefan Reinauera67aab72008-09-27 10:08:28 +0000809
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000810 break;
Stefan Reinauera67aab72008-09-27 10:08:28 +0000811
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000812 case CMOS_ENTRY_RESERVED:
813 default:
814 BUG();
815 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000816
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000817 return OK;
818}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000819
820/****************************************************************************
821 * convert_checksum_value
822 *
823 * 'value' is the string representation of a checksum value that the user
824 * wishes to set using the -c option. Convert the string to a 16-bit
825 * unsigned integer and return the result. Exit with an error message if
826 * 'value' is invalid.
827 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000828static uint16_t convert_checksum_value(const char value[])
829{
830 unsigned long n;
831 const char *p;
832 uint16_t result;
833 int negative;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000834
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000835 for (p = value; isspace(*p); p++) ;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000836
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000837 negative = (*p == '-');
838 n = strtoul(value, (char **)&p, 0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000839
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000840 if (*p) {
841 fprintf(stderr,
842 "%s: Checksum value %s is not a valid integer.\n",
843 prog_name, value);
844 exit(1);
845 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000846
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000847 if (negative) {
848 fprintf(stderr,
849 "%s: Checksum must be an unsigned integer.\n",
850 prog_name);
851 exit(1);
852 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000853
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000854 result = (uint16_t) n;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000855
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000856 if (result != n) {
857 fprintf(stderr,
858 "%s: Checksum value must fit within 16 bits.\n",
859 prog_name);
860 exit(1);
861 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000862
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000863 return result;
864}