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
)
343 nvram_header_t
*header
;
345 /* If erase size or file are undefined then try to define them */
346 if( (nvram_erase_size
== 0) || (file
== NULL
) )
348 /* Finding the mtd will set the appropriate erase size */
349 if( (mtd
= nvram_find_mtd()) == NULL
|| nvram_erase_size
== 0 )
356 if( (fd
= open(file
? file
: mtd
, O_RDWR
)) > -1 )
358 char *mmap_area
= (char *) mmap(
359 NULL
, nvram_erase_size
, PROT_READ
| PROT_WRITE
,
360 ( rdonly
== NVRAM_RO
) ? MAP_PRIVATE
: MAP_SHARED
, fd
, 0);
362 if( mmap_area
!= MAP_FAILED
)
364 memset(mmap_area
, 0xFF, NVRAM_START(nvram_erase_size
));
366 if((h
= (nvram_handle_t
*) malloc(sizeof(nvram_handle_t
))) != NULL
)
368 memset(h
, 0, sizeof(nvram_handle_t
));
372 h
->length
= nvram_erase_size
;
374 header
= nvram_header(h
);
376 if( header
->magic
== NVRAM_MAGIC
)
384 munmap(h
->mmap
, h
->length
);
395 /* Close NVRAM and free memory. */
396 int nvram_close(nvram_handle_t
*h
)
399 munmap(h
->mmap
, h
->length
);
406 /* Determine NVRAM device node. */
407 char * nvram_find_mtd(void)
415 if( (fp
= fopen("/proc/mtd", "r")) )
417 while( fgets(dev
, sizeof(dev
), fp
) )
419 if( strstr(dev
, "nvram") && sscanf(dev
, "mtd%d: %08x", &i
, &esz
) )
421 nvram_erase_size
= esz
;
423 sprintf(dev
, "/dev/mtdblock/%d", i
);
424 if( stat(dev
, &s
) > -1 && (s
.st_mode
& S_IFBLK
) )
426 if( (path
= (char *) malloc(strlen(dev
)+1)) != NULL
)
428 strncpy(path
, dev
, strlen(dev
)+1);
434 sprintf(dev
, "/dev/mtdblock%d", i
);
435 if( stat(dev
, &s
) > -1 && (s
.st_mode
& S_IFBLK
) )
437 if( (path
= (char *) malloc(strlen(dev
)+1)) != NULL
)
439 strncpy(path
, dev
, strlen(dev
)+1);
452 /* Check NVRAM staging file. */
453 char * nvram_find_staging(void)
457 if( (stat(NVRAM_STAGING
, &s
) > -1) && (s
.st_mode
& S_IFREG
) )
459 return NVRAM_STAGING
;
465 /* Copy NVRAM contents to staging file. */
466 int nvram_to_staging(void)
468 int fdmtd
, fdstg
, stat
;
469 char *mtd
= nvram_find_mtd();
470 char buf
[nvram_erase_size
];
474 if( (mtd
!= NULL
) && (nvram_erase_size
> 0) )
476 if( (fdmtd
= open(mtd
, O_RDONLY
)) > -1 )
478 if( read(fdmtd
, buf
, sizeof(buf
)) == sizeof(buf
) )
480 if((fdstg
= open(NVRAM_STAGING
, O_WRONLY
| O_CREAT
, 0600)) > -1)
482 write(fdstg
, buf
, sizeof(buf
));
498 /* Copy staging file to NVRAM device. */
499 int staging_to_nvram(void)
501 int fdmtd
, fdstg
, stat
;
502 char *mtd
= nvram_find_mtd();
503 char buf
[nvram_erase_size
];
507 if( (mtd
!= NULL
) && (nvram_erase_size
> 0) )
509 if( (fdstg
= open(NVRAM_STAGING
, O_RDONLY
)) > -1 )
511 if( read(fdstg
, buf
, sizeof(buf
)) == sizeof(buf
) )
513 if( (fdmtd
= open(mtd
, O_WRONLY
| O_SYNC
)) > -1 )
515 write(fdmtd
, buf
, sizeof(buf
));
525 stat
= unlink(NVRAM_STAGING
) ? 1 : 0;
This page took 0.073093 seconds and 5 git commands to generate.