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
nvpart_checksum(nvpart_t * hdr)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
nvpart_size(nvpart_t * p)74 nvpart_size( nvpart_t *p )
75 {
76 return (p->len_lo | ((int)p->len_hi<<8)) * 16;
77 }
78
79 static int
next_nvpart(nvpart_t ** p)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
create_free_part(char * ptr,int size)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, "77777777777", 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
create_nv_part(int signature,const char * name,int size)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
zap_nvram(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
update_nvram(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
nvconf_init(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 for( ;; ) {
190 nvpart_t *p = NULL;
191 int err;
192
193 while( (err=next_nvpart(&p)) > 0 ) {
194 if( nvpart_checksum(p) != p->checksum ) {
195 err = -1;
196 break;
197 }
198 if( p->signature == NV_SIG_SYSTEM ) {
199 nvram.config = p;
200 nvram.config_size = nvpart_size(p) - 0x10;
201
202 if( !once++ ) {
203 PUSH( pointer2cell(p->data) );
204 PUSH( nvram.config_size );
205 fword("nvram-load-configs");
206 }
207 }
208 }
209 if( err || !nvram.config ) {
210 printk("nvram error detected, zapping pram\n");
211 zap_nvram();
212 if( !once++ )
213 fword("set-defaults");
214 continue;
215 }
216 break;
217 }
218 }
219
220
221 /************************************************************************/
222 /* nvram */
223 /************************************************************************/
224
225 typedef struct {
226 unsigned int mark_hi;
227 unsigned int mark_lo;
228 } nvram_ibuf_t;
229
230 DECLARE_UNNAMED_NODE( nvram, INSTALL_OPEN, sizeof(nvram_ibuf_t ));
231
232 /* ( pos_lo pos_hi -- status ) */
233 static void
nvram_seek(nvram_ibuf_t * nd)234 nvram_seek( nvram_ibuf_t *nd )
235 {
236 int pos_hi = POP();
237 int pos_lo = POP();
238
239 DPRINTF("seek %08x %08x\n", pos_hi, pos_lo );
240 nd->mark_lo = pos_lo;
241 nd->mark_hi = pos_hi;
242
243 if( nd->mark_lo >= nvram.size ) {
244 PUSH(-1);
245 return;
246 }
247
248 /* 0=success, -1=failure (1=legacy success) */
249 PUSH(0);
250 }
251
252 /* ( addr len -- actual ) */
253 static void
nvram_read(nvram_ibuf_t * nd)254 nvram_read( nvram_ibuf_t *nd )
255 {
256 int len = POP();
257 char *p = (char*)cell2pointer(POP());
258 int n=0;
259
260 while( nd->mark_lo < nvram.size && n < len ) {
261 *p++ = nvram.data[nd->mark_lo++];
262 n++;
263 }
264 PUSH(n);
265 DPRINTF("read %p %x -- %x\n", p, len, n);
266 }
267
268 /* ( addr len -- actual ) */
269 static void
nvram_write(nvram_ibuf_t * nd)270 nvram_write( nvram_ibuf_t *nd )
271 {
272 int len = POP();
273 char *p = (char*)cell2pointer(POP());
274 int n=0;
275
276 while( nd->mark_lo < nvram.size && n < len ) {
277 nvram.data[nd->mark_lo++] = *p++;
278 n++;
279 }
280 PUSH(n);
281 DPRINTF("write %p %x -- %x\n", p, len, n );
282 }
283
284 /* ( -- size ) */
285 static void
nvram_size(nvram_ibuf_t * nd)286 nvram_size( __attribute__((unused)) nvram_ibuf_t *nd )
287 {
288 DPRINTF("nvram_size %d\n", nvram.size);
289 PUSH( nvram.size );
290 }
291
292 static void
nvram_open(nvram_ibuf_t * nd)293 nvram_open( __attribute__((unused)) nvram_ibuf_t *nd )
294 {
295 RET(-1);
296 }
297
298 static void
nvram_close(nvram_ibuf_t * nd)299 nvram_close( __attribute__((unused)) nvram_ibuf_t *nd )
300 {
301 }
302
303 NODE_METHODS( nvram ) = {
304 { "open", (void*)nvram_open },
305 { "close", (void*)nvram_close },
306 { "size", (void*)nvram_size },
307 { "read", (void*)nvram_read },
308 { "write", (void*)nvram_write },
309 { "seek", (void*)nvram_seek },
310 { "update-nvram", (void*)update_nvram },
311 };
312
313
314 phandle_t
nvram_init(const char * path)315 nvram_init( const char *path )
316 {
317 phandle_t ph;
318
319 push_str(path);
320 fword("find-device");
321
322 fword("new-device");
323
324 ph = get_cur_dev();
325
326 push_str("nvram");
327 fword("device-name");
328
329 BIND_NODE_METHODS(get_cur_dev(), nvram);
330 fword("finish-device");
331
332 return ph;
333 }
334