3
* @brief nvram access utility for powerpc platforms.
6
* @mainpage nvram documentation
8
* Copyright (c) 2003, 2004, 2005 International Business Machines
9
* Common Public License Version 1.0 (see COPYRIGHT)
12
* The nvram command is used to print and modify data stored in the
13
* non-volatile RAM (NVRAM) on powerpc systems. NVRAM on powerpc systems
14
* is split into several partitions, each with their own format.
16
* The print options allow you to view the available partitions in NVRAM
17
* and print their contents.
19
* The update options allow you to update certain partitions of NVRAM,
20
* namely those containing name=value pairs. On many systems, the
21
* following NVRAM partitions contain data formatted as name=value pairs:
22
* common, of-config, and ibm,setupcfg.
24
* @author Nathan Fontenot <nfont@austin.ibm.com>
25
* @author Michael Strosaker <strosake@us.ibm.com>
26
* @author Todd Inglett <tinglett@us.ibm.com>
29
#include <sys/types.h>
42
#include <netinet/in.h> /* for ntohs */
50
* @brief name used to invoke thre nvram command (argv[0])
55
static struct option long_options[] = {
56
{"verbose", optional_argument, NULL, 'v'},
57
{"print-config", optional_argument, NULL, 'o'},
58
{"print-vpd", optional_argument, NULL, 'V'},
59
{"print-all-vpd", optional_argument, NULL, 'W'},
60
{"print-err-log", no_argument, NULL, 'e'},
61
{"print-event-scan", no_argument, NULL, 'E'},
62
{"partitions", no_argument, NULL, 'P'},
63
{"dump", required_argument, NULL, 'd'},
64
{"nvram-file", required_argument, NULL, 'n'},
65
{"nvram-size", required_argument, NULL, 's'},
66
{"update-config", required_argument, NULL, 'u'},
67
{"help", no_argument, NULL, 'h'},
68
{"partition", required_argument, NULL, 'p'},
74
* @brief print the help/usage message for nvram
79
printf("nvram options:\n"
80
" --print-config[=var]\n"
81
" print value of a config variable, or print all variables in\n"
82
" the specified (or all) partitions\n"
83
" --update-config <var>=<value>\n"
84
" update the config variable in the specified partition; the -p\n"
85
" option must also be specified\n"
87
" specify a partition; required with --update-config option,\n"
88
" optional with --print-config option\n"
92
" print VPD, including vendor specific data\n"
94
" print checkstop error log\n"
95
" --print-event-scan\n"
96
" print event scan log\n"
98
" print NVRAM paritition header info\n"
100
" raw dump of partition (use --partitions to see names)\n"
101
" --nvram-file <path>\n"
102
" specify alternate nvram data file (default is /dev/nvram)\n"
104
" specify size of nvram data (for repair operations)\n"
106
" be (more) verbose\n"
108
" print what you are reading right now.\n"
114
* @brief define to denote error messages
119
* @brief define to denote warning messages
124
* @brief maximum line length
130
* @brief print a message to stderr with the specified prefix
132
* @param msg_type either ERR_MSG or WARN_MSG
133
* @param fmt formatted string a la printf()
134
* @param ap initialized varaiable arg list
137
_msg(int msg_type, const char *fmt, va_list ap)
142
n = sprintf(buf, "%s: %s", nvram_cmdname,
143
(msg_type == WARN_MSG ? "WARNING: " : "ERROR: "));
145
vsprintf(buf + n, fmt, ap);
154
* @brief print an error message to stderr
156
* @param fmt formatted string a la printf()
158
void err_msg(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
160
err_msg(const char *fmt, ...)
165
_msg(ERR_MSG, fmt, ap);
171
* @brief print a warning message to stderr
173
* @param fmt formatted string a la printf()
175
void warn_msg(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
177
warn_msg(const char *fmt, ...)
182
_msg(WARN_MSG, fmt, ap);
188
* @brief resolve an Open Firmware node name
190
* In a device tree node with a single child, "foo@0", all of the following
191
* names refer to that child: "foo@0", "foo", "@0".
193
* @param parent fully-qualified path to the parent device node
194
* @param node the (possibly abbreviated) name of the child node
195
* @param nodelen length of the node parameter
196
* @param resolved pointer to return resolved node name in
197
* @return 0 if a suitable child can be found, and 'resolved' is a
198
* dynamically-allocated string containing the resolved node name.
202
resolve_of_node(const char *parent, const char *node, int nodelen,
205
static char nodebuf[1024]; /* XXX hardcoded length */
212
snprintf(nodebuf, sizeof(nodebuf), "%s/%.*s", parent,
214
rc = stat(nodebuf, &sbuf);
216
*resolved = malloc(nodelen+2);
217
snprintf(*resolved, nodelen+2, "/%.*s", nodelen, node);
221
goto out; /* report unusual errors */
223
if (node[0] == '@') {
224
/* it's a unit address; glob for *@unitaddr */
225
snprintf(nodebuf, sizeof(nodebuf), "%s/*%.*s*", parent, nodelen, node);
226
rc = glob(nodebuf, 0, NULL, &pglob);
228
if (pglob.gl_pathc > 1) {
229
err_msg("Ambiguous node name \"%.*s\"\n", nodelen, node);
230
while (pglob.gl_pathc) {
231
free(pglob.gl_pathv[pglob.gl_pathc]);
237
/* skip the leading fully-qualified path */
238
*resolved = strdup(pglob.gl_pathv[0] + strlen(parent));
239
free(pglob.gl_pathv[0]);
243
/* must be a node name; glob for node@* */
244
snprintf(nodebuf, sizeof(nodebuf), "%s/%.*s@*", parent, nodelen, node);
245
rc = glob(nodebuf, 0, NULL, &pglob);
247
if (pglob.gl_pathc > 1) {
248
err_msg("Ambiguous node name \"%.*s\"\n", nodelen, node);
249
while (pglob.gl_pathc) {
250
free(pglob.gl_pathv[pglob.gl_pathc]);
256
/* skip the leading fully-qualified path */
257
*resolved = strdup(pglob.gl_pathv[0] + strlen(parent));
258
free(pglob.gl_pathv[0]);
264
if (*resolved != NULL)
271
* @brief open an Open Firmware path under DEVICE_TREE
273
* @param ofpath the path to open, such as "/pci/@d/mac-io/nvram/#bytes"
275
* An Open Firmware path may contain "shortcut" node names that are not present
276
* under /proc/device-tree. In the above example, we may need to open
277
* "pci@80000000" instead of "pci".
279
* @return file descriptor to the opened node, or -1 on failure
282
open_of_path(const char *ofpath)
284
static char resolved_ofpath[1024]; /* XXX hardcoded length */
289
strcpy(resolved_ofpath, DEVICE_TREE);
296
ofpath = strchr(node + 1, '/');
298
nodelen = ofpath - node;
300
nodelen = strlen(node);
302
rc = resolve_of_node(resolved_ofpath, node, nodelen, &resolved_node);
306
strcat(resolved_ofpath, resolved_node);
311
fd = open(resolved_ofpath, O_RDONLY);
318
* @brief Get the size of nvram from the device tree
320
* Retrieve the size of nvram as specified by the Open Firmware
321
* device tree. If this fails we return a default size of
324
* @return size of nvram
327
get_of_nvram_size(void)
329
char buf[1024] = NVRAM_DEFAULT "/#bytes";
333
fd = open(buf, O_RDONLY);
335
/* Check the aliases directory */
339
fd = open(NVRAM_ALIAS, O_RDONLY);
341
err_msg("%s", "Could not determine nvram size from "
343
return DEFAULT_NVRAM_SZ;
346
if (fstat(fd, &sbuf) != 0) {
347
err_msg("%s", "Could not determine nvram size from "
350
return DEFAULT_NVRAM_SZ;
353
offset = read(fd, buf, sbuf.st_size - 1);
354
offset += sprintf(buf + offset, "%s", "/#bytes");
358
fd = open_of_path(buf);
362
warn_msg("cannot open nvram node \"%s\" in device tree: %s\n", buf,
365
return DEFAULT_NVRAM_SZ;
368
len = read(fd, &size, sizeof(size));
371
if (len != sizeof(size)) {
372
perror("got odd size for nvram node in device tree");
373
return DEFAULT_NVRAM_SZ;
381
* @brief read in the contents of nvram
383
* @param nvram nvram struct to read data into
384
* @return 0 on success, !0 on failure
387
nvram_read(struct nvram *nvram)
392
/* read in small chunks */
393
for (p = nvram->data, remaining = nvram->nbytes;
394
(len = read(nvram->fd, p, 512)) > 0;
395
p += len, remaining -= len) {
396
if (remaining <= 0) {
403
err_msg("cannot read \"%s\": %s\n", nvram->filename, strerror(errno));
407
/* If we are using the DEFAULT_NVRAM_SZ value we to do a small bit of
408
* fixup here. All of the remaining code assumes that nbytes contains
409
* the actual size of nvram, not a guess-timated amount and bad things
410
* ensue if it is not correct.
412
if (nvram->nbytes == DEFAULT_NVRAM_SZ) {
413
nvram->nbytes = nvram->nbytes - remaining;
414
remaining = DEFAULT_NVRAM_SZ - (remaining + nvram->nbytes);
418
warn_msg("expected %d bytes, but only read %d!\n",
419
nvram->nbytes, nvram->nbytes - remaining);
420
/* preserve the given nbytes, but zero the rest in case someone cares */
421
memset(p, 0, remaining);
425
printf("NVRAM size %d bytes\n", nvram->nbytes);
432
* @brief calculate the checksum for a partition header
434
* @param p pointer to partition header
435
* @return calculated checksum
438
checksum(struct partition_header *p)
440
unsigned int c_sum, c_sum2;
441
unsigned short *sp = (unsigned short *)p->name; /* assume 6 shorts */
443
c_sum = p->signature + p->length + sp[0] + sp[1] + sp[2] + sp[3]
446
/* The sum probably may have spilled into the 3rd byte. Fold it back. */
447
c_sum = ((c_sum & 0xffff) + (c_sum >> 16)) & 0xffff;
449
/* The sum cannot exceed 2 bytes. Fold it into a checksum */
450
c_sum2 = (c_sum >> 8) + (c_sum << 8);
451
c_sum = ((c_sum + c_sum2) >> 8) & 0xff;
458
* @brief raw data dump of a partition.
460
* Note that data_len must be a multiple of 16 bytes which makes
461
* for a cheap implementation.
463
* @param data pointer to data to be dumped
464
* @param data_len length of data buffer to be dumped
467
dump_raw_data(char *data, int data_len)
472
char *end = data + data_len;
477
printf("0x%08x ", offset);
480
for (i = 0; i < 4; i++) {
481
for (j = 0; j < 4; j++) {
483
printf("%02x", *h++);
492
for (i = 0; i < 16; i++) {
494
if ((*a >= ' ') && (*a <= '~'))
508
* @brief parse a config definition
510
* Parse an Open Firmware common config definition which
511
* is of the form name=value and return its length.
513
* Note that the name will always be < 32 chars. OF does
514
* not specify the max value length, but the value is binary
515
* and must be unquoted. We assume 4k is enough.
517
* @param data pointer to start of raw data (NULL terminated)
518
* @param data_len length of remaining raw data
519
* @param outname buffer to write parsed name
520
* @param outval buffer to write parsed output value
521
* @return number of bytes parsed
524
parse_of_common(char *data, int data_len, char *outname, char *outval)
527
char *p_end = data + data_len;
529
for (p = data, np = outname; *p && *p != '='; p++) {
531
if (np - outname > 32)
532
break; /* don't overrun */
534
err_msg("partition corrupt: ran off end parsing name\n");
541
err_msg("corrupt data: no = sign found or name > 31 chars\n");
546
/* Value needs to be unquoted */
547
for (np = outval; *p; p++) {
548
if (*p == (char)0xff) {
553
err_msg("partition corrupt: ran off end parsing "
559
ch = (*p & 0x80) ? 0xff : 0; /* hi bit chooses ff or 00. */
560
if (np + num - outval > 4096)
561
break; /* don't overrun */
572
if (np - outval > 4096)
573
break; /* don't overrun */
577
err_msg("partition corrupt: ran off end parsing value\n");
584
err_msg("data value too long for this utility (>4k)\n");
593
* nvram_parse_partitions
594
* @brief fill in the nvram structure with data from nvram
596
* Fill in the partition parts of the struct nvram.
597
* This makes handling partitions easier for the rest of the code.
599
* The spec says that partitions are made up of 16 byte blocks and
600
* the partition header must be 16 bytes. We verify that here.
602
* @param nvram pointer to nvram struct to fill out
603
* @return 0 on success, !0 otherwise
606
nvram_parse_partitions(struct nvram *nvram)
608
char *nvram_end = nvram->data + nvram->nbytes;
609
char *p_start = nvram->data;
610
struct partition_header *phead;
613
if (sizeof(struct partition_header) != 16) {
614
err_msg("partition_header struct is not 16 bytes\n");
618
while (p_start < nvram_end) {
619
phead = (struct partition_header *)p_start;
620
nvram->parts[nvram->nparts++] = phead;
621
c_sum = checksum(phead);
622
if (c_sum != phead->checksum)
623
warn_msg("this partition checksum should be %02x!\n", c_sum);
624
p_start += phead->length * NVRAM_BLOCK_SIZE;
628
printf("NVRAM contains %d partitions\n", nvram->nparts);
634
* nvram_find_fd_partition
635
* @brief Find a particular nvram partition using a file descriptor
637
* @param name name of the partition to find
638
* @param nvram pointer to nvram struct to search
639
* @return 0 on success, !0 otherwise
642
nvram_find_fd_partition(struct nvram *nvram, char *name)
644
struct partition_header phead;
648
if (lseek(nvram->fd, SEEK_SET, 0) == -1) {
649
err_msg("could not seek to beginning of file %s\n", nvram->filename);
654
len = read(nvram->fd, &phead, sizeof(phead));
655
if (len == 0) { /* EOF */
656
err_msg("could not find %s partition in %s\n",
657
name, nvram->filename);
660
else if (len != sizeof(phead)) {
661
err_msg("Invalid read from %s: %s\n", nvram->filename,
666
if (! strncmp(phead.name, name, sizeof(phead.name)))
669
int offset = phead.length * NVRAM_BLOCK_SIZE - len;
670
if (lseek(nvram->fd, offset, SEEK_CUR) == -1) {
671
err_msg("seek error in file %s: %s\n", nvram->filename,
679
err_msg("could not find %s partition in %s\n", name, nvram->filename);
683
/* we found the correct partition seek back to the beginning of it */
684
if (lseek(nvram->fd, -len, SEEK_CUR) == -1) {
685
err_msg("could not seek to %s partition\n", name);
693
* nvram_find_partition
694
* @brief Find a partition given a signature and name.
696
* If signature is zero (invalid) it is not used for matching.
697
* If name is NULL it is ignored.
698
* start is the partition in which to resume a search (NULL starts at the first
701
* @param signature partition signature to find
702
* @param name partition name to find
703
* @param start partition header to start search at
704
* @param nvram nvram struct to search
705
* @return pointer to partition header on success, NULL otherwise
707
static struct partition_header *
708
nvram_find_partition(struct nvram *nvram, unsigned char signature, char *name,
709
struct partition_header *start)
711
struct partition_header *phead;
714
/* Get starting partition. This is not terribly efficient... */
718
printf("find partition starts with zero\n");
721
for (i = 0; i < nvram->nparts; i++)
722
if (nvram->parts[i] == start)
724
i++; /* start at next partition */
726
printf("find partition starts with %d\n", i);
729
/* Search starting with partition i... */
730
while (i < nvram->nparts) {
731
phead = nvram->parts[i];
732
if (signature == '\0' || signature == phead->signature) {
734
|| strncmp(name, phead->name, sizeof(phead->name)) == 0) {
745
* print_partition_table
746
* @brief print a table of available partitions
748
* @param nvram nvram struct of partitions
751
print_partition_table(struct nvram *nvram)
753
struct partition_header *phead;
756
printf(" # Sig Chk Len Name\n");
757
for (i = 0; i < nvram->nparts; i++) {
758
phead = nvram->parts[i];
759
printf("%2d %02x %02x %04x %.12s\n", i, phead->signature,
760
phead->checksum, phead->length, phead->name);
766
* @brief Copy a value into a buf.
767
* The first two bytes of the value is a length.
768
* Return pointer to byte after the value.
770
* @param p pointer to value to copy
771
* @param buf buffer to copy value into
772
* @return pointer past the copied value in p
775
getvalue(char *p, char *buf)
778
len |= ((*p++) << 8);
786
* @brief Copy a value into a buf.
787
* The first one bytes of the value is a length.
789
* @param p pointer to value to copy
790
* @param buf buffer to copy value into
791
* @return pointer past the copied value in p
794
getsmallvalue(char *p, char *buf)
804
* @brief translate a VPD field to human readable string
806
* Lookup a VPD field name (always 2 chars) and return a human
809
* @param p VPD field name
810
* @return pointer to human readable string on success, NULL otherwise
817
for (i = 0; (i < sizeof(descs) / sizeof(descs[0])); i++) {
818
if (strcmp(p, descs[i].name) == 0)
819
return descs[i].desc;
827
* @brief Format and print a VPD field and return a ptr to the next field.
829
* @param p pointer to VPD field
830
* @param show_all verbosity level
831
* @return pointer to next VPD field
834
printVPDfield(char *p, int show_all)
840
field[0] = p[0]; field[1] = p[1]; field[2] = 0;
842
p = getsmallvalue(p, value);
843
if ((fname = lookupfield(field)) != NULL)
844
printf(" %-20s %s\n", fname, value);
846
printf(" %-20s %s\n", field, value);
853
* @brief Dump Vital Product Data
855
* See Chapter 18: Expansion ROMs of the PCI spec.
857
* @param nvram nvram struct to retrieve VPD data from
858
* @param show_all verbosity level
861
dump_vpd(struct nvram *nvram, int show_all)
863
struct partition_header *phead;
867
phead = nvram_find_partition(nvram, NVRAM_SIG_HW, "ibm,vpd", NULL);
869
err_msg("there is no ibm,vpd partition!\n");
873
p = (char *)(phead + 1);
874
p_end = (char *)(phead + phead->length);
876
while (*p && p < p_end) {
877
if (*p == (char)0x82) { /* Identification string descriptor. */
879
p = getvalue(p, value);
880
printf("%s\n", value); /* print id string */
882
while (*p != 0x79) { /* loop until VPD end tag */
887
vpdlen |= ((*p++) << 8);
888
vpd_endp = p + vpdlen;
890
p = printVPDfield(p, show_all);
894
/* printf("checksum byte=0x%x\n", *p); */
897
else if (*p == 0) { /* end tag */
902
if (*p && p < p_end) {
903
warn_msg("found unknown descriptor byte 0x%x\n", *p);
911
* @brief Dump ibm,err-log partition which contains checkstop info.
913
* ToDo: this code needs more work.
914
* See IBM RPA (IBM internal use only -- sorry).
916
* @param nvram nvram struct to dump errlog from
917
* @return 0 on success, !0 otherwise
920
dump_errlog(struct nvram *nvram)
922
struct partition_header *phead;
923
uint16_t *p, *p_end; /* Note: data is organized into 16bit big
924
* endian (network byte order) */
925
int p_max; /* max index to go out of bounds of the partition */
927
char checkstop_count;
932
uint16_t *sys_regs; /* System specific registers
933
* (e.g. bus arbitration chips, etc */
934
uint16_t *cpu_regs[MAX_CPUS+1];
935
uint16_t *memctrl_data;
936
uint16_t *ioctrl_data;
938
phead = nvram_find_partition(nvram, NVRAM_SIG_SP, "ibm,err-log", NULL);
940
err_msg("there is no ibm,err-log partition!\n");
944
p = (uint16_t *)(phead + 1);
945
p_end = (uint16_t *)(phead + phead->length);
946
p_max = p_end - p; /* max in 16bit values */
948
err_msg("Corrupt ibm,err-log partition in nvram\n");
952
/* index 0 is checkstop count (high byte), semaphores (low byte) */
953
i = 0; /* index through short words */
954
checkstop_count = p[i] >> 8;
956
printf("Checkstops detected: %d\n", checkstop_count);
958
printf("No checkstops have been detected.\n");
960
/* index 1 is system specific register offset */
962
offset = ntohs(p[i])/2+1;
963
sys_regs = offset + i < p_max ? p + offset + i : 0;
965
/* index 2 is number of cpus */
967
num_cpus = ntohs(p[i]);
968
printf("CPUS: %d\n", num_cpus);
970
/* Next indexes are offsets to cpu specific regs */
971
for (cpu = 0; cpu < num_cpus; cpu++) {
973
if (cpu < MAX_CPUS) {
974
offset = ntohs(p[i])/2+1;
975
cpu_regs[cpu] = offset + i < p_max ? p + offset + i : 0;
979
if (num_cpus > MAX_CPUS)
980
num_cpus = MAX_CPUS; /* just in case... */
982
/* next index is number of memory controllers */
984
num_memctrls = ntohs(p[i]);
985
printf("Memory Controllers: %d\n", num_memctrls);
987
/* next index is offset of memory controller data */
988
i++; /* ToDo: this may be a list of offsets...manual doesn't show
989
that but only 1 seems odd */
990
offset = ntohs(p[i])/2+1;
991
memctrl_data = offset + i < p_max ? p + offset + i : 0;
993
/* next index is number of I/O Subsystem controllers */
995
num_ioctrls = ntohs(p[i]);
996
printf("I/O Controllers: %d\n", num_ioctrls);
998
/* next index is offset of I/O Subsystem controller data */
999
i++; /* ToDo: this may be a list of offsets...manual doesn't show
1000
that but only 1 seems odd */
1001
offset = ntohs(p[i])/2+1;
1002
ioctrl_data = offset + i < p_max ? p + offset + i : 0;
1004
/*** End of header ***/
1006
/* Now dump sections collected by the header. */
1007
if (sys_regs && num_cpus > 0) {
1008
/* ToDo: what is the length of the data? We dump until the
1010
printf("System Specific Registers\n");
1011
dump_raw_data((char *)sys_regs, cpu_regs[0] - sys_regs);
1014
/* artificial "next cpu" data for length */
1015
cpu_regs[num_cpus] = ioctrl_data;
1017
for (cpu = 0; cpu < num_cpus; cpu++) {
1020
/* ToDo: what is the length of the data? We dump until the
1022
len = cpu_regs[cpu+1] - cpu_regs[cpu];
1023
printf("CPU %d Register Data (len=%x, offset=%x)\n", cpu, len,
1025
if (len < 4096) /* reasonable bound */
1026
dump_raw_data((char *)cpu_regs[cpu], len);
1033
* dump_rtas_event_entry
1034
* @brief Dump event-scan data.
1036
* Note: This is really only valid for PAPR machines. To ensure
1037
* the nvram command can run on all powerpc machines we dlopen the
1038
* the librtasevent library to dump the rtas event.
1040
* @param data pointer to rtas error to dump
1041
* @param len length of data buffer
1042
* @return 0 on success, !0 otherwise
1045
dump_rtas_event_entry(char *data, int len)
1049
void *(*parse_rtas_event)();
1050
void (*rtas_print_event)();
1051
void (*cleanup_rtas_event)();
1053
handle = dlopen("/usr/lib/librtasevent.so", RTLD_LAZY);
1057
parse_rtas_event = dlsym(handle, "parse_rtas_event");
1058
if (parse_rtas_event == NULL) {
1063
rtas_print_event = dlsym(handle, "rtas_print_event");
1064
if (rtas_print_event == NULL) {
1069
cleanup_rtas_event = dlsym(handle, "cleanup_rtas_event");
1070
if (cleanup_rtas_event == NULL) {
1075
rtas_event = parse_rtas_event(data, len);
1076
if (rtas_event == NULL) {
1081
rtas_print_event(stdout, rtas_event, 0);
1083
cleanup_rtas_event(rtas_event);
1091
* @brief Dump ibm,es-logs partition, which contains a service processor log
1093
* See IBM RPA (IBM internal use only -- sorry).
1095
* @param nvram nvram struct to get eventscan log from
1096
* @return 0 on success, !0 otherwise
1099
dump_eventscanlog(struct nvram *nvram)
1101
struct partition_header *phead;
1102
uint32_t *p, *p_end; /* Note: data is organized into 32bit big
1103
* endian (network byte order) */
1104
int p_max; /* max index to go out of bounds of the partition */
1108
#define MAX_EVENTLOGS 100
1109
uint32_t loghdr[MAX_EVENTLOGS+1];
1111
phead = nvram_find_partition(nvram, NVRAM_SIG_SP, "ibm,es-logs", NULL);
1113
err_msg("there is no ibm,es-logs partition!\n");
1117
p = (uint32_t *)(phead + 1);
1118
p_end = (uint32_t *)(phead + phead->length);
1119
p_max = p_end - p; /* max in 32bit values */
1121
err_msg("Corrupt ibm,es-logs partition in nvram\n");
1125
num_logs = ntohl(*p);
1126
printf("Number of Logs: %d\n", num_logs);
1128
if (num_logs > MAX_EVENTLOGS) {
1129
num_logs = MAX_EVENTLOGS;
1130
warn_msg("limiting to %d log entries (program limit)\n", num_logs);
1133
if (num_logs > p_max-1) {
1134
/* of course this leaves no room for log data
1135
(i.e. corrupt partition) */
1137
warn_msg("limiting to %d log entries (partition limit)\n", num_logs);
1140
for (lognum = 0; lognum < num_logs; lognum++) {
1141
loghdr[lognum] = ntohl(p[lognum+1]);
1144
/* artificial log entry (offset) to put a limit on the last log */
1145
loghdr[num_logs] = p_max * sizeof(uint32_t);
1147
for (lognum = 0; lognum < num_logs; lognum++) {
1148
uint32_t hdr = loghdr[lognum];
1149
int flags = (hdr >> 24) & 0xff;
1150
int logtype = (hdr >> 16) & 0xff;
1151
int start = hdr & 0xffff;
1152
int end = loghdr[lognum+1] & 0xffff;
1153
printf("Log Entry %d: flags: 0x%02x type: 0x%02x\n", lognum,
1155
rc = dump_rtas_event_entry(((char *)p) + start, end - start);
1157
printf("==== Log %d ====\n", lognum);
1158
dump_raw_data(((char *)p) + start, end - start);
1167
* dump_raw_partition
1168
* @brief Dump raw data of a partition. Mainly for debugging.
1170
* @param nvram nvram struct containing partition
1171
* @param name name of partition to dump
1172
* @return 0 on success, !0 otherwise
1175
dump_raw_partition(struct nvram *nvram, char *name)
1177
struct partition_header *phead;
1179
phead = nvram_find_partition(nvram, 0, name, NULL);
1181
err_msg("there is no %s partition!\n", name);
1185
dump_raw_data((char *)phead, phead->length * NVRAM_BLOCK_SIZE);
1191
* print_of_config_part
1192
* @brief Print the name/value pairs of a partition
1194
* @param pname partition name containing name/value pairs
1195
* @param nvram nvram struct containing partition to dump
1196
* @return 0 on success, !0 otherwise
1199
print_of_config_part(struct nvram *nvram, char *pname)
1201
struct partition_header *phead;
1205
phead = nvram_find_partition(nvram, 0, pname, NULL);
1209
data = (char *)phead + sizeof(*phead);
1211
printf("\"%s\" Partition\n", pname);
1212
for (i = 0; i <= (strlen(pname) + 14); i++)
1216
while (*data != '\0') {
1217
printf("%s\n", data);
1218
data += strlen(data) + 1;
1226
/* Print a single OF var...or all if "" is used */
1228
* @var name_value_parts
1229
* @brief List of partition names that contain name/value pairs
1232
* @var num_name_value_parts
1233
* @brief number of names in the name_vlaue_parts array
1235
static char *name_value_parts[] = {
1236
"common", "ibm,setupcfg", "of-config"
1238
static int num_name_value_parts = 3;
1242
* @brief Print the contents of an Open Firmware config partition
1244
* This will print the name/value pair for a specified Open
1245
* Firmware config variable or print all of the name/value pairs
1246
* in the partition if the name is NULL.
1248
* @param config_var config variable to print
1249
* @param pname partition name containing config_var
1250
* @param nvram nvram struct containing pname
1251
* @return 0 on success, !0 otherwise
1254
print_of_config(struct nvram *nvram, char *config_var, char *pname)
1256
struct partition_header *phead;
1261
/* if config_var is NULL , print the data from the
1262
* partition specified by pname or all of the
1263
* name/value pair partitions if pname is NULL.
1265
if (config_var == NULL) {
1266
if (pname == NULL) {
1267
for (i = 0; i < num_name_value_parts; i++)
1268
(void)print_of_config_part(nvram, name_value_parts[i]);
1271
for (i = 0; i < num_name_value_parts; i++) {
1272
if (strcmp(pname, name_value_parts[i]) == 0) {
1273
(void)print_of_config_part(nvram, name_value_parts[i]);
1278
err_msg("There is no Open Firmware \"%s\" partition!\n", pname);
1283
/* the config_var is a variable name */
1284
varlen = strlen(config_var);
1286
if (pname == NULL) {
1287
for (i = 0; i < num_name_value_parts; i++) {
1288
phead = nvram_find_partition(nvram, 0, name_value_parts[i], NULL);
1292
data = (char *)phead + sizeof(*phead);
1294
while (*data != '\0') {
1295
if ((data[varlen] == '=') &&
1296
strncmp(config_var, data, varlen) == 0) {
1297
printf("%s\n", data + varlen + 1);
1300
data += strlen(data) + 1;
1305
phead = nvram_find_partition(nvram, 0, pname, NULL);
1306
if (phead == NULL) {
1307
err_msg("There is no Open Firmware \"%s\" partition.\n", pname);
1311
data = (char *)phead + sizeof(*phead);
1312
while (*data != '\0') {
1313
if ((data[varlen] == '=') &&
1314
strncmp(config_var, data, varlen) == 0) {
1315
printf("%s\n", data + varlen + 1);
1318
data += strlen(data) + 1;
1327
* @brief Update an Open Firmware config variable in nvram
1329
* This will attempt to update the value half of a name/value
1330
* pair in the nvram config partition. If the name/value pair
1331
* is not found in the partition then the specified name/value pair
1332
* is added to the end of the data in the partition.
1334
* @param config_var OF config variable to update
1335
* @param pname partition containing config_var
1336
* @param nvram nvram struct containing pname
1337
* @return 0 on success, !0 otherwise
1340
update_of_config_var(struct nvram *nvram, char *config_var, char *pname)
1342
struct partition_header *phead, *new_phead;
1345
char *new_part_offset, *new_part_end;
1347
int config_name_len;
1348
int len, part_size, found = 0;
1350
phead = nvram_find_partition(nvram, 0, pname, NULL);
1351
if (phead == NULL) {
1352
err_msg("there is no \"%s\" partition!\n", pname);
1356
part_size = phead->length * NVRAM_BLOCK_SIZE;
1357
data_offset = (char *)((unsigned long)phead + sizeof(*phead));
1359
new_part = malloc(part_size);
1360
if (new_part == NULL) {
1361
err_msg("cannot allocate space to update \"%s\" partition\n", pname);
1365
/* get the length of then name of the config variable we are updating */
1366
config_name_len = strstr(config_var, "=") - config_var;
1369
/* now find this config variable in the partition */
1370
while (*data_offset != '\0') {
1371
if (strncmp(data_offset, config_var, config_name_len) == 0) {
1376
data_offset += strlen(data_offset) + 1;
1380
err_msg("cannot update %s\n"
1381
"\tThe config var does not exist in the \"%s\" partition\n",
1387
/* Copy everything up to the config name we are modifying
1388
* to the new partition
1390
memcpy(new_part, phead, data_offset - (char *)phead);
1392
/* make sure the new config var will fit into the partition and add it */
1393
new_phead = (struct partition_header *)new_part;
1394
new_part_offset = new_part + (data_offset - (char *)phead);
1395
new_part_end = new_part + part_size;
1397
if ((new_part_offset + strlen(config_var) + 1) >= new_part_end) {
1398
err_msg("cannot update config var to\"%s\".\n"
1399
"\tThere is not enough room in the \"%s\" partition\n",
1405
strncpy(new_part_offset, config_var, strlen(config_var));
1406
new_part_offset += strlen(config_var);
1407
*new_part_offset++ = '\0';
1409
/* Find the end of the name/value pairs in the partition so we
1410
* can copy them over to the new partition.
1412
data_offset += strlen(data_offset) + 1;
1413
tmp_offset = data_offset;
1414
while (*data_offset != '\0') {
1415
data_offset += strlen(data_offset) + 1;
1418
/* we should now be pointing to a double NULL, verify this */
1419
if ((data_offset[-1] != '\0') && (data_offset[0] != '\0')) {
1420
err_msg("the \"%s\" partition appears to be corrupt\n", pname);
1425
/* go past double NULL */
1428
/* verify that this will fit into the new partition */
1429
if ((new_part_offset + (data_offset - tmp_offset)) > new_part_end) {
1430
err_msg("cannot update open firmware config var to \"%s\".\n"
1431
"\tThere is not enough room in the \"%s\" partition\n",
1437
memcpy(new_part_offset, tmp_offset, data_offset - tmp_offset);
1439
/* recalculate the checksum */
1440
new_phead->checksum = checksum(new_phead);
1442
/* seek the position in the /dev/nvram for the common partition */
1443
if (nvram_find_fd_partition(nvram, new_phead->name) != 0) {
1448
/* write the partition out to nvram */
1449
len = write(nvram->fd, new_part, part_size);
1450
if (len != part_size) {
1451
err_msg("only wrote %d bytes of the \"%s\" partition back\n"
1452
"\tto %s, expected to write %d bytes\n",
1453
len, pname, nvram->filename, part_size);
1461
main (int argc, char *argv[])
1469
char *of_config_var = NULL;
1470
int print_partitions = 0;
1472
int print_errlog = 0;
1473
int print_event_scan = 0;
1474
int print_config_var = 0;
1475
char *dump_name = NULL;
1476
char *update_config_var = NULL;
1477
char *config_pname = "common";
1479
nvram_cmdname = argv[0];
1485
/* initialize nvram struct */
1486
memset(&nvram, 0, sizeof(struct nvram));
1491
ret = getopt_long(argc, argv, "+v:p:", long_options, &option_index);
1499
verbose += (optarg ? atoi(optarg) : 1);
1501
case 'd': /* dump */
1504
case 'n': /* nvram-file */
1505
nvram.filename = optarg;
1507
case 'o': /*print-config */
1508
print_config_var = 1;
1509
of_config_var = optarg;
1511
case 'P': /* partitions */
1512
print_partitions = 1;
1514
case 's': /* nvram-size */
1515
nvram.nbytes = strtoul(optarg, &endp, 10);
1516
if (!*optarg || *endp) {
1517
err_msg("specify nvram-size as an integer\n");
1521
case 'V': /* print-vpd */
1524
case 'W': /* print-all-vpd */
1527
case 'e': /* print-err-log */
1530
case 'E': /* print-event-scan */
1531
print_event_scan = 1;
1533
case 'u': /* update-config */
1534
update_config_var = optarg;
1536
case 'p': /* update-config partition name */
1537
config_pname = optarg;
1548
if (optind < argc) {
1549
err_msg("Could not parse the option %s correctly.\n",
1557
if (nvram.filename) {
1558
nvram.fd = open(nvram.filename, O_RDWR);
1559
if (nvram.fd == -1) {
1560
err_msg("cannot open \"%s\": %s\n",
1561
nvram.filename, strerror(errno));
1566
nvram.filename = NVRAM_FILENAME1;
1567
nvram.fd = open(nvram.filename, O_RDWR);
1568
if (nvram.fd == -1) {
1571
nvram.filename = NVRAM_FILENAME2;
1572
nvram.fd = open(nvram.filename, O_RDWR);
1573
if (nvram.fd == -1) {
1574
err_msg("cannot open \"%s\": %s\n",
1575
NVRAM_FILENAME1, strerror(errno1));
1576
err_msg("cannot open \"%s\": %s\n",
1577
NVRAM_FILENAME2, strerror(errno));
1584
if (fstat(nvram.fd, &sbuf) < 0) {
1585
err_msg("cannot stat %s: %s\n", nvram.filename, strerror(errno));
1590
of_nvram_size = get_of_nvram_size();
1591
nvram.nbytes = sbuf.st_size ? sbuf.st_size : of_nvram_size;
1592
if (nvram.nbytes != of_nvram_size) {
1593
warn_msg("specified nvram size %d does not match this machine %d!\n",
1594
nvram.nbytes, of_nvram_size);
1597
nvram.data = malloc(nvram.nbytes);
1598
if (nvram.data == NULL) {
1599
err_msg("cannot allocate space for nvram of %d bytes\n", nvram.nbytes);
1604
if (nvram_read(&nvram) != 0) {
1609
if (nvram_parse_partitions(&nvram) != 0) {
1614
if (print_partitions)
1615
print_partition_table(&nvram);
1617
if (update_config_var) {
1618
if (config_pname == NULL) {
1619
err_msg("you must specify the partition name with the -p option\n"
1620
"\twhen using the --update-config option\n");
1623
if (update_of_config_var(&nvram, update_config_var, config_pname) != 0)
1626
if (print_config_var)
1627
if (print_of_config(&nvram, of_config_var, config_pname) != 0)
1630
if (dump_vpd(&nvram, print_vpd == 2) != 0)
1633
if (dump_errlog(&nvram) != 0)
1635
if (print_event_scan)
1636
if (dump_eventscanlog(&nvram) != 0)
1639
if (dump_raw_partition(&nvram, dump_name) != 0)