blob: 7716bd8710a3ab248b3b9d2c4d8b2ef0d2e399bd [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>
Zheng Bao54516722012-10-22 16:41:42 +080034#ifndef __MINGW32__
Patrick Georgi202be7b2011-01-21 07:29:40 +000035#include <sys/mman.h>
Zheng Bao54516722012-10-22 16:41:42 +080036#endif
Stefan Reinauer6540ae52007-07-12 16:35:42 +000037#include "common.h"
38#include "opts.h"
39#include "lbtable.h"
40#include "layout.h"
Patrick Georgi49a74432011-01-28 07:50:33 +000041#include "accessors/layout-text.h"
Stefan Reinauer6540ae52007-07-12 16:35:42 +000042#include "input_file.h"
43#include "cmos_ops.h"
44#include "cmos_lowlevel.h"
45#include "reg_expr.h"
46#include "hexdump.h"
Patrick Georgi269e9322011-01-21 07:24:08 +000047#include "cbfs.h"
Stefan Reinauer6540ae52007-07-12 16:35:42 +000048
49typedef void (*op_fn_t) (void);
50
Stefan Reinauer90b96b62010-01-13 21:00:23 +000051static void op_show_version(void);
52static void op_show_usage(void);
53static void op_lbtable_show_info(void);
54static void op_lbtable_dump(void);
55static void op_show_param_values(void);
56static void op_cmos_show_one_param(void);
57static void op_cmos_show_all_params(void);
58static void op_cmos_set_one_param(void);
59static void op_cmos_set_params_stdin(void);
60static void op_cmos_set_params_file(void);
61static void op_cmos_checksum(void);
62static void op_show_layout(void);
63static void op_write_cmos_dump(void);
64static void op_read_cmos_dump(void);
65static void op_show_cmos_hex_dump(void);
66static void op_show_cmos_dumpfile(void);
Vikram Narayanana8111cf2012-04-14 15:25:13 +053067static void op_write_cmos_layout_bin(void);
68static void op_write_cmos_layout_header(void);
Stefan Reinauer90b96b62010-01-13 21:00:23 +000069static int list_one_param(const char name[], int show_name);
70static int list_all_params(void);
71static void list_param_enums(const char name[]);
72static void set_one_param(const char name[], const char value[]);
73static void set_params(FILE * f);
74static void parse_assignment(char arg[], const char **name, const char **value);
75static int list_cmos_entry(const cmos_entry_t * e, int show_name);
76static uint16_t convert_checksum_value(const char value[]);
Stefan Reinauer6540ae52007-07-12 16:35:42 +000077
Stefan Reinauer90b96b62010-01-13 21:00:23 +000078static const op_fn_t op_fns[] = { op_show_version,
79 op_show_usage,
80 op_lbtable_show_info,
81 op_lbtable_dump,
82 op_show_param_values,
83 op_cmos_show_one_param,
84 op_cmos_show_all_params,
85 op_cmos_set_one_param,
86 op_cmos_set_params_stdin,
87 op_cmos_set_params_file,
88 op_cmos_checksum,
89 op_show_layout,
90 op_write_cmos_dump,
91 op_read_cmos_dump,
92 op_show_cmos_hex_dump,
Vikram Narayanana8111cf2012-04-14 15:25:13 +053093 op_show_cmos_dumpfile,
94 op_write_cmos_layout_bin,
95 op_write_cmos_layout_header
Stefan Reinauer90b96b62010-01-13 21:00:23 +000096};
Stefan Reinauer6540ae52007-07-12 16:35:42 +000097
Vikram Narayanana8111cf2012-04-14 15:25:13 +053098static void op_write_cmos_layout_bin(void)
99{
100 get_layout_from_file();
101 write_cmos_output_bin(nvramtool_op.param);
102}
103
104static void op_write_cmos_layout_header(void)
105{
106 get_layout_from_file();
107 write_cmos_layout_header(nvramtool_op.param);
108}
109
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000110static const hexdump_format_t cmos_dump_format =
Patrick Georgi024ec852011-01-18 12:14:08 +0000111 { 16, 2, "", " | ", " ", " | ", '.' };
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000112
113/****************************************************************************
114 * main
115 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000116int main(int argc, char *argv[])
117{
Patrick Georgi202be7b2011-01-21 07:29:40 +0000118 void *cmos_default = NULL;
Patrick Georgi269e9322011-01-21 07:24:08 +0000119 cmos_layout_get_fn_t fn = get_layout_from_cmos_table;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000120
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000121 parse_nvramtool_args(argc, argv);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000122
Mathias Krause943b8b52011-03-08 12:58:16 +0000123 /* If we should operate on a CBFS file default to reading the layout
124 * and CMOS contents from it. */
125 if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CBFS_FILE].found) {
Patrick Georgi269e9322011-01-21 07:24:08 +0000126 open_cbfs(nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CBFS_FILE].param);
Patrick Georgi202be7b2011-01-21 07:29:40 +0000127 if (!nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].found) {
128 cmos_default = cbfs_find_file("cmos.default", CBFS_COMPONENT_CMOS_DEFAULT, NULL);
129 if (cmos_default == NULL) {
130 fprintf(stderr, "Need a cmos.default in the CBFS image or separate cmos file (-D).\n");
131 exit(1);
132 }
133 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000134 fn = get_layout_from_cbfs_file;
Patrick Georgi202be7b2011-01-21 07:29:40 +0000135 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000136
137 /* If the user wants to use a specific layout file or explicitly use
138 * the coreboot option table allow him to override previous settings. */
139 if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_LAYOUT_FILE].found) {
140 set_layout_filename(nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_LAYOUT_FILE].param);
141 fn = get_layout_from_file;
142 } else if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_OPT_TABLE].found) {
143 fn = get_layout_from_cmos_table;
144 }
145
146 /* Allow the user to use a file for the CMOS contents, possibly
147 * overriding a previously opened "cmos.default" file from the CBFS. */
Patrick Georgi202be7b2011-01-21 07:29:40 +0000148 if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].found) {
Patrick Georgi202be7b2011-01-21 07:29:40 +0000149 struct stat fd_stat;
Mathias Krause943b8b52011-03-08 12:58:16 +0000150 int fd;
151
152 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 +0000153 fprintf(stderr, "Couldn't open '%s'\n", nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param);
Patrick Georgi269e9322011-01-21 07:24:08 +0000154 exit(1);
155 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000156
Patrick Georgi202be7b2011-01-21 07:29:40 +0000157 if (fstat(fd, &fd_stat) == -1) {
158 fprintf(stderr, "Couldn't stat '%s'\n", nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param);
159 exit(1);
160 }
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700161
Patrick Georgi202be7b2011-01-21 07:29:40 +0000162 if (fd_stat.st_size < 128) {
163 lseek(fd, 127, SEEK_SET);
Stefan Reinauera7b296d2011-11-14 12:40:34 -0800164 if (write(fd, "\0", 1) != 1) {
165 fprintf(stderr, "Unable to extended '%s' to its full size.\n",
166 nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param);
167 exit(1);
168 }
Zheng Bao54516722012-10-22 16:41:42 +0800169#ifndef __MINGW32__
Patrick Georgi202be7b2011-01-21 07:29:40 +0000170 fsync(fd);
Zheng Bao54516722012-10-22 16:41:42 +0800171#endif
Patrick Georgi202be7b2011-01-21 07:29:40 +0000172 }
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700173
Patrick Georgi202be7b2011-01-21 07:29:40 +0000174 cmos_default = mmap(NULL, 128, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
175 if (cmos_default == MAP_FAILED) {
176 fprintf(stderr, "Couldn't map '%s'\n", nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param);
177 exit(1);
178 }
179 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000180
181 /* Switch to memory based CMOS access. */
Patrick Georgi202be7b2011-01-21 07:29:40 +0000182 if (cmos_default) {
183 select_hal(HAL_MEMORY, cmos_default);
Patrick Georgi269e9322011-01-21 07:24:08 +0000184 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000185
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000186 register_cmos_layout_get_fn(fn);
Mathias Krause943b8b52011-03-08 12:58:16 +0000187 op_fns[nvramtool_op.op]();
188
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000189 return 0;
190}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000191
192/****************************************************************************
193 * op_show_version
194 *
195 * -v
196 *
197 * Show version information for this program.
198 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000199static void op_show_version(void)
200{
201 printf("This is %s version %s.\n", prog_name, prog_version);
202}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000203
204/****************************************************************************
205 * op_show_usage
206 *
207 * -h
208 *
209 * Show a usage message for this program.
210 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000211static void op_show_usage(void)
212{
213 usage(stdout);
214}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000215
216/****************************************************************************
217 * op_lbtable_show_info
218 *
219 * -l [ARG]
220 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000221 * If ARG is present, show coreboot table information specified by ARG.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000222 * Else show all possible values for ARG.
223 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000224static void op_lbtable_show_info(void)
225{
226 if (nvramtool_op.param == NULL)
227 list_lbtable_choices();
228 else {
229 get_lbtable();
230 list_lbtable_item(nvramtool_op.param);
231 }
232}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000233
234/****************************************************************************
235 * op_lbtable_dump
236 *
237 * -d
238 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000239 * Do low-level dump of coreboot table.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000240 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000241static void op_lbtable_dump(void)
242{
243 get_lbtable();
244 dump_lbtable();
245}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000246
247/****************************************************************************
248 * op_show_param_values
249 *
250 * -e NAME option
251 *
252 * Show all possible values for parameter NAME.
253 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000254static void op_show_param_values(void)
255{
256 get_cmos_layout();
257 list_param_enums(nvramtool_op.param);
258}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000259
260/****************************************************************************
261 * op_cmos_show_one_param
262 *
263 * [-n] -r NAME
264 *
265 * Show parameter NAME. If -n is specified, show value only. Else show name
266 * and value.
267 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000268static void op_cmos_show_one_param(void)
269{
270 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000271
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000272 get_cmos_layout();
273 result = list_one_param(nvramtool_op.param,
274 !nvramtool_op_modifiers
275 [NVRAMTOOL_MOD_SHOW_VALUE_ONLY].found);
276 cmos_checksum_verify();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000277
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000278 if (result)
279 exit(1);
280}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000281
282/****************************************************************************
283 * op_cmos_show_all_params
284 *
285 * -a
286 *
287 * Show names and values for all parameters.
288 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000289static void op_cmos_show_all_params(void)
290{
291 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000292
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000293 get_cmos_layout();
294 result = list_all_params();
295 cmos_checksum_verify();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000296
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000297 if (result)
298 exit(1);
299}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000300
301/****************************************************************************
302 * op_cmos_set_one_param
303 *
304 * -w NAME=VALUE
305 *
306 * Set parameter NAME to VALUE.
307 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000308static void op_cmos_set_one_param(void)
309{
310 const char *name, *value;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000311
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000312 get_cmos_layout();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000313
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000314 /* Separate 'NAME=VALUE' syntax into two strings representing NAME and
315 * VALUE.
316 */
317 parse_assignment(nvramtool_op.param, &name, &value);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000318
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000319 set_one_param(name, value);
320}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000321
322/****************************************************************************
323 * op_cmos_set_params_stdin
324 *
325 * -i
326 *
327 * Set parameters according to standard input.
328 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000329static void op_cmos_set_params_stdin(void)
330{
331 get_cmos_layout();
332 set_params(stdin);
333}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000334
335/****************************************************************************
336 * op_cmos_set_params_file
337 *
338 * -p INPUT_FILE
339 *
340 * Set parameters according to INPUT_FILE.
341 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000342static void op_cmos_set_params_file(void)
343{
344 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000345
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000346 if ((f = fopen(nvramtool_op.param, "r")) == NULL) {
347 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
348 prog_name, nvramtool_op.param, strerror(errno));
349 exit(1);
350 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000351
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000352 get_cmos_layout();
353 set_params(f);
354 fclose(f);
355}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000356
357/****************************************************************************
358 * op_cmos_checksum
359 *
360 * -c [VALUE]
361 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000362 * If VALUE is present, set coreboot CMOS checksum to VALUE. Else show
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000363 * checksum value.
364 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000365static void op_cmos_checksum(void)
366{
367 uint16_t checksum;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000368
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000369 get_cmos_layout();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000370
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000371 if (nvramtool_op.param == NULL) {
372 set_iopl(3);
373 checksum = cmos_checksum_read();
374 set_iopl(0);
375 printf("0x%x\n", checksum);
376 } else {
377 checksum = convert_checksum_value(nvramtool_op.param);
378 set_iopl(3);
379 cmos_checksum_write(checksum);
380 set_iopl(0);
381 }
382}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000383
384/****************************************************************************
385 * op_show_layout
386 *
387 * -Y
388 *
389 * Write CMOS layout information to standard output.
390 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000391static void op_show_layout(void)
392{
393 get_cmos_layout();
394 write_cmos_layout(stdout);
395}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000396
397/****************************************************************************
398 * op_write_cmos_dump
399 *
400 * -b OUTPUT_FILE
401 *
402 * Write the contents of CMOS memory to a binary file.
403 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000404static void op_write_cmos_dump(void)
405{
406 unsigned char data[CMOS_SIZE];
407 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000408
Patrick Georgi5c637612012-09-20 13:26:42 +0200409 if ((f = fopen(nvramtool_op.param, "wb")) == NULL) {
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000410 fprintf(stderr, "%s: Can not open file %s for writing: %s\n",
411 prog_name, nvramtool_op.param, strerror(errno));
412 exit(1);
413 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000414
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000415 set_iopl(3);
416 cmos_read_all(data);
417 set_iopl(0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000418
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000419 if (fwrite(data, 1, CMOS_SIZE, f) != CMOS_SIZE) {
420 fprintf(stderr, "%s: Error writing CMOS data to file %s: %s\n",
421 prog_name, nvramtool_op.param, strerror(errno));
422 exit(1);
423 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000424
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000425 fclose(f);
426}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000427
428/****************************************************************************
429 * op_read_cmos_dump
430 *
431 * -B INPUT_FILE
432 *
433 * Read binary data from a file and write the data to CMOS memory.
434 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000435static void op_read_cmos_dump(void)
436{
437 unsigned char data[CMOS_SIZE];
438 size_t nr_bytes;
439 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000440
Patrick Georgi5c637612012-09-20 13:26:42 +0200441 if ((f = fopen(nvramtool_op.param, "rb")) == NULL) {
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000442 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
443 prog_name, nvramtool_op.param, strerror(errno));
444 exit(1);
445 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000446
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000447 if ((nr_bytes = fread(data, 1, CMOS_SIZE, f)) != CMOS_SIZE) {
448 fprintf(stderr,
449 "%s: Error: Only able to read %d bytes of CMOS data "
450 "from file %s. CMOS data is unchanged.\n", prog_name,
451 (int)nr_bytes, nvramtool_op.param);
452 exit(1);
453 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000454
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000455 fclose(f);
456 set_iopl(3);
457 cmos_write_all(data);
458 set_iopl(0);
459}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000460
461/****************************************************************************
462 * op_show_cmos_hex_dump
463 *
464 * -x
465 *
466 * Write a hex dump of CMOS memory to standard output.
467 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000468static void op_show_cmos_hex_dump(void)
469{
470 unsigned char data[CMOS_SIZE];
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000471
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000472 set_iopl(3);
473 cmos_read_all(data);
474 set_iopl(0);
475 hexdump(data, CMOS_SIZE, 0, stdout, &cmos_dump_format);
476}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000477
478/****************************************************************************
479 * op_show_cmos_dumpfile
480 *
481 * -X DUMP_FILE
482 *
483 * Read binary data from a file (presumably a CMOS dump file) and display a
484 * hex dump of the CMOS data from the file.
485 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000486static void op_show_cmos_dumpfile(void)
487{
488 unsigned char data[CMOS_SIZE];
489 size_t nr_bytes;
490 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000491
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000492 if ((f = fopen(nvramtool_op.param, "r")) == NULL) {
493 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
494 prog_name, nvramtool_op.param, strerror(errno));
495 exit(1);
496 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000497
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000498 nr_bytes = fread(data, 1, CMOS_SIZE, f);
499 fclose(f);
500 hexdump(data, nr_bytes, 0, stdout, &cmos_dump_format);
501}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000502
503/****************************************************************************
504 * list_one_param
505 *
506 * Attempt to list one CMOS parameter given by 'name'. 'show_name' is a
507 * boolean value indicating whether the parameter name should be displayed
508 * along with its value. Return 1 if error was encountered. Else return OK.
509 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000510static int list_one_param(const char name[], int show_name)
511{
512 const cmos_entry_t *e;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000513
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000514 if (is_checksum_name(name) || ((e = find_cmos_entry(name)) == NULL)) {
515 fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name,
516 name);
517 exit(1);
518 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000519
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000520 if (e->config == CMOS_ENTRY_RESERVED) {
521 fprintf(stderr, "%s: Parameter %s is reserved.\n", prog_name,
522 name);
523 exit(1);
524 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000525
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000526 return (list_cmos_entry(e, show_name) != 0);
527}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000528
529/****************************************************************************
530 * list_all_params
531 *
532 * Attempt to list all CMOS parameters. Return 1 if error was encountered.
533 * Else return OK.
534 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000535static int list_all_params(void)
536{
537 const cmos_entry_t *e;
538 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000539
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000540 result = OK;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000541
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000542 for (e = first_cmos_entry(); e != NULL; e = next_cmos_entry(e)) {
543 if ((e->config == CMOS_ENTRY_RESERVED)
544 || is_checksum_name(e->name))
545 continue;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000546
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000547 if (list_cmos_entry(e, TRUE))
548 result = 1;
549 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000550
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000551 return result;
552}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000553
554/****************************************************************************
555 * list_param_enums
556 *
557 * List all possible values for CMOS parameter given by 'name'.
558 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000559static void list_param_enums(const char name[])
560{
561 const cmos_entry_t *e;
562 const cmos_enum_t *p;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000563
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000564 if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL) {
565 fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name,
566 name);
567 exit(1);
568 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000569
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000570 switch (e->config) {
571 case CMOS_ENTRY_ENUM:
572 for (p = first_cmos_enum_id(e->config_id);
573 p != NULL; p = next_cmos_enum_id(p))
574 printf("%s\n", p->text);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000575
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000576 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000577
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000578 case CMOS_ENTRY_HEX:
579 printf("Parameter %s requires a %u-bit unsigned integer.\n",
580 name, e->length);
581 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000582
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000583 case CMOS_ENTRY_STRING:
584 printf("Parameter %s requires a %u-byte string.\n", name,
585 e->length / 8);
586 break;
Stefan Reinauera67aab72008-09-27 10:08:28 +0000587
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000588 case CMOS_ENTRY_RESERVED:
589 printf("Parameter %s is reserved.\n", name);
590 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000591
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000592 default:
593 BUG();
594 }
595}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000596
597/****************************************************************************
598 * set_one_param
599 *
600 * Set the CMOS parameter given by 'name' to 'value'. The 'name' parameter
601 * is case-sensitive. If we are setting an enum parameter, then 'value' is
602 * interpreted as a case-sensitive string that must match the option name
603 * exactly. If we are setting a 'hex' parameter, then 'value' is treated as
604 * a string representation of an unsigned integer that may be specified in
605 * decimal, hex, or octal.
606 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000607static void set_one_param(const char name[], const char value[])
608{
609 const cmos_entry_t *e;
610 unsigned long long n;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000611
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000612 if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL) {
613 fprintf(stderr, "%s: CMOS parameter %s not found.", prog_name,
614 name);
615 exit(1);
616 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000617
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000618 switch (prepare_cmos_write(e, value, &n)) {
619 case OK:
620 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000621
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000622 case CMOS_OP_BAD_ENUM_VALUE:
623 fprintf(stderr, "%s: Bad value for parameter %s.", prog_name,
624 name);
625 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000626
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000627 case CMOS_OP_NEGATIVE_INT:
628 fprintf(stderr,
629 "%s: This program does not support assignment of negative "
630 "numbers to coreboot parameters.", prog_name);
631 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000632
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000633 case CMOS_OP_INVALID_INT:
634 fprintf(stderr, "%s: %s is not a valid integer.", prog_name,
635 value);
636 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000637
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000638 case CMOS_OP_RESERVED:
639 fprintf(stderr,
640 "%s: Can not modify reserved coreboot parameter %s.",
641 prog_name, name);
642 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000643
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000644 case CMOS_OP_VALUE_TOO_WIDE:
645 fprintf(stderr,
646 "%s: Can not write value %s to CMOS parameter %s that is "
647 "only %d bits wide.", prog_name, value, name,
648 e->length);
649 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000650
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000651 case CMOS_OP_NO_MATCHING_ENUM:
652 fprintf(stderr,
653 "%s: coreboot parameter %s has no matching enums.",
654 prog_name, name);
655 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000656
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000657 case CMOS_AREA_OUT_OF_RANGE:
658 fprintf(stderr,
659 "%s: The CMOS area specified by the layout info for "
660 "coreboot parameter %s is out of range.", prog_name,
661 name);
662 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000663
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000664 case CMOS_AREA_OVERLAPS_RTC:
665 fprintf(stderr,
666 "%s: The CMOS area specified by the layout info for "
667 "coreboot parameter %s overlaps the realtime clock area.",
668 prog_name, name);
669 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000670
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000671 case CMOS_AREA_TOO_WIDE:
672 fprintf(stderr,
673 "%s: The CMOS area specified by the layout info for "
674 "coreboot parameter %s is too wide.", prog_name, name);
675 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000676
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000677 default:
678 fprintf(stderr,
679 "%s: Unknown error encountered while attempting to modify "
680 "coreboot parameter %s.", prog_name, name);
681 goto fail;
682 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000683
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000684 /* write the value to nonvolatile RAM */
685 set_iopl(3);
686 cmos_write(e, n);
687 cmos_checksum_write(cmos_checksum_compute());
688 set_iopl(0);
689 return;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000690
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000691 fail:
692 fprintf(stderr, " CMOS write not performed.\n");
693 exit(1);
694}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000695
696/****************************************************************************
697 * set_params
698 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000699 * Set coreboot parameters according to the contents of file 'f'.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000700 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000701static void set_params(FILE * f)
702{ /* First process the input file. Then perform writes only if there were
703 * no problems processing the input. Either all values will be written
704 * successfully or no values will be written.
705 */
706 do_cmos_writes(process_input_file(f));
707}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000708
709/****************************************************************************
710 * parse_assignment
711 *
712 * Parse the string 'arg' (which supposedly represents an assignment) into a
713 * NAME and a VALUE. If 'arg' does not conform to the proper assignment
714 * syntax, exit with a usage message. Otherwise, on return, 'arg' is broken
715 * into substrings representing NAME and VALUE, and *name and *value are set
716 * to point to these two substrings.
717 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000718static void parse_assignment(char arg[], const char **name, const char **value)
719{
720 static const size_t N_MATCHES = 4;
721 regmatch_t match[N_MATCHES];
722 regex_t assignment;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000723
Patrick Georgic6d2b092011-01-28 07:47:10 +0000724 compile_reg_expr(REG_EXTENDED | REG_NEWLINE, assignment_regex, &assignment);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000725
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000726 /* Does 'arg' conform to proper assignment syntax? If not, exit with a
727 * usage message.
728 */
729 if (regexec(&assignment, arg, N_MATCHES, match, 0))
730 usage(stderr);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000731
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000732 /* Ok, we found a valid assignment. Break it into two strings
733 * representing NAME and VALUE.
734 */
735 arg[match[1].rm_eo] = '\0';
736 arg[match[2].rm_eo] = '\0';
737 *name = &arg[match[1].rm_so];
738 *value = &arg[match[2].rm_so];
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000739
Patrick Georgic6d2b092011-01-28 07:47:10 +0000740 regfree(&assignment);
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000741}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000742
743/****************************************************************************
744 * list_cmos_entry
745 *
746 * Attempt to list the CMOS entry represented by 'e'. 'show_name' is a
747 * boolean value indicating whether the parameter name should be displayed
748 * along with its value. On success, return OK. On error, print an error
749 * message and return 1.
750 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000751static int list_cmos_entry(const cmos_entry_t * e, int show_name)
752{
753 const cmos_enum_t *p;
754 unsigned long long value;
Stefan Reinauer42944c32010-01-16 14:57:32 +0000755 char *w;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000756
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000757 /* sanity check CMOS entry */
758 switch (prepare_cmos_read(e)) {
759 case OK:
760 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000761
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000762 case CMOS_OP_RESERVED:
763 BUG();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000764
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000765 case CMOS_AREA_OUT_OF_RANGE:
766 fprintf(stderr,
767 "%s: Can not read coreboot parameter %s because "
768 "layout info specifies out of range CMOS area.\n",
769 prog_name, e->name);
770 return 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000771
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000772 case CMOS_AREA_OVERLAPS_RTC:
773 fprintf(stderr,
774 "%s: Can not read coreboot parameter %s because "
775 "layout info specifies CMOS area that overlaps realtime "
776 "clock area.\n", prog_name, e->name);
777 return 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000778
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000779 case CMOS_AREA_TOO_WIDE:
780 fprintf(stderr,
781 "%s: Can not read coreboot parameter %s because "
782 "layout info specifies CMOS area that is too wide.\n",
783 prog_name, e->name);
784 return 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000785
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000786 default:
787 fprintf(stderr,
788 "%s: Unknown error encountered while attempting to "
789 "read coreboot parameter %s\n", prog_name, e->name);
790 return 1;
791 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000792
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000793 /* read the value from CMOS */
794 set_iopl(3);
795 value = cmos_read(e);
796 set_iopl(0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000797
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000798 /* display the value */
799 switch (e->config) {
800 case CMOS_ENTRY_ENUM:
801 if ((p = find_cmos_enum(e->config_id, value)) == NULL) {
802 if (show_name)
803 printf("# Bad value -> %s = 0x%llx\n", e->name,
804 value);
805 else
806 printf("Bad value -> 0x%llx\n", value);
807 } else {
808 if (show_name)
809 printf("%s = %s\n", e->name, p->text);
810 else
811 printf("%s\n", p->text);
812 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000813
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000814 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000815
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000816 case CMOS_ENTRY_HEX:
817 if (show_name)
818 printf("%s = 0x%llx\n", e->name, value);
819 else
820 printf("0x%llx\n", value);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000821
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000822 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000823
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000824 case CMOS_ENTRY_STRING:
Stefan Reinauer42944c32010-01-16 14:57:32 +0000825 w = (char *)(unsigned long)value;
826 while (*w) {
Jonathan Kollasch1571dc92011-04-19 19:34:25 +0000827 if(!isprint((int)(unsigned char)*w)) {
Stefan Reinauer42944c32010-01-16 14:57:32 +0000828 if (show_name)
829 printf("# Bad value -> %s\n", e->name);
830 else
831 printf("Bad value\n");
832 break;
833 }
834 w++;
835 }
836
837 if (!*w) {
838
839 if (show_name)
840 printf("%s = %s\n", e->name,
841 (char *)(unsigned long)value);
842 else
843 printf("%s\n", (char *)(unsigned long)value);
844 }
Stefan Reinauera67aab72008-09-27 10:08:28 +0000845
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000846 free((void *)(unsigned long)value);
Stefan Reinauera67aab72008-09-27 10:08:28 +0000847
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000848 break;
Stefan Reinauera67aab72008-09-27 10:08:28 +0000849
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000850 case CMOS_ENTRY_RESERVED:
851 default:
852 BUG();
853 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000854
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000855 return OK;
856}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000857
858/****************************************************************************
859 * convert_checksum_value
860 *
861 * 'value' is the string representation of a checksum value that the user
862 * wishes to set using the -c option. Convert the string to a 16-bit
863 * unsigned integer and return the result. Exit with an error message if
864 * 'value' is invalid.
865 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000866static uint16_t convert_checksum_value(const char value[])
867{
868 unsigned long n;
869 const char *p;
870 uint16_t result;
871 int negative;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000872
Jonathan Kollasch1571dc92011-04-19 19:34:25 +0000873 for (p = value; isspace((int)(unsigned char)*p); p++) ;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000874
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000875 negative = (*p == '-');
876 n = strtoul(value, (char **)&p, 0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000877
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000878 if (*p) {
879 fprintf(stderr,
880 "%s: Checksum value %s is not a valid integer.\n",
881 prog_name, value);
882 exit(1);
883 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000884
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000885 if (negative) {
886 fprintf(stderr,
887 "%s: Checksum must be an unsigned integer.\n",
888 prog_name);
889 exit(1);
890 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000891
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000892 result = (uint16_t) n;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000893
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000894 if (result != n) {
895 fprintf(stderr,
896 "%s: Checksum value must fit within 16 bits.\n",
897 prog_name);
898 exit(1);
899 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000900
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000901 return result;
902}