blob: bcb10bbf34bce9ab47c124c0b7be14cffd076c17 [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"
Patrick Georgi49a74432011-01-28 07:50:33 +000039#include "accessors/layout-text.h"
Stefan Reinauer6540ae52007-07-12 16:35:42 +000040#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
Mathias Krause943b8b52011-03-08 12:58:16 +0000105 /* 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) {
Patrick Georgi269e9322011-01-21 07:24:08 +0000108 open_cbfs(nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CBFS_FILE].param);
Patrick Georgi202be7b2011-01-21 07:29:40 +0000109 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 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000116 fn = get_layout_from_cbfs_file;
Patrick Georgi202be7b2011-01-21 07:29:40 +0000117 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000118
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. */
Patrick Georgi202be7b2011-01-21 07:29:40 +0000130 if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].found) {
Patrick Georgi202be7b2011-01-21 07:29:40 +0000131 struct stat fd_stat;
Mathias Krause943b8b52011-03-08 12:58:16 +0000132 int fd;
133
134 if ((fd = open(nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param, O_RDWR | O_CREAT, 0666)) < 0) {
Patrick Georgi202be7b2011-01-21 07:29:40 +0000135 fprintf(stderr, "Couldn't open '%s'\n", nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param);
Patrick Georgi269e9322011-01-21 07:24:08 +0000136 exit(1);
137 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000138
Patrick Georgi202be7b2011-01-21 07:29:40 +0000139 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 }
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700143
Patrick Georgi202be7b2011-01-21 07:29:40 +0000144 if (fd_stat.st_size < 128) {
145 lseek(fd, 127, SEEK_SET);
Stefan Reinauera7b296d2011-11-14 12:40:34 -0800146 if (write(fd, "\0", 1) != 1) {
147 fprintf(stderr, "Unable to extended '%s' to its full size.\n",
148 nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param);
149 exit(1);
150 }
Patrick Georgi202be7b2011-01-21 07:29:40 +0000151 fsync(fd);
152 }
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700153
Patrick Georgi202be7b2011-01-21 07:29:40 +0000154 cmos_default = mmap(NULL, 128, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
155 if (cmos_default == MAP_FAILED) {
156 fprintf(stderr, "Couldn't map '%s'\n", nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param);
157 exit(1);
158 }
159 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000160
161 /* Switch to memory based CMOS access. */
Patrick Georgi202be7b2011-01-21 07:29:40 +0000162 if (cmos_default) {
163 select_hal(HAL_MEMORY, cmos_default);
Patrick Georgi269e9322011-01-21 07:24:08 +0000164 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000165
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000166 register_cmos_layout_get_fn(fn);
Mathias Krause943b8b52011-03-08 12:58:16 +0000167 op_fns[nvramtool_op.op]();
168
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000169 return 0;
170}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000171
172/****************************************************************************
173 * op_show_version
174 *
175 * -v
176 *
177 * Show version information for this program.
178 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000179static void op_show_version(void)
180{
181 printf("This is %s version %s.\n", prog_name, prog_version);
182}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000183
184/****************************************************************************
185 * op_show_usage
186 *
187 * -h
188 *
189 * Show a usage message for this program.
190 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000191static void op_show_usage(void)
192{
193 usage(stdout);
194}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000195
196/****************************************************************************
197 * op_lbtable_show_info
198 *
199 * -l [ARG]
200 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000201 * If ARG is present, show coreboot table information specified by ARG.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000202 * Else show all possible values for ARG.
203 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000204static void op_lbtable_show_info(void)
205{
206 if (nvramtool_op.param == NULL)
207 list_lbtable_choices();
208 else {
209 get_lbtable();
210 list_lbtable_item(nvramtool_op.param);
211 }
212}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000213
214/****************************************************************************
215 * op_lbtable_dump
216 *
217 * -d
218 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000219 * Do low-level dump of coreboot table.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000220 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000221static void op_lbtable_dump(void)
222{
223 get_lbtable();
224 dump_lbtable();
225}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000226
227/****************************************************************************
228 * op_show_param_values
229 *
230 * -e NAME option
231 *
232 * Show all possible values for parameter NAME.
233 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000234static void op_show_param_values(void)
235{
236 get_cmos_layout();
237 list_param_enums(nvramtool_op.param);
238}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000239
240/****************************************************************************
241 * op_cmos_show_one_param
242 *
243 * [-n] -r NAME
244 *
245 * Show parameter NAME. If -n is specified, show value only. Else show name
246 * and value.
247 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000248static void op_cmos_show_one_param(void)
249{
250 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000251
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000252 get_cmos_layout();
253 result = list_one_param(nvramtool_op.param,
254 !nvramtool_op_modifiers
255 [NVRAMTOOL_MOD_SHOW_VALUE_ONLY].found);
256 cmos_checksum_verify();
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_show_all_params
264 *
265 * -a
266 *
267 * Show names and values for all parameters.
268 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000269static void op_cmos_show_all_params(void)
270{
271 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000272
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000273 get_cmos_layout();
274 result = list_all_params();
275 cmos_checksum_verify();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000276
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000277 if (result)
278 exit(1);
279}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000280
281/****************************************************************************
282 * op_cmos_set_one_param
283 *
284 * -w NAME=VALUE
285 *
286 * Set parameter NAME to VALUE.
287 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000288static void op_cmos_set_one_param(void)
289{
290 const char *name, *value;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000291
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000292 get_cmos_layout();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000293
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000294 /* Separate 'NAME=VALUE' syntax into two strings representing NAME and
295 * VALUE.
296 */
297 parse_assignment(nvramtool_op.param, &name, &value);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000298
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000299 set_one_param(name, value);
300}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000301
302/****************************************************************************
303 * op_cmos_set_params_stdin
304 *
305 * -i
306 *
307 * Set parameters according to standard input.
308 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000309static void op_cmos_set_params_stdin(void)
310{
311 get_cmos_layout();
312 set_params(stdin);
313}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000314
315/****************************************************************************
316 * op_cmos_set_params_file
317 *
318 * -p INPUT_FILE
319 *
320 * Set parameters according to INPUT_FILE.
321 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000322static void op_cmos_set_params_file(void)
323{
324 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000325
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000326 if ((f = fopen(nvramtool_op.param, "r")) == NULL) {
327 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
328 prog_name, nvramtool_op.param, strerror(errno));
329 exit(1);
330 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000331
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000332 get_cmos_layout();
333 set_params(f);
334 fclose(f);
335}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000336
337/****************************************************************************
338 * op_cmos_checksum
339 *
340 * -c [VALUE]
341 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000342 * If VALUE is present, set coreboot CMOS checksum to VALUE. Else show
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000343 * checksum value.
344 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000345static void op_cmos_checksum(void)
346{
347 uint16_t checksum;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000348
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000349 get_cmos_layout();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000350
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000351 if (nvramtool_op.param == NULL) {
352 set_iopl(3);
353 checksum = cmos_checksum_read();
354 set_iopl(0);
355 printf("0x%x\n", checksum);
356 } else {
357 checksum = convert_checksum_value(nvramtool_op.param);
358 set_iopl(3);
359 cmos_checksum_write(checksum);
360 set_iopl(0);
361 }
362}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000363
364/****************************************************************************
365 * op_show_layout
366 *
367 * -Y
368 *
369 * Write CMOS layout information to standard output.
370 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000371static void op_show_layout(void)
372{
373 get_cmos_layout();
374 write_cmos_layout(stdout);
375}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000376
377/****************************************************************************
378 * op_write_cmos_dump
379 *
380 * -b OUTPUT_FILE
381 *
382 * Write the contents of CMOS memory to a binary file.
383 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000384static void op_write_cmos_dump(void)
385{
386 unsigned char data[CMOS_SIZE];
387 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000388
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000389 if ((f = fopen(nvramtool_op.param, "w")) == NULL) {
390 fprintf(stderr, "%s: Can not open file %s for writing: %s\n",
391 prog_name, nvramtool_op.param, strerror(errno));
392 exit(1);
393 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000394
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000395 set_iopl(3);
396 cmos_read_all(data);
397 set_iopl(0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000398
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000399 if (fwrite(data, 1, CMOS_SIZE, f) != CMOS_SIZE) {
400 fprintf(stderr, "%s: Error writing CMOS data to file %s: %s\n",
401 prog_name, nvramtool_op.param, strerror(errno));
402 exit(1);
403 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000404
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000405 fclose(f);
406}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000407
408/****************************************************************************
409 * op_read_cmos_dump
410 *
411 * -B INPUT_FILE
412 *
413 * Read binary data from a file and write the data to CMOS memory.
414 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000415static void op_read_cmos_dump(void)
416{
417 unsigned char data[CMOS_SIZE];
418 size_t nr_bytes;
419 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000420
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000421 if ((f = fopen(nvramtool_op.param, "r")) == NULL) {
422 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
423 prog_name, nvramtool_op.param, strerror(errno));
424 exit(1);
425 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000426
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000427 if ((nr_bytes = fread(data, 1, CMOS_SIZE, f)) != CMOS_SIZE) {
428 fprintf(stderr,
429 "%s: Error: Only able to read %d bytes of CMOS data "
430 "from file %s. CMOS data is unchanged.\n", prog_name,
431 (int)nr_bytes, nvramtool_op.param);
432 exit(1);
433 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000434
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000435 fclose(f);
436 set_iopl(3);
437 cmos_write_all(data);
438 set_iopl(0);
439}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000440
441/****************************************************************************
442 * op_show_cmos_hex_dump
443 *
444 * -x
445 *
446 * Write a hex dump of CMOS memory to standard output.
447 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000448static void op_show_cmos_hex_dump(void)
449{
450 unsigned char data[CMOS_SIZE];
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000451
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000452 set_iopl(3);
453 cmos_read_all(data);
454 set_iopl(0);
455 hexdump(data, CMOS_SIZE, 0, stdout, &cmos_dump_format);
456}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000457
458/****************************************************************************
459 * op_show_cmos_dumpfile
460 *
461 * -X DUMP_FILE
462 *
463 * Read binary data from a file (presumably a CMOS dump file) and display a
464 * hex dump of the CMOS data from the file.
465 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000466static void op_show_cmos_dumpfile(void)
467{
468 unsigned char data[CMOS_SIZE];
469 size_t nr_bytes;
470 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000471
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000472 if ((f = fopen(nvramtool_op.param, "r")) == NULL) {
473 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
474 prog_name, nvramtool_op.param, strerror(errno));
475 exit(1);
476 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000477
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000478 nr_bytes = fread(data, 1, CMOS_SIZE, f);
479 fclose(f);
480 hexdump(data, nr_bytes, 0, stdout, &cmos_dump_format);
481}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000482
483/****************************************************************************
484 * list_one_param
485 *
486 * Attempt to list one CMOS parameter given by 'name'. 'show_name' is a
487 * boolean value indicating whether the parameter name should be displayed
488 * along with its value. Return 1 if error was encountered. Else return OK.
489 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000490static int list_one_param(const char name[], int show_name)
491{
492 const cmos_entry_t *e;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000493
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000494 if (is_checksum_name(name) || ((e = find_cmos_entry(name)) == NULL)) {
495 fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name,
496 name);
497 exit(1);
498 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000499
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000500 if (e->config == CMOS_ENTRY_RESERVED) {
501 fprintf(stderr, "%s: Parameter %s is reserved.\n", prog_name,
502 name);
503 exit(1);
504 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000505
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000506 return (list_cmos_entry(e, show_name) != 0);
507}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000508
509/****************************************************************************
510 * list_all_params
511 *
512 * Attempt to list all CMOS parameters. Return 1 if error was encountered.
513 * Else return OK.
514 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000515static int list_all_params(void)
516{
517 const cmos_entry_t *e;
518 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000519
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000520 result = OK;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000521
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000522 for (e = first_cmos_entry(); e != NULL; e = next_cmos_entry(e)) {
523 if ((e->config == CMOS_ENTRY_RESERVED)
524 || is_checksum_name(e->name))
525 continue;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000526
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000527 if (list_cmos_entry(e, TRUE))
528 result = 1;
529 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000530
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000531 return result;
532}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000533
534/****************************************************************************
535 * list_param_enums
536 *
537 * List all possible values for CMOS parameter given by 'name'.
538 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000539static void list_param_enums(const char name[])
540{
541 const cmos_entry_t *e;
542 const cmos_enum_t *p;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000543
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000544 if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL) {
545 fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name,
546 name);
547 exit(1);
548 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000549
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000550 switch (e->config) {
551 case CMOS_ENTRY_ENUM:
552 for (p = first_cmos_enum_id(e->config_id);
553 p != NULL; p = next_cmos_enum_id(p))
554 printf("%s\n", p->text);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000555
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000556 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000557
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000558 case CMOS_ENTRY_HEX:
559 printf("Parameter %s requires a %u-bit unsigned integer.\n",
560 name, e->length);
561 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000562
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000563 case CMOS_ENTRY_STRING:
564 printf("Parameter %s requires a %u-byte string.\n", name,
565 e->length / 8);
566 break;
Stefan Reinauera67aab72008-09-27 10:08:28 +0000567
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000568 case CMOS_ENTRY_RESERVED:
569 printf("Parameter %s is reserved.\n", name);
570 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000571
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000572 default:
573 BUG();
574 }
575}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000576
577/****************************************************************************
578 * set_one_param
579 *
580 * Set the CMOS parameter given by 'name' to 'value'. The 'name' parameter
581 * is case-sensitive. If we are setting an enum parameter, then 'value' is
582 * interpreted as a case-sensitive string that must match the option name
583 * exactly. If we are setting a 'hex' parameter, then 'value' is treated as
584 * a string representation of an unsigned integer that may be specified in
585 * decimal, hex, or octal.
586 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000587static void set_one_param(const char name[], const char value[])
588{
589 const cmos_entry_t *e;
590 unsigned long long n;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000591
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000592 if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL) {
593 fprintf(stderr, "%s: CMOS parameter %s not found.", prog_name,
594 name);
595 exit(1);
596 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000597
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000598 switch (prepare_cmos_write(e, value, &n)) {
599 case OK:
600 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000601
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000602 case CMOS_OP_BAD_ENUM_VALUE:
603 fprintf(stderr, "%s: Bad value for parameter %s.", prog_name,
604 name);
605 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000606
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000607 case CMOS_OP_NEGATIVE_INT:
608 fprintf(stderr,
609 "%s: This program does not support assignment of negative "
610 "numbers to coreboot parameters.", prog_name);
611 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000612
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000613 case CMOS_OP_INVALID_INT:
614 fprintf(stderr, "%s: %s is not a valid integer.", prog_name,
615 value);
616 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000617
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000618 case CMOS_OP_RESERVED:
619 fprintf(stderr,
620 "%s: Can not modify reserved coreboot parameter %s.",
621 prog_name, name);
622 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000623
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000624 case CMOS_OP_VALUE_TOO_WIDE:
625 fprintf(stderr,
626 "%s: Can not write value %s to CMOS parameter %s that is "
627 "only %d bits wide.", prog_name, value, name,
628 e->length);
629 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000630
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000631 case CMOS_OP_NO_MATCHING_ENUM:
632 fprintf(stderr,
633 "%s: coreboot parameter %s has no matching enums.",
634 prog_name, name);
635 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000636
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000637 case CMOS_AREA_OUT_OF_RANGE:
638 fprintf(stderr,
639 "%s: The CMOS area specified by the layout info for "
640 "coreboot parameter %s is out of range.", prog_name,
641 name);
642 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000643
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000644 case CMOS_AREA_OVERLAPS_RTC:
645 fprintf(stderr,
646 "%s: The CMOS area specified by the layout info for "
647 "coreboot parameter %s overlaps the realtime clock area.",
648 prog_name, name);
649 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000650
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000651 case CMOS_AREA_TOO_WIDE:
652 fprintf(stderr,
653 "%s: The CMOS area specified by the layout info for "
654 "coreboot parameter %s is too wide.", prog_name, name);
655 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000656
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000657 default:
658 fprintf(stderr,
659 "%s: Unknown error encountered while attempting to modify "
660 "coreboot parameter %s.", prog_name, name);
661 goto fail;
662 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000663
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000664 /* write the value to nonvolatile RAM */
665 set_iopl(3);
666 cmos_write(e, n);
667 cmos_checksum_write(cmos_checksum_compute());
668 set_iopl(0);
669 return;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000670
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000671 fail:
672 fprintf(stderr, " CMOS write not performed.\n");
673 exit(1);
674}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000675
676/****************************************************************************
677 * set_params
678 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000679 * Set coreboot parameters according to the contents of file 'f'.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000680 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000681static void set_params(FILE * f)
682{ /* First process the input file. Then perform writes only if there were
683 * no problems processing the input. Either all values will be written
684 * successfully or no values will be written.
685 */
686 do_cmos_writes(process_input_file(f));
687}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000688
689/****************************************************************************
690 * parse_assignment
691 *
692 * Parse the string 'arg' (which supposedly represents an assignment) into a
693 * NAME and a VALUE. If 'arg' does not conform to the proper assignment
694 * syntax, exit with a usage message. Otherwise, on return, 'arg' is broken
695 * into substrings representing NAME and VALUE, and *name and *value are set
696 * to point to these two substrings.
697 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000698static void parse_assignment(char arg[], const char **name, const char **value)
699{
700 static const size_t N_MATCHES = 4;
701 regmatch_t match[N_MATCHES];
702 regex_t assignment;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000703
Patrick Georgic6d2b092011-01-28 07:47:10 +0000704 compile_reg_expr(REG_EXTENDED | REG_NEWLINE, assignment_regex, &assignment);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000705
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000706 /* Does 'arg' conform to proper assignment syntax? If not, exit with a
707 * usage message.
708 */
709 if (regexec(&assignment, arg, N_MATCHES, match, 0))
710 usage(stderr);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000711
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000712 /* Ok, we found a valid assignment. Break it into two strings
713 * representing NAME and VALUE.
714 */
715 arg[match[1].rm_eo] = '\0';
716 arg[match[2].rm_eo] = '\0';
717 *name = &arg[match[1].rm_so];
718 *value = &arg[match[2].rm_so];
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000719
Patrick Georgic6d2b092011-01-28 07:47:10 +0000720 regfree(&assignment);
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000721}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000722
723/****************************************************************************
724 * list_cmos_entry
725 *
726 * Attempt to list the CMOS entry represented by 'e'. 'show_name' is a
727 * boolean value indicating whether the parameter name should be displayed
728 * along with its value. On success, return OK. On error, print an error
729 * message and return 1.
730 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000731static int list_cmos_entry(const cmos_entry_t * e, int show_name)
732{
733 const cmos_enum_t *p;
734 unsigned long long value;
Stefan Reinauer42944c32010-01-16 14:57:32 +0000735 char *w;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000736
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000737 /* sanity check CMOS entry */
738 switch (prepare_cmos_read(e)) {
739 case OK:
740 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000741
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000742 case CMOS_OP_RESERVED:
743 BUG();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000744
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000745 case CMOS_AREA_OUT_OF_RANGE:
746 fprintf(stderr,
747 "%s: Can not read coreboot parameter %s because "
748 "layout info specifies out of range CMOS area.\n",
749 prog_name, e->name);
750 return 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000751
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000752 case CMOS_AREA_OVERLAPS_RTC:
753 fprintf(stderr,
754 "%s: Can not read coreboot parameter %s because "
755 "layout info specifies CMOS area that overlaps realtime "
756 "clock area.\n", prog_name, e->name);
757 return 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000758
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000759 case CMOS_AREA_TOO_WIDE:
760 fprintf(stderr,
761 "%s: Can not read coreboot parameter %s because "
762 "layout info specifies CMOS area that is too wide.\n",
763 prog_name, e->name);
764 return 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000765
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000766 default:
767 fprintf(stderr,
768 "%s: Unknown error encountered while attempting to "
769 "read coreboot parameter %s\n", prog_name, e->name);
770 return 1;
771 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000772
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000773 /* read the value from CMOS */
774 set_iopl(3);
775 value = cmos_read(e);
776 set_iopl(0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000777
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000778 /* display the value */
779 switch (e->config) {
780 case CMOS_ENTRY_ENUM:
781 if ((p = find_cmos_enum(e->config_id, value)) == NULL) {
782 if (show_name)
783 printf("# Bad value -> %s = 0x%llx\n", e->name,
784 value);
785 else
786 printf("Bad value -> 0x%llx\n", value);
787 } else {
788 if (show_name)
789 printf("%s = %s\n", e->name, p->text);
790 else
791 printf("%s\n", p->text);
792 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000793
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000794 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000795
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000796 case CMOS_ENTRY_HEX:
797 if (show_name)
798 printf("%s = 0x%llx\n", e->name, value);
799 else
800 printf("0x%llx\n", value);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000801
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000802 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000803
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000804 case CMOS_ENTRY_STRING:
Stefan Reinauer42944c32010-01-16 14:57:32 +0000805 w = (char *)(unsigned long)value;
806 while (*w) {
Jonathan Kollasch1571dc92011-04-19 19:34:25 +0000807 if(!isprint((int)(unsigned char)*w)) {
Stefan Reinauer42944c32010-01-16 14:57:32 +0000808 if (show_name)
809 printf("# Bad value -> %s\n", e->name);
810 else
811 printf("Bad value\n");
812 break;
813 }
814 w++;
815 }
816
817 if (!*w) {
818
819 if (show_name)
820 printf("%s = %s\n", e->name,
821 (char *)(unsigned long)value);
822 else
823 printf("%s\n", (char *)(unsigned long)value);
824 }
Stefan Reinauera67aab72008-09-27 10:08:28 +0000825
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000826 free((void *)(unsigned long)value);
Stefan Reinauera67aab72008-09-27 10:08:28 +0000827
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000828 break;
Stefan Reinauera67aab72008-09-27 10:08:28 +0000829
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000830 case CMOS_ENTRY_RESERVED:
831 default:
832 BUG();
833 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000834
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000835 return OK;
836}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000837
838/****************************************************************************
839 * convert_checksum_value
840 *
841 * 'value' is the string representation of a checksum value that the user
842 * wishes to set using the -c option. Convert the string to a 16-bit
843 * unsigned integer and return the result. Exit with an error message if
844 * 'value' is invalid.
845 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000846static uint16_t convert_checksum_value(const char value[])
847{
848 unsigned long n;
849 const char *p;
850 uint16_t result;
851 int negative;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000852
Jonathan Kollasch1571dc92011-04-19 19:34:25 +0000853 for (p = value; isspace((int)(unsigned char)*p); p++) ;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000854
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000855 negative = (*p == '-');
856 n = strtoul(value, (char **)&p, 0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000857
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000858 if (*p) {
859 fprintf(stderr,
860 "%s: Checksum value %s is not a valid integer.\n",
861 prog_name, value);
862 exit(1);
863 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000864
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000865 if (negative) {
866 fprintf(stderr,
867 "%s: Checksum must be an unsigned integer.\n",
868 prog_name);
869 exit(1);
870 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000871
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000872 result = (uint16_t) n;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000873
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000874 if (result != n) {
875 fprintf(stderr,
876 "%s: Checksum value must fit within 16 bits.\n",
877 prog_name);
878 exit(1);
879 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000880
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000881 return result;
882}