SVN-Revision: 15426master
parent
70c8870f64
commit
400c1a7fbf
@ -0,0 +1,50 @@ |
||||
#
|
||||
# Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk |
||||
|
||||
PKG_NAME:=unvram
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk |
||||
|
||||
define Package/unvram |
||||
SECTION:=utils
|
||||
CATEGORY:=Base system
|
||||
TITLE:=Userspace port of the Broadcom NVRAM manipulation tool
|
||||
endef |
||||
|
||||
define Package/unvram/description |
||||
This package contains an utility to manipulate NVRAM on Broadcom based devices.
|
||||
It works on both brcm-2.4 and bcm47xx (Linux 2.6) without using the kernel api.
|
||||
endef |
||||
|
||||
define Build/Prepare |
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
$(CP) ./src/* $(PKG_BUILD_DIR)/
|
||||
endef |
||||
|
||||
define Build/Configure |
||||
endef |
||||
|
||||
define Build/Compile |
||||
$(MAKE) -C $(PKG_BUILD_DIR) \
|
||||
CC="$(TARGET_CC)" \
|
||||
CFLAGS="$(TARGET_CFLAGS) -Wall" \
|
||||
LDFLAGS="$(TARGET_LDFLAGS)"
|
||||
endef |
||||
|
||||
define Package/unvram/install |
||||
$(INSTALL_DIR) $(1)/sbin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/unvram $(1)/sbin/
|
||||
$(INSTALL_DIR) $(1)/usr/lib
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/libnvram.so.0.1 $(1)/usr/lib/
|
||||
endef |
||||
|
||||
$(eval $(call BuildPackage,unvram)) |
@ -0,0 +1,33 @@ |
||||
CLI_FILENAME = unvram
|
||||
|
||||
LIB_VERMAJOR = 0
|
||||
LIB_VERMINOR = 1
|
||||
LIB_FILENAME = libnvram.so
|
||||
|
||||
LIB_CFLAGS = $(CFLAGS) -shared -fPIC
|
||||
LIB_LDFLAGS = $(LDFLAGS) -Wl,-soname,$(LIB_FILENAME).$(LIB_VERMAJOR).$(LIB_VERMINOR)
|
||||
|
||||
CLI_CFLAGS = $(CFLAGS)
|
||||
CLI_LDFLAGS = $(LDFLAGS)
|
||||
|
||||
CLI_OBJ = cli.o
|
||||
LIB_OBJ = crc.o nvram.o
|
||||
|
||||
all: cli libnvram |
||||
|
||||
cli: libnvram |
||||
$(CC) $(CLI_CFLAGS) -c -o cli.o cli.c
|
||||
$(CC) -o $(CLI_FILENAME) $(CLI_LDFLAGS) $(CLI_OBJ) \
|
||||
$(LIB_FILENAME).$(LIB_VERMAJOR).$(LIB_VERMINOR)
|
||||
|
||||
cli.o: cli.c |
||||
$(CC) $(CLI_CFLAGS) -c -o $@ $<
|
||||
|
||||
libnvram: |
||||
$(CC) $(LIB_CFLAGS) -c -o crc.o crc.c
|
||||
$(CC) $(LIB_CFLAGS) -c -o nvram.o nvram.c
|
||||
$(CC) $(LIB_CFLAGS) $(LIB_LDFLAGS) \
|
||||
-o $(LIB_FILENAME).$(LIB_VERMAJOR).$(LIB_VERMINOR) $(LIB_OBJ)
|
||||
|
||||
clean: |
||||
rm -f nvram $(LIB_FILENAME)* *.o
|
@ -0,0 +1,233 @@ |
||||
/*
|
||||
* Command line interface for libnvram |
||||
* |
||||
* Copyright 2009, Jo-Philipp Wich <xm@subsignal.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License |
||||
* as published by the Free Software Foundation; either version 2 |
||||
* of the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||
* |
||||
* |
||||
* The libnvram code is based on Broadcom code for Linux 2.4.x . |
||||
* |
||||
*/ |
||||
|
||||
#include "nvram.h" |
||||
|
||||
|
||||
static nvram_handle_t * nvram_open_rdonly(void) |
||||
{ |
||||
const char *file = nvram_find_staging(); |
||||
|
||||
if( file == NULL ) |
||||
file = nvram_find_mtd(); |
||||
|
||||
if( file != NULL ) |
||||
return nvram_open(file, NVRAM_RO); |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
static nvram_handle_t * nvram_open_staging(void) |
||||
{ |
||||
if( nvram_find_staging() != NULL || nvram_to_staging() == 0 ) |
||||
return nvram_open(NVRAM_STAGING, NVRAM_RW); |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
static int do_show(nvram_handle_t *nvram) |
||||
{ |
||||
nvram_tuple_t *t; |
||||
int stat = 1; |
||||
|
||||
if( (t = nvram_getall(nvram)) != NULL ) |
||||
{ |
||||
while( t ) |
||||
{ |
||||
printf("%s=%s\n", t->name, t->value); |
||||
t = t->next; |
||||
} |
||||
|
||||
stat = 0; |
||||
} |
||||
|
||||
return stat; |
||||
} |
||||
|
||||
static int do_get(nvram_handle_t *nvram, const char *var) |
||||
{ |
||||
const char *val; |
||||
int stat = 1; |
||||
|
||||
if( (val = nvram_get(nvram, var)) != NULL ) |
||||
{ |
||||
printf("%s\n", val); |
||||
stat = 0; |
||||
} |
||||
|
||||
return stat; |
||||
} |
||||
|
||||
static int do_unset(nvram_handle_t *nvram, const char *var) |
||||
{ |
||||
return nvram_unset(nvram, var); |
||||
} |
||||
|
||||
static int do_set(nvram_handle_t *nvram, const char *pair) |
||||
{ |
||||
char *val = strstr(pair, "="); |
||||
char var[strlen(pair)]; |
||||
int stat = 1; |
||||
|
||||
if( val != NULL ) |
||||
{ |
||||
memset(var, 0, sizeof(var)); |
||||
strncpy(var, pair, (int)(val-pair)); |
||||
stat = nvram_set(nvram, var, (char *)(val + 1)); |
||||
} |
||||
|
||||
return stat; |
||||
} |
||||
|
||||
static int do_info(nvram_handle_t *nvram) |
||||
{ |
||||
nvram_header_t *hdr = nvram_header(nvram); |
||||
|
||||
/* CRC8 over the last 11 bytes of the header and data bytes */ |
||||
uint8_t crc = hndcrc8((unsigned char *) &hdr[0] + NVRAM_CRC_START_POSITION, |
||||
hdr->len - NVRAM_CRC_START_POSITION, 0xff); |
||||
|
||||
/* Show info */ |
||||
printf("Magic: 0x%08X\n", hdr->magic); |
||||
printf("Length: 0x%08X\n", hdr->len); |
||||
|
||||
printf("CRC8: 0x%02X (calculated: 0x%02X)\n", |
||||
hdr->crc_ver_init & 0xFF, crc); |
||||
|
||||
printf("Version: 0x%02X\n", (hdr->crc_ver_init >> 8) & 0xFF); |
||||
printf("SDRAM init: 0x%04X\n", (hdr->crc_ver_init >> 16) & 0xFFFF); |
||||
printf("SDRAM config: 0x%04X\n", hdr->config_refresh & 0xFFFF); |
||||
printf("SDRAM refresh: 0x%04X\n", (hdr->config_refresh >> 16) & 0xFFFF); |
||||
printf("NCDL values: 0x%08X\n\n", hdr->config_ncdl); |
||||
|
||||
printf("%i bytes used / %i bytes available (%.2f%%)\n", |
||||
hdr->len, NVRAM_SPACE - hdr->len, |
||||
(100.00 / (double)NVRAM_SPACE) * (double)hdr->len); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
int main( int argc, const char *argv[] ) |
||||
{ |
||||
nvram_handle_t *nvram; |
||||
int commit = 0; |
||||
int write = 0; |
||||
int stat = 1; |
||||
int done = 0; |
||||
int i; |
||||
|
||||
/* Ugly... iterate over arguments to see whether we can expect a write */ |
||||
for( i = 1; i < argc; i++ ) |
||||
if( ( !strcmp(argv[i], "set") && ++i < argc ) || |
||||
( !strcmp(argv[i], "unset") && ++i < argc ) || |
||||
!strcmp(argv[i], "commit") ) |
||||
{ |
||||
write = 1; |
||||
break; |
||||
} |
||||
|
||||
|
||||
nvram = write ? nvram_open_staging() : nvram_open_rdonly(); |
||||
|
||||
if( nvram != NULL && argc > 1 ) |
||||
{ |
||||
for( i = 1; i < argc; i++ ) |
||||
{ |
||||
if( !strcmp(argv[i], "show") ) |
||||
{ |
||||
stat = do_show(nvram); |
||||
done++; |
||||
} |
||||
else if( !strcmp(argv[i], "info") ) |
||||
{ |
||||
stat = do_info(nvram); |
||||
done++; |
||||
} |
||||
else if( !strcmp(argv[i], "get") && ++i < argc ) |
||||
{ |
||||
stat = do_get(nvram, argv[i]); |
||||
done++; |
||||
} |
||||
else if( !strcmp(argv[i], "unset") && ++i < argc ) |
||||
{ |
||||
stat = do_unset(nvram, argv[i]); |
||||
done++; |
||||
} |
||||
else if( !strcmp(argv[i], "set") && ++i < argc ) |
||||
{ |
||||
stat = do_set(nvram, argv[i]); |
||||
done++; |
||||
} |
||||
else if( !strcmp(argv[i], "commit") ) |
||||
{ |
||||
commit = 1; |
||||
done++; |
||||
} |
||||
else |
||||
{ |
||||
fprintf(stderr, "Unknown option '%s' !\n", argv[i]); |
||||
done = 0; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if( write ) |
||||
stat = nvram_commit(nvram); |
||||
|
||||
nvram_close(nvram); |
||||
|
||||
if( commit ) |
||||
stat = staging_to_nvram(); |
||||
} |
||||
|
||||
if( !nvram ) |
||||
{ |
||||
fprintf(stderr, |
||||
"Could not open nvram! Possible reasons are:\n" |
||||
" - No device found (/proc not mounted or no nvram present)\n" |
||||
" - Insufficient permissions to open mtd device\n" |
||||
" - Insufficient memory to complete operation\n" |
||||
" - Memory mapping failed or not supported\n" |
||||
); |
||||
|
||||
stat = 1; |
||||
} |
||||
else if( !done ) |
||||
{ |
||||
fprintf(stderr, |
||||
"Usage:\n" |
||||
" nvram show\n" |
||||
" nvram info\n" |
||||
" nvram get variable\n" |
||||
" nvram set variable=value [set ...]\n" |
||||
" nvram unset variable [unset ...]\n" |
||||
" nvram commit\n" |
||||
); |
||||
|
||||
stat = 1; |
||||
} |
||||
|
||||
return stat; |
||||
} |
@ -0,0 +1,69 @@ |
||||
#include "nvram.h" |
||||
|
||||
/*******************************************************************************
|
||||
* crc8 |
||||
* |
||||
* Computes a crc8 over the input data using the polynomial: |
||||
* |
||||
* x^8 + x^7 +x^6 + x^4 + x^2 + 1 |
||||
* |
||||
* The caller provides the initial value (either CRC8_INIT_VALUE |
||||
* or the previous returned value) to allow for processing of |
||||
* discontiguous blocks of data. When generating the CRC the |
||||
* caller is responsible for complementing the final return value |
||||
* and inserting it into the byte stream. When checking, a final |
||||
* return value of CRC8_GOOD_VALUE indicates a valid CRC. |
||||
* |
||||
* Reference: Dallas Semiconductor Application Note 27 |
||||
* Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms", |
||||
* ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd., |
||||
* ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
|
||||
* |
||||
* **************************************************************************** |
||||
*/ |
||||
|
||||
static const uint8_t crc8_table[256] = { |
||||
0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B, |
||||
0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21, |
||||
0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF, |
||||
0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5, |
||||
0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14, |
||||
0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E, |
||||
0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80, |
||||
0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA, |
||||
0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95, |
||||
0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF, |
||||
0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01, |
||||
0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B, |
||||
0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA, |
||||
0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0, |
||||
0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E, |
||||
0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34, |
||||
0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0, |
||||
0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A, |
||||
0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54, |
||||
0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E, |
||||
0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF, |
||||
0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5, |
||||
0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B, |
||||
0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61, |
||||
0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E, |
||||
0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74, |
||||
0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA, |
||||
0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0, |
||||
0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41, |
||||
0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B, |
||||
0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5, |
||||
0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F |
||||
}; |
||||
|
||||
uint8_t hndcrc8 ( |
||||
uint8_t * pdata, /* pointer to array of data to process */ |
||||
uint32_t nbytes, /* number of input data bytes to process */ |
||||
uint8_t crc /* either CRC8_INIT_VALUE or previous return value */ |
||||
) { |
||||
while (nbytes-- > 0) |
||||
crc = crc8_table[(crc ^ *pdata++) & 0xff]; |
||||
|
||||
return crc; |
||||
} |
@ -0,0 +1,511 @@ |
||||
/*
|
||||
* NVRAM variable manipulation (common) |
||||
* |
||||
* Copyright 2004, Broadcom Corporation |
||||
* Copyright 2009, OpenWrt.org |
||||
* All Rights Reserved. |
||||
* |
||||
* THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY |
||||
* KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM |
||||
* SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS |
||||
* FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. |
||||
* |
||||
*/ |
||||
|
||||
#include "nvram.h" |
||||
|
||||
#define TRACE(msg) \ |
||||
printf("%s(%i) in %s(): %s\n", \
|
||||
__FILE__, __LINE__, __FUNCTION__, msg ? msg : "?") |
||||
|
||||
size_t nvram_erase_size = 0; |
||||
|
||||
|
||||
/*
|
||||
* -- Helper functions -- |
||||
*/ |
||||
|
||||
/* String hash */ |
||||
static uint32_t hash(const char *s) |
||||
{ |
||||
uint32_t hash = 0; |
||||
|
||||
while (*s) |
||||
hash = 31 * hash + *s++; |
||||
|
||||
return hash; |
||||
} |
||||
|
||||
/* Free all tuples. */ |
||||
static void _nvram_free(nvram_handle_t *h) |
||||
{ |
||||
uint32_t i; |
||||
nvram_tuple_t *t, *next; |
||||
|
||||
/* Free hash table */ |
||||
for (i = 0; i < NVRAM_ARRAYSIZE(h->nvram_hash); i++) { |
||||
for (t = h->nvram_hash[i]; t; t = next) { |
||||
next = t->next; |
||||
free(t); |
||||
} |
||||
h->nvram_hash[i] = NULL; |
||||
} |
||||
|
||||
/* Free dead table */ |
||||
for (t = h->nvram_dead; t; t = next) { |
||||
next = t->next; |
||||
free(t); |
||||
} |
||||
|
||||
h->nvram_dead = NULL; |
||||
} |
||||
|
||||
/* (Re)allocate NVRAM tuples. */ |
||||
static nvram_tuple_t * _nvram_realloc( nvram_handle_t *h, nvram_tuple_t *t, |
||||
const char *name, const char *value ) |
||||
{ |
||||
if ((strlen(value) + 1) > NVRAM_SPACE) |
||||
return NULL; |
||||
|
||||
if (!t) { |
||||
if (!(t = malloc(sizeof(nvram_tuple_t) + strlen(name) + 1))) |
||||
return NULL; |
||||
|
||||
/* Copy name */ |
||||
t->name = (char *) &t[1]; |
||||
strcpy(t->name, name); |
||||
|
||||
t->value = NULL; |
||||
} |
||||
|
||||
/* Copy value */ |
||||
if (!t->value || strcmp(t->value, value)) |
||||
{ |
||||
if(!(t->value = (char *) realloc(t->value, strlen(value)+1))) |
||||
return NULL; |
||||
|
||||
strcpy(t->value, value); |
||||
t->value[strlen(value)] = '\0'; |
||||
} |
||||
|
||||
return t; |
||||
} |
||||
|
||||
/* (Re)initialize the hash table. */ |
||||
static int _nvram_rehash(nvram_handle_t *h) |
||||
{ |
||||
nvram_header_t *header = nvram_header(h); |
||||
char buf[] = "0xXXXXXXXX", *name, *value, *eq; |
||||
|
||||
/* (Re)initialize hash table */ |
||||
_nvram_free(h); |
||||
|
||||
/* Parse and set "name=value\0 ... \0\0" */ |
||||
name = (char *) &header[1]; |
||||
|
||||
for (; *name; name = value + strlen(value) + 1) { |
||||
if (!(eq = strchr(name, '='))) |
||||
break; |
||||
*eq = '\0'; |
||||
value = eq + 1; |
||||
nvram_set(h, name, value); |
||||
*eq = '='; |
||||
} |
||||
|
||||
/* Set special SDRAM parameters */ |
||||
if (!nvram_get(h, "sdram_init")) { |
||||
sprintf(buf, "0x%04X", (uint16_t)(header->crc_ver_init >> 16)); |
||||
nvram_set(h, "sdram_init", buf); |
||||
} |
||||
if (!nvram_get(h, "sdram_config")) { |
||||
sprintf(buf, "0x%04X", (uint16_t)(header->config_refresh & 0xffff)); |
||||
nvram_set(h, "sdram_config", buf); |
||||
} |
||||
if (!nvram_get(h, "sdram_refresh")) { |
||||
sprintf(buf, "0x%04X", |
||||
(uint16_t)((header->config_refresh >> 16) & 0xffff)); |
||||
nvram_set(h, "sdram_refresh", buf); |
||||
} |
||||
if (!nvram_get(h, "sdram_ncdl")) { |
||||
sprintf(buf, "0x%08X", header->config_ncdl); |
||||
nvram_set(h, "sdram_ncdl", buf); |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* -- Public functions -- |
||||
*/ |
||||
|
||||
/* Get nvram header. */ |
||||
nvram_header_t * nvram_header(nvram_handle_t *h) |
||||
{ |
||||
return (nvram_header_t *) &h->mmap[NVRAM_START(nvram_erase_size)]; |
||||
} |
||||
|
||||
/* Get the value of an NVRAM variable. */ |
||||
char * nvram_get(nvram_handle_t *h, const char *name) |
||||
{ |
||||
uint32_t i; |
||||
nvram_tuple_t *t; |
||||
char *value; |
||||
|
||||
if (!name) |
||||
return NULL; |
||||
|
||||
/* Hash the name */ |
||||
i = hash(name) % NVRAM_ARRAYSIZE(h->nvram_hash); |
||||
|
||||
/* Find the associated tuple in the hash table */ |
||||
for (t = h->nvram_hash[i]; t && strcmp(t->name, name); t = t->next); |
||||
|
||||
value = t ? t->value : NULL; |
||||
|
||||
return value; |
||||
} |
||||
|
||||
/* Set the value of an NVRAM variable. */ |
||||
int nvram_set(nvram_handle_t *h, const char *name, const char *value) |
||||
{ |
||||
uint32_t i; |
||||
nvram_tuple_t *t, *u, **prev; |
||||
|
||||
/* Hash the name */ |
||||
i = hash(name) % NVRAM_ARRAYSIZE(h->nvram_hash); |
||||
|
||||
/* Find the associated tuple in the hash table */ |
||||
for (prev = &h->nvram_hash[i], t = *prev; |
||||
t && strcmp(t->name, name); prev = &t->next, t = *prev); |
||||
|
||||
/* (Re)allocate tuple */ |
||||
if (!(u = _nvram_realloc(h, t, name, value))) |
||||
return -12; /* -ENOMEM */ |
||||
|
||||
/* Value reallocated */ |
||||
if (t && t == u) |
||||
return 0; |
||||
|
||||
/* Move old tuple to the dead table */ |
||||
if (t) { |
||||
*prev = t->next; |
||||
t->next = h->nvram_dead; |
||||
h->nvram_dead = t; |
||||
} |
||||
|
||||
/* Add new tuple to the hash table */ |
||||
u->next = h->nvram_hash[i]; |
||||
h->nvram_hash[i] = u; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/* Unset the value of an NVRAM variable. */ |
||||
int nvram_unset(nvram_handle_t *h, const char *name) |
||||
{ |
||||
uint32_t i; |
||||
nvram_tuple_t *t, **prev; |
||||
|
||||
if (!name) |
||||
return 0; |
||||
|
||||
/* Hash the name */ |
||||
i = hash(name) % NVRAM_ARRAYSIZE(h->nvram_hash); |
||||
|
||||
/* Find the associated tuple in the hash table */ |
||||
for (prev = &h->nvram_hash[i], t = *prev; |
||||
t && strcmp(t->name, name); prev = &t->next, t = *prev); |
||||
|
||||
/* Move it to the dead table */ |
||||
if (t) { |
||||
*prev = t->next; |
||||
t->next = h->nvram_dead; |
||||
h->nvram_dead = t; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/* Get all NVRAM variables. */ |
||||
nvram_tuple_t * nvram_getall(nvram_handle_t *h) |
||||
{ |
||||
int i; |
||||
nvram_tuple_t *t, *l, *x; |
||||
|
||||
l = NULL; |
||||
|
||||
for (i = 0; i < NVRAM_ARRAYSIZE(h->nvram_hash); i++) { |
||||
for (t = h->nvram_hash[i]; t; t = t->next) { |
||||
if( (x = (nvram_tuple_t *) malloc(sizeof(nvram_tuple_t))) != NULL ) |
||||
{ |
||||
x->name = t->name; |
||||
x->value = t->value; |
||||
x->next = l; |
||||
l = x; |
||||
} |
||||
else |
||||
{ |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return l; |
||||
} |
||||
|
||||
/* Regenerate NVRAM. */ |
||||
int nvram_commit(nvram_handle_t *h) |
||||
{ |
||||
nvram_header_t *header = nvram_header(h); |
||||
char *init, *config, *refresh, *ncdl; |
||||
char *ptr, *end; |
||||
int i; |
||||
nvram_tuple_t *t; |
||||
nvram_header_t tmp; |
||||
uint8_t crc; |
||||
|
||||
/* Regenerate header */ |
||||
header->magic = NVRAM_MAGIC; |
||||
header->crc_ver_init = (NVRAM_VERSION << 8); |
||||
if (!(init = nvram_get(h, "sdram_init")) || |
||||
!(config = nvram_get(h, "sdram_config")) || |
||||
!(refresh = nvram_get(h, "sdram_refresh")) || |
||||
!(ncdl = nvram_get(h, "sdram_ncdl"))) { |
||||
header->crc_ver_init |= SDRAM_INIT << 16; |
||||
header->config_refresh = SDRAM_CONFIG; |
||||
header->config_refresh |= SDRAM_REFRESH << 16; |
||||
header->config_ncdl = 0; |
||||
} else { |
||||
header->crc_ver_init |= (strtoul(init, NULL, 0) & 0xffff) << 16; |
||||
header->config_refresh = strtoul(config, NULL, 0) & 0xffff; |
||||
header->config_refresh |= (strtoul(refresh, NULL, 0) & 0xffff) << 16; |
||||
header->config_ncdl = strtoul(ncdl, NULL, 0); |
||||
} |
||||
|
||||
/* Clear data area */ |
||||
ptr = (char *) header + sizeof(nvram_header_t); |
||||
memset(ptr, 0xFF, NVRAM_SPACE - sizeof(nvram_header_t)); |
||||
memset(&tmp, 0, sizeof(nvram_header_t)); |
||||
|
||||
/* Leave space for a double NUL at the end */ |
||||
end = (char *) header + NVRAM_SPACE - 2; |
||||
|
||||
/* Write out all tuples */ |
||||
for (i = 0; i < NVRAM_ARRAYSIZE(h->nvram_hash); i++) { |
||||
for (t = h->nvram_hash[i]; t; t = t->next) { |
||||
if ((ptr + strlen(t->name) + 1 + strlen(t->value) + 1) > end) |
||||
break; |
||||
ptr += sprintf(ptr, "%s=%s", t->name, t->value) + 1; |
||||
} |
||||
} |
||||
|
||||
/* End with a double NULL and pad to 4 bytes */ |
||||
*ptr = '\0'; |
||||
ptr++; |
||||
|
||||
if( (int)ptr % 4 ) |
||||
memset(ptr, 0, 4 - ((int)ptr % 4)); |
||||
|
||||
ptr++; |
||||
|
||||
/* Set new length */ |
||||
header->len = NVRAM_ROUNDUP(ptr - (char *) header, 4); |
||||
|
||||
/* Little-endian CRC8 over the last 11 bytes of the header */ |
||||
tmp.crc_ver_init = header->crc_ver_init; |
||||
tmp.config_refresh = header->config_refresh; |
||||
tmp.config_ncdl = header->config_ncdl; |
||||
crc = hndcrc8((unsigned char *) &tmp + NVRAM_CRC_START_POSITION, |
||||
sizeof(nvram_header_t) - NVRAM_CRC_START_POSITION, 0xff); |
||||
|
||||
/* Continue CRC8 over data bytes */ |
||||
crc = hndcrc8((unsigned char *) &header[0] + sizeof(nvram_header_t), |
||||
header->len - sizeof(nvram_header_t), crc); |
||||
|
||||
/* Set new CRC8 */ |
||||
header->crc_ver_init |= crc; |
||||
|
||||
/* Write out */ |
||||
msync(h->mmap, h->length, MS_SYNC); |
||||
fsync(h->fd); |
||||
|
||||
/* Reinitialize hash table */ |
||||
return _nvram_rehash(h); |
||||
} |
||||
|
||||
/* Open NVRAM and obtain a handle. */ |
||||
nvram_handle_t * nvram_open(const char *file, int rdonly) |
||||
{ |
||||
int fd; |
||||
nvram_handle_t *h; |
||||
nvram_header_t *header; |
||||
|
||||
/* If erase size or file are undefined then try to define them */ |
||||
if( (nvram_erase_size == 0) || (file == NULL) ) |
||||
{ |
||||
/* Finding the mtd will set the appropriate erase size */ |
||||
if( file == NULL ) |
||||
file = nvram_find_mtd(); |
||||
else |
||||
(void) nvram_find_mtd(); |
||||
|
||||
if( nvram_erase_size == 0 ) |
||||
return NULL; |
||||
} |
||||
|
||||
if( (fd = open(file, O_RDWR)) > -1 ) |
||||
{ |
||||
char *mmap_area = (char *) mmap( |
||||
NULL, nvram_erase_size, PROT_READ | PROT_WRITE, |
||||
( rdonly == NVRAM_RO ) ? MAP_PRIVATE : MAP_SHARED, fd, 0); |
||||
|
||||
if( mmap_area != MAP_FAILED ) |
||||
{ |
||||
memset(mmap_area, 0xFF, NVRAM_START(nvram_erase_size)); |
||||
|
||||
if((h = (nvram_handle_t *) malloc(sizeof(nvram_handle_t))) != NULL) |
||||
{ |
||||
memset(h, 0, sizeof(nvram_handle_t)); |
||||
|
||||
h->fd = fd; |
||||
h->mmap = mmap_area; |
||||
h->length = nvram_erase_size; |
||||
|
||||
header = nvram_header(h); |
||||
|
||||
if( header->magic == NVRAM_MAGIC ) |
||||
{ |
||||
_nvram_rehash(h); |
||||
return h; |
||||
} |
||||
else |
||||
{ |
||||
munmap(h->mmap, h->length); |
||||
free(h); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
/* Close NVRAM and free memory. */ |
||||
int nvram_close(nvram_handle_t *h) |
||||
{ |
||||
_nvram_free(h); |
||||
munmap(h->mmap, h->length); |
||||
close(h->fd); |
||||
free(h); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/* Determine NVRAM device node. */ |
||||
const char * nvram_find_mtd(void) |
||||
{ |
||||
FILE *fp; |
||||
int i, esz; |
||||
char dev[PATH_MAX]; |
||||
char *path = NULL; |
||||
|
||||
// "/dev/mtdblock/" + ( 0 < x < 99 ) + \0 = 19
|
||||
if( (path = (char *) malloc(19)) == NULL ) |
||||
return NULL; |
||||
|
||||
if ((fp = fopen("/proc/mtd", "r"))) { |
||||
while (fgets(dev, sizeof(dev), fp)) { |
||||
if (strstr(dev, "nvram") && sscanf(dev, "mtd%d: %08x", &i, &esz)) { |
||||
if( (path = (char *) malloc(19)) != NULL ) |
||||
{ |
||||
nvram_erase_size = esz; |
||||
snprintf(path, 19, "/dev/mtdblock/%d", i); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
fclose(fp); |
||||
} |
||||
|
||||
return path; |
||||
} |
||||
|
||||
/* Check NVRAM staging file. */ |
||||
const char * nvram_find_staging(void) |
||||
{ |
||||
struct stat s; |
||||
|
||||
if( (stat(NVRAM_STAGING, &s) > -1) && (s.st_mode & S_IFREG) ) |
||||
{ |
||||
return NVRAM_STAGING; |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
/* Copy NVRAM contents to staging file. */ |
||||
int nvram_to_staging(void) |
||||
{ |
||||
int fdmtd, fdstg, stat; |
||||
const char *mtd = nvram_find_mtd(); |
||||
char buf[nvram_erase_size]; |
||||
|
||||
stat = -1; |
||||
|
||||
if( (mtd != NULL) && (nvram_erase_size > 0) ) |
||||
{ |
||||
if( (fdmtd = open(mtd, O_RDONLY)) > -1 ) |
||||
{ |
||||
if( read(fdmtd, buf, sizeof(buf)) == sizeof(buf) ) |
||||
{ |
||||
if((fdstg = open(NVRAM_STAGING, O_WRONLY | O_CREAT, 0600)) > -1) |
||||
{ |
||||
write(fdstg, buf, sizeof(buf)); |
||||
fsync(fdstg); |
||||
close(fdstg); |
||||
|
||||
stat = 0; |
||||
} |
||||
} |
||||
|
||||
close(fdmtd); |
||||
} |
||||
} |
||||
|
||||
return stat; |
||||
} |
||||
|
||||
/* Copy staging file to NVRAM device. */ |
||||
int staging_to_nvram(void) |
||||
{ |
||||
int fdmtd, fdstg, stat; |
||||
const char *mtd = nvram_find_mtd(); |
||||
char buf[nvram_erase_size]; |
||||
|
||||
stat = -1; |
||||
|
||||
if( (mtd != NULL) && (nvram_erase_size > 0) ) |
||||
{ |
||||
if( (fdstg = open(NVRAM_STAGING, O_RDONLY)) > -1 ) |
||||
{ |
||||
if( read(fdstg, buf, sizeof(buf)) == sizeof(buf) ) |
||||
{ |
||||
if( (fdmtd = open(mtd, O_WRONLY | O_SYNC)) > -1 ) |
||||
{ |
||||
write(fdmtd, buf, sizeof(buf)); |
||||
fsync(fdmtd); |
||||
close(fdmtd); |
||||
stat = 0; |
||||
} |
||||
} |
||||
|
||||
close(fdstg); |
||||
|
||||
if( !stat ) |
||||
stat = unlink(NVRAM_STAGING) ? 1 : 0; |
||||
} |
||||
} |
||||
|
||||
return stat; |
||||
} |
@ -0,0 +1,125 @@ |
||||
/*
|
||||
* NVRAM variable manipulation |
||||
* |
||||
* Copyright 2007, Broadcom Corporation |
||||
* Copyright 2009, OpenWrt.org |
||||
* All Rights Reserved. |
||||
* |
||||
* THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY |
||||
* KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM |
||||
* SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS |
||||
* FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef _nvram_h_ |
||||
#define _nvram_h_ |
||||
|
||||
#include <stdint.h> |
||||
#include <string.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <fcntl.h> |
||||
#include <unistd.h> |
||||
#include <errno.h> |
||||
#include <sys/mman.h> |
||||
#include <sys/stat.h> |
||||
#include <sys/ioctl.h> |
||||
#include <arpa/inet.h> |
||||
#include <linux/limits.h> |
||||
|
||||
#include "sdinitvals.h" |
||||
|
||||
|
||||
struct nvram_header { |
||||
uint32_t magic; |
||||
uint32_t len; |
||||
uint32_t crc_ver_init; /* 0:7 crc, 8:15 ver, 16:31 sdram_init */ |
||||
uint32_t config_refresh; /* 0:15 sdram_config, 16:31 sdram_refresh */ |
||||
uint32_t config_ncdl; /* ncdl values for memc */ |
||||
} __attribute__((__packed__)); |
||||
|
||||
struct nvram_tuple { |
||||
char *name; |
||||
char *value; |
||||
struct nvram_tuple *next; |
||||
}; |
||||
|
||||
struct nvram_handle { |
||||
int fd; |
||||
char *mmap; |
||||
unsigned long length; |
||||
struct nvram_tuple *nvram_hash[257]; |
||||
struct nvram_tuple *nvram_dead; |
||||
}; |
||||
|
||||
typedef struct nvram_handle nvram_handle_t; |
||||
typedef struct nvram_header nvram_header_t; |
||||
typedef struct nvram_tuple nvram_tuple_t; |
||||
|
||||
|
||||
/* Get nvram header. */ |
||||
nvram_header_t * nvram_header(nvram_handle_t *h); |
||||
|
||||
/* Set the value of an NVRAM variable */ |
||||
int nvram_set(nvram_handle_t *h, const char *name, const char *value); |
||||
|
||||
/* Get the value of an NVRAM variable. */ |
||||
char * nvram_get(nvram_handle_t *h, const char *name); |
||||
|
||||
/* Unset the value of an NVRAM variable. */ |
||||
int nvram_unset(nvram_handle_t *h, const char *name); |
||||
|
||||
/* Get all NVRAM variables. */ |
||||
nvram_tuple_t * nvram_getall(nvram_handle_t *h); |
||||
|
||||
/* Regenerate NVRAM. */ |
||||
int nvram_commit(nvram_handle_t *h); |
||||
|
||||
/* Open NVRAM and obtain a handle. */ |
||||
nvram_handle_t * nvram_open(const char *file, int rdonly); |
||||
|
||||
/* Close NVRAM and free memory. */ |
||||
int nvram_close(nvram_handle_t *h); |
||||
|
||||
/* Get the value of an NVRAM variable in a safe way, use "" instead of NULL. */ |
||||
#define nvram_safe_get(h, name) (nvram_get(h, name) ? : "") |
||||
|
||||
/* Computes a crc8 over the input data. */ |
||||
uint8_t hndcrc8 (uint8_t * pdata, uint32_t nbytes, uint8_t crc); |
||||
|
||||
/* Returns the crc value of the nvram. */ |
||||
uint8_t nvram_calc_crc(nvram_header_t * nvh); |
||||
|
||||
/* Determine NVRAM device node. */ |
||||
const char * nvram_find_mtd(void); |
||||
|
||||
/* Copy NVRAM contents to staging file. */ |
||||
int nvram_to_staging(void); |
||||
|
||||
/* Copy staging file to NVRAM device. */ |
||||
int staging_to_nvram(void); |
||||
|
||||
/* Check NVRAM staging file. */ |
||||
const char * nvram_find_staging(void); |
||||
|
||||
|
||||
/* Staging file for NVRAM */ |
||||
#define NVRAM_STAGING "/tmp/.nvram" |
||||
#define NVRAM_RO 1 |
||||
#define NVRAM_RW 0 |
||||
|
||||
/* Helper macros */ |
||||
#define NVRAM_ARRAYSIZE(a) sizeof(a)/sizeof(a[0]) |
||||
#define NVRAM_ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y)) |
||||
|
||||
/* NVRAM constants */ |
||||
#define NVRAM_SPACE 0x8000 |
||||
#define NVRAM_START(x) x - NVRAM_SPACE |
||||
#define NVRAM_MAGIC 0x48534C46 /* 'FLSH' */ |
||||
#define NVRAM_VERSION 1 |
||||
|
||||
#define NVRAM_CRC_START_POSITION 9 /* magic, len, crc8 to be skipped */ |
||||
|
||||
|
||||
#endif /* _nvram_h_ */ |
@ -0,0 +1,30 @@ |
||||
/*
|
||||
* SDRAM init values |
||||
* |
||||
* Copyright 2007, Broadcom Corporation |
||||
* Copyright 2009, OpenWrt.org |
||||
* All Rights Reserved. |
||||
* |
||||
* THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY |
||||
* KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM |
||||
* SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS |
||||
* FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef _sdinitvals_h_ |
||||
#define _sdinitvals_h_ |
||||
|
||||
/* SDRAM refresh control (refresh) register bits */ |
||||
#define SDRAM_REF(p) (((p)&0xff) | SDRAM_REF_EN) /* Refresh period */ |
||||
#define SDRAM_REF_EN 0x8000 /* Writing 1 enables periodic refresh */ |
||||
|
||||
/* SDRAM Core default Init values (OCP ID 0x803) */ |
||||
#define MEM4MX16X2 0x419 /* 16 MB */ |
||||
|
||||
#define SDRAM_INIT MEM4MX16X2 |
||||
#define SDRAM_BURSTFULL 0x0000 /* Use full page bursts */ |
||||
#define SDRAM_CONFIG SDRAM_BURSTFULL |
||||
#define SDRAM_REFRESH SDRAM_REF(0x40) |
||||
|
||||
#endif /* _sdinitvals_h_ */ |
Loading…
Reference in new issue