source: ar5315_microredboot/microredboot/boot/src/misc_lzma.c @ 12336

Last change on this file since 12336 was 12336, checked in by BrainSlayer, 4 years ago

fix compiling bugs and increase version number

File size: 6.7 KB
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
31typedef unsigned char uch;
32typedef unsigned short ush;
33typedef unsigned long ulg;
34
35static uch *inbuf;              /* input buffer */
36static unsigned int nvramdetect = 0;
37
38static unsigned insize = 0;     /* valid bytes in inbuf */
39static unsigned inptr = 0;      /* index of next byte to be processed in inbuf */
40static unsigned outcnt;         /* bytes in output buffer */
41
42static void fill_inbuf(void);
43
44static 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
57static void flush_window(void);
58static void error(char *m);
59
60extern unsigned char input_data[];
61extern unsigned char input_data_end[];
62
63static ulg output_ptr = 0;
64static uch *output_data;
65static ulg bytes_out;
66
67extern int end;
68static ulg free_mem_ptr;
69static ulg free_mem_ptr_end;
70
71#define _LZMA_IN_CB
72
73#include "lib/LzmaDecode.h"
74static unsigned int icnt = 0;
75static 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
88int bootoffset = 0x800004bc;
89
90/*
91 * Do the lzma decompression
92 */
93
94static int disaster = 0;
95static 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 */
176static int resettrigger = 0;
177
178static 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
203static 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 */
215static 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
225ulg
226decompress_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        nvram_init();
235        char *ddboard = nvram_get("DD_BOARD");
236        if (ddboard)
237                printf("Board: %s\n", ddboard);
238        char *resetbutton = nvram_get("resetbutton_enable");
239        if (resetbutton && !strcmp(resetbutton, "1"))
240                puts("reset button manual override detected! (nvram var resetbutton_enable=1)\n");
241        if (resetTouched() || (resetbutton && !strcmp(resetbutton, "1"))) {
242                puts("Reset Button triggered\nBooting Recovery RedBoot\n");
243
244                int count = 5;
245                while (count--) {
246                        if (!resetTouched())    // check if reset button is unpressed again
247                                break;
248                        udelay(1000000);
249                }
250                if (count <= 0) {
251                        puts("reset button 5 seconds pushed, erasing nvram\n");
252
253                        if (!flashdetect())
254                                flash_erase_nvram(flashsize, sectorsize);
255                }
256
257                bootoffset = 0x800004bc;
258                resettrigger = 0;
259        } else {
260                flashdetect();
261                linuxaddr = getLinux();
262                puts("Booting Linux\n");
263                resettrigger = 1;
264                /* initialize clock */
265                HAL_CLOCK_INITIALIZE(RTC_PERIOD);
266
267                /* 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 */
268                enable_ethernet();
269        }
270        puts("loading");
271        lzma_unzip();
272        puts("\n\n\n");
273
274        return output_ptr;
275}
Note: See TracBrowser for help on using the repository browser.