Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / packages / nvram.c
diff --git a/qemu/roms/openbios/packages/nvram.c b/qemu/roms/openbios/packages/nvram.c
new file mode 100644 (file)
index 0000000..3182edf
--- /dev/null
@@ -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 );
+}