blob: f3fb16d1b1087432f56c7ea1d22b7e036c03bd41 [file] [log] [blame]
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001/*****************************************************************************\
Uwe Hermann6e565942008-03-01 19:06:32 +00002 * nvramtool.c
Stefan Reinauer6540ae52007-07-12 16:35:42 +00003 *****************************************************************************
4 * Copyright (C) 2002-2005 The Regents of the University of California.
5 * Produced at the Lawrence Livermore National Laboratory.
6 * Written by Dave Peterson <dsp@llnl.gov> <dave_peterson@pobox.com>.
7 * UCRL-CODE-2003-012
8 * All rights reserved.
9 *
Uwe Hermann6e565942008-03-01 19:06:32 +000010 * This file is part of nvramtool, a utility for reading/writing coreboot
Stefan Reinauerf527e702008-01-18 15:33:49 +000011 * parameters and displaying information from the coreboot table.
Uwe Hermann6e565942008-03-01 19:06:32 +000012 * For details, see http://coreboot.org/nvramtool.
Stefan Reinauer6540ae52007-07-12 16:35:42 +000013 *
14 * Please also read the file DISCLAIMER which is included in this software
15 * distribution.
16 *
17 * This program is free software; you can redistribute it and/or modify it
18 * under the terms of the GNU General Public License (as published by the
19 * Free Software Foundation) version 2, dated June 1991.
20 *
21 * This program is distributed in the hope that it will be useful, but
22 * WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
24 * conditions of the GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License along
27 * with this program; if not, write to the Free Software Foundation, Inc.,
Stefan Reinauerac7a2d22009-09-23 21:53:25 +000028 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
Stefan Reinauer6540ae52007-07-12 16:35:42 +000029\*****************************************************************************/
30
Patrick Georgi202be7b2011-01-21 07:29:40 +000031#include <fcntl.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <sys/mman.h>
Stefan Reinauer6540ae52007-07-12 16:35:42 +000035#include "common.h"
36#include "opts.h"
37#include "lbtable.h"
38#include "layout.h"
Patrick Georgi49a74432011-01-28 07:50:33 +000039#include "accessors/layout-text.h"
Stefan Reinauer6540ae52007-07-12 16:35:42 +000040#include "input_file.h"
41#include "cmos_ops.h"
42#include "cmos_lowlevel.h"
43#include "reg_expr.h"
44#include "hexdump.h"
Patrick Georgi269e9322011-01-21 07:24:08 +000045#include "cbfs.h"
Stefan Reinauer6540ae52007-07-12 16:35:42 +000046
47typedef void (*op_fn_t) (void);
48
Stefan Reinauer90b96b62010-01-13 21:00:23 +000049static void op_show_version(void);
50static void op_show_usage(void);
51static void op_lbtable_show_info(void);
52static void op_lbtable_dump(void);
53static void op_show_param_values(void);
54static void op_cmos_show_one_param(void);
55static void op_cmos_show_all_params(void);
56static void op_cmos_set_one_param(void);
57static void op_cmos_set_params_stdin(void);
58static void op_cmos_set_params_file(void);
59static void op_cmos_checksum(void);
60static void op_show_layout(void);
61static void op_write_cmos_dump(void);
62static void op_read_cmos_dump(void);
63static void op_show_cmos_hex_dump(void);
64static void op_show_cmos_dumpfile(void);
Vikram Narayanana8111cf2012-04-14 15:25:13 +053065static void op_write_cmos_layout_bin(void);
66static void op_write_cmos_layout_header(void);
Stefan Reinauer90b96b62010-01-13 21:00:23 +000067static int list_one_param(const char name[], int show_name);
68static int list_all_params(void);
69static void list_param_enums(const char name[]);
70static void set_one_param(const char name[], const char value[]);
71static void set_params(FILE * f);
72static void parse_assignment(char arg[], const char **name, const char **value);
73static int list_cmos_entry(const cmos_entry_t * e, int show_name);
74static uint16_t convert_checksum_value(const char value[]);
Stefan Reinauer6540ae52007-07-12 16:35:42 +000075
Stefan Reinauer90b96b62010-01-13 21:00:23 +000076static const op_fn_t op_fns[] = { op_show_version,
77 op_show_usage,
78 op_lbtable_show_info,
79 op_lbtable_dump,
80 op_show_param_values,
81 op_cmos_show_one_param,
82 op_cmos_show_all_params,
83 op_cmos_set_one_param,
84 op_cmos_set_params_stdin,
85 op_cmos_set_params_file,
86 op_cmos_checksum,
87 op_show_layout,
88 op_write_cmos_dump,
89 op_read_cmos_dump,
90 op_show_cmos_hex_dump,
Vikram Narayanana8111cf2012-04-14 15:25:13 +053091 op_show_cmos_dumpfile,
92 op_write_cmos_layout_bin,
93 op_write_cmos_layout_header
Stefan Reinauer90b96b62010-01-13 21:00:23 +000094};
Stefan Reinauer6540ae52007-07-12 16:35:42 +000095
Vikram Narayanana8111cf2012-04-14 15:25:13 +053096static void op_write_cmos_layout_bin(void)
97{
98 get_layout_from_file();
99 write_cmos_output_bin(nvramtool_op.param);
100}
101
102static void op_write_cmos_layout_header(void)
103{
104 get_layout_from_file();
105 write_cmos_layout_header(nvramtool_op.param);
106}
107
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000108static const hexdump_format_t cmos_dump_format =
Patrick Georgi024ec852011-01-18 12:14:08 +0000109 { 16, 2, "", " | ", " ", " | ", '.' };
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000110
111/****************************************************************************
112 * main
113 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000114int main(int argc, char *argv[])
115{
Patrick Georgi202be7b2011-01-21 07:29:40 +0000116 void *cmos_default = NULL;
Patrick Georgi269e9322011-01-21 07:24:08 +0000117 cmos_layout_get_fn_t fn = get_layout_from_cmos_table;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000118
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000119 parse_nvramtool_args(argc, argv);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000120
Mathias Krause943b8b52011-03-08 12:58:16 +0000121 /* If we should operate on a CBFS file default to reading the layout
122 * and CMOS contents from it. */
123 if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CBFS_FILE].found) {
Patrick Georgi269e9322011-01-21 07:24:08 +0000124 open_cbfs(nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CBFS_FILE].param);
Patrick Georgi202be7b2011-01-21 07:29:40 +0000125 if (!nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].found) {
126 cmos_default = cbfs_find_file("cmos.default", CBFS_COMPONENT_CMOS_DEFAULT, NULL);
127 if (cmos_default == NULL) {
128 fprintf(stderr, "Need a cmos.default in the CBFS image or separate cmos file (-D).\n");
129 exit(1);
130 }
131 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000132 fn = get_layout_from_cbfs_file;
Patrick Georgi202be7b2011-01-21 07:29:40 +0000133 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000134
135 /* If the user wants to use a specific layout file or explicitly use
136 * the coreboot option table allow him to override previous settings. */
137 if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_LAYOUT_FILE].found) {
138 set_layout_filename(nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_LAYOUT_FILE].param);
139 fn = get_layout_from_file;
140 } else if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_OPT_TABLE].found) {
141 fn = get_layout_from_cmos_table;
142 }
143
144 /* Allow the user to use a file for the CMOS contents, possibly
145 * overriding a previously opened "cmos.default" file from the CBFS. */
Patrick Georgi202be7b2011-01-21 07:29:40 +0000146 if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].found) {
Patrick Georgi202be7b2011-01-21 07:29:40 +0000147 struct stat fd_stat;
Mathias Krause943b8b52011-03-08 12:58:16 +0000148 int fd;
149
150 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 +0000151 fprintf(stderr, "Couldn't open '%s'\n", nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param);
Patrick Georgi269e9322011-01-21 07:24:08 +0000152 exit(1);
153 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000154
Patrick Georgi202be7b2011-01-21 07:29:40 +0000155 if (fstat(fd, &fd_stat) == -1) {
156 fprintf(stderr, "Couldn't stat '%s'\n", nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param);
157 exit(1);
158 }
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700159
Patrick Georgi202be7b2011-01-21 07:29:40 +0000160 if (fd_stat.st_size < 128) {
161 lseek(fd, 127, SEEK_SET);
Stefan Reinauera7b296d2011-11-14 12:40:34 -0800162 if (write(fd, "\0", 1) != 1) {
163 fprintf(stderr, "Unable to extended '%s' to its full size.\n",
164 nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param);
165 exit(1);
166 }
Patrick Georgi202be7b2011-01-21 07:29:40 +0000167 fsync(fd);
168 }
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700169
Patrick Georgi202be7b2011-01-21 07:29:40 +0000170 cmos_default = mmap(NULL, 128, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
171 if (cmos_default == MAP_FAILED) {
172 fprintf(stderr, "Couldn't map '%s'\n", nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param);
173 exit(1);
174 }
175 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000176
177 /* Switch to memory based CMOS access. */
Patrick Georgi202be7b2011-01-21 07:29:40 +0000178 if (cmos_default) {
179 select_hal(HAL_MEMORY, cmos_default);
Patrick Georgi269e9322011-01-21 07:24:08 +0000180 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000181
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000182 register_cmos_layout_get_fn(fn);
Mathias Krause943b8b52011-03-08 12:58:16 +0000183 op_fns[nvramtool_op.op]();
184
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000185 return 0;
186}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000187
188/****************************************************************************
189 * op_show_version
190 *
191 * -v
192 *
193 * Show version information for this program.
194 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000195static void op_show_version(void)
196{
197 printf("This is %s version %s.\n", prog_name, prog_version);
198}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000199
200/****************************************************************************
201 * op_show_usage
202 *
203 * -h
204 *
205 * Show a usage message for this program.
206 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000207static void op_show_usage(void)
208{
209 usage(stdout);
210}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000211
212/****************************************************************************
213 * op_lbtable_show_info
214 *
215 * -l [ARG]
216 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000217 * If ARG is present, show coreboot table information specified by ARG.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000218 * Else show all possible values for ARG.
219 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000220static void op_lbtable_show_info(void)
221{
222 if (nvramtool_op.param == NULL)
223 list_lbtable_choices();
224 else {
225 get_lbtable();
226 list_lbtable_item(nvramtool_op.param);
227 }
228}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000229
230/****************************************************************************
231 * op_lbtable_dump
232 *
233 * -d
234 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000235 * Do low-level dump of coreboot table.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000236 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000237static void op_lbtable_dump(void)
238{
239 get_lbtable();
240 dump_lbtable();
241}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000242
243/****************************************************************************
244 * op_show_param_values
245 *
246 * -e NAME option
247 *
248 * Show all possible values for parameter NAME.
249 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000250static void op_show_param_values(void)
251{
252 get_cmos_layout();
253 list_param_enums(nvramtool_op.param);
254}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000255
256/****************************************************************************
257 * op_cmos_show_one_param
258 *
259 * [-n] -r NAME
260 *
261 * Show parameter NAME. If -n is specified, show value only. Else show name
262 * and value.
263 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000264static void op_cmos_show_one_param(void)
265{
266 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000267
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000268 get_cmos_layout();
269 result = list_one_param(nvramtool_op.param,
270 !nvramtool_op_modifiers
271 [NVRAMTOOL_MOD_SHOW_VALUE_ONLY].found);
272 cmos_checksum_verify();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000273
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000274 if (result)
275 exit(1);
276}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000277
278/****************************************************************************
279 * op_cmos_show_all_params
280 *
281 * -a
282 *
283 * Show names and values for all parameters.
284 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000285static void op_cmos_show_all_params(void)
286{
287 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000288
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000289 get_cmos_layout();
290 result = list_all_params();
291 cmos_checksum_verify();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000292
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000293 if (result)
294 exit(1);
295}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000296
297/****************************************************************************
298 * op_cmos_set_one_param
299 *
300 * -w NAME=VALUE
301 *
302 * Set parameter NAME to VALUE.
303 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000304static void op_cmos_set_one_param(void)
305{
306 const char *name, *value;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000307
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000308 get_cmos_layout();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000309
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000310 /* Separate 'NAME=VALUE' syntax into two strings representing NAME and
311 * VALUE.
312 */
313 parse_assignment(nvramtool_op.param, &name, &value);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000314
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000315 set_one_param(name, value);
316}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000317
318/****************************************************************************
319 * op_cmos_set_params_stdin
320 *
321 * -i
322 *
323 * Set parameters according to standard input.
324 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000325static void op_cmos_set_params_stdin(void)
326{
327 get_cmos_layout();
328 set_params(stdin);
329}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000330
331/****************************************************************************
332 * op_cmos_set_params_file
333 *
334 * -p INPUT_FILE
335 *
336 * Set parameters according to INPUT_FILE.
337 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000338static void op_cmos_set_params_file(void)
339{
340 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000341
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000342 if ((f = fopen(nvramtool_op.param, "r")) == NULL) {
343 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
344 prog_name, nvramtool_op.param, strerror(errno));
345 exit(1);
346 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000347
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000348 get_cmos_layout();
349 set_params(f);
350 fclose(f);
351}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000352
353/****************************************************************************
354 * op_cmos_checksum
355 *
356 * -c [VALUE]
357 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000358 * If VALUE is present, set coreboot CMOS checksum to VALUE. Else show
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000359 * checksum value.
360 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000361static void op_cmos_checksum(void)
362{
363 uint16_t checksum;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000364
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000365 get_cmos_layout();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000366
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000367 if (nvramtool_op.param == NULL) {
368 set_iopl(3);
369 checksum = cmos_checksum_read();
370 set_iopl(0);
371 printf("0x%x\n", checksum);
372 } else {
373 checksum = convert_checksum_value(nvramtool_op.param);
374 set_iopl(3);
375 cmos_checksum_write(checksum);
376 set_iopl(0);
377 }
378}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000379
380/****************************************************************************
381 * op_show_layout
382 *
383 * -Y
384 *
385 * Write CMOS layout information to standard output.
386 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000387static void op_show_layout(void)
388{
389 get_cmos_layout();
390 write_cmos_layout(stdout);
391}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000392
393/****************************************************************************
394 * op_write_cmos_dump
395 *
396 * -b OUTPUT_FILE
397 *
398 * Write the contents of CMOS memory to a binary file.
399 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000400static void op_write_cmos_dump(void)
401{
402 unsigned char data[CMOS_SIZE];
403 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000404
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000405 if ((f = fopen(nvramtool_op.param, "w")) == NULL) {
406 fprintf(stderr, "%s: Can not open file %s for writing: %s\n",
407 prog_name, nvramtool_op.param, strerror(errno));
408 exit(1);
409 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000410
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000411 set_iopl(3);
412 cmos_read_all(data);
413 set_iopl(0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000414
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000415 if (fwrite(data, 1, CMOS_SIZE, f) != CMOS_SIZE) {
416 fprintf(stderr, "%s: Error writing CMOS data to file %s: %s\n",
417 prog_name, nvramtool_op.param, strerror(errno));
418 exit(1);
419 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000420
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000421 fclose(f);
422}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000423
424/****************************************************************************
425 * op_read_cmos_dump
426 *
427 * -B INPUT_FILE
428 *
429 * Read binary data from a file and write the data to CMOS memory.
430 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000431static void op_read_cmos_dump(void)
432{
433 unsigned char data[CMOS_SIZE];
434 size_t nr_bytes;
435 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000436
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000437 if ((f = fopen(nvramtool_op.param, "r")) == NULL) {
438 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
439 prog_name, nvramtool_op.param, strerror(errno));
440 exit(1);
441 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000442
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000443 if ((nr_bytes = fread(data, 1, CMOS_SIZE, f)) != CMOS_SIZE) {
444 fprintf(stderr,
445 "%s: Error: Only able to read %d bytes of CMOS data "
446 "from file %s. CMOS data is unchanged.\n", prog_name,
447 (int)nr_bytes, nvramtool_op.param);
448 exit(1);
449 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000450
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000451 fclose(f);
452 set_iopl(3);
453 cmos_write_all(data);
454 set_iopl(0);
455}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000456
457/****************************************************************************
458 * op_show_cmos_hex_dump
459 *
460 * -x
461 *
462 * Write a hex dump of CMOS memory to standard output.
463 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000464static void op_show_cmos_hex_dump(void)
465{
466 unsigned char data[CMOS_SIZE];
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000467
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000468 set_iopl(3);
469 cmos_read_all(data);
470 set_iopl(0);
471 hexdump(data, CMOS_SIZE, 0, stdout, &cmos_dump_format);
472}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000473
474/****************************************************************************
475 * op_show_cmos_dumpfile
476 *
477 * -X DUMP_FILE
478 *
479 * Read binary data from a file (presumably a CMOS dump file) and display a
480 * hex dump of the CMOS data from the file.
481 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000482static void op_show_cmos_dumpfile(void)
483{
484 unsigned char data[CMOS_SIZE];
485 size_t nr_bytes;
486 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000487
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000488 if ((f = fopen(nvramtool_op.param, "r")) == NULL) {
489 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
490 prog_name, nvramtool_op.param, strerror(errno));
491 exit(1);
492 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000493
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000494 nr_bytes = fread(data, 1, CMOS_SIZE, f);
495 fclose(f);
496 hexdump(data, nr_bytes, 0, stdout, &cmos_dump_format);
497}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000498
499/****************************************************************************
500 * list_one_param
501 *
502 * Attempt to list one CMOS parameter given by 'name'. 'show_name' is a
503 * boolean value indicating whether the parameter name should be displayed
504 * along with its value. Return 1 if error was encountered. Else return OK.
505 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000506static int list_one_param(const char name[], int show_name)
507{
508 const cmos_entry_t *e;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000509
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000510 if (is_checksum_name(name) || ((e = find_cmos_entry(name)) == NULL)) {
511 fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name,
512 name);
513 exit(1);
514 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000515
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000516 if (e->config == CMOS_ENTRY_RESERVED) {
517 fprintf(stderr, "%s: Parameter %s is reserved.\n", prog_name,
518 name);
519 exit(1);
520 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000521
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000522 return (list_cmos_entry(e, show_name) != 0);
523}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000524
525/****************************************************************************
526 * list_all_params
527 *
528 * Attempt to list all CMOS parameters. Return 1 if error was encountered.
529 * Else return OK.
530 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000531static int list_all_params(void)
532{
533 const cmos_entry_t *e;
534 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000535
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000536 result = OK;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000537
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000538 for (e = first_cmos_entry(); e != NULL; e = next_cmos_entry(e)) {
539 if ((e->config == CMOS_ENTRY_RESERVED)
540 || is_checksum_name(e->name))
541 continue;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000542
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000543 if (list_cmos_entry(e, TRUE))
544 result = 1;
545 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000546
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000547 return result;
548}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000549
550/****************************************************************************
551 * list_param_enums
552 *
553 * List all possible values for CMOS parameter given by 'name'.
554 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000555static void list_param_enums(const char name[])
556{
557 const cmos_entry_t *e;
558 const cmos_enum_t *p;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000559
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000560 if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL) {
561 fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name,
562 name);
563 exit(1);
564 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000565
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000566 switch (e->config) {
567 case CMOS_ENTRY_ENUM:
568 for (p = first_cmos_enum_id(e->config_id);
569 p != NULL; p = next_cmos_enum_id(p))
570 printf("%s\n", p->text);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000571
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000572 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000573
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000574 case CMOS_ENTRY_HEX:
575 printf("Parameter %s requires a %u-bit unsigned integer.\n",
576 name, e->length);
577 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000578
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000579 case CMOS_ENTRY_STRING:
580 printf("Parameter %s requires a %u-byte string.\n", name,
581 e->length / 8);
582 break;
Stefan Reinauera67aab72008-09-27 10:08:28 +0000583
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000584 case CMOS_ENTRY_RESERVED:
585 printf("Parameter %s is reserved.\n", name);
586 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000587
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000588 default:
589 BUG();
590 }
591}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000592
593/****************************************************************************
594 * set_one_param
595 *
596 * Set the CMOS parameter given by 'name' to 'value'. The 'name' parameter
597 * is case-sensitive. If we are setting an enum parameter, then 'value' is
598 * interpreted as a case-sensitive string that must match the option name
599 * exactly. If we are setting a 'hex' parameter, then 'value' is treated as
600 * a string representation of an unsigned integer that may be specified in
601 * decimal, hex, or octal.
602 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000603static void set_one_param(const char name[], const char value[])
604{
605 const cmos_entry_t *e;
606 unsigned long long n;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000607
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000608 if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL) {
609 fprintf(stderr, "%s: CMOS parameter %s not found.", prog_name,
610 name);
611 exit(1);
612 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000613
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000614 switch (prepare_cmos_write(e, value, &n)) {
615 case OK:
616 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000617
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000618 case CMOS_OP_BAD_ENUM_VALUE:
619 fprintf(stderr, "%s: Bad value for parameter %s.", prog_name,
620 name);
621 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000622
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000623 case CMOS_OP_NEGATIVE_INT:
624 fprintf(stderr,
625 "%s: This program does not support assignment of negative "
626 "numbers to coreboot parameters.", prog_name);
627 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000628
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000629 case CMOS_OP_INVALID_INT:
630 fprintf(stderr, "%s: %s is not a valid integer.", prog_name,
631 value);
632 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000633
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000634 case CMOS_OP_RESERVED:
635 fprintf(stderr,
636 "%s: Can not modify reserved coreboot parameter %s.",
637 prog_name, name);
638 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000639
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000640 case CMOS_OP_VALUE_TOO_WIDE:
641 fprintf(stderr,
642 "%s: Can not write value %s to CMOS parameter %s that is "
643 "only %d bits wide.", prog_name, value, name,
644 e->length);
645 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000646
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000647 case CMOS_OP_NO_MATCHING_ENUM:
648 fprintf(stderr,
649 "%s: coreboot parameter %s has no matching enums.",
650 prog_name, name);
651 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000652
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000653 case CMOS_AREA_OUT_OF_RANGE:
654 fprintf(stderr,
655 "%s: The CMOS area specified by the layout info for "
656 "coreboot parameter %s is out of range.", prog_name,
657 name);
658 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000659
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000660 case CMOS_AREA_OVERLAPS_RTC:
661 fprintf(stderr,
662 "%s: The CMOS area specified by the layout info for "
663 "coreboot parameter %s overlaps the realtime clock area.",
664 prog_name, name);
665 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000666
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000667 case CMOS_AREA_TOO_WIDE:
668 fprintf(stderr,
669 "%s: The CMOS area specified by the layout info for "
670 "coreboot parameter %s is too wide.", prog_name, name);
671 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000672
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000673 default:
674 fprintf(stderr,
675 "%s: Unknown error encountered while attempting to modify "
676 "coreboot parameter %s.", prog_name, name);
677 goto fail;
678 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000679
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000680 /* write the value to nonvolatile RAM */
681 set_iopl(3);
682 cmos_write(e, n);
683 cmos_checksum_write(cmos_checksum_compute());
684 set_iopl(0);
685 return;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000686
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000687 fail:
688 fprintf(stderr, " CMOS write not performed.\n");
689 exit(1);
690}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000691
692/****************************************************************************
693 * set_params
694 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000695 * Set coreboot parameters according to the contents of file 'f'.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000696 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000697static void set_params(FILE * f)
698{ /* First process the input file. Then perform writes only if there were
699 * no problems processing the input. Either all values will be written
700 * successfully or no values will be written.
701 */
702 do_cmos_writes(process_input_file(f));
703}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000704
705/****************************************************************************
706 * parse_assignment
707 *
708 * Parse the string 'arg' (which supposedly represents an assignment) into a
709 * NAME and a VALUE. If 'arg' does not conform to the proper assignment
710 * syntax, exit with a usage message. Otherwise, on return, 'arg' is broken
711 * into substrings representing NAME and VALUE, and *name and *value are set
712 * to point to these two substrings.
713 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000714static void parse_assignment(char arg[], const char **name, const char **value)
715{
716 static const size_t N_MATCHES = 4;
717 regmatch_t match[N_MATCHES];
718 regex_t assignment;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000719
Patrick Georgic6d2b092011-01-28 07:47:10 +0000720 compile_reg_expr(REG_EXTENDED | REG_NEWLINE, assignment_regex, &assignment);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000721
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000722 /* Does 'arg' conform to proper assignment syntax? If not, exit with a
723 * usage message.
724 */
725 if (regexec(&assignment, arg, N_MATCHES, match, 0))
726 usage(stderr);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000727
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000728 /* Ok, we found a valid assignment. Break it into two strings
729 * representing NAME and VALUE.
730 */
731 arg[match[1].rm_eo] = '\0';
732 arg[match[2].rm_eo] = '\0';
733 *name = &arg[match[1].rm_so];
734 *value = &arg[match[2].rm_so];
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000735
Patrick Georgic6d2b092011-01-28 07:47:10 +0000736 regfree(&assignment);
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000737}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000738
739/****************************************************************************
740 * list_cmos_entry
741 *
742 * Attempt to list the CMOS entry represented by 'e'. 'show_name' is a
743 * boolean value indicating whether the parameter name should be displayed
744 * along with its value. On success, return OK. On error, print an error
745 * message and return 1.
746 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000747static int list_cmos_entry(const cmos_entry_t * e, int show_name)
748{
749 const cmos_enum_t *p;
750 unsigned long long value;
Stefan Reinauer42944c32010-01-16 14:57:32 +0000751 char *w;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000752
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000753 /* sanity check CMOS entry */
754 switch (prepare_cmos_read(e)) {
755 case OK:
756 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000757
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000758 case CMOS_OP_RESERVED:
759 BUG();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000760
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000761 case CMOS_AREA_OUT_OF_RANGE:
762 fprintf(stderr,
763 "%s: Can not read coreboot parameter %s because "
764 "layout info specifies out of range CMOS area.\n",
765 prog_name, e->name);
766 return 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000767
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000768 case CMOS_AREA_OVERLAPS_RTC:
769 fprintf(stderr,
770 "%s: Can not read coreboot parameter %s because "
771 "layout info specifies CMOS area that overlaps realtime "
772 "clock area.\n", prog_name, e->name);
773 return 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000774
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000775 case CMOS_AREA_TOO_WIDE:
776 fprintf(stderr,
777 "%s: Can not read coreboot parameter %s because "
778 "layout info specifies CMOS area that is too wide.\n",
779 prog_name, e->name);
780 return 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000781
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000782 default:
783 fprintf(stderr,
784 "%s: Unknown error encountered while attempting to "
785 "read coreboot parameter %s\n", prog_name, e->name);
786 return 1;
787 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000788
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000789 /* read the value from CMOS */
790 set_iopl(3);
791 value = cmos_read(e);
792 set_iopl(0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000793
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000794 /* display the value */
795 switch (e->config) {
796 case CMOS_ENTRY_ENUM:
797 if ((p = find_cmos_enum(e->config_id, value)) == NULL) {
798 if (show_name)
799 printf("# Bad value -> %s = 0x%llx\n", e->name,
800 value);
801 else
802 printf("Bad value -> 0x%llx\n", value);
803 } else {
804 if (show_name)
805 printf("%s = %s\n", e->name, p->text);
806 else
807 printf("%s\n", p->text);
808 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000809
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000810 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000811
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000812 case CMOS_ENTRY_HEX:
813 if (show_name)
814 printf("%s = 0x%llx\n", e->name, value);
815 else
816 printf("0x%llx\n", value);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000817
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000818 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000819
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000820 case CMOS_ENTRY_STRING:
Stefan Reinauer42944c32010-01-16 14:57:32 +0000821 w = (char *)(unsigned long)value;
822 while (*w) {
Jonathan Kollasch1571dc92011-04-19 19:34:25 +0000823 if(!isprint((int)(unsigned char)*w)) {
Stefan Reinauer42944c32010-01-16 14:57:32 +0000824 if (show_name)
825 printf("# Bad value -> %s\n", e->name);
826 else
827 printf("Bad value\n");
828 break;
829 }
830 w++;
831 }
832
833 if (!*w) {
834
835 if (show_name)
836 printf("%s = %s\n", e->name,
837 (char *)(unsigned long)value);
838 else
839 printf("%s\n", (char *)(unsigned long)value);
840 }
Stefan Reinauera67aab72008-09-27 10:08:28 +0000841
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000842 free((void *)(unsigned long)value);
Stefan Reinauera67aab72008-09-27 10:08:28 +0000843
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000844 break;
Stefan Reinauera67aab72008-09-27 10:08:28 +0000845
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000846 case CMOS_ENTRY_RESERVED:
847 default:
848 BUG();
849 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000850
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000851 return OK;
852}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000853
854/****************************************************************************
855 * convert_checksum_value
856 *
857 * 'value' is the string representation of a checksum value that the user
858 * wishes to set using the -c option. Convert the string to a 16-bit
859 * unsigned integer and return the result. Exit with an error message if
860 * 'value' is invalid.
861 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000862static uint16_t convert_checksum_value(const char value[])
863{
864 unsigned long n;
865 const char *p;
866 uint16_t result;
867 int negative;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000868
Jonathan Kollasch1571dc92011-04-19 19:34:25 +0000869 for (p = value; isspace((int)(unsigned char)*p); p++) ;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000870
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000871 negative = (*p == '-');
872 n = strtoul(value, (char **)&p, 0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000873
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000874 if (*p) {
875 fprintf(stderr,
876 "%s: Checksum value %s is not a valid integer.\n",
877 prog_name, value);
878 exit(1);
879 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000880
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000881 if (negative) {
882 fprintf(stderr,
883 "%s: Checksum must be an unsigned integer.\n",
884 prog_name);
885 exit(1);
886 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000887
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000888 result = (uint16_t) n;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000889
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000890 if (result != n) {
891 fprintf(stderr,
892 "%s: Checksum value must fit within 16 bits.\n",
893 prog_name);
894 exit(1);
895 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000896
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000897 return result;
898}