blob: 9bc3e4e5251e3a32b05c5cb4600d2e9b40433de6 [file] [log] [blame]
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001/*****************************************************************************\
Uwe Hermann6e565942008-03-01 19:06:32 +00002 * nvramtool.c
Stefan Reinauer6540ae52007-07-12 16:35:42 +00003 *****************************************************************************
4 * Copyright (C) 2002-2005 The Regents of the University of California.
5 * Produced at the Lawrence Livermore National Laboratory.
6 * Written by Dave Peterson <dsp@llnl.gov> <dave_peterson@pobox.com>.
7 * UCRL-CODE-2003-012
8 * All rights reserved.
9 *
Uwe Hermann6e565942008-03-01 19:06:32 +000010 * This file is part of nvramtool, a utility for reading/writing coreboot
Stefan Reinauerf527e702008-01-18 15:33:49 +000011 * parameters and displaying information from the coreboot table.
Uwe Hermann6e565942008-03-01 19:06:32 +000012 * For details, see http://coreboot.org/nvramtool.
Stefan Reinauer6540ae52007-07-12 16:35:42 +000013 *
14 * Please also read the file DISCLAIMER which is included in this software
15 * distribution.
16 *
17 * This program is free software; you can redistribute it and/or modify it
18 * under the terms of the GNU General Public License (as published by the
19 * Free Software Foundation) version 2, dated June 1991.
20 *
21 * This program is distributed in the hope that it will be useful, but
22 * WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
24 * conditions of the GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License along
27 * with this program; if not, write to the Free Software Foundation, Inc.,
Stefan Reinauerac7a2d22009-09-23 21:53:25 +000028 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
Stefan Reinauer6540ae52007-07-12 16:35:42 +000029\*****************************************************************************/
30
Patrick Georgi202be7b2011-01-21 07:29:40 +000031#include <fcntl.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <sys/mman.h>
Stefan Reinauer6540ae52007-07-12 16:35:42 +000035#include "common.h"
36#include "opts.h"
37#include "lbtable.h"
38#include "layout.h"
Patrick Georgi49a74432011-01-28 07:50:33 +000039#include "accessors/layout-text.h"
Stefan Reinauer6540ae52007-07-12 16:35:42 +000040#include "input_file.h"
41#include "cmos_ops.h"
42#include "cmos_lowlevel.h"
43#include "reg_expr.h"
44#include "hexdump.h"
Patrick Georgi269e9322011-01-21 07:24:08 +000045#include "cbfs.h"
Stefan Reinauer6540ae52007-07-12 16:35:42 +000046
47typedef void (*op_fn_t) (void);
48
Stefan Reinauer90b96b62010-01-13 21:00:23 +000049static void op_show_version(void);
50static void op_show_usage(void);
51static void op_lbtable_show_info(void);
52static void op_lbtable_dump(void);
53static void op_show_param_values(void);
54static void op_cmos_show_one_param(void);
55static void op_cmos_show_all_params(void);
56static void op_cmos_set_one_param(void);
57static void op_cmos_set_params_stdin(void);
58static void op_cmos_set_params_file(void);
59static void op_cmos_checksum(void);
60static void op_show_layout(void);
61static void op_write_cmos_dump(void);
62static void op_read_cmos_dump(void);
63static void op_show_cmos_hex_dump(void);
64static void op_show_cmos_dumpfile(void);
65static int list_one_param(const char name[], int show_name);
66static int list_all_params(void);
67static void list_param_enums(const char name[]);
68static void set_one_param(const char name[], const char value[]);
69static void set_params(FILE * f);
70static void parse_assignment(char arg[], const char **name, const char **value);
71static int list_cmos_entry(const cmos_entry_t * e, int show_name);
72static uint16_t convert_checksum_value(const char value[]);
Stefan Reinauer6540ae52007-07-12 16:35:42 +000073
Stefan Reinauer90b96b62010-01-13 21:00:23 +000074static const op_fn_t op_fns[] = { op_show_version,
75 op_show_usage,
76 op_lbtable_show_info,
77 op_lbtable_dump,
78 op_show_param_values,
79 op_cmos_show_one_param,
80 op_cmos_show_all_params,
81 op_cmos_set_one_param,
82 op_cmos_set_params_stdin,
83 op_cmos_set_params_file,
84 op_cmos_checksum,
85 op_show_layout,
86 op_write_cmos_dump,
87 op_read_cmos_dump,
88 op_show_cmos_hex_dump,
89 op_show_cmos_dumpfile
90};
Stefan Reinauer6540ae52007-07-12 16:35:42 +000091
92static const hexdump_format_t cmos_dump_format =
Patrick Georgi024ec852011-01-18 12:14:08 +000093 { 16, 2, "", " | ", " ", " | ", '.' };
Stefan Reinauer6540ae52007-07-12 16:35:42 +000094
95/****************************************************************************
96 * main
97 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +000098int main(int argc, char *argv[])
99{
Patrick Georgi202be7b2011-01-21 07:29:40 +0000100 void *cmos_default = NULL;
Patrick Georgi269e9322011-01-21 07:24:08 +0000101 cmos_layout_get_fn_t fn = get_layout_from_cmos_table;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000102
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000103 parse_nvramtool_args(argc, argv);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000104
Mathias Krause943b8b52011-03-08 12:58:16 +0000105 /* If we should operate on a CBFS file default to reading the layout
106 * and CMOS contents from it. */
107 if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CBFS_FILE].found) {
Patrick Georgi269e9322011-01-21 07:24:08 +0000108 open_cbfs(nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CBFS_FILE].param);
Patrick Georgi202be7b2011-01-21 07:29:40 +0000109 if (!nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].found) {
110 cmos_default = cbfs_find_file("cmos.default", CBFS_COMPONENT_CMOS_DEFAULT, NULL);
111 if (cmos_default == NULL) {
112 fprintf(stderr, "Need a cmos.default in the CBFS image or separate cmos file (-D).\n");
113 exit(1);
114 }
115 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000116 fn = get_layout_from_cbfs_file;
Patrick Georgi202be7b2011-01-21 07:29:40 +0000117 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000118
119 /* If the user wants to use a specific layout file or explicitly use
120 * the coreboot option table allow him to override previous settings. */
121 if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_LAYOUT_FILE].found) {
122 set_layout_filename(nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_LAYOUT_FILE].param);
123 fn = get_layout_from_file;
124 } else if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_OPT_TABLE].found) {
125 fn = get_layout_from_cmos_table;
126 }
127
128 /* Allow the user to use a file for the CMOS contents, possibly
129 * overriding a previously opened "cmos.default" file from the CBFS. */
Patrick Georgi202be7b2011-01-21 07:29:40 +0000130 if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].found) {
Patrick Georgi202be7b2011-01-21 07:29:40 +0000131 struct stat fd_stat;
Mathias Krause943b8b52011-03-08 12:58:16 +0000132 int fd;
133
134 if ((fd = open(nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param, O_RDWR | O_CREAT, 0666)) < 0) {
Patrick Georgi202be7b2011-01-21 07:29:40 +0000135 fprintf(stderr, "Couldn't open '%s'\n", nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param);
Patrick Georgi269e9322011-01-21 07:24:08 +0000136 exit(1);
137 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000138
Patrick Georgi202be7b2011-01-21 07:29:40 +0000139 if (fstat(fd, &fd_stat) == -1) {
140 fprintf(stderr, "Couldn't stat '%s'\n", nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param);
141 exit(1);
142 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000143
Patrick Georgi202be7b2011-01-21 07:29:40 +0000144 if (fd_stat.st_size < 128) {
145 lseek(fd, 127, SEEK_SET);
146 write(fd, "\0", 1);
147 fsync(fd);
148 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000149
Patrick Georgi202be7b2011-01-21 07:29:40 +0000150 cmos_default = mmap(NULL, 128, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
151 if (cmos_default == MAP_FAILED) {
152 fprintf(stderr, "Couldn't map '%s'\n", nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param);
153 exit(1);
154 }
155 }
Mathias Krause943b8b52011-03-08 12:58:16 +0000156
157 /* Switch to memory based CMOS access. */
Patrick Georgi202be7b2011-01-21 07:29:40 +0000158 if (cmos_default) {
159 select_hal(HAL_MEMORY, cmos_default);
Patrick Georgi269e9322011-01-21 07:24:08 +0000160 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000161
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000162 register_cmos_layout_get_fn(fn);
Mathias Krause943b8b52011-03-08 12:58:16 +0000163 op_fns[nvramtool_op.op]();
164
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000165 return 0;
166}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000167
168/****************************************************************************
169 * op_show_version
170 *
171 * -v
172 *
173 * Show version information for this program.
174 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000175static void op_show_version(void)
176{
177 printf("This is %s version %s.\n", prog_name, prog_version);
178}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000179
180/****************************************************************************
181 * op_show_usage
182 *
183 * -h
184 *
185 * Show a usage message for this program.
186 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000187static void op_show_usage(void)
188{
189 usage(stdout);
190}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000191
192/****************************************************************************
193 * op_lbtable_show_info
194 *
195 * -l [ARG]
196 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000197 * If ARG is present, show coreboot table information specified by ARG.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000198 * Else show all possible values for ARG.
199 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000200static void op_lbtable_show_info(void)
201{
202 if (nvramtool_op.param == NULL)
203 list_lbtable_choices();
204 else {
205 get_lbtable();
206 list_lbtable_item(nvramtool_op.param);
207 }
208}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000209
210/****************************************************************************
211 * op_lbtable_dump
212 *
213 * -d
214 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000215 * Do low-level dump of coreboot table.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000216 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000217static void op_lbtable_dump(void)
218{
219 get_lbtable();
220 dump_lbtable();
221}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000222
223/****************************************************************************
224 * op_show_param_values
225 *
226 * -e NAME option
227 *
228 * Show all possible values for parameter NAME.
229 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000230static void op_show_param_values(void)
231{
232 get_cmos_layout();
233 list_param_enums(nvramtool_op.param);
234}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000235
236/****************************************************************************
237 * op_cmos_show_one_param
238 *
239 * [-n] -r NAME
240 *
241 * Show parameter NAME. If -n is specified, show value only. Else show name
242 * and value.
243 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000244static void op_cmos_show_one_param(void)
245{
246 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000247
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000248 get_cmos_layout();
249 result = list_one_param(nvramtool_op.param,
250 !nvramtool_op_modifiers
251 [NVRAMTOOL_MOD_SHOW_VALUE_ONLY].found);
252 cmos_checksum_verify();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000253
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000254 if (result)
255 exit(1);
256}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000257
258/****************************************************************************
259 * op_cmos_show_all_params
260 *
261 * -a
262 *
263 * Show names and values for all parameters.
264 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000265static void op_cmos_show_all_params(void)
266{
267 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000268
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000269 get_cmos_layout();
270 result = list_all_params();
271 cmos_checksum_verify();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000272
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000273 if (result)
274 exit(1);
275}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000276
277/****************************************************************************
278 * op_cmos_set_one_param
279 *
280 * -w NAME=VALUE
281 *
282 * Set parameter NAME to VALUE.
283 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000284static void op_cmos_set_one_param(void)
285{
286 const char *name, *value;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000287
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000288 get_cmos_layout();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000289
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000290 /* Separate 'NAME=VALUE' syntax into two strings representing NAME and
291 * VALUE.
292 */
293 parse_assignment(nvramtool_op.param, &name, &value);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000294
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000295 set_one_param(name, value);
296}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000297
298/****************************************************************************
299 * op_cmos_set_params_stdin
300 *
301 * -i
302 *
303 * Set parameters according to standard input.
304 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000305static void op_cmos_set_params_stdin(void)
306{
307 get_cmos_layout();
308 set_params(stdin);
309}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000310
311/****************************************************************************
312 * op_cmos_set_params_file
313 *
314 * -p INPUT_FILE
315 *
316 * Set parameters according to INPUT_FILE.
317 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000318static void op_cmos_set_params_file(void)
319{
320 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000321
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000322 if ((f = fopen(nvramtool_op.param, "r")) == NULL) {
323 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
324 prog_name, nvramtool_op.param, strerror(errno));
325 exit(1);
326 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000327
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000328 get_cmos_layout();
329 set_params(f);
330 fclose(f);
331}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000332
333/****************************************************************************
334 * op_cmos_checksum
335 *
336 * -c [VALUE]
337 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000338 * If VALUE is present, set coreboot CMOS checksum to VALUE. Else show
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000339 * checksum value.
340 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000341static void op_cmos_checksum(void)
342{
343 uint16_t checksum;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000344
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000345 get_cmos_layout();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000346
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000347 if (nvramtool_op.param == NULL) {
348 set_iopl(3);
349 checksum = cmos_checksum_read();
350 set_iopl(0);
351 printf("0x%x\n", checksum);
352 } else {
353 checksum = convert_checksum_value(nvramtool_op.param);
354 set_iopl(3);
355 cmos_checksum_write(checksum);
356 set_iopl(0);
357 }
358}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000359
360/****************************************************************************
361 * op_show_layout
362 *
363 * -Y
364 *
365 * Write CMOS layout information to standard output.
366 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000367static void op_show_layout(void)
368{
369 get_cmos_layout();
370 write_cmos_layout(stdout);
371}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000372
373/****************************************************************************
374 * op_write_cmos_dump
375 *
376 * -b OUTPUT_FILE
377 *
378 * Write the contents of CMOS memory to a binary file.
379 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000380static void op_write_cmos_dump(void)
381{
382 unsigned char data[CMOS_SIZE];
383 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000384
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000385 if ((f = fopen(nvramtool_op.param, "w")) == NULL) {
386 fprintf(stderr, "%s: Can not open file %s for writing: %s\n",
387 prog_name, nvramtool_op.param, strerror(errno));
388 exit(1);
389 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000390
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000391 set_iopl(3);
392 cmos_read_all(data);
393 set_iopl(0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000394
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000395 if (fwrite(data, 1, CMOS_SIZE, f) != CMOS_SIZE) {
396 fprintf(stderr, "%s: Error writing CMOS data to file %s: %s\n",
397 prog_name, nvramtool_op.param, strerror(errno));
398 exit(1);
399 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000400
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000401 fclose(f);
402}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000403
404/****************************************************************************
405 * op_read_cmos_dump
406 *
407 * -B INPUT_FILE
408 *
409 * Read binary data from a file and write the data to CMOS memory.
410 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000411static void op_read_cmos_dump(void)
412{
413 unsigned char data[CMOS_SIZE];
414 size_t nr_bytes;
415 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000416
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000417 if ((f = fopen(nvramtool_op.param, "r")) == NULL) {
418 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
419 prog_name, nvramtool_op.param, strerror(errno));
420 exit(1);
421 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000422
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000423 if ((nr_bytes = fread(data, 1, CMOS_SIZE, f)) != CMOS_SIZE) {
424 fprintf(stderr,
425 "%s: Error: Only able to read %d bytes of CMOS data "
426 "from file %s. CMOS data is unchanged.\n", prog_name,
427 (int)nr_bytes, nvramtool_op.param);
428 exit(1);
429 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000430
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000431 fclose(f);
432 set_iopl(3);
433 cmos_write_all(data);
434 set_iopl(0);
435}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000436
437/****************************************************************************
438 * op_show_cmos_hex_dump
439 *
440 * -x
441 *
442 * Write a hex dump of CMOS memory to standard output.
443 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000444static void op_show_cmos_hex_dump(void)
445{
446 unsigned char data[CMOS_SIZE];
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000447
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000448 set_iopl(3);
449 cmos_read_all(data);
450 set_iopl(0);
451 hexdump(data, CMOS_SIZE, 0, stdout, &cmos_dump_format);
452}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000453
454/****************************************************************************
455 * op_show_cmos_dumpfile
456 *
457 * -X DUMP_FILE
458 *
459 * Read binary data from a file (presumably a CMOS dump file) and display a
460 * hex dump of the CMOS data from the file.
461 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000462static void op_show_cmos_dumpfile(void)
463{
464 unsigned char data[CMOS_SIZE];
465 size_t nr_bytes;
466 FILE *f;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000467
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000468 if ((f = fopen(nvramtool_op.param, "r")) == NULL) {
469 fprintf(stderr, "%s: Can not open file %s for reading: %s\n",
470 prog_name, nvramtool_op.param, strerror(errno));
471 exit(1);
472 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000473
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000474 nr_bytes = fread(data, 1, CMOS_SIZE, f);
475 fclose(f);
476 hexdump(data, nr_bytes, 0, stdout, &cmos_dump_format);
477}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000478
479/****************************************************************************
480 * list_one_param
481 *
482 * Attempt to list one CMOS parameter given by 'name'. 'show_name' is a
483 * boolean value indicating whether the parameter name should be displayed
484 * along with its value. Return 1 if error was encountered. Else return OK.
485 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000486static int list_one_param(const char name[], int show_name)
487{
488 const cmos_entry_t *e;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000489
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000490 if (is_checksum_name(name) || ((e = find_cmos_entry(name)) == NULL)) {
491 fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name,
492 name);
493 exit(1);
494 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000495
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000496 if (e->config == CMOS_ENTRY_RESERVED) {
497 fprintf(stderr, "%s: Parameter %s is reserved.\n", prog_name,
498 name);
499 exit(1);
500 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000501
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000502 return (list_cmos_entry(e, show_name) != 0);
503}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000504
505/****************************************************************************
506 * list_all_params
507 *
508 * Attempt to list all CMOS parameters. Return 1 if error was encountered.
509 * Else return OK.
510 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000511static int list_all_params(void)
512{
513 const cmos_entry_t *e;
514 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000515
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000516 result = OK;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000517
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000518 for (e = first_cmos_entry(); e != NULL; e = next_cmos_entry(e)) {
519 if ((e->config == CMOS_ENTRY_RESERVED)
520 || is_checksum_name(e->name))
521 continue;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000522
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000523 if (list_cmos_entry(e, TRUE))
524 result = 1;
525 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000526
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000527 return result;
528}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000529
530/****************************************************************************
531 * list_param_enums
532 *
533 * List all possible values for CMOS parameter given by 'name'.
534 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000535static void list_param_enums(const char name[])
536{
537 const cmos_entry_t *e;
538 const cmos_enum_t *p;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000539
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000540 if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL) {
541 fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name,
542 name);
543 exit(1);
544 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000545
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000546 switch (e->config) {
547 case CMOS_ENTRY_ENUM:
548 for (p = first_cmos_enum_id(e->config_id);
549 p != NULL; p = next_cmos_enum_id(p))
550 printf("%s\n", p->text);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000551
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000552 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000553
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000554 case CMOS_ENTRY_HEX:
555 printf("Parameter %s requires a %u-bit unsigned integer.\n",
556 name, e->length);
557 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000558
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000559 case CMOS_ENTRY_STRING:
560 printf("Parameter %s requires a %u-byte string.\n", name,
561 e->length / 8);
562 break;
Stefan Reinauera67aab72008-09-27 10:08:28 +0000563
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000564 case CMOS_ENTRY_RESERVED:
565 printf("Parameter %s is reserved.\n", name);
566 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000567
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000568 default:
569 BUG();
570 }
571}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000572
573/****************************************************************************
574 * set_one_param
575 *
576 * Set the CMOS parameter given by 'name' to 'value'. The 'name' parameter
577 * is case-sensitive. If we are setting an enum parameter, then 'value' is
578 * interpreted as a case-sensitive string that must match the option name
579 * exactly. If we are setting a 'hex' parameter, then 'value' is treated as
580 * a string representation of an unsigned integer that may be specified in
581 * decimal, hex, or octal.
582 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000583static void set_one_param(const char name[], const char value[])
584{
585 const cmos_entry_t *e;
586 unsigned long long n;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000587
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000588 if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL) {
589 fprintf(stderr, "%s: CMOS parameter %s not found.", prog_name,
590 name);
591 exit(1);
592 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000593
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000594 switch (prepare_cmos_write(e, value, &n)) {
595 case OK:
596 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000597
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000598 case CMOS_OP_BAD_ENUM_VALUE:
599 fprintf(stderr, "%s: Bad value for parameter %s.", prog_name,
600 name);
601 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000602
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000603 case CMOS_OP_NEGATIVE_INT:
604 fprintf(stderr,
605 "%s: This program does not support assignment of negative "
606 "numbers to coreboot parameters.", prog_name);
607 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000608
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000609 case CMOS_OP_INVALID_INT:
610 fprintf(stderr, "%s: %s is not a valid integer.", prog_name,
611 value);
612 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000613
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000614 case CMOS_OP_RESERVED:
615 fprintf(stderr,
616 "%s: Can not modify reserved coreboot parameter %s.",
617 prog_name, name);
618 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000619
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000620 case CMOS_OP_VALUE_TOO_WIDE:
621 fprintf(stderr,
622 "%s: Can not write value %s to CMOS parameter %s that is "
623 "only %d bits wide.", prog_name, value, name,
624 e->length);
625 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000626
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000627 case CMOS_OP_NO_MATCHING_ENUM:
628 fprintf(stderr,
629 "%s: coreboot parameter %s has no matching enums.",
630 prog_name, name);
631 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000632
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000633 case CMOS_AREA_OUT_OF_RANGE:
634 fprintf(stderr,
635 "%s: The CMOS area specified by the layout info for "
636 "coreboot parameter %s is out of range.", prog_name,
637 name);
638 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000639
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000640 case CMOS_AREA_OVERLAPS_RTC:
641 fprintf(stderr,
642 "%s: The CMOS area specified by the layout info for "
643 "coreboot parameter %s overlaps the realtime clock area.",
644 prog_name, name);
645 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000646
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000647 case CMOS_AREA_TOO_WIDE:
648 fprintf(stderr,
649 "%s: The CMOS area specified by the layout info for "
650 "coreboot parameter %s is too wide.", prog_name, name);
651 goto fail;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000652
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000653 default:
654 fprintf(stderr,
655 "%s: Unknown error encountered while attempting to modify "
656 "coreboot parameter %s.", prog_name, name);
657 goto fail;
658 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000659
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000660 /* write the value to nonvolatile RAM */
661 set_iopl(3);
662 cmos_write(e, n);
663 cmos_checksum_write(cmos_checksum_compute());
664 set_iopl(0);
665 return;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000666
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000667 fail:
668 fprintf(stderr, " CMOS write not performed.\n");
669 exit(1);
670}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000671
672/****************************************************************************
673 * set_params
674 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000675 * Set coreboot parameters according to the contents of file 'f'.
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000676 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000677static void set_params(FILE * f)
678{ /* First process the input file. Then perform writes only if there were
679 * no problems processing the input. Either all values will be written
680 * successfully or no values will be written.
681 */
682 do_cmos_writes(process_input_file(f));
683}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000684
685/****************************************************************************
686 * parse_assignment
687 *
688 * Parse the string 'arg' (which supposedly represents an assignment) into a
689 * NAME and a VALUE. If 'arg' does not conform to the proper assignment
690 * syntax, exit with a usage message. Otherwise, on return, 'arg' is broken
691 * into substrings representing NAME and VALUE, and *name and *value are set
692 * to point to these two substrings.
693 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000694static void parse_assignment(char arg[], const char **name, const char **value)
695{
696 static const size_t N_MATCHES = 4;
697 regmatch_t match[N_MATCHES];
698 regex_t assignment;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000699
Patrick Georgic6d2b092011-01-28 07:47:10 +0000700 compile_reg_expr(REG_EXTENDED | REG_NEWLINE, assignment_regex, &assignment);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000701
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000702 /* Does 'arg' conform to proper assignment syntax? If not, exit with a
703 * usage message.
704 */
705 if (regexec(&assignment, arg, N_MATCHES, match, 0))
706 usage(stderr);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000707
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000708 /* Ok, we found a valid assignment. Break it into two strings
709 * representing NAME and VALUE.
710 */
711 arg[match[1].rm_eo] = '\0';
712 arg[match[2].rm_eo] = '\0';
713 *name = &arg[match[1].rm_so];
714 *value = &arg[match[2].rm_so];
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000715
Patrick Georgic6d2b092011-01-28 07:47:10 +0000716 regfree(&assignment);
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000717}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000718
719/****************************************************************************
720 * list_cmos_entry
721 *
722 * Attempt to list the CMOS entry represented by 'e'. 'show_name' is a
723 * boolean value indicating whether the parameter name should be displayed
724 * along with its value. On success, return OK. On error, print an error
725 * message and return 1.
726 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000727static int list_cmos_entry(const cmos_entry_t * e, int show_name)
728{
729 const cmos_enum_t *p;
730 unsigned long long value;
Stefan Reinauer42944c32010-01-16 14:57:32 +0000731 char *w;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000732
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000733 /* sanity check CMOS entry */
734 switch (prepare_cmos_read(e)) {
735 case OK:
736 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000737
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000738 case CMOS_OP_RESERVED:
739 BUG();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000740
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000741 case CMOS_AREA_OUT_OF_RANGE:
742 fprintf(stderr,
743 "%s: Can not read coreboot parameter %s because "
744 "layout info specifies out of range CMOS area.\n",
745 prog_name, e->name);
746 return 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000747
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000748 case CMOS_AREA_OVERLAPS_RTC:
749 fprintf(stderr,
750 "%s: Can not read coreboot parameter %s because "
751 "layout info specifies CMOS area that overlaps realtime "
752 "clock area.\n", prog_name, e->name);
753 return 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000754
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000755 case CMOS_AREA_TOO_WIDE:
756 fprintf(stderr,
757 "%s: Can not read coreboot parameter %s because "
758 "layout info specifies CMOS area that is too wide.\n",
759 prog_name, e->name);
760 return 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000761
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000762 default:
763 fprintf(stderr,
764 "%s: Unknown error encountered while attempting to "
765 "read coreboot parameter %s\n", prog_name, e->name);
766 return 1;
767 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000768
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000769 /* read the value from CMOS */
770 set_iopl(3);
771 value = cmos_read(e);
772 set_iopl(0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000773
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000774 /* display the value */
775 switch (e->config) {
776 case CMOS_ENTRY_ENUM:
777 if ((p = find_cmos_enum(e->config_id, value)) == NULL) {
778 if (show_name)
779 printf("# Bad value -> %s = 0x%llx\n", e->name,
780 value);
781 else
782 printf("Bad value -> 0x%llx\n", value);
783 } else {
784 if (show_name)
785 printf("%s = %s\n", e->name, p->text);
786 else
787 printf("%s\n", p->text);
788 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000789
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000790 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000791
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000792 case CMOS_ENTRY_HEX:
793 if (show_name)
794 printf("%s = 0x%llx\n", e->name, value);
795 else
796 printf("0x%llx\n", value);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000797
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000798 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000799
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000800 case CMOS_ENTRY_STRING:
Stefan Reinauer42944c32010-01-16 14:57:32 +0000801 w = (char *)(unsigned long)value;
802 while (*w) {
803 if(!isprint(*w)) {
804 if (show_name)
805 printf("# Bad value -> %s\n", e->name);
806 else
807 printf("Bad value\n");
808 break;
809 }
810 w++;
811 }
812
813 if (!*w) {
814
815 if (show_name)
816 printf("%s = %s\n", e->name,
817 (char *)(unsigned long)value);
818 else
819 printf("%s\n", (char *)(unsigned long)value);
820 }
Stefan Reinauera67aab72008-09-27 10:08:28 +0000821
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000822 free((void *)(unsigned long)value);
Stefan Reinauera67aab72008-09-27 10:08:28 +0000823
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000824 break;
Stefan Reinauera67aab72008-09-27 10:08:28 +0000825
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000826 case CMOS_ENTRY_RESERVED:
827 default:
828 BUG();
829 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000830
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000831 return OK;
832}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000833
834/****************************************************************************
835 * convert_checksum_value
836 *
837 * 'value' is the string representation of a checksum value that the user
838 * wishes to set using the -c option. Convert the string to a 16-bit
839 * unsigned integer and return the result. Exit with an error message if
840 * 'value' is invalid.
841 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000842static uint16_t convert_checksum_value(const char value[])
843{
844 unsigned long n;
845 const char *p;
846 uint16_t result;
847 int negative;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000848
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000849 for (p = value; isspace(*p); p++) ;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000850
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000851 negative = (*p == '-');
852 n = strtoul(value, (char **)&p, 0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000853
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000854 if (*p) {
855 fprintf(stderr,
856 "%s: Checksum value %s is not a valid integer.\n",
857 prog_name, value);
858 exit(1);
859 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000860
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000861 if (negative) {
862 fprintf(stderr,
863 "%s: Checksum must be an unsigned integer.\n",
864 prog_name);
865 exit(1);
866 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000867
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000868 result = (uint16_t) n;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000869
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000870 if (result != n) {
871 fprintf(stderr,
872 "%s: Checksum value must fit within 16 bits.\n",
873 prog_name);
874 exit(1);
875 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000876
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000877 return result;
878}