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

Revision 12368, 6.8 kB (checked in by BrainSlayer, 5 months ago)

tftp server added, supports wiligear, ubiquiti and dd-wrt webflash format

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 ulg
226 decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p)
227 {
228         output_data = (uch *) output_start;
229         free_mem_ptr = free_mem_ptr_p;
230         free_mem_ptr_end = free_mem_ptr_end_p;
231         disable_watchdog();
232         arch_decomp_setup();
233         printf("MicroRedBoot v1.3, (c) 2009 DD-WRT.COM (%s)\n", __DATE__);
234         printf("CPU Clock: %dMhz\n", cpu_frequency() / 1000000);
235         nvram_init();
236         char *ddboard = nvram_get("DD_BOARD");
237         if (ddboard)
238                 printf("Board: %s\n", ddboard);
239         char *resetbutton = nvram_get("resetbutton_enable");
240         if (resetbutton && !strcmp(resetbutton, "0"))
241                 puts("reset button manual override detected! (nvram var resetbutton_enable=0)\n");
242         if (resetTouched() || (resetbutton && !strcmp(resetbutton, "0"))) {
243                 puts("Reset Button triggered\nBooting Recovery RedBoot\n");
244
245                 int count = 5;
246                 while (count--) {
247                         if (!resetTouched())    // check if reset button is unpressed again
248                                 break;
249                         udelay(1000000);
250                 }
251                 if (count <= 0) {
252                         puts("reset button 5 seconds pushed, erasing nvram\n");
253
254                         if (!flashdetect())
255                                 flash_erase_nvram(flashsize, NVRAM_SPACE);
256                 }
257
258                 bootoffset = 0x800004bc;
259                 resettrigger = 0;
260         } else {
261                 flashdetect();
262                 linuxaddr = getLinux();
263                 puts("Booting Linux\n");
264                 resettrigger = 1;
265                 /* initialize clock */
266                 HAL_CLOCK_INITIALIZE(RTC_PERIOD);
267
268                 /* 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 */
269                 enable_ethernet();
270         }
271         puts("loading");
272         lzma_unzip();
273         puts("\n\n\n");
274
275         return output_ptr;
276 }
Note: See TracBrowser for help on using the browser.