blob: 8183572b4da4d9c78a414d7c51e8fafd405725e3 [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.
Stefan Reinauer6540ae52007-07-12 16:35:42 +000025\*****************************************************************************/
26
Patrick Georgi202be7b2011-01-21 07:29:40 +000027#include <fcntl.h>
28#include <stdio.h>
29#include <stdlib.h>
Zheng Bao54516722012-10-22 16:41:42 +080030#ifndef __MINGW32__
Patrick Georgi202be7b2011-01-21 07:29:40 +000031#include <sys/mman.h>
Zheng Bao54516722012-10-22 16:41:42 +080032#endif
Stefan Reinauer6540ae52007-07-12 16:35:42 +000033#include "common.h"
34#include "opts.h"
35#include "lbtable.h"
36#include "layout.h"
Patrick Georgi49a74432011-01-28 07:50:33 +000037#include "accessors/layout-text.h"
Stefan Reinauer6540ae52007-07-12 16:35:42 +000038#include "input_file.h"
39#include "cmos_ops.h"
40#include "cmos_lowlevel.h"
41#include "reg_expr.h"
42#include "hexdump.h"
Patrick Georgi269e9322011-01-21 07:24:08 +000043#include "cbfs.h"
Zheng Baof6659ca2012-11-08 14:21:46 +080044#ifdef __MINGW32__
45#include <windows.h>
46#endif
Stefan Reinauer6540ae52007-07-12 16:35:42 +000047
48typedef void (*op_fn_t) (void);
49
Stefan Reinauer90b96b62010-01-13 21:00:23 +000050static void op_show_version(void);
51static void op_show_usage(void);
52static void op_lbtable_show_info(void);
53static void op_lbtable_dump(void);
54static void op_show_param_values(void);
55static void op_cmos_show_one_param(void);
56static void op_cmos_show_all_params(void);
57static void op_cmos_set_one_param(void);
58static void op_cmos_set_params_stdin(void);
59static void op_cmos_set_params_file(void);
60static void op_cmos_checksum(void);
61static void op_show_layout(void);
62static void op_write_cmos_dump(void);
63static void op_read_cmos_dump(void);
64static void op_show_cmos_hex_dump(void);
65static void op_show_cmos_dumpfile(void);
Vikram Narayanana8111cf2012-04-14 15:25:13 +053066static void op_write_cmos_layout_bin(void);
67static void op_write_cmos_layout_header(void);
Stefan Reinauer90b96b62010-01-13 21:00:23 +000068static int list_one_param(const char name[], int show_name);
69static int list_all_params(void);
70static void list_param_enums(const char name[]);
71static void set_one_param(const char name[], const char value[]);
72static void set_params(FILE * f);
73static void parse_assignment(char arg[], const char **name, const char **value);
74static int list_cmos_entry(const cmos_entry_t * e, int show_name);
75static uint16_t convert_checksum_value(const char value[]);
Stefan Reinauer6540ae52007-07-12 16:35:42 +000076
Stefan Reinauer90b96b62010-01-13 21:00:23 +000077static const op_fn_t op_fns[] = { op_show_version,
78 op_show_usage,
79 op_lbtable_show_info,
80 op_lbtable_dump,
81 op_show_param_values,
82 op_cmos_show_one_param,
83 op_cmos_show_all_params,
84 op_cmos_set_one_param,
85 op_cmos_set_params_stdin,
86 op_cmos_set_params_file,
87 op_cmos_checksum,
88 op_show_layout,
89 op_write_cmos_dump,
90 op_read_cmos_dump,
91 op_show_cmos_hex_dump,
Vikram Narayanana8111cf2012-04-14 15:25:13 +053092 op_show_cmos_dumpfile,
93 op_write_cmos_layout_bin,
94 op_write_cmos_layout_header
Stefan Reinauer90b96b62010-01-13 21:00:23 +000095};
Stefan Reinauer6540ae52007-07-12 16:35:42 +000096
Vikram Narayanana8111cf2012-04-14 15:25:13 +053097static void op_write_cmos_layout_bin(void)
98{
99 get_layout_from_file();
100 write_cmos_output_bin(nvramtool_op.param);
101}
102
103static void op_write_cmos_layout_header(void)
104{
105 get_layout_from_file();
106 write_cmos_layout_header(nvramtool_op.param);
107}
108
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000109static const hexdump_format_t cmos_dump_format =
Patrick Georgi024ec852011-01-18 12:14:08 +0000110 { 16, 2, "", " | ", " ", " | ", '.' };
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000111
112/****************************************************************************
113 * main
114 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000115int main(int argc, char *argv[])
116{
Patrick Georgi202be7b2011-01-21 07:29:40 +0000117 void *cmos_default = NULL;
Patrick Georgi269e9322011-01-21 07:24:08 +0000118 cmos_layout_get_fn_t fn = get_layout_from_cmos_table;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000119
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000120 parse_nvramtool_args(argc, argv);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000121
Mathias Krause943b8b52011-03-08 12:58:16 +0000122 /* If we should operate on a CBFS file default to reading the layout
123 * and CMOS contents from it. */
124 if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CBFS_FILE].found) {
Patrick Georgi269e9322011-01-21 07:24:08 +0000125 open_cbfs(nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CBFS_FILE].param);
Patrick Georgi202be7b2011-01-21 07:29:40 +0000126 if (!nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].found) {
127 cmos_default = cbfs_find_file("cmos.default", CBFS_COMPONENT_CMOS_DEFAULT, NULL);
128 if (cmos_default == NULL) {
129 fprintf(stderr, "Need a cmos.default in the CBFS image or separate cmos file (-D).\n");
130 exit(1);
131 }
132 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000133 fn = get_layout_from_cbfs_file;
Patrick Georgi202be7b2011-01-21 07:29:40 +0000134 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000135
136 /* If the user wants to use a specific layout file or explicitly use
137 * the coreboot option table allow him to override previous settings. */
138 if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_LAYOUT_FILE].found) {
139 set_layout_filename(nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_LAYOUT_FILE].param);
140 fn = get_layout_from_file;
141 } else if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_OPT_TABLE].found) {
142 fn = get_layout_from_cmos_table;
143 }
144
145 /* Allow the user to use a file for the CMOS contents, possibly
146 * overriding a previously opened "cmos.default" file from the CBFS. */
Patrick Georgi202be7b2011-01-21 07:29:40 +0000147 if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].found) {
Patrick Georgi202be7b2011-01-21 07:29:40 +0000148 struct stat fd_stat;
Mathias Krause943b8b52011-03-08 12:58:16 +0000149 int fd;
150
151 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 +0000152 fprintf(stderr, "Couldn't open '%s'\n", nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param);
Patrick Georgi269e9322011-01-21 07:24:08 +0000153 exit(1);
154 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000155
Patrick Georgi202be7b2011-01-21 07:29:40 +0000156 if (fstat(fd, &fd_stat) == -1) {
157 fprintf(stderr, "Couldn't stat '%s'\n", nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param);
158 exit(1);
159 }
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700160
Patrick Georgia98d3062013-04-11 12:32:32 +0200161 if (fd_stat.st_size < CMOS_SIZE) {
Patrick Georgic5d17912014-08-09 17:02:00 +0200162 if ((lseek(fd, CMOS_SIZE - 1, SEEK_SET) == -1) ||
163 (write(fd, "\0", 1) != 1)) {
Stefan Reinauera7b296d2011-11-14 12:40:34 -0800164 fprintf(stderr, "Unable to extended '%s' to its full size.\n",
165 nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param);
166 exit(1);
167 }
Zheng Bao54516722012-10-22 16:41:42 +0800168#ifndef __MINGW32__
Patrick Georgi202be7b2011-01-21 07:29:40 +0000169 fsync(fd);
Zheng Baof6659ca2012-11-08 14:21:46 +0800170#else
171 FlushFileBuffers ((HANDLE) _get_osfhandle (fd));
Zheng Bao54516722012-10-22 16:41:42 +0800172#endif
Patrick Georgi202be7b2011-01-21 07:29:40 +0000173 }
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700174
Patrick Georgia98d3062013-04-11 12:32:32 +0200175 cmos_default = mmap(NULL, CMOS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
Patrick Georgi202be7b2011-01-21 07:29:40 +0000176 if (cmos_default == MAP_FAILED) {
177 fprintf(stderr, "Couldn't map '%s'\n", nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param);
178 exit(1);
179 }
180 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000181
182 /* Switch to memory based CMOS access. */
Patrick Georgi202be7b2011-01-21 07:29:40 +0000183 if (cmos_default) {
184 select_hal(HAL_MEMORY, cmos_default);
Patrick Georgi269e9322011-01-21 07:24:08 +0000185 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000186
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000187 register_cmos_layout_get_fn(fn);
Mathias Krause943b8b52011-03-08 12:58:16 +0000188 op_fns[nvramtool_op.op]();
189
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000190 return 0;
191}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000192
193/****************************************************************************
194 * op_show_version
195 *
196 * -v
197 *
198 * Show version information for this program.
199 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000200static void op_show_version(void)
201{
202 printf("This is %s version %s.\n", prog_name, prog_version);
203}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000204
205/****************************************************************************
206 * op_show_usage
207 *
208 * -h
209 *
210 * Show a usage message for this program.
211 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000212static void op_show_usage(void)
213{
214 usage(stdout);
215}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000216
217/****************************************************************************
218 * op_lbtable_show_info
219 *
220 * -l [ARG]
221 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000222 * If ARG is present, show coreboot table information specified by ARG.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000223 * Else show all possible values for ARG.
224 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000225static void op_lbtable_show_info(void)
226{
227 if (nvramtool_op.param == NULL)
228 list_lbtable_choices();
229 else {
230 get_lbtable();
231 list_lbtable_item(nvramtool_op.param);
232 }
233}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000234
235/****************************************************************************
236 * op_lbtable_dump
237 *
238 * -d
239 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000240 * Do low-level dump of coreboot table.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000241 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000242static void op_lbtable_dump(void)
243{
244 get_lbtable();
245 dump_lbtable();
246}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000247
248/****************************************************************************
249 * op_show_param_values
250 *
251 * -e NAME option
252 *
253 * Show all possible values for parameter NAME.
254 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000255static void op_show_param_values(void)
256{
257 get_cmos_layout();
258 list_param_enums(nvramtool_op.param);
259}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000260
261/****************************************************************************
262 * op_cmos_show_one_param
263 *
264 * [-n] -r NAME
265 *
266 * Show parameter NAME. If -n is specified, show value only. Else show name
267 * and value.
268 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000269static void op_cmos_show_one_param(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_one_param(nvramtool_op.param,
275 !nvramtool_op_modifiers
276 [NVRAMTOOL_MOD_SHOW_VALUE_ONLY].found);
277 cmos_checksum_verify();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000278
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000279 if (result)
280 exit(1);
281}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000282
283/****************************************************************************
284 * op_cmos_show_all_params
285 *
286 * -a
287 *
288 * Show names and values for all parameters.
289 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000290static void op_cmos_show_all_params(void)
291{
292 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000293
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000294 get_cmos_layout();
295 result = list_all_params();
296 cmos_checksum_verify();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000297
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000298 if (result)
299 exit(1);
300}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000301
302/****************************************************************************
303 * op_cmos_set_one_param
304 *
305 * -w NAME=VALUE
306 *
307 * Set parameter NAME to VALUE.
308 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000309static void op_cmos_set_one_param(void)
310{
311 const char *name, *value;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000312
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000313 get_cmos_layout();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000314
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000315 /* Separate 'NAME=VALUE' syntax into two strings representing NAME and
316 * VALUE.
317 */
318 parse_assignment(nvramtool_op.param, &name, &value);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000319
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000320 set_one_param(name, value);
321}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000322
323/****************************************************************************
324 * op_cmos_set_params_stdin
325 *
326 * -i
327 *
328 * Set parameters according to standard input.
329 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000330static void op_cmos_set_params_stdin(void)
331{
332 get_cmos_layout();
333 set_params(stdin);
334}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000335
336/****************************************************************************
337 * op_cmos_set_params_file
338 *
339 * -p INPUT_FILE
340 *
341 * Set parameters according to INPUT_FILE.
342 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000343static void op_cmos_set_params_file(void)
344{
345 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000346
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000347 if ((f = fopen(nvramtool_op.param, "r")) == NULL) {
348 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
349 prog_name, nvramtool_op.param, strerror(errno));
350 exit(1);
351 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000352
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000353 get_cmos_layout();
354 set_params(f);
355 fclose(f);
356}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000357
358/****************************************************************************
359 * op_cmos_checksum
360 *
361 * -c [VALUE]
362 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000363 * If VALUE is present, set coreboot CMOS checksum to VALUE. Else show
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000364 * checksum value.
365 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000366static void op_cmos_checksum(void)
367{
368 uint16_t checksum;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000369
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000370 get_cmos_layout();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000371
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000372 if (nvramtool_op.param == NULL) {
373 set_iopl(3);
374 checksum = cmos_checksum_read();
375 set_iopl(0);
376 printf("0x%x\n", checksum);
377 } else {
378 checksum = convert_checksum_value(nvramtool_op.param);
379 set_iopl(3);
380 cmos_checksum_write(checksum);
381 set_iopl(0);
382 }
383}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000384
385/****************************************************************************
386 * op_show_layout
387 *
388 * -Y
389 *
390 * Write CMOS layout information to standard output.
391 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000392static void op_show_layout(void)
393{
394 get_cmos_layout();
395 write_cmos_layout(stdout);
396}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000397
398/****************************************************************************
399 * op_write_cmos_dump
400 *
401 * -b OUTPUT_FILE
402 *
403 * Write the contents of CMOS memory to a binary file.
404 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000405static void op_write_cmos_dump(void)
406{
407 unsigned char data[CMOS_SIZE];
408 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000409
Patrick Georgi5c637612012-09-20 13:26:42 +0200410 if ((f = fopen(nvramtool_op.param, "wb")) == NULL) {
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000411 fprintf(stderr, "%s: Can not open file %s for writing: %s\n",
412 prog_name, nvramtool_op.param, strerror(errno));
413 exit(1);
414 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000415
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000416 set_iopl(3);
417 cmos_read_all(data);
418 set_iopl(0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000419
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000420 if (fwrite(data, 1, CMOS_SIZE, f) != CMOS_SIZE) {
421 fprintf(stderr, "%s: Error writing CMOS data to file %s: %s\n",
422 prog_name, nvramtool_op.param, strerror(errno));
423 exit(1);
424 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000425
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000426 fclose(f);
427}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000428
429/****************************************************************************
430 * op_read_cmos_dump
431 *
432 * -B INPUT_FILE
433 *
434 * Read binary data from a file and write the data to CMOS memory.
435 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000436static void op_read_cmos_dump(void)
437{
438 unsigned char data[CMOS_SIZE];
439 size_t nr_bytes;
440 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000441
Patrick Georgi5c637612012-09-20 13:26:42 +0200442 if ((f = fopen(nvramtool_op.param, "rb")) == NULL) {
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000443 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
444 prog_name, nvramtool_op.param, strerror(errno));
445 exit(1);
446 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000447
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000448 if ((nr_bytes = fread(data, 1, CMOS_SIZE, f)) != CMOS_SIZE) {
449 fprintf(stderr,
450 "%s: Error: Only able to read %d bytes of CMOS data "
451 "from file %s. CMOS data is unchanged.\n", prog_name,
452 (int)nr_bytes, nvramtool_op.param);
453 exit(1);
454 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000455
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000456 fclose(f);
457 set_iopl(3);
458 cmos_write_all(data);
459 set_iopl(0);
460}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000461
462/****************************************************************************
463 * op_show_cmos_hex_dump
464 *
465 * -x
466 *
467 * Write a hex dump of CMOS memory to standard output.
468 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000469static void op_show_cmos_hex_dump(void)
470{
471 unsigned char data[CMOS_SIZE];
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000472
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000473 set_iopl(3);
474 cmos_read_all(data);
475 set_iopl(0);
476 hexdump(data, CMOS_SIZE, 0, stdout, &cmos_dump_format);
477}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000478
479/****************************************************************************
480 * op_show_cmos_dumpfile
481 *
482 * -X DUMP_FILE
483 *
484 * Read binary data from a file (presumably a CMOS dump file) and display a
485 * hex dump of the CMOS data from the file.
486 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000487static void op_show_cmos_dumpfile(void)
488{
489 unsigned char data[CMOS_SIZE];
490 size_t nr_bytes;
491 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000492
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000493 if ((f = fopen(nvramtool_op.param, "r")) == NULL) {
494 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
495 prog_name, nvramtool_op.param, strerror(errno));
496 exit(1);
497 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000498
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000499 nr_bytes = fread(data, 1, CMOS_SIZE, f);
500 fclose(f);
501 hexdump(data, nr_bytes, 0, stdout, &cmos_dump_format);
502}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000503
504/****************************************************************************
505 * list_one_param
506 *
507 * Attempt to list one CMOS parameter given by 'name'. 'show_name' is a
508 * boolean value indicating whether the parameter name should be displayed
509 * along with its value. Return 1 if error was encountered. Else return OK.
510 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000511static int list_one_param(const char name[], int show_name)
512{
513 const cmos_entry_t *e;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000514
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000515 if (is_checksum_name(name) || ((e = find_cmos_entry(name)) == NULL)) {
516 fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name,
517 name);
518 exit(1);
519 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000520
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000521 if (e->config == CMOS_ENTRY_RESERVED) {
522 fprintf(stderr, "%s: Parameter %s is reserved.\n", prog_name,
523 name);
524 exit(1);
525 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000526
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000527 return (list_cmos_entry(e, show_name) != 0);
528}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000529
530/****************************************************************************
531 * list_all_params
532 *
533 * Attempt to list all CMOS parameters. Return 1 if error was encountered.
534 * Else return OK.
535 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000536static int list_all_params(void)
537{
538 const cmos_entry_t *e;
539 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000540
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000541 result = OK;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000542
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000543 for (e = first_cmos_entry(); e != NULL; e = next_cmos_entry(e)) {
544 if ((e->config == CMOS_ENTRY_RESERVED)
545 || is_checksum_name(e->name))
546 continue;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000547
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000548 if (list_cmos_entry(e, TRUE))
549 result = 1;
550 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000551
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000552 return result;
553}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000554
555/****************************************************************************
556 * list_param_enums
557 *
558 * List all possible values for CMOS parameter given by 'name'.
559 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000560static void list_param_enums(const char name[])
561{
562 const cmos_entry_t *e;
563 const cmos_enum_t *p;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000564
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000565 if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL) {
566 fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name,
567 name);
568 exit(1);
569 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000570
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000571 switch (e->config) {
572 case CMOS_ENTRY_ENUM:
573 for (p = first_cmos_enum_id(e->config_id);
574 p != NULL; p = next_cmos_enum_id(p))
575 printf("%s\n", p->text);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000576
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000577 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000578
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000579 case CMOS_ENTRY_HEX:
580 printf("Parameter %s requires a %u-bit unsigned integer.\n",
581 name, e->length);
582 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000583
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000584 case CMOS_ENTRY_STRING:
585 printf("Parameter %s requires a %u-byte string.\n", name,
586 e->length / 8);
587 break;
Stefan Reinauera67aab72008-09-27 10:08:28 +0000588
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000589 case CMOS_ENTRY_RESERVED:
590 printf("Parameter %s is reserved.\n", name);
591 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000592
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000593 default:
594 BUG();
595 }
596}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000597
598/****************************************************************************
599 * set_one_param
600 *
601 * Set the CMOS parameter given by 'name' to 'value'. The 'name' parameter
602 * is case-sensitive. If we are setting an enum parameter, then 'value' is
603 * interpreted as a case-sensitive string that must match the option name
604 * exactly. If we are setting a 'hex' parameter, then 'value' is treated as
605 * a string representation of an unsigned integer that may be specified in
606 * decimal, hex, or octal.
607 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000608static void set_one_param(const char name[], const char value[])
609{
610 const cmos_entry_t *e;
611 unsigned long long n;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000612
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000613 if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL) {
614 fprintf(stderr, "%s: CMOS parameter %s not found.", prog_name,
615 name);
616 exit(1);
617 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000618
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000619 switch (prepare_cmos_write(e, value, &n)) {
620 case OK:
621 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000622
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000623 case CMOS_OP_BAD_ENUM_VALUE:
624 fprintf(stderr, "%s: Bad value for parameter %s.", prog_name,
625 name);
626 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000627
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000628 case CMOS_OP_NEGATIVE_INT:
629 fprintf(stderr,
630 "%s: This program does not support assignment of negative "
631 "numbers to coreboot parameters.", prog_name);
632 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000633
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000634 case CMOS_OP_INVALID_INT:
635 fprintf(stderr, "%s: %s is not a valid integer.", prog_name,
636 value);
637 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000638
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000639 case CMOS_OP_RESERVED:
640 fprintf(stderr,
641 "%s: Can not modify reserved coreboot parameter %s.",
642 prog_name, name);
643 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000644
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000645 case CMOS_OP_VALUE_TOO_WIDE:
646 fprintf(stderr,
647 "%s: Can not write value %s to CMOS parameter %s that is "
648 "only %d bits wide.", prog_name, value, name,
649 e->length);
650 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000651
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000652 case CMOS_OP_NO_MATCHING_ENUM:
653 fprintf(stderr,
654 "%s: coreboot parameter %s has no matching enums.",
655 prog_name, name);
656 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000657
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000658 case CMOS_AREA_OUT_OF_RANGE:
659 fprintf(stderr,
660 "%s: The CMOS area specified by the layout info for "
661 "coreboot parameter %s is out of range.", prog_name,
662 name);
663 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000664
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000665 case CMOS_AREA_OVERLAPS_RTC:
666 fprintf(stderr,
667 "%s: The CMOS area specified by the layout info for "
668 "coreboot parameter %s overlaps the realtime clock area.",
669 prog_name, name);
670 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000671
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000672 case CMOS_AREA_TOO_WIDE:
673 fprintf(stderr,
674 "%s: The CMOS area specified by the layout info for "
675 "coreboot parameter %s is too wide.", prog_name, name);
676 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000677
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000678 default:
679 fprintf(stderr,
680 "%s: Unknown error encountered while attempting to modify "
681 "coreboot parameter %s.", prog_name, name);
682 goto fail;
683 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000684
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000685 /* write the value to nonvolatile RAM */
686 set_iopl(3);
687 cmos_write(e, n);
688 cmos_checksum_write(cmos_checksum_compute());
689 set_iopl(0);
690 return;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000691
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000692 fail:
693 fprintf(stderr, " CMOS write not performed.\n");
694 exit(1);
695}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000696
697/****************************************************************************
698 * set_params
699 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000700 * Set coreboot parameters according to the contents of file 'f'.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000701 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000702static void set_params(FILE * f)
703{ /* First process the input file. Then perform writes only if there were
704 * no problems processing the input. Either all values will be written
705 * successfully or no values will be written.
706 */
707 do_cmos_writes(process_input_file(f));
708}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000709
710/****************************************************************************
711 * parse_assignment
712 *
713 * Parse the string 'arg' (which supposedly represents an assignment) into a
714 * NAME and a VALUE. If 'arg' does not conform to the proper assignment
715 * syntax, exit with a usage message. Otherwise, on return, 'arg' is broken
716 * into substrings representing NAME and VALUE, and *name and *value are set
717 * to point to these two substrings.
718 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000719static void parse_assignment(char arg[], const char **name, const char **value)
720{
721 static const size_t N_MATCHES = 4;
722 regmatch_t match[N_MATCHES];
723 regex_t assignment;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000724
Patrick Georgic6d2b092011-01-28 07:47:10 +0000725 compile_reg_expr(REG_EXTENDED | REG_NEWLINE, assignment_regex, &assignment);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000726
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000727 /* Does 'arg' conform to proper assignment syntax? If not, exit with a
728 * usage message.
729 */
730 if (regexec(&assignment, arg, N_MATCHES, match, 0))
731 usage(stderr);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000732
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000733 /* Ok, we found a valid assignment. Break it into two strings
734 * representing NAME and VALUE.
735 */
736 arg[match[1].rm_eo] = '\0';
737 arg[match[2].rm_eo] = '\0';
738 *name = &arg[match[1].rm_so];
739 *value = &arg[match[2].rm_so];
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000740
Patrick Georgic6d2b092011-01-28 07:47:10 +0000741 regfree(&assignment);
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000742}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000743
744/****************************************************************************
745 * list_cmos_entry
746 *
747 * Attempt to list the CMOS entry represented by 'e'. 'show_name' is a
748 * boolean value indicating whether the parameter name should be displayed
749 * along with its value. On success, return OK. On error, print an error
750 * message and return 1.
751 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000752static int list_cmos_entry(const cmos_entry_t * e, int show_name)
753{
754 const cmos_enum_t *p;
755 unsigned long long value;
Stefan Reinauer42944c32010-01-16 14:57:32 +0000756 char *w;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000757
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000758 /* sanity check CMOS entry */
759 switch (prepare_cmos_read(e)) {
760 case OK:
761 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000762
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000763 case CMOS_OP_RESERVED:
764 BUG();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000765
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000766 case CMOS_AREA_OUT_OF_RANGE:
767 fprintf(stderr,
768 "%s: Can not read coreboot parameter %s because "
769 "layout info specifies out of range CMOS area.\n",
770 prog_name, e->name);
771 return 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000772
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000773 case CMOS_AREA_OVERLAPS_RTC:
774 fprintf(stderr,
775 "%s: Can not read coreboot parameter %s because "
776 "layout info specifies CMOS area that overlaps realtime "
777 "clock area.\n", prog_name, e->name);
778 return 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000779
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000780 case CMOS_AREA_TOO_WIDE:
781 fprintf(stderr,
782 "%s: Can not read coreboot parameter %s because "
783 "layout info specifies CMOS area that is too wide.\n",
784 prog_name, e->name);
785 return 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000786
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000787 default:
788 fprintf(stderr,
789 "%s: Unknown error encountered while attempting to "
790 "read coreboot parameter %s\n", prog_name, e->name);
791 return 1;
792 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000793
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000794 /* read the value from CMOS */
795 set_iopl(3);
796 value = cmos_read(e);
797 set_iopl(0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000798
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000799 /* display the value */
800 switch (e->config) {
801 case CMOS_ENTRY_ENUM:
802 if ((p = find_cmos_enum(e->config_id, value)) == NULL) {
803 if (show_name)
804 printf("# Bad value -> %s = 0x%llx\n", e->name,
805 value);
806 else
807 printf("Bad value -> 0x%llx\n", value);
808 } else {
809 if (show_name)
810 printf("%s = %s\n", e->name, p->text);
811 else
812 printf("%s\n", p->text);
813 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000814
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000815 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000816
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000817 case CMOS_ENTRY_HEX:
818 if (show_name)
819 printf("%s = 0x%llx\n", e->name, value);
820 else
821 printf("0x%llx\n", value);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000822
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000823 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000824
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000825 case CMOS_ENTRY_STRING:
Stefan Reinauer42944c32010-01-16 14:57:32 +0000826 w = (char *)(unsigned long)value;
827 while (*w) {
Jonathan Kollasch1571dc92011-04-19 19:34:25 +0000828 if(!isprint((int)(unsigned char)*w)) {
Stefan Reinauer42944c32010-01-16 14:57:32 +0000829 if (show_name)
830 printf("# Bad value -> %s\n", e->name);
831 else
832 printf("Bad value\n");
833 break;
834 }
835 w++;
836 }
837
838 if (!*w) {
839
840 if (show_name)
841 printf("%s = %s\n", e->name,
842 (char *)(unsigned long)value);
843 else
844 printf("%s\n", (char *)(unsigned long)value);
845 }
Stefan Reinauera67aab72008-09-27 10:08:28 +0000846
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000847 free((void *)(unsigned long)value);
Stefan Reinauera67aab72008-09-27 10:08:28 +0000848
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000849 break;
Stefan Reinauera67aab72008-09-27 10:08:28 +0000850
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000851 case CMOS_ENTRY_RESERVED:
852 default:
853 BUG();
854 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000855
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000856 return OK;
857}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000858
859/****************************************************************************
860 * convert_checksum_value
861 *
862 * 'value' is the string representation of a checksum value that the user
863 * wishes to set using the -c option. Convert the string to a 16-bit
864 * unsigned integer and return the result. Exit with an error message if
865 * 'value' is invalid.
866 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000867static uint16_t convert_checksum_value(const char value[])
868{
869 unsigned long n;
870 const char *p;
871 uint16_t result;
872 int negative;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000873
Jonathan Kollasch1571dc92011-04-19 19:34:25 +0000874 for (p = value; isspace((int)(unsigned char)*p); p++) ;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000875
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000876 negative = (*p == '-');
877 n = strtoul(value, (char **)&p, 0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000878
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000879 if (*p) {
880 fprintf(stderr,
881 "%s: Checksum value %s is not a valid integer.\n",
882 prog_name, value);
883 exit(1);
884 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000885
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000886 if (negative) {
887 fprintf(stderr,
888 "%s: Checksum must be an unsigned integer.\n",
889 prog_name);
890 exit(1);
891 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000892
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000893 result = (uint16_t) n;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000894
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000895 if (result != n) {
896 fprintf(stderr,
897 "%s: Checksum value must fit within 16 bits.\n",
898 prog_name);
899 exit(1);
900 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000901
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000902 return result;
903}