root/ar5315_microredboot/microredboot/boot/src/misc_lzma.c

Revision 12381, 7.8 kB (checked in by BrainSlayer, 5 months ago)

fixes bootcode for Atheros LSDK based firmwares

Line 
1 /*
2  * misc_lzma.c
3  * originally written for xscale based linux kernel decompression
4  * now adapted for AR531X based redboot stub and kernel loader
5  * copyright 2009 Sebastian Gottschall / NewMedia-NET GmbH / DD-WRT.COM
6  * licensed under GPL conditions
7  * this stub will load and decompress redboot if the reset button is pushed, otherwise it parses the redboot directory for a partition named linux*, vmlinux* or kernel*
8  * if such a partition has been found, it will be decompressed and executed, if not. redboot is started. if a decompression error occures while loading the linux partition,
9  * the redboot is started too.
10  * take care about the ramconfig.h header since it must contain the correct ram size and gpio button value for the reset button
11  * this code is partially based on redboot and linux sources
12  */
13
14 #ifdef STANDALONE_DEBUG
15 #define putstr printf
16 #else
17
18 #include <linux/kernel.h>
19
20 #include <asm/uaccess.h>
21 #include "ramconfig.h"
22 #include "uncompress.h"
23 #include "lib/lib.c"
24 #include "lib/print.c"
25 #include "lib/printf.c"
26
27 #endif
28
29 #define __ptr_t void *
30
31 typedef unsigned char uch;
32 typedef unsigned short ush;
33 typedef unsigned long ulg;
34
35 static uch *inbuf;              /* input buffer */
36 static unsigned int nvramdetect = 0;
37
38 static unsigned insize = 0;     /* valid bytes in inbuf */
39 static unsigned inptr = 0;      /* index of next byte to be processed in inbuf */
40 static unsigned outcnt;         /* bytes in output buffer */
41
42 static void fill_inbuf(void);
43
44 static inline unsigned char get_byte(void)
45 {
46         static unsigned int vall;
47
48         if (((unsigned int)inptr % 4) == 0) {
49                 vall = *(unsigned int *)inbuf;
50                 inbuf += 4;
51         }
52         return *(((unsigned char *)&vall) + (inptr++ & 3));
53 }
54
55 //#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
56
57 static void flush_window(void);
58 static void error(char *m);
59
60 extern unsigned char input_data[];
61 extern unsigned char input_data_end[];
62
63 static ulg output_ptr = 0;
64 static uch *output_data;
65 static ulg bytes_out;
66
67 extern int end;
68 static ulg free_mem_ptr;
69 static ulg free_mem_ptr_end;
70
71 #define _LZMA_IN_CB
72
73 #include "lib/LzmaDecode.h"
74 static unsigned int icnt = 0;
75 static inline int read_byte(unsigned char **buffer, UInt32 * bufferSize)
76 {
77         static unsigned char val;
78         *bufferSize = 1;
79         val = get_byte();
80         *buffer = &val;
81         if (icnt++ % (1024 * 10) == 0)
82                 putc('.');
83         return LZMA_RESULT_OK;
84 }
85
86 #include "lib/LzmaDecode.c"
87
88 int bootoffset = 0x800004bc;
89
90 /*
91  * Do the lzma decompression
92  */
93
94 static int disaster = 0;
95 static int lzma_unzip(void)
96 {
97
98         unsigned int i;
99         unsigned int uncompressedSize = 0;
100         unsigned char *workspace;
101         unsigned int lc, lp, pb;
102         if (inptr >= insize)
103                 fill_inbuf();
104
105         // lzma args
106         i = get_byte();
107         lc = i % 9, i = i / 9;
108         lp = i % 5, pb = i / 5;
109
110         // skip dictionary size
111         for (i = 0; i < 4; i++)
112                 get_byte();
113         // get uncompressed size
114         int a, b, c, d;
115         a = get_byte();
116         b = get_byte();
117         c = get_byte();
118         d = get_byte();
119         uncompressedSize = (a) + (b << 8) + (c << 16) + (d << 24);
120         if (uncompressedSize > 0x400000 || lc > 3 || pb > 3 || lp > 3) {
121                 if (disaster) {
122                         error
123                             ("\ndata corrupted in recovery RedBoot too, this is a disaster condition. please re-jtag\n");
124                 }
125                 disaster = 1;
126                 puts("\ndata corrupted!\nswitching to recovery RedBoot\nloading");
127                 inbuf = input_data;
128                 insize = &input_data_end[0] - &input_data[0];
129                 inptr = 0;
130                 output_data = (uch *) 0x80000400;
131                 bootoffset = 0x800004bc;
132                 return lzma_unzip();
133
134         }
135         workspace = output_data + uncompressedSize;
136         // skip high order bytes
137         for (i = 0; i < 4; i++)
138                 get_byte();
139         // decompress kernel
140         if (LzmaDecode
141             (workspace, ~0, lc, lp, pb, (unsigned char *)output_data,
142              uncompressedSize, &i) == LZMA_RESULT_OK) {
143                 if (i != uncompressedSize) {
144                         if (disaster) {
145                                 error
146                                     ("data corrupted in recovery RedBoot too, this is a disaster condition. please re-jtag\n");
147                         }
148                         disaster = 1;
149                         puts("\ndata corrupted!\nswitching to recovery RedBoot\nloading");
150                         inbuf = input_data;
151                         insize = &input_data_end[0] - &input_data[0];
152                         inptr = 0;
153                         output_data = (uch *) 0x80000400;
154                         bootoffset = 0x800004bc;
155                         return lzma_unzip();
156                 }
157                 //copy it back to low_buffer
158                 bytes_out = i;
159                 output_ptr = i;
160                 return 0;
161         }
162         return 1;
163 }
164
165 #ifdef AR5312
166 #include "arch/ar5312.c"
167 #else
168 #include "arch/ar2315.c"
169 #endif
170
171 #include "lib/fis.c"
172 /* ===========================================================================
173  * Fill the input buffer. This is called only when the buffer is empty
174  * and at least one byte is really needed.
175  */
176 static int resettrigger = 0;
177
178 static void fill_inbuf(void)
179 {
180         if (insize != 0)
181                 error("ran out of input data");
182         if (resettrigger) {
183                 inbuf = (uch *) linuxaddr;
184                 insize = 0x400000;
185                 inptr = 0;
186         } else {
187                 inbuf = input_data;
188                 insize = &input_data_end[0] - &input_data[0];
189                 inptr = 0;
190         }
191         return;
192 }
193
194 /* ===========================================================================
195  * Write the output window window[0..outcnt-1] and update crc and bytes_out.
196  * (Used for the decompressed data only.)
197  */
198
199 #ifndef arch_error
200 #define arch_error(x)
201 #endif
202
203 static void error(char *x)
204 {
205         arch_error(x);
206
207         printf("\n\n%s\n\n -- System halted", x);
208
209         while (1) ;             /* Halt */
210 }
211
212 /*
213  * checks if the reset button is pressed, return 1 if the button is pressed and 0 if not
214  */
215 static int resetTouched(void)
216 {
217         int trigger = getGPIO(RESETBUTTON & 0x0f);
218         if (RESETBUTTON & 0xf0)
219                 trigger = 1 - trigger;
220         return trigger;
221 }
222
223 #include <lib/nvram.c>
224
225 typedef struct {
226         char *name;
227         char *val;
228 } t_env_var;
229
230 struct parmblock {
231         t_env_var memsize;
232         t_env_var modetty0;
233         t_env_var ethaddr;
234         t_env_var env_end;
235         char *argv[2];
236         char text[0];
237 };
238
239 static void set_cmdline(void)
240 {
241         char *pcmd;
242         struct parmblock *pb;
243         pb = (struct parmblock *)0x80030000;
244         pcmd = pb->text;
245
246         pb->memsize.name = pcmd;
247         strcpy(pcmd, "memsize");
248         pcmd += 7;
249         pb->memsize.val = ++pcmd;
250         strcpy(pcmd, "0x");
251         pcmd += 2;
252         static char *xlate = "0123456789abcdef";
253         int i;
254         int c = 0;
255         unsigned int val = RAM_SIZE;
256         for (i = 28; i >= 0; i -= 4) {
257                 pcmd[c++] = xlate[(val >> i) & 0xf];
258         }
259         pcmd += c;
260         pb->modetty0.name = ++pcmd;
261         strcpy(pcmd, "modetty0");
262         pcmd += 8;
263         pb->modetty0.val = ++pcmd;
264         strcpy(pcmd, "115200,n,8,1,hw");
265         pcmd += 15;
266         pb->ethaddr.name = NULL;
267         pb->ethaddr.val = NULL;
268         pb->argv[0] = pcmd;
269         pb->argv[1] = ++pcmd;
270         pcmd[0] = 0;            //terminate, no commandline
271
272         void (*tt) (int a, char **b, void *c);
273         tt = bootoffset;
274         tt(2, pb->argv, pb);
275
276 }
277
278 ulg
279 decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p)
280 {
281         output_data = (uch *) output_start;
282         free_mem_ptr = free_mem_ptr_p;
283         free_mem_ptr_end = free_mem_ptr_end_p;
284         disable_watchdog();
285         arch_decomp_setup();
286         printf("MicroRedBoot v1.3, (c) 2009 DD-WRT.COM (%s)\n", __DATE__);
287         printf("CPU Clock: %dMhz\n", cpu_frequency() / 1000000);
288         nvram_init();
289         char *ddboard = nvram_get("DD_BOARD");
290         if (ddboard)
291                 printf("Board: %s\n", ddboard);
292         char *resetbutton = nvram_get("resetbutton_enable");
293         if (resetbutton && !strcmp(resetbutton, "0"))
294                 puts("reset button manual override detected! (nvram var resetbutton_enable=0)\n");
295         if (resetTouched() || (resetbutton && !strcmp(resetbutton, "0"))) {
296                 puts("Reset Button triggered\nBooting Recovery RedBoot\n");
297
298                 int count = 5;
299                 while (count--) {
300                         if (!resetTouched())    // check if reset button is unpressed again
301                                 break;
302                         udelay(1000000);
303                 }
304                 if (count <= 0) {
305                         puts("reset button 5 seconds pushed, erasing nvram\n");
306
307                         if (!flashdetect())
308                                 flash_erase_nvram(flashsize, NVRAM_SPACE);
309                 }
310
311                 bootoffset = 0x800004bc;
312                 resettrigger = 0;
313                 puts("loading");
314                 lzma_unzip();
315                 puts("\n\n\n");
316                 return output_ptr;
317         } else {
318                 flashdetect();
319                 linuxaddr = getLinux();
320                 puts("Booting Linux\n");
321                 resettrigger = 1;
322                 /* initialize clock */
323                 HAL_CLOCK_INITIALIZE(RTC_PERIOD);
324
325                 /* important, enable ethernet bus, if the following lines are not initialized linux will not be able to use the ethernet mac, taken from redboot source */
326                 enable_ethernet();
327                 puts("loading");
328                 lzma_unzip();
329                 set_cmdline();
330         }
331 }
Note: See TracBrowser for help on using the browser.