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(): %s\n", \
19 __FILE__, __LINE__, __FUNCTION__, msg ? msg : "?")
21 size_t nvram_erase_size
= 0;
25 * -- Helper functions --
29 static uint32_t hash(const char *s
)
34 hash
= 31 * hash
+ *s
++;
39 /* Free all tuples. */
40 static void _nvram_free(nvram_handle_t
*h
)
43 nvram_tuple_t
*t
, *next
;
46 for (i
= 0; i
< NVRAM_ARRAYSIZE(h
->nvram_hash
); i
++) {
47 for (t
= h
->nvram_hash
[i
]; t
; t
= next
) {
51 h
->nvram_hash
[i
] = NULL
;
55 for (t
= h
->nvram_dead
; t
; t
= next
) {
63 /* (Re)allocate NVRAM tuples. */
64 static nvram_tuple_t
* _nvram_realloc( nvram_handle_t
*h
, nvram_tuple_t
*t
,
65 const char *name
, const char *value
)
67 if ((strlen(value
) + 1) > NVRAM_SPACE
)
71 if (!(t
= malloc(sizeof(nvram_tuple_t
) + strlen(name
) + 1)))
75 t
->name
= (char *) &t
[1];
76 strcpy(t
->name
, name
);
82 if (!t
->value
|| strcmp(t
->value
, value
))
84 if(!(t
->value
= (char *) realloc(t
->value
, strlen(value
)+1)))
87 strcpy(t
->value
, value
);
88 t
->value
[strlen(value
)] = '\0';
94 /* (Re)initialize the hash table. */
95 static int _nvram_rehash(nvram_handle_t
*h
)
97 nvram_header_t
*header
= nvram_header(h
);
98 char buf
[] = "0xXXXXXXXX", *name
, *value
, *eq
;
100 /* (Re)initialize hash table */
103 /* Parse and set "name=value\0 ... \0\0" */
104 name
= (char *) &header
[1];
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 nvram header. */
143 nvram_header_t
* nvram_header(nvram_handle_t
*h
)
145 return (nvram_header_t
*) &h
->mmap
[NVRAM_START(nvram_erase_size
)];
148 /* Get the value of an NVRAM variable. */
149 char * nvram_get(nvram_handle_t
*h
, const char *name
)
159 i
= hash(name
) % NVRAM_ARRAYSIZE(h
->nvram_hash
);
161 /* Find the associated tuple in the hash table */
162 for (t
= h
->nvram_hash
[i
]; t
&& strcmp(t
->name
, name
); t
= t
->next
);
164 value
= t
? t
->value
: NULL
;
169 /* Set the value of an NVRAM variable. */
170 int nvram_set(nvram_handle_t
*h
, const char *name
, const char *value
)
173 nvram_tuple_t
*t
, *u
, **prev
;
176 i
= hash(name
) % NVRAM_ARRAYSIZE(h
->nvram_hash
);
178 /* Find the associated tuple in the hash table */
179 for (prev
= &h
->nvram_hash
[i
], t
= *prev
;
180 t
&& strcmp(t
->name
, name
); prev
= &t
->next
, t
= *prev
);
182 /* (Re)allocate tuple */
183 if (!(u
= _nvram_realloc(h
, t
, name
, value
)))
184 return -12; /* -ENOMEM */
186 /* Value reallocated */
190 /* Move old tuple to the dead table */
193 t
->next
= h
->nvram_dead
;
197 /* Add new tuple to the hash table */
198 u
->next
= h
->nvram_hash
[i
];
199 h
->nvram_hash
[i
] = u
;
204 /* Unset the value of an NVRAM variable. */
205 int nvram_unset(nvram_handle_t
*h
, const char *name
)
208 nvram_tuple_t
*t
, **prev
;
214 i
= hash(name
) % NVRAM_ARRAYSIZE(h
->nvram_hash
);
216 /* Find the associated tuple in the hash table */
217 for (prev
= &h
->nvram_hash
[i
], t
= *prev
;
218 t
&& strcmp(t
->name
, name
); prev
= &t
->next
, t
= *prev
);
220 /* Move it to the dead table */
223 t
->next
= h
->nvram_dead
;
230 /* Get all NVRAM variables. */
231 nvram_tuple_t
* nvram_getall(nvram_handle_t
*h
)
234 nvram_tuple_t
*t
, *l
, *x
;
238 for (i
= 0; i
< NVRAM_ARRAYSIZE(h
->nvram_hash
); i
++) {
239 for (t
= h
->nvram_hash
[i
]; t
; t
= t
->next
) {
240 if( (x
= (nvram_tuple_t
*) malloc(sizeof(nvram_tuple_t
))) != NULL
)
257 /* Regenerate NVRAM. */
258 int nvram_commit(nvram_handle_t
*h
)
260 nvram_header_t
*header
= nvram_header(h
);
261 char *init
, *config
, *refresh
, *ncdl
;
268 /* Regenerate header */
269 header
->magic
= NVRAM_MAGIC
;
270 header
->crc_ver_init
= (NVRAM_VERSION
<< 8);
271 if (!(init
= nvram_get(h
, "sdram_init")) ||
272 !(config
= nvram_get(h
, "sdram_config")) ||
273 !(refresh
= nvram_get(h
, "sdram_refresh")) ||
274 !(ncdl
= nvram_get(h
, "sdram_ncdl"))) {
275 header
->crc_ver_init
|= SDRAM_INIT
<< 16;
276 header
->config_refresh
= SDRAM_CONFIG
;
277 header
->config_refresh
|= SDRAM_REFRESH
<< 16;
278 header
->config_ncdl
= 0;
280 header
->crc_ver_init
|= (strtoul(init
, NULL
, 0) & 0xffff) << 16;
281 header
->config_refresh
= strtoul(config
, NULL
, 0) & 0xffff;
282 header
->config_refresh
|= (strtoul(refresh
, NULL
, 0) & 0xffff) << 16;
283 header
->config_ncdl
= strtoul(ncdl
, NULL
, 0);
286 /* Clear data area */
287 ptr
= (char *) header
+ sizeof(nvram_header_t
);
288 memset(ptr
, 0xFF, NVRAM_SPACE
- sizeof(nvram_header_t
));
289 memset(&tmp
, 0, sizeof(nvram_header_t
));
291 /* Leave space for a double NUL at the end */
292 end
= (char *) header
+ NVRAM_SPACE
- 2;
294 /* Write out all tuples */
295 for (i
= 0; i
< NVRAM_ARRAYSIZE(h
->nvram_hash
); i
++) {
296 for (t
= h
->nvram_hash
[i
]; t
; t
= t
->next
) {
297 if ((ptr
+ strlen(t
->name
) + 1 + strlen(t
->value
) + 1) > end
)
299 ptr
+= sprintf(ptr
, "%s=%s", t
->name
, t
->value
) + 1;
303 /* End with a double NULL and pad to 4 bytes */
308 memset(ptr
, 0, 4 - ((int)ptr
% 4));
313 header
->len
= NVRAM_ROUNDUP(ptr
- (char *) header
, 4);
315 /* Little-endian CRC8 over the last 11 bytes of the header */
316 tmp
.crc_ver_init
= header
->crc_ver_init
;
317 tmp
.config_refresh
= header
->config_refresh
;
318 tmp
.config_ncdl
= header
->config_ncdl
;
319 crc
= hndcrc8((unsigned char *) &tmp
+ NVRAM_CRC_START_POSITION
,
320 sizeof(nvram_header_t
) - NVRAM_CRC_START_POSITION
, 0xff);
322 /* Continue CRC8 over data bytes */
323 crc
= hndcrc8((unsigned char *) &header
[0] + sizeof(nvram_header_t
),
324 header
->len
- sizeof(nvram_header_t
), crc
);
327 header
->crc_ver_init
|= crc
;
330 msync(h
->mmap
, h
->length
, MS_SYNC
);
333 /* Reinitialize hash table */
334 return _nvram_rehash(h
);
337 /* Open NVRAM and obtain a handle. */
338 nvram_handle_t
* nvram_open(const char *file
, int rdonly
)
342 nvram_header_t
*header
;
344 /* If erase size or file are undefined then try to define them */
345 if( (nvram_erase_size
== 0) || (file
== NULL
) )
347 /* Finding the mtd will set the appropriate erase size */
349 file
= nvram_find_mtd();
351 (void) nvram_find_mtd();
353 if( nvram_erase_size
== 0 )
357 if( (fd
= open(file
, O_RDWR
)) > -1 )
359 char *mmap_area
= (char *) mmap(
360 NULL
, nvram_erase_size
, PROT_READ
| PROT_WRITE
,
361 ( rdonly
== NVRAM_RO
) ? MAP_PRIVATE
: MAP_SHARED
, fd
, 0);
363 if( mmap_area
!= MAP_FAILED
)
365 memset(mmap_area
, 0xFF, NVRAM_START(nvram_erase_size
));
367 if((h
= (nvram_handle_t
*) malloc(sizeof(nvram_handle_t
))) != NULL
)
369 memset(h
, 0, sizeof(nvram_handle_t
));
373 h
->length
= nvram_erase_size
;
375 header
= nvram_header(h
);
377 if( header
->magic
== NVRAM_MAGIC
)
384 munmap(h
->mmap
, h
->length
);
394 /* Close NVRAM and free memory. */
395 int nvram_close(nvram_handle_t
*h
)
398 munmap(h
->mmap
, h
->length
);
405 /* Determine NVRAM device node. */
406 const char * nvram_find_mtd(void)
413 // "/dev/mtdblock/" + ( 0 < x < 99 ) + \0 = 19
414 if( (path
= (char *) malloc(19)) == NULL
)
417 if ((fp
= fopen("/proc/mtd", "r"))) {
418 while (fgets(dev
, sizeof(dev
), fp
)) {
419 if (strstr(dev
, "nvram") && sscanf(dev
, "mtd%d: %08x", &i
, &esz
)) {
420 if( (path
= (char *) malloc(19)) != NULL
)
422 nvram_erase_size
= esz
;
423 snprintf(path
, 19, "/dev/mtdblock/%d", i
);
434 /* Check NVRAM staging file. */
435 const char * nvram_find_staging(void)
439 if( (stat(NVRAM_STAGING
, &s
) > -1) && (s
.st_mode
& S_IFREG
) )
441 return NVRAM_STAGING
;
447 /* Copy NVRAM contents to staging file. */
448 int nvram_to_staging(void)
450 int fdmtd
, fdstg
, stat
;
451 const char *mtd
= nvram_find_mtd();
452 char buf
[nvram_erase_size
];
456 if( (mtd
!= NULL
) && (nvram_erase_size
> 0) )
458 if( (fdmtd
= open(mtd
, O_RDONLY
)) > -1 )
460 if( read(fdmtd
, buf
, sizeof(buf
)) == sizeof(buf
) )
462 if((fdstg
= open(NVRAM_STAGING
, O_WRONLY
| O_CREAT
, 0600)) > -1)
464 write(fdstg
, buf
, sizeof(buf
));
479 /* Copy staging file to NVRAM device. */
480 int staging_to_nvram(void)
482 int fdmtd
, fdstg
, stat
;
483 const char *mtd
= nvram_find_mtd();
484 char buf
[nvram_erase_size
];
488 if( (mtd
!= NULL
) && (nvram_erase_size
> 0) )
490 if( (fdstg
= open(NVRAM_STAGING
, O_RDONLY
)) > -1 )
492 if( read(fdstg
, buf
, sizeof(buf
)) == sizeof(buf
) )
494 if( (fdmtd
= open(mtd
, O_WRONLY
| O_SYNC
)) > -1 )
496 write(fdmtd
, buf
, sizeof(buf
));
506 stat
= unlink(NVRAM_STAGING
) ? 1 : 0;
This page took 0.07373 seconds and 5 git commands to generate.