2 * NVRAM variable manipulation (common)
4 * Copyright 2004, Broadcom Corporation
5 * Copyright 2009, OpenWrt.org
8 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
9 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
10 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
11 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
18 printf("%s(%i) in %s()\n", \
19 __FILE__, __LINE__, __FUNCTION__)
22 * -- Helper functions --
26 static uint32_t hash(const char *s
)
31 hash
= 31 * hash
+ *s
++;
36 /* Free all tuples. */
37 static void _nvram_free(nvram_handle_t
*h
)
40 nvram_tuple_t
*t
, *next
;
43 for (i
= 0; i
< NVRAM_ARRAYSIZE(h
->nvram_hash
); i
++) {
44 for (t
= h
->nvram_hash
[i
]; t
; t
= next
) {
48 h
->nvram_hash
[i
] = NULL
;
52 for (t
= h
->nvram_dead
; t
; t
= next
) {
60 /* (Re)allocate NVRAM tuples. */
61 static nvram_tuple_t
* _nvram_realloc( nvram_handle_t
*h
, nvram_tuple_t
*t
,
62 const char *name
, const char *value
)
64 if ((strlen(value
) + 1) > NVRAM_SPACE
)
68 if (!(t
= malloc(sizeof(nvram_tuple_t
) + strlen(name
) + 1)))
72 t
->name
= (char *) &t
[1];
73 strcpy(t
->name
, name
);
79 if (!t
->value
|| strcmp(t
->value
, value
))
81 if(!(t
->value
= (char *) realloc(t
->value
, strlen(value
)+1)))
84 strcpy(t
->value
, value
);
85 t
->value
[strlen(value
)] = '\0';
91 /* (Re)initialize the hash table. */
92 static int _nvram_rehash(nvram_handle_t
*h
)
94 nvram_header_t
*header
= (nvram_header_t
*) &h
->mmap
[NVRAM_SPACE
];
95 char buf
[] = "0xXXXXXXXX", *name
, *value
, *end
, *eq
;
97 /* (Re)initialize hash table */
100 /* Parse and set "name=value\0 ... \0\0" */
101 name
= (char *) &header
[1];
103 end = (char *) header + NVRAM_SPACE - 2;
104 end[0] = end[1] = '\0';
106 for (; *name
; name
= value
+ strlen(value
) + 1) {
107 if (!(eq
= strchr(name
, '=')))
111 nvram_set(h
, name
, value
);
115 /* Set special SDRAM parameters */
116 if (!nvram_get(h
, "sdram_init")) {
117 sprintf(buf
, "0x%04X", (uint16_t)(header
->crc_ver_init
>> 16));
118 nvram_set(h
, "sdram_init", buf
);
120 if (!nvram_get(h
, "sdram_config")) {
121 sprintf(buf
, "0x%04X", (uint16_t)(header
->config_refresh
& 0xffff));
122 nvram_set(h
, "sdram_config", buf
);
124 if (!nvram_get(h
, "sdram_refresh")) {
125 sprintf(buf
, "0x%04X",
126 (uint16_t)((header
->config_refresh
>> 16) & 0xffff));
127 nvram_set(h
, "sdram_refresh", buf
);
129 if (!nvram_get(h
, "sdram_ncdl")) {
130 sprintf(buf
, "0x%08X", header
->config_ncdl
);
131 nvram_set(h
, "sdram_ncdl", buf
);
139 * -- Public functions --
142 /* Get the value of an NVRAM variable. */
143 char * nvram_get(nvram_handle_t
*h
, const char *name
)
153 i
= hash(name
) % NVRAM_ARRAYSIZE(h
->nvram_hash
);
155 /* Find the associated tuple in the hash table */
156 for (t
= h
->nvram_hash
[i
]; t
&& strcmp(t
->name
, name
); t
= t
->next
);
158 value
= t
? t
->value
: NULL
;
163 /* Set the value of an NVRAM variable. */
164 int nvram_set(nvram_handle_t
*h
, const char *name
, const char *value
)
167 nvram_tuple_t
*t
, *u
, **prev
;
170 i
= hash(name
) % NVRAM_ARRAYSIZE(h
->nvram_hash
);
172 /* Find the associated tuple in the hash table */
173 for (prev
= &h
->nvram_hash
[i
], t
= *prev
;
174 t
&& strcmp(t
->name
, name
); prev
= &t
->next
, t
= *prev
);
176 /* (Re)allocate tuple */
177 if (!(u
= _nvram_realloc(h
, t
, name
, value
)))
178 return -12; /* -ENOMEM */
180 /* Value reallocated */
184 /* Move old tuple to the dead table */
187 t
->next
= h
->nvram_dead
;
191 /* Add new tuple to the hash table */
192 u
->next
= h
->nvram_hash
[i
];
193 h
->nvram_hash
[i
] = u
;
198 /* Unset the value of an NVRAM variable. */
199 int nvram_unset(nvram_handle_t
*h
, const char *name
)
202 nvram_tuple_t
*t
, **prev
;
208 i
= hash(name
) % NVRAM_ARRAYSIZE(h
->nvram_hash
);
210 /* Find the associated tuple in the hash table */
211 for (prev
= &h
->nvram_hash
[i
], t
= *prev
;
212 t
&& strcmp(t
->name
, name
); prev
= &t
->next
, t
= *prev
);
214 /* Move it to the dead table */
217 t
->next
= h
->nvram_dead
;
224 /* Get all NVRAM variables. */
225 nvram_tuple_t
* nvram_getall(nvram_handle_t
*h
)
228 nvram_tuple_t
*t
, *l
, *x
;
232 for (i
= 0; i
< NVRAM_ARRAYSIZE(h
->nvram_hash
); i
++) {
233 for (t
= h
->nvram_hash
[i
]; t
; t
= t
->next
) {
234 if( (x
= (nvram_tuple_t
*) malloc(sizeof(nvram_tuple_t
))) != NULL
)
251 /* Regenerate NVRAM. */
252 int nvram_commit(nvram_handle_t
*h
)
254 nvram_header_t
*header
= (nvram_header_t
*) &h
->mmap
[NVRAM_SPACE
];
255 char *init
, *config
, *refresh
, *ncdl
;
262 /* Regenerate header */
263 header
->magic
= NVRAM_MAGIC
;
264 header
->crc_ver_init
= (NVRAM_VERSION
<< 8);
265 if (!(init
= nvram_get(h
, "sdram_init")) ||
266 !(config
= nvram_get(h
, "sdram_config")) ||
267 !(refresh
= nvram_get(h
, "sdram_refresh")) ||
268 !(ncdl
= nvram_get(h
, "sdram_ncdl"))) {
269 header
->crc_ver_init
|= SDRAM_INIT
<< 16;
270 header
->config_refresh
= SDRAM_CONFIG
;
271 header
->config_refresh
|= SDRAM_REFRESH
<< 16;
272 header
->config_ncdl
= 0;
274 header
->crc_ver_init
|= (strtoul(init
, NULL
, 0) & 0xffff) << 16;
275 header
->config_refresh
= strtoul(config
, NULL
, 0) & 0xffff;
276 header
->config_refresh
|= (strtoul(refresh
, NULL
, 0) & 0xffff) << 16;
277 header
->config_ncdl
= strtoul(ncdl
, NULL
, 0);
280 /* Clear data area */
281 ptr
= (char *) header
+ sizeof(nvram_header_t
);
282 memset(ptr
, 0xFF, NVRAM_SPACE
- sizeof(nvram_header_t
));
284 /* Leave space for a double NUL at the end */
285 end
= (char *) header
+ NVRAM_SPACE
- 2;
287 /* Write out all tuples */
288 for (i
= 0; i
< NVRAM_ARRAYSIZE(h
->nvram_hash
); i
++) {
289 for (t
= h
->nvram_hash
[i
]; t
; t
= t
->next
) {
290 if ((ptr
+ strlen(t
->name
) + 1 + strlen(t
->value
) + 1) > end
)
292 ptr
+= sprintf(ptr
, "%s=%s", t
->name
, t
->value
) + 1;
296 /* End with a double NUL */
301 header
->len
= NVRAM_ROUNDUP(ptr
- (char *) header
, 4);
303 /* Little-endian CRC8 over the last 11 bytes of the header */
304 tmp
.crc_ver_init
= htonl(header
->crc_ver_init
);
305 tmp
.config_refresh
= htonl(header
->config_refresh
);
306 tmp
.config_ncdl
= htonl(header
->config_ncdl
);
307 crc
= hndcrc8((unsigned char *) &tmp
+ 9, sizeof(nvram_header_t
) - 9, 0xff);
309 /* Continue CRC8 over data bytes */
310 crc
= hndcrc8((unsigned char *) &header
[1],
311 header
->len
- sizeof(nvram_header_t
), crc
);
314 header
->crc_ver_init
|= crc
;
317 msync(h
->mmap
, h
->length
, MS_SYNC
);
320 /* Reinitialize hash table */
321 return _nvram_rehash(h
);
324 /* Open NVRAM and obtain a handle. */
325 nvram_handle_t
* nvram_open(const char *file
, int rdonly
)
329 nvram_header_t
*header
;
331 if( (fd
= open(file
, O_RDWR
)) > -1 )
333 char *mmap_area
= (char *) mmap(
334 NULL
, 0x10000, PROT_READ
| PROT_WRITE
,
335 ( rdonly
== NVRAM_RO
) ? MAP_PRIVATE
: MAP_SHARED
, fd
, 0);
337 if( mmap_area
!= MAP_FAILED
)
339 memset(mmap_area
, 0xFF, NVRAM_SPACE
);
341 if((h
= (nvram_handle_t
*) malloc(sizeof(nvram_handle_t
))) != NULL
)
343 memset(h
, 0, sizeof(nvram_handle_t
));
349 header
= (nvram_header_t
*) &h
->mmap
[NVRAM_SPACE
];
351 if( header
->magic
== NVRAM_MAGIC
)
358 munmap(h
->mmap
, h
->length
);
368 /* Close NVRAM and free memory. */
369 int nvram_close(nvram_handle_t
*h
)
372 munmap(h
->mmap
, h
->length
);
379 /* Determine NVRAM device node. */
380 const char * nvram_find_mtd(void)
382 //return "./samples/nvram.1";
389 // "/dev/mtdblock/" + ( 0 < x < 99 ) + "ro" + \0 = 19
390 if( (path
= (char *) malloc(19)) == NULL
)
393 if ((fp
= fopen("/proc/mtd", "r"))) {
394 while (fgets(dev
, sizeof(dev
), fp
)) {
395 if (sscanf(dev
, "mtd%d:", &i
) && strstr(dev
, "nvram")) {
396 snprintf(path
, 19, "/dev/mtdblock/%d", i
);
402 return (const char *) path
;
405 /* Check NVRAM staging file. */
406 const char * nvram_find_staging(void)
410 if( (stat(NVRAM_STAGING
, &s
) > -1) && (s
.st_mode
& S_IFREG
) )
412 return NVRAM_STAGING
;
418 /* Copy NVRAM contents to staging file. */
419 int nvram_to_staging(void)
421 int fdmtd
, fdstg
, stat
;
427 if( (mtd
= nvram_find_mtd()) != NULL
)
429 if( (fdmtd
= open(mtd
, O_RDONLY
)) > -1 )
431 if( read(fdmtd
, buf
, sizeof(buf
)) == sizeof(buf
) )
433 if((fdstg
= open(NVRAM_STAGING
, O_WRONLY
| O_CREAT
, 0600)) > -1)
435 write(fdstg
, buf
, sizeof(buf
));
450 /* Copy staging file to NVRAM device. */
451 int staging_to_nvram(void)
453 int fdmtd
, fdstg
, stat
;
459 if( (mtd
= nvram_find_mtd()) != NULL
)
461 if( (fdstg
= open(NVRAM_STAGING
, O_RDONLY
)) > -1 )
463 if( read(fdstg
, buf
, sizeof(buf
)) == sizeof(buf
) )
465 if( (fdmtd
= open(mtd
, O_WRONLY
| O_SYNC
)) > -1 )
467 write(fdmtd
, buf
, sizeof(buf
));
477 stat
= unlink(NVRAM_STAGING
) ? 1 : 0;