summaryrefslogtreecommitdiffstats
path: root/qemu/roms/openbios/packages/nvram.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/openbios/packages/nvram.c')
-rw-r--r--qemu/roms/openbios/packages/nvram.c308
1 files changed, 308 insertions, 0 deletions
diff --git a/qemu/roms/openbios/packages/nvram.c b/qemu/roms/openbios/packages/nvram.c
new file mode 100644
index 000000000..3182edf58
--- /dev/null
+++ b/qemu/roms/openbios/packages/nvram.c
@@ -0,0 +1,308 @@
+/*
+ * 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, "777777777777", 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 );
+
+ bind_func( "update-nvram", update_nvram );
+
+ 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 );
+}
+
+NODE_METHODS( nvram ) = {
+ { "size", (void*)nvram_size },
+ { "read", (void*)nvram_read },
+ { "write", (void*)nvram_write },
+ { "seek", (void*)nvram_seek },
+};
+
+
+void
+nvram_init( const char *path )
+{
+ nvconf_init();
+
+ REGISTER_NAMED_NODE( nvram, path );
+}