diff options
Diffstat (limited to 'roms/openbios/packages/nvram.c')
-rw-r--r-- | roms/openbios/packages/nvram.c | 333 |
1 files changed, 333 insertions, 0 deletions
diff --git a/roms/openbios/packages/nvram.c b/roms/openbios/packages/nvram.c new file mode 100644 index 000000000..a402f003a --- /dev/null +++ b/roms/openbios/packages/nvram.c @@ -0,0 +1,333 @@ +/* + * Creation Date: <2003/12/01 00:26:13 samuel> + * Time-stamp: <2004/01/07 19:59:53 samuel> + * + * <nvram.c> + * + * medium-level NVRAM handling + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "config.h" +#include "libopenbios/bindings.h" +#include "arch/common/nvram.h" +#include "packages/nvram.h" + +//#define CONFIG_DEBUG_NVRAM 1 + +#ifdef CONFIG_DEBUG_NVRAM +#define DPRINTF(fmt, args...) \ +do { printk("NVRAM: " fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) do {} while(0) +#endif + +#define DEF_SYSTEM_SIZE 0xc10 + +#define NV_SIG_SYSTEM 0x70 +#define NV_SIG_FREE 0x7f + + +typedef struct { + unsigned char signature; + unsigned char checksum; + unsigned char len_hi; + unsigned char len_lo; + char name[12]; + char data[0]; +} nvpart_t; + +static struct { + char *data; + int size; + + nvpart_t *config; + int config_size; +} nvram; + + +/************************************************************************/ +/* generic */ +/************************************************************************/ + +static unsigned int +nvpart_checksum( nvpart_t* hdr ) +{ + unsigned char *p = (unsigned char*)hdr; + int i, val = p[0]; + + for( i=2; i<16; i++ ) { + val += p[i]; + if( val > 255 ) + val = (val - 256 + 1) & 0xff; + } + return val; +} + +static inline int +nvpart_size( nvpart_t *p ) +{ + return (p->len_lo | ((int)p->len_hi<<8)) * 16; +} + +static int +next_nvpart( nvpart_t **p ) +{ + nvpart_t *end = (nvpart_t*)(nvram.data + nvram.size); + int len; + + if( !*p ) { + *p = (nvpart_t*)nvram.data; + return 1; + } + + if( !(len=nvpart_size(*p)) ) { + printk("invalid nvram partition length\n"); + return -1; + } + *p = (nvpart_t*)((char*)*p + len); + if( *p < end ) + return 1; + if( *p == end ) + return 0; + return -1; +} + +static void +create_free_part( char *ptr, int size ) +{ + nvpart_t *nvp = (nvpart_t*)ptr; + memset( nvp, 0, size ); + + strncpy( nvp->name, "77777777777", sizeof(nvp->name) ); + nvp->signature = NV_SIG_FREE; + nvp->len_hi = (size /16) >> 8; + nvp->len_lo = size /16; + nvp->checksum = nvpart_checksum(nvp); +} + +static int +create_nv_part( int signature, const char *name, int size ) +{ + nvpart_t *p = NULL; + int fs; + + while( next_nvpart(&p) > 0 ) { + if( p->signature != NV_SIG_FREE ) + continue; + + fs = nvpart_size( p ); + if( fs < size ) + size = fs; + p->signature = signature; + memset( p->name, 0, sizeof(p->name) ); + strncpy( p->name, name, sizeof(p->name) ); + p->len_hi = (size>>8)/16; + p->len_lo = size/16; + p->checksum = nvpart_checksum(p); + if( fs > size ) { + char *fp = (char*)p + size; + create_free_part( fp, fs-size ); + } + return size; + } + printk("create-failed\n"); + return -1; +} + +static void +zap_nvram( void ) +{ + create_free_part( nvram.data, nvram.size ); + create_nv_part( NV_SIG_SYSTEM, "common", DEF_SYSTEM_SIZE ); +} + +#if 0 +static void +show_partitions( void ) +{ + nvpart_t *p = NULL; + char buf[13]; + + while( next_nvpart(&p) > 0 ) { + memcpy( buf, p->name, sizeof(p->name) ); + buf[12] = 0; + printk("[%02x] %-13s: %03x\n", + p->signature, buf, nvpart_size(p)); + } +} +#endif + +void +update_nvram( void ) +{ + PUSH( pointer2cell(nvram.config->data) ); + PUSH( nvram.config_size ); + fword("nvram-store-configs"); + arch_nvram_put( nvram.data ); +} + +void +nvconf_init( void ) +{ + int once=0; + + /* initialize nvram structure completely */ + nvram.config = NULL; + nvram.config_size = 0; + + nvram.size = arch_nvram_size(); + nvram.data = malloc( nvram.size ); + arch_nvram_get( nvram.data ); + + for( ;; ) { + nvpart_t *p = NULL; + int err; + + while( (err=next_nvpart(&p)) > 0 ) { + if( nvpart_checksum(p) != p->checksum ) { + err = -1; + break; + } + if( p->signature == NV_SIG_SYSTEM ) { + nvram.config = p; + nvram.config_size = nvpart_size(p) - 0x10; + + if( !once++ ) { + PUSH( pointer2cell(p->data) ); + PUSH( nvram.config_size ); + fword("nvram-load-configs"); + } + } + } + if( err || !nvram.config ) { + printk("nvram error detected, zapping pram\n"); + zap_nvram(); + if( !once++ ) + fword("set-defaults"); + continue; + } + break; + } +} + + +/************************************************************************/ +/* nvram */ +/************************************************************************/ + +typedef struct { + unsigned int mark_hi; + unsigned int mark_lo; +} nvram_ibuf_t; + +DECLARE_UNNAMED_NODE( nvram, INSTALL_OPEN, sizeof(nvram_ibuf_t )); + +/* ( pos_lo pos_hi -- status ) */ +static void +nvram_seek( nvram_ibuf_t *nd ) +{ + int pos_hi = POP(); + int pos_lo = POP(); + + DPRINTF("seek %08x %08x\n", pos_hi, pos_lo ); + nd->mark_lo = pos_lo; + nd->mark_hi = pos_hi; + + if( nd->mark_lo >= nvram.size ) { + PUSH(-1); + return; + } + + /* 0=success, -1=failure (1=legacy success) */ + PUSH(0); +} + +/* ( addr len -- actual ) */ +static void +nvram_read( nvram_ibuf_t *nd ) +{ + int len = POP(); + char *p = (char*)cell2pointer(POP()); + int n=0; + + while( nd->mark_lo < nvram.size && n < len ) { + *p++ = nvram.data[nd->mark_lo++]; + n++; + } + PUSH(n); + DPRINTF("read %p %x -- %x\n", p, len, n); +} + +/* ( addr len -- actual ) */ +static void +nvram_write( nvram_ibuf_t *nd ) +{ + int len = POP(); + char *p = (char*)cell2pointer(POP()); + int n=0; + + while( nd->mark_lo < nvram.size && n < len ) { + nvram.data[nd->mark_lo++] = *p++; + n++; + } + PUSH(n); + DPRINTF("write %p %x -- %x\n", p, len, n ); +} + +/* ( -- size ) */ +static void +nvram_size( __attribute__((unused)) nvram_ibuf_t *nd ) +{ + DPRINTF("nvram_size %d\n", nvram.size); + PUSH( nvram.size ); +} + +static void +nvram_open( __attribute__((unused)) nvram_ibuf_t *nd ) +{ + RET(-1); +} + +static void +nvram_close( __attribute__((unused)) nvram_ibuf_t *nd ) +{ +} + +NODE_METHODS( nvram ) = { + { "open", (void*)nvram_open }, + { "close", (void*)nvram_close }, + { "size", (void*)nvram_size }, + { "read", (void*)nvram_read }, + { "write", (void*)nvram_write }, + { "seek", (void*)nvram_seek }, + { "update-nvram", (void*)update_nvram }, +}; + + +phandle_t +nvram_init( const char *path ) +{ + phandle_t ph; + + push_str(path); + fword("find-device"); + + fword("new-device"); + + ph = get_cur_dev(); + + push_str("nvram"); + fword("device-name"); + + BIND_NODE_METHODS(get_cur_dev(), nvram); + fword("finish-device"); + + return ph; +} |