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