Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / packages / nvram.c
1 /*
2  *   Creation Date: <2003/12/01 00:26:13 samuel>
3  *   Time-stamp: <2004/01/07 19:59:53 samuel>
4  *
5  *      <nvram.c>
6  *
7  *      medium-level NVRAM handling
8  *
9  *   Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se)
10  *
11  *   This program is free software; you can redistribute it and/or
12  *   modify it under the terms of the GNU General Public License
13  *   version 2
14  *
15  */
16
17 #include "config.h"
18 #include "libopenbios/bindings.h"
19 #include "arch/common/nvram.h"
20 #include "packages/nvram.h"
21
22 //#define CONFIG_DEBUG_NVRAM 1
23
24 #ifdef CONFIG_DEBUG_NVRAM
25 #define DPRINTF(fmt, args...) \
26 do { printk("NVRAM: " fmt , ##args); } while (0)
27 #else
28 #define DPRINTF(fmt, args...) do {} while(0)
29 #endif
30
31 #define DEF_SYSTEM_SIZE 0xc10
32
33 #define NV_SIG_SYSTEM   0x70
34 #define NV_SIG_FREE     0x7f
35
36
37 typedef struct {
38         unsigned char   signature;
39         unsigned char   checksum;
40         unsigned char   len_hi;
41         unsigned char   len_lo;
42         char            name[12];
43         char            data[0];
44 } nvpart_t;
45
46 static struct {
47         char            *data;
48         int             size;
49
50         nvpart_t        *config;
51         int             config_size;
52 } nvram;
53
54
55 /************************************************************************/
56 /*      generic                                                         */
57 /************************************************************************/
58
59 static unsigned int
60 nvpart_checksum( nvpart_t* hdr )
61 {
62         unsigned char *p = (unsigned char*)hdr;
63         int i, val = p[0];
64
65         for( i=2; i<16; i++ ) {
66                 val += p[i];
67                 if( val > 255 )
68                         val = (val - 256 + 1) & 0xff;
69         }
70         return val;
71 }
72
73 static inline int
74 nvpart_size( nvpart_t *p )
75 {
76         return (p->len_lo | ((int)p->len_hi<<8)) * 16;
77 }
78
79 static int
80 next_nvpart( nvpart_t **p )
81 {
82         nvpart_t *end = (nvpart_t*)(nvram.data + nvram.size);
83         int len;
84
85         if( !*p ) {
86                 *p = (nvpart_t*)nvram.data;
87                 return 1;
88         }
89
90         if( !(len=nvpart_size(*p)) ) {
91                 printk("invalid nvram partition length\n");
92                 return -1;
93         }
94         *p = (nvpart_t*)((char*)*p + len);
95         if( *p < end )
96                 return 1;
97         if( *p == end )
98                 return 0;
99         return -1;
100 }
101
102 static void
103 create_free_part( char *ptr, int size )
104 {
105         nvpart_t *nvp = (nvpart_t*)ptr;
106         memset( nvp, 0, size );
107
108         strncpy( nvp->name, "777777777777", sizeof(nvp->name) );
109         nvp->signature = NV_SIG_FREE;
110         nvp->len_hi = (size /16) >> 8;
111         nvp->len_lo = size /16;
112         nvp->checksum = nvpart_checksum(nvp);
113 }
114
115 static int
116 create_nv_part( int signature, const char *name, int size )
117 {
118         nvpart_t *p = NULL;
119         int fs;
120
121         while( next_nvpart(&p) > 0 ) {
122                 if( p->signature != NV_SIG_FREE )
123                         continue;
124
125                 fs = nvpart_size( p );
126                 if( fs < size )
127                         size = fs;
128                 p->signature = signature;
129                 memset( p->name, 0, sizeof(p->name) );
130                 strncpy( p->name, name, sizeof(p->name) );
131                 p->len_hi = (size>>8)/16;
132                 p->len_lo = size/16;
133                 p->checksum = nvpart_checksum(p);
134                 if( fs > size ) {
135                         char *fp = (char*)p + size;
136                         create_free_part( fp, fs-size );
137                 }
138                 return size;
139         }
140         printk("create-failed\n");
141         return -1;
142 }
143
144 static void
145 zap_nvram( void )
146 {
147         create_free_part( nvram.data, nvram.size );
148         create_nv_part( NV_SIG_SYSTEM, "common", DEF_SYSTEM_SIZE );
149 }
150
151 #if 0
152 static void
153 show_partitions( void )
154 {
155         nvpart_t *p = NULL;
156         char buf[13];
157
158         while( next_nvpart(&p) > 0 ) {
159                 memcpy( buf, p->name, sizeof(p->name) );
160                 buf[12] = 0;
161                 printk("[%02x] %-13s:  %03x\n",
162                        p->signature, buf, nvpart_size(p));
163         }
164 }
165 #endif
166
167 void
168 update_nvram( void )
169 {
170         PUSH( pointer2cell(nvram.config->data) );
171         PUSH( nvram.config_size );
172         fword("nvram-store-configs");
173         arch_nvram_put( nvram.data );
174 }
175
176 void
177 nvconf_init( void )
178 {
179         int once=0;
180
181         /* initialize nvram structure completely */
182         nvram.config = NULL;
183         nvram.config_size = 0;
184
185         nvram.size = arch_nvram_size();
186         nvram.data = malloc( nvram.size );
187         arch_nvram_get( nvram.data );
188
189         bind_func( "update-nvram", update_nvram );
190
191         for( ;; ) {
192                 nvpart_t *p = NULL;
193                 int err;
194
195                 while( (err=next_nvpart(&p)) > 0 ) {
196                         if( nvpart_checksum(p) != p->checksum ) {
197                                 err = -1;
198                                 break;
199                         }
200                         if( p->signature == NV_SIG_SYSTEM ) {
201                                 nvram.config = p;
202                                 nvram.config_size = nvpart_size(p) - 0x10;
203
204                                 if( !once++ ) {
205                                         PUSH( pointer2cell(p->data) );
206                                         PUSH( nvram.config_size );
207                                         fword("nvram-load-configs");
208                                 }
209                         }
210                 }
211                 if( err || !nvram.config ) {
212                         printk("nvram error detected, zapping pram\n");
213                         zap_nvram();
214                         if( !once++ )
215                                 fword("set-defaults");
216                         continue;
217                 }
218                 break;
219         }
220 }
221
222
223 /************************************************************************/
224 /*      nvram                                                           */
225 /************************************************************************/
226
227 typedef struct {
228         unsigned int   mark_hi;
229         unsigned int   mark_lo;
230 } nvram_ibuf_t;
231
232 DECLARE_UNNAMED_NODE( nvram, INSTALL_OPEN, sizeof(nvram_ibuf_t ));
233
234 /* ( pos_lo pos_hi -- status ) */
235 static void
236 nvram_seek( nvram_ibuf_t *nd )
237 {
238         int pos_hi = POP();
239         int pos_lo = POP();
240
241         DPRINTF("seek %08x %08x\n", pos_hi, pos_lo );
242         nd->mark_lo = pos_lo;
243         nd->mark_hi = pos_hi;
244
245         if( nd->mark_lo >= nvram.size ) {
246                 PUSH(-1);
247                 return;
248         }
249
250         /* 0=success, -1=failure (1=legacy success) */
251         PUSH(0);
252 }
253
254 /* ( addr len -- actual ) */
255 static void
256 nvram_read( nvram_ibuf_t *nd )
257 {
258         int len = POP();
259         char *p = (char*)cell2pointer(POP());
260         int n=0;
261
262         while( nd->mark_lo < nvram.size && n < len ) {
263                 *p++ = nvram.data[nd->mark_lo++];
264                 n++;
265         }
266         PUSH(n);
267         DPRINTF("read %p %x -- %x\n", p, len, n);
268 }
269
270 /* ( addr len -- actual ) */
271 static void
272 nvram_write( nvram_ibuf_t *nd )
273 {
274         int len = POP();
275         char *p = (char*)cell2pointer(POP());
276         int n=0;
277
278         while( nd->mark_lo < nvram.size && n < len ) {
279                 nvram.data[nd->mark_lo++] = *p++;
280                 n++;
281         }
282         PUSH(n);
283         DPRINTF("write %p %x -- %x\n", p, len, n );
284 }
285
286 /* ( -- size ) */
287 static void
288 nvram_size( __attribute__((unused)) nvram_ibuf_t *nd )
289 {
290         DPRINTF("nvram_size %d\n", nvram.size);
291         PUSH( nvram.size );
292 }
293
294 NODE_METHODS( nvram ) = {
295         { "size",       (void*)nvram_size       },
296         { "read",       (void*)nvram_read       },
297         { "write",      (void*)nvram_write      },
298         { "seek",       (void*)nvram_seek       },
299 };
300
301
302 void
303 nvram_init( const char *path )
304 {
305         nvconf_init();
306
307         REGISTER_NAMED_NODE( nvram, path );
308 }