blob: d5acc5838e56e1c7c05ef4c7df3829ca70a453a3 [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"
Zheng Baof6659ca2012-11-08 14:21:46 +080048#ifdef __MINGW32__
49#include <windows.h>
50#endif
Stefan Reinauer6540ae52007-07-12 16:35:42 +000051
52typedef void (*op_fn_t) (void);
53
Stefan Reinauer90b96b62010-01-13 21:00:23 +000054static void op_show_version(void);
55static void op_show_usage(void);
56static void op_lbtable_show_info(void);
57static void op_lbtable_dump(void);
58static void op_show_param_values(void);
59static void op_cmos_show_one_param(void);
60static void op_cmos_show_all_params(void);
61static void op_cmos_set_one_param(void);
62static void op_cmos_set_params_stdin(void);
63static void op_cmos_set_params_file(void);
64static void op_cmos_checksum(void);
65static void op_show_layout(void);
66static void op_write_cmos_dump(void);
67static void op_read_cmos_dump(void);
68static void op_show_cmos_hex_dump(void);
69static void op_show_cmos_dumpfile(void);
Vikram Narayanana8111cf2012-04-14 15:25:13 +053070static void op_write_cmos_layout_bin(void);
71static void op_write_cmos_layout_header(void);
Stefan Reinauer90b96b62010-01-13 21:00:23 +000072static int list_one_param(const char name[], int show_name);
73static int list_all_params(void);
74static void list_param_enums(const char name[]);
75static void set_one_param(const char name[], const char value[]);
76static void set_params(FILE * f);
77static void parse_assignment(char arg[], const char **name, const char **value);
78static int list_cmos_entry(const cmos_entry_t * e, int show_name);
79static uint16_t convert_checksum_value(const char value[]);
Stefan Reinauer6540ae52007-07-12 16:35:42 +000080
Stefan Reinauer90b96b62010-01-13 21:00:23 +000081static const op_fn_t op_fns[] = { op_show_version,
82 op_show_usage,
83 op_lbtable_show_info,
84 op_lbtable_dump,
85 op_show_param_values,
86 op_cmos_show_one_param,
87 op_cmos_show_all_params,
88 op_cmos_set_one_param,
89 op_cmos_set_params_stdin,
90 op_cmos_set_params_file,
91 op_cmos_checksum,
92 op_show_layout,
93 op_write_cmos_dump,
94 op_read_cmos_dump,
95 op_show_cmos_hex_dump,
Vikram Narayanana8111cf2012-04-14 15:25:13 +053096 op_show_cmos_dumpfile,
97 op_write_cmos_layout_bin,
98 op_write_cmos_layout_header
Stefan Reinauer90b96b62010-01-13 21:00:23 +000099};
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000100
Vikram Narayanana8111cf2012-04-14 15:25:13 +0530101static void op_write_cmos_layout_bin(void)
102{
103 get_layout_from_file();
104 write_cmos_output_bin(nvramtool_op.param);
105}
106
107static void op_write_cmos_layout_header(void)
108{
109 get_layout_from_file();
110 write_cmos_layout_header(nvramtool_op.param);
111}
112
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000113static const hexdump_format_t cmos_dump_format =
Patrick Georgi024ec852011-01-18 12:14:08 +0000114 { 16, 2, "", " | ", " ", " | ", '.' };
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000115
116/****************************************************************************
117 * main
118 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000119int main(int argc, char *argv[])
120{
Patrick Georgi202be7b2011-01-21 07:29:40 +0000121 void *cmos_default = NULL;
Patrick Georgi269e9322011-01-21 07:24:08 +0000122 cmos_layout_get_fn_t fn = get_layout_from_cmos_table;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000123
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000124 parse_nvramtool_args(argc, argv);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000125
Mathias Krause943b8b52011-03-08 12:58:16 +0000126 /* If we should operate on a CBFS file default to reading the layout
127 * and CMOS contents from it. */
128 if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CBFS_FILE].found) {
Patrick Georgi269e9322011-01-21 07:24:08 +0000129 open_cbfs(nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CBFS_FILE].param);
Patrick Georgi202be7b2011-01-21 07:29:40 +0000130 if (!nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].found) {
131 cmos_default = cbfs_find_file("cmos.default", CBFS_COMPONENT_CMOS_DEFAULT, NULL);
132 if (cmos_default == NULL) {
133 fprintf(stderr, "Need a cmos.default in the CBFS image or separate cmos file (-D).\n");
134 exit(1);
135 }
136 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000137 fn = get_layout_from_cbfs_file;
Patrick Georgi202be7b2011-01-21 07:29:40 +0000138 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000139
140 /* If the user wants to use a specific layout file or explicitly use
141 * the coreboot option table allow him to override previous settings. */
142 if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_LAYOUT_FILE].found) {
143 set_layout_filename(nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_LAYOUT_FILE].param);
144 fn = get_layout_from_file;
145 } else if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_OPT_TABLE].found) {
146 fn = get_layout_from_cmos_table;
147 }
148
149 /* Allow the user to use a file for the CMOS contents, possibly
150 * overriding a previously opened "cmos.default" file from the CBFS. */
Patrick Georgi202be7b2011-01-21 07:29:40 +0000151 if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].found) {
Patrick Georgi202be7b2011-01-21 07:29:40 +0000152 struct stat fd_stat;
Mathias Krause943b8b52011-03-08 12:58:16 +0000153 int fd;
154
155 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 +0000156 fprintf(stderr, "Couldn't open '%s'\n", nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param);
Patrick Georgi269e9322011-01-21 07:24:08 +0000157 exit(1);
158 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000159
Patrick Georgi202be7b2011-01-21 07:29:40 +0000160 if (fstat(fd, &fd_stat) == -1) {
161 fprintf(stderr, "Couldn't stat '%s'\n", nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param);
162 exit(1);
163 }
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700164
Patrick Georgia98d3062013-04-11 12:32:32 +0200165 if (fd_stat.st_size < CMOS_SIZE) {
166 lseek(fd, CMOS_SIZE - 1, SEEK_SET);
Stefan Reinauera7b296d2011-11-14 12:40:34 -0800167 if (write(fd, "\0", 1) != 1) {
168 fprintf(stderr, "Unable to extended '%s' to its full size.\n",
169 nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param);
170 exit(1);
171 }
Zheng Bao54516722012-10-22 16:41:42 +0800172#ifndef __MINGW32__
Patrick Georgi202be7b2011-01-21 07:29:40 +0000173 fsync(fd);
Zheng Baof6659ca2012-11-08 14:21:46 +0800174#else
175 FlushFileBuffers ((HANDLE) _get_osfhandle (fd));
Zheng Bao54516722012-10-22 16:41:42 +0800176#endif
Patrick Georgi202be7b2011-01-21 07:29:40 +0000177 }
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700178
Patrick Georgia98d3062013-04-11 12:32:32 +0200179 cmos_default = mmap(NULL, CMOS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
Patrick Georgi202be7b2011-01-21 07:29:40 +0000180 if (cmos_default == MAP_FAILED) {
181 fprintf(stderr, "Couldn't map '%s'\n", nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param);
182 exit(1);
183 }
184 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000185
186 /* Switch to memory based CMOS access. */
Patrick Georgi202be7b2011-01-21 07:29:40 +0000187 if (cmos_default) {
188 select_hal(HAL_MEMORY, cmos_default);
Patrick Georgi269e9322011-01-21 07:24:08 +0000189 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000190
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000191 register_cmos_layout_get_fn(fn);
Mathias Krause943b8b52011-03-08 12:58:16 +0000192 op_fns[nvramtool_op.op]();
193
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000194 return 0;
195}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000196
197/****************************************************************************
198 * op_show_version
199 *
200 * -v
201 *
202 * Show version information for this program.
203 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000204static void op_show_version(void)
205{
206 printf("This is %s version %s.\n", prog_name, prog_version);
207}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000208
209/****************************************************************************
210 * op_show_usage
211 *
212 * -h
213 *
214 * Show a usage message for this program.
215 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000216static void op_show_usage(void)
217{
218 usage(stdout);
219}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000220
221/****************************************************************************
222 * op_lbtable_show_info
223 *
224 * -l [ARG]
225 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000226 * If ARG is present, show coreboot table information specified by ARG.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000227 * Else show all possible values for ARG.
228 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000229static void op_lbtable_show_info(void)
230{
231 if (nvramtool_op.param == NULL)
232 list_lbtable_choices();
233 else {
234 get_lbtable();
235 list_lbtable_item(nvramtool_op.param);
236 }
237}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000238
239/****************************************************************************
240 * op_lbtable_dump
241 *
242 * -d
243 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000244 * Do low-level dump of coreboot table.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000245 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000246static void op_lbtable_dump(void)
247{
248 get_lbtable();
249 dump_lbtable();
250}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000251
252/****************************************************************************
253 * op_show_param_values
254 *
255 * -e NAME option
256 *
257 * Show all possible values for parameter NAME.
258 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000259static void op_show_param_values(void)
260{
261 get_cmos_layout();
262 list_param_enums(nvramtool_op.param);
263}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000264
265/****************************************************************************
266 * op_cmos_show_one_param
267 *
268 * [-n] -r NAME
269 *
270 * Show parameter NAME. If -n is specified, show value only. Else show name
271 * and value.
272 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000273static void op_cmos_show_one_param(void)
274{
275 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000276
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000277 get_cmos_layout();
278 result = list_one_param(nvramtool_op.param,
279 !nvramtool_op_modifiers
280 [NVRAMTOOL_MOD_SHOW_VALUE_ONLY].found);
281 cmos_checksum_verify();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000282
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000283 if (result)
284 exit(1);
285}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000286
287/****************************************************************************
288 * op_cmos_show_all_params
289 *
290 * -a
291 *
292 * Show names and values for all parameters.
293 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000294static void op_cmos_show_all_params(void)
295{
296 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000297
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000298 get_cmos_layout();
299 result = list_all_params();
300 cmos_checksum_verify();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000301
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000302 if (result)
303 exit(1);
304}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000305
306/****************************************************************************
307 * op_cmos_set_one_param
308 *
309 * -w NAME=VALUE
310 *
311 * Set parameter NAME to VALUE.
312 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000313static void op_cmos_set_one_param(void)
314{
315 const char *name, *value;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000316
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000317 get_cmos_layout();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000318
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000319 /* Separate 'NAME=VALUE' syntax into two strings representing NAME and
320 * VALUE.
321 */
322 parse_assignment(nvramtool_op.param, &name, &value);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000323
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000324 set_one_param(name, value);
325}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000326
327/****************************************************************************
328 * op_cmos_set_params_stdin
329 *
330 * -i
331 *
332 * Set parameters according to standard input.
333 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000334static void op_cmos_set_params_stdin(void)
335{
336 get_cmos_layout();
337 set_params(stdin);
338}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000339
340/****************************************************************************
341 * op_cmos_set_params_file
342 *
343 * -p INPUT_FILE
344 *
345 * Set parameters according to INPUT_FILE.
346 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000347static void op_cmos_set_params_file(void)
348{
349 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000350
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000351 if ((f = fopen(nvramtool_op.param, "r")) == NULL) {
352 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
353 prog_name, nvramtool_op.param, strerror(errno));
354 exit(1);
355 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000356
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000357 get_cmos_layout();
358 set_params(f);
359 fclose(f);
360}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000361
362/****************************************************************************
363 * op_cmos_checksum
364 *
365 * -c [VALUE]
366 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000367 * If VALUE is present, set coreboot CMOS checksum to VALUE. Else show
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000368 * checksum value.
369 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000370static void op_cmos_checksum(void)
371{
372 uint16_t checksum;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000373
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000374 get_cmos_layout();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000375
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000376 if (nvramtool_op.param == NULL) {
377 set_iopl(3);
378 checksum = cmos_checksum_read();
379 set_iopl(0);
380 printf("0x%x\n", checksum);
381 } else {
382 checksum = convert_checksum_value(nvramtool_op.param);
383 set_iopl(3);
384 cmos_checksum_write(checksum);
385 set_iopl(0);
386 }
387}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000388
389/****************************************************************************
390 * op_show_layout
391 *
392 * -Y
393 *
394 * Write CMOS layout information to standard output.
395 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000396static void op_show_layout(void)
397{
398 get_cmos_layout();
399 write_cmos_layout(stdout);
400}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000401
402/****************************************************************************
403 * op_write_cmos_dump
404 *
405 * -b OUTPUT_FILE
406 *
407 * Write the contents of CMOS memory to a binary file.
408 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000409static void op_write_cmos_dump(void)
410{
411 unsigned char data[CMOS_SIZE];
412 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000413
Patrick Georgi5c637612012-09-20 13:26:42 +0200414 if ((f = fopen(nvramtool_op.param, "wb")) == NULL) {
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000415 fprintf(stderr, "%s: Can not open file %s for writing: %s\n",
416 prog_name, nvramtool_op.param, strerror(errno));
417 exit(1);
418 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000419
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000420 set_iopl(3);
421 cmos_read_all(data);
422 set_iopl(0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000423
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000424 if (fwrite(data, 1, CMOS_SIZE, f) != CMOS_SIZE) {
425 fprintf(stderr, "%s: Error writing CMOS data to file %s: %s\n",
426 prog_name, nvramtool_op.param, strerror(errno));
427 exit(1);
428 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000429
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000430 fclose(f);
431}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000432
433/****************************************************************************
434 * op_read_cmos_dump
435 *
436 * -B INPUT_FILE
437 *
438 * Read binary data from a file and write the data to CMOS memory.
439 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000440static void op_read_cmos_dump(void)
441{
442 unsigned char data[CMOS_SIZE];
443 size_t nr_bytes;
444 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000445
Patrick Georgi5c637612012-09-20 13:26:42 +0200446 if ((f = fopen(nvramtool_op.param, "rb")) == NULL) {
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000447 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
448 prog_name, nvramtool_op.param, strerror(errno));
449 exit(1);
450 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000451
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000452 if ((nr_bytes = fread(data, 1, CMOS_SIZE, f)) != CMOS_SIZE) {
453 fprintf(stderr,
454 "%s: Error: Only able to read %d bytes of CMOS data "
455 "from file %s. CMOS data is unchanged.\n", prog_name,
456 (int)nr_bytes, nvramtool_op.param);
457 exit(1);
458 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000459
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000460 fclose(f);
461 set_iopl(3);
462 cmos_write_all(data);
463 set_iopl(0);
464}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000465
466/****************************************************************************
467 * op_show_cmos_hex_dump
468 *
469 * -x
470 *
471 * Write a hex dump of CMOS memory to standard output.
472 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000473static void op_show_cmos_hex_dump(void)
474{
475 unsigned char data[CMOS_SIZE];
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000476
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000477 set_iopl(3);
478 cmos_read_all(data);
479 set_iopl(0);
480 hexdump(data, CMOS_SIZE, 0, stdout, &cmos_dump_format);
481}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000482
483/****************************************************************************
484 * op_show_cmos_dumpfile
485 *
486 * -X DUMP_FILE
487 *
488 * Read binary data from a file (presumably a CMOS dump file) and display a
489 * hex dump of the CMOS data from the file.
490 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000491static void op_show_cmos_dumpfile(void)
492{
493 unsigned char data[CMOS_SIZE];
494 size_t nr_bytes;
495 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000496
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000497 if ((f = fopen(nvramtool_op.param, "r")) == NULL) {
498 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
499 prog_name, nvramtool_op.param, strerror(errno));
500 exit(1);
501 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000502
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000503 nr_bytes = fread(data, 1, CMOS_SIZE, f);
504 fclose(f);
505 hexdump(data, nr_bytes, 0, stdout, &cmos_dump_format);
506}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000507
508/****************************************************************************
509 * list_one_param
510 *
511 * Attempt to list one CMOS parameter given by 'name'. 'show_name' is a
512 * boolean value indicating whether the parameter name should be displayed
513 * along with its value. Return 1 if error was encountered. Else return OK.
514 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000515static int list_one_param(const char name[], int show_name)
516{
517 const cmos_entry_t *e;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000518
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000519 if (is_checksum_name(name) || ((e = find_cmos_entry(name)) == NULL)) {
520 fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name,
521 name);
522 exit(1);
523 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000524
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000525 if (e->config == CMOS_ENTRY_RESERVED) {
526 fprintf(stderr, "%s: Parameter %s is reserved.\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 return (list_cmos_entry(e, show_name) != 0);
532}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000533
534/****************************************************************************
535 * list_all_params
536 *
537 * Attempt to list all CMOS parameters. Return 1 if error was encountered.
538 * Else return OK.
539 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000540static int list_all_params(void)
541{
542 const cmos_entry_t *e;
543 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000544
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000545 result = OK;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000546
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000547 for (e = first_cmos_entry(); e != NULL; e = next_cmos_entry(e)) {
548 if ((e->config == CMOS_ENTRY_RESERVED)
549 || is_checksum_name(e->name))
550 continue;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000551
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000552 if (list_cmos_entry(e, TRUE))
553 result = 1;
554 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000555
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000556 return result;
557}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000558
559/****************************************************************************
560 * list_param_enums
561 *
562 * List all possible values for CMOS parameter given by 'name'.
563 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000564static void list_param_enums(const char name[])
565{
566 const cmos_entry_t *e;
567 const cmos_enum_t *p;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000568
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000569 if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL) {
570 fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name,
571 name);
572 exit(1);
573 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000574
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000575 switch (e->config) {
576 case CMOS_ENTRY_ENUM:
577 for (p = first_cmos_enum_id(e->config_id);
578 p != NULL; p = next_cmos_enum_id(p))
579 printf("%s\n", p->text);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000580
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000581 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000582
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000583 case CMOS_ENTRY_HEX:
584 printf("Parameter %s requires a %u-bit unsigned integer.\n",
585 name, e->length);
586 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000587
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000588 case CMOS_ENTRY_STRING:
589 printf("Parameter %s requires a %u-byte string.\n", name,
590 e->length / 8);
591 break;
Stefan Reinauera67aab72008-09-27 10:08:28 +0000592
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000593 case CMOS_ENTRY_RESERVED:
594 printf("Parameter %s is reserved.\n", name);
595 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000596
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000597 default:
598 BUG();
599 }
600}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000601
602/****************************************************************************
603 * set_one_param
604 *
605 * Set the CMOS parameter given by 'name' to 'value'. The 'name' parameter
606 * is case-sensitive. If we are setting an enum parameter, then 'value' is
607 * interpreted as a case-sensitive string that must match the option name
608 * exactly. If we are setting a 'hex' parameter, then 'value' is treated as
609 * a string representation of an unsigned integer that may be specified in
610 * decimal, hex, or octal.
611 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000612static void set_one_param(const char name[], const char value[])
613{
614 const cmos_entry_t *e;
615 unsigned long long n;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000616
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000617 if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL) {
618 fprintf(stderr, "%s: CMOS parameter %s not found.", prog_name,
619 name);
620 exit(1);
621 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000622
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000623 switch (prepare_cmos_write(e, value, &n)) {
624 case OK:
625 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000626
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000627 case CMOS_OP_BAD_ENUM_VALUE:
628 fprintf(stderr, "%s: Bad value for parameter %s.", prog_name,
629 name);
630 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000631
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000632 case CMOS_OP_NEGATIVE_INT:
633 fprintf(stderr,
634 "%s: This program does not support assignment of negative "
635 "numbers to coreboot parameters.", prog_name);
636 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000637
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000638 case CMOS_OP_INVALID_INT:
639 fprintf(stderr, "%s: %s is not a valid integer.", prog_name,
640 value);
641 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000642
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000643 case CMOS_OP_RESERVED:
644 fprintf(stderr,
645 "%s: Can not modify reserved coreboot parameter %s.",
646 prog_name, name);
647 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000648
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000649 case CMOS_OP_VALUE_TOO_WIDE:
650 fprintf(stderr,
651 "%s: Can not write value %s to CMOS parameter %s that is "
652 "only %d bits wide.", prog_name, value, name,
653 e->length);
654 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000655
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000656 case CMOS_OP_NO_MATCHING_ENUM:
657 fprintf(stderr,
658 "%s: coreboot parameter %s has no matching enums.",
659 prog_name, name);
660 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000661
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000662 case CMOS_AREA_OUT_OF_RANGE:
663 fprintf(stderr,
664 "%s: The CMOS area specified by the layout info for "
665 "coreboot parameter %s is out of range.", prog_name,
666 name);
667 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000668
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000669 case CMOS_AREA_OVERLAPS_RTC:
670 fprintf(stderr,
671 "%s: The CMOS area specified by the layout info for "
672 "coreboot parameter %s overlaps the realtime clock area.",
673 prog_name, name);
674 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000675
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000676 case CMOS_AREA_TOO_WIDE:
677 fprintf(stderr,
678 "%s: The CMOS area specified by the layout info for "
679 "coreboot parameter %s is too wide.", prog_name, name);
680 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000681
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000682 default:
683 fprintf(stderr,
684 "%s: Unknown error encountered while attempting to modify "
685 "coreboot parameter %s.", prog_name, name);
686 goto fail;
687 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000688
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000689 /* write the value to nonvolatile RAM */
690 set_iopl(3);
691 cmos_write(e, n);
692 cmos_checksum_write(cmos_checksum_compute());
693 set_iopl(0);
694 return;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000695
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000696 fail:
697 fprintf(stderr, " CMOS write not performed.\n");
698 exit(1);
699}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000700
701/****************************************************************************
702 * set_params
703 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000704 * Set coreboot parameters according to the contents of file 'f'.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000705 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000706static void set_params(FILE * f)
707{ /* First process the input file. Then perform writes only if there were
708 * no problems processing the input. Either all values will be written
709 * successfully or no values will be written.
710 */
711 do_cmos_writes(process_input_file(f));
712}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000713
714/****************************************************************************
715 * parse_assignment
716 *
717 * Parse the string 'arg' (which supposedly represents an assignment) into a
718 * NAME and a VALUE. If 'arg' does not conform to the proper assignment
719 * syntax, exit with a usage message. Otherwise, on return, 'arg' is broken
720 * into substrings representing NAME and VALUE, and *name and *value are set
721 * to point to these two substrings.
722 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000723static void parse_assignment(char arg[], const char **name, const char **value)
724{
725 static const size_t N_MATCHES = 4;
726 regmatch_t match[N_MATCHES];
727 regex_t assignment;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000728
Patrick Georgic6d2b092011-01-28 07:47:10 +0000729 compile_reg_expr(REG_EXTENDED | REG_NEWLINE, assignment_regex, &assignment);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000730
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000731 /* Does 'arg' conform to proper assignment syntax? If not, exit with a
732 * usage message.
733 */
734 if (regexec(&assignment, arg, N_MATCHES, match, 0))
735 usage(stderr);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000736
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000737 /* Ok, we found a valid assignment. Break it into two strings
738 * representing NAME and VALUE.
739 */
740 arg[match[1].rm_eo] = '\0';
741 arg[match[2].rm_eo] = '\0';
742 *name = &arg[match[1].rm_so];
743 *value = &arg[match[2].rm_so];
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000744
Patrick Georgic6d2b092011-01-28 07:47:10 +0000745 regfree(&assignment);
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000746}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000747
748/****************************************************************************
749 * list_cmos_entry
750 *
751 * Attempt to list the CMOS entry represented by 'e'. 'show_name' is a
752 * boolean value indicating whether the parameter name should be displayed
753 * along with its value. On success, return OK. On error, print an error
754 * message and return 1.
755 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000756static int list_cmos_entry(const cmos_entry_t * e, int show_name)
757{
758 const cmos_enum_t *p;
759 unsigned long long value;
Stefan Reinauer42944c32010-01-16 14:57:32 +0000760 char *w;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000761
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000762 /* sanity check CMOS entry */
763 switch (prepare_cmos_read(e)) {
764 case OK:
765 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000766
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000767 case CMOS_OP_RESERVED:
768 BUG();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000769
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000770 case CMOS_AREA_OUT_OF_RANGE:
771 fprintf(stderr,
772 "%s: Can not read coreboot parameter %s because "
773 "layout info specifies out of range CMOS area.\n",
774 prog_name, e->name);
775 return 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000776
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000777 case CMOS_AREA_OVERLAPS_RTC:
778 fprintf(stderr,
779 "%s: Can not read coreboot parameter %s because "
780 "layout info specifies CMOS area that overlaps realtime "
781 "clock area.\n", prog_name, e->name);
782 return 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000783
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000784 case CMOS_AREA_TOO_WIDE:
785 fprintf(stderr,
786 "%s: Can not read coreboot parameter %s because "
787 "layout info specifies CMOS area that is too wide.\n",
788 prog_name, e->name);
789 return 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000790
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000791 default:
792 fprintf(stderr,
793 "%s: Unknown error encountered while attempting to "
794 "read coreboot parameter %s\n", prog_name, e->name);
795 return 1;
796 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000797
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000798 /* read the value from CMOS */
799 set_iopl(3);
800 value = cmos_read(e);
801 set_iopl(0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000802
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000803 /* display the value */
804 switch (e->config) {
805 case CMOS_ENTRY_ENUM:
806 if ((p = find_cmos_enum(e->config_id, value)) == NULL) {
807 if (show_name)
808 printf("# Bad value -> %s = 0x%llx\n", e->name,
809 value);
810 else
811 printf("Bad value -> 0x%llx\n", value);
812 } else {
813 if (show_name)
814 printf("%s = %s\n", e->name, p->text);
815 else
816 printf("%s\n", p->text);
817 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000818
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000819 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000820
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000821 case CMOS_ENTRY_HEX:
822 if (show_name)
823 printf("%s = 0x%llx\n", e->name, value);
824 else
825 printf("0x%llx\n", value);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000826
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000827 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000828
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000829 case CMOS_ENTRY_STRING:
Stefan Reinauer42944c32010-01-16 14:57:32 +0000830 w = (char *)(unsigned long)value;
831 while (*w) {
Jonathan Kollasch1571dc92011-04-19 19:34:25 +0000832 if(!isprint((int)(unsigned char)*w)) {
Stefan Reinauer42944c32010-01-16 14:57:32 +0000833 if (show_name)
834 printf("# Bad value -> %s\n", e->name);
835 else
836 printf("Bad value\n");
837 break;
838 }
839 w++;
840 }
841
842 if (!*w) {
843
844 if (show_name)
845 printf("%s = %s\n", e->name,
846 (char *)(unsigned long)value);
847 else
848 printf("%s\n", (char *)(unsigned long)value);
849 }
Stefan Reinauera67aab72008-09-27 10:08:28 +0000850
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000851 free((void *)(unsigned long)value);
Stefan Reinauera67aab72008-09-27 10:08:28 +0000852
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000853 break;
Stefan Reinauera67aab72008-09-27 10:08:28 +0000854
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000855 case CMOS_ENTRY_RESERVED:
856 default:
857 BUG();
858 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000859
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000860 return OK;
861}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000862
863/****************************************************************************
864 * convert_checksum_value
865 *
866 * 'value' is the string representation of a checksum value that the user
867 * wishes to set using the -c option. Convert the string to a 16-bit
868 * unsigned integer and return the result. Exit with an error message if
869 * 'value' is invalid.
870 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000871static uint16_t convert_checksum_value(const char value[])
872{
873 unsigned long n;
874 const char *p;
875 uint16_t result;
876 int negative;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000877
Jonathan Kollasch1571dc92011-04-19 19:34:25 +0000878 for (p = value; isspace((int)(unsigned char)*p); p++) ;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000879
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000880 negative = (*p == '-');
881 n = strtoul(value, (char **)&p, 0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000882
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000883 if (*p) {
884 fprintf(stderr,
885 "%s: Checksum value %s is not a valid integer.\n",
886 prog_name, value);
887 exit(1);
888 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000889
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000890 if (negative) {
891 fprintf(stderr,
892 "%s: Checksum must be an unsigned integer.\n",
893 prog_name);
894 exit(1);
895 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000896
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000897 result = (uint16_t) n;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000898
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000899 if (result != n) {
900 fprintf(stderr,
901 "%s: Checksum value must fit within 16 bits.\n",
902 prog_name);
903 exit(1);
904 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000905
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000906 return result;
907}