strip the kernel version suffix from target directories, except for brcm-2.4 (the...
[10.03/openwrt.git] / target / linux / adm5120 / image / lzma-loader / src / decompress.c
1 /*
2  * $Id$
3  *
4  * LZMA compressed kernel decompressor for ADM5120 boards
5  *
6  * Copyright (C) 2005 by Oleg I. Vdovikin <oleg@cs.msu.su>
7  * Copyright (C) 2007 OpenWrt.org
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  *
23  *
24  * Please note, this was code based on the bunzip2 decompressor code
25  * by Manuel Novoa III  (mjn3@codepoet.org), although the only thing left
26  * is an idea and part of original vendor code
27  *
28  *
29  * 12-Mar-2005  Mineharu Takahara <mtakahar@yahoo.com>
30  *   pass actual output size to decoder (stream mode
31  *   compressed input is not a requirement anymore)
32  *
33  * 24-Apr-2005 Oleg I. Vdovikin
34  *   reordered functions using lds script, removed forward decl
35  *
36  * 24-Mar-2007 Gabor Juhos
37  *   pass original values of the a0,a1,a2,a3 registers to the kernel
38  *
39  * 19-May-2007 Gabor Juhos
40  *   endiannes related cleanups
41  *   add support for decompressing an embedded kernel
42  *
43  */
44
45 #include <stddef.h>
46
47 #include "config.h"
48 #include "printf.h"
49 #include "LzmaDecode.h"
50
51 #define ADM5120_FLASH_START     0x1fc00000      /* Flash start */
52 #define ADM5120_FLASH_END       0x1fe00000      /* Flash end */
53
54 #define KSEG0                   0x80000000
55 #define KSEG1                   0xa0000000
56
57 #define KSEG1ADDR(a)            ((((unsigned)(a)) & 0x1fffffffU) | KSEG1)
58
59 #define Index_Invalidate_I      0x00
60 #define Index_Writeback_Inv_D   0x01
61
62 #define cache_unroll(base,op)   \
63         __asm__ __volatile__(           \
64                 ".set noreorder;\n"             \
65                 ".set mips3;\n"                 \
66                 "cache %1, (%0);\n"             \
67                 ".set mips0;\n"                 \
68                 ".set reorder\n"                \
69                 :                               \
70                 : "r" (base),                   \
71                   "i" (op));
72
73 #ifdef LZMA_DEBUG
74 #  define DBG(f, a...)  printf(f, ## a)
75 #else
76 #  define DBG(f, a...)  do {} while (0)
77 #endif
78
79 static __inline__ void blast_icache(unsigned long size, unsigned long lsize)
80 {
81         unsigned long start = KSEG0;
82         unsigned long end = (start + size);
83
84         while(start < end) {
85                 cache_unroll(start,Index_Invalidate_I);
86                 start += lsize;
87         }
88 }
89
90 static __inline__ void blast_dcache(unsigned long size, unsigned long lsize)
91 {
92         unsigned long start = KSEG0;
93         unsigned long end = (start + size);
94
95         while(start < end) {
96                 cache_unroll(start,Index_Writeback_Inv_D);
97                 start += lsize;
98         }
99 }
100
101 #define TRX_MAGIC       0x30524448      /* "HDR0" */
102 #define TRX_ALIGN       0x1000
103
104 struct trx_header {
105         unsigned int magic;             /* "HDR0" */
106         unsigned int len;               /* Length of file including header */
107         unsigned int crc32;             /* 32-bit CRC from flag_version to end of file */
108         unsigned int flag_version;      /* 0:15 flags, 16:31 version */
109         unsigned int offsets[3];        /* Offsets of partitions from start of header */
110 };
111
112 struct env_var {
113         char    *name;
114         char    *value;
115 };
116
117 /* beyound the image end, size not known in advance */
118 extern unsigned char workspace[];
119 extern void board_init(void);
120
121 typedef void (*kernel_entry)(unsigned long reg_a0, unsigned long reg_a1,
122         unsigned long reg_a2, unsigned long reg_a3);
123
124 static int decompress_data(unsigned char *buffer, UInt32 bufferSize,
125         int lc, int lp, int pb, unsigned char *outStream, UInt32 outSize,
126         UInt32 *outSizeProcessed);
127
128 #ifdef CONFIG_PASS_KARGS
129 #define ENVV(n,v)       {.name = (n), .value = (v)}
130 struct env_var env_vars[] = {
131         ENVV("board_name",      CONFIG_BOARD_NAME),
132         ENVV(NULL, NULL)
133 };
134 #endif
135
136 static void halt(void)
137 {
138         printf("\nSystem halted!\n");
139         for(;;);
140 }
141
142 #if LZMA_WRAPPER
143 extern unsigned char _lzma_data_start[];
144 extern unsigned char _lzma_data_end[];
145
146 unsigned char *data;
147 unsigned long datalen;
148
149 static __inline__ unsigned char get_byte(void)
150 {
151         datalen--;
152         return *data++;
153 }
154
155 static void decompress_init(void)
156 {
157         data = _lzma_data_start;
158         datalen = _lzma_data_end - _lzma_data_start;
159 }
160
161 static int decompress_data(unsigned char *buffer, UInt32 bufferSize,
162         int lc, int lp, int pb, unsigned char *outStream, UInt32 outSize,
163         UInt32 *outSizeProcessed)
164 {
165         return LzmaDecode(buffer, bufferSize, lc, lp, pb, data, datalen,
166                 outStream, outSize, outSizeProcessed);
167 }
168 #endif /* LZMA_WRAPPER */
169
170 #if !(LZMA_WRAPPER)
171
172 #define FLASH_BANK_SIZE (2<<20)
173
174 static unsigned char *flash_base = (unsigned char *) KSEG1ADDR(ADM5120_FLASH_START);
175 static unsigned long flash_ofs = 0;
176 static unsigned long flash_max = 0;
177 static unsigned long flash_ofs_mask = (FLASH_BANK_SIZE-1);
178
179 static __inline__ unsigned char get_byte(void)
180 {
181         return *(flash_base+flash_ofs++);
182 }
183
184 static int lzma_read_byte(void *object, unsigned char **buffer, UInt32 *bufferSize)
185 {
186         unsigned long len;
187
188         if (flash_ofs >= flash_max)
189                 return LZMA_RESULT_DATA_ERROR;
190
191         len = flash_max-flash_ofs;
192
193 #if (CONFIG_FLASH_SIZE > FLASH_BANK_SIZE)
194         if (flash_ofs < FLASH_BANK_SIZE) {
195                 /* switch to bank 0 */
196                 DBG("lzma_read_byte: switch to bank 0\n");
197
198                 if (len > FLASH_BANK_SIZE-flash_ofs)
199                         len = FLASH_BANK_SIZE-flash_ofs;
200         } else {
201                 /* switch to bank 1 */
202                 DBG("lzma_read_byte: switch to bank 1\n");
203         }
204 #endif
205         DBG("lzma_read_byte: ofs=%08X, len=%08X\n", flash_ofs, len);
206
207         *buffer = flash_base+(flash_ofs & flash_ofs_mask);
208         *bufferSize = len;
209         flash_ofs += len;
210
211         return LZMA_RESULT_OK;
212 }
213
214 static ILzmaInCallback lzma_callback = {
215         .Read   = lzma_read_byte,
216 };
217
218 static __inline__ unsigned int read_le32(void *buf)
219 {
220         unsigned char *p = buf;
221
222         return ((unsigned int)p[0] + ((unsigned int)p[1] << 8) +
223                 ((unsigned int)p[2] << 16) +((unsigned int)p[3] << 24));
224 }
225
226 static void decompress_init(void)
227 {
228         struct trx_header *hdr = NULL;
229         unsigned long kofs,klen;
230
231         printf("Looking for TRX header... ");
232         /* look for trx header, 32-bit data access */
233         for (flash_ofs = 0; flash_ofs < FLASH_BANK_SIZE; flash_ofs += TRX_ALIGN) {
234                 if (read_le32(&flash_base[flash_ofs]) == TRX_MAGIC) {
235                         hdr = (struct trx_header *)&flash_base[flash_ofs];
236                         break;
237                 }
238         }
239
240         if (hdr == NULL) {
241                 printf("not found!\n");
242                 /* no compressed kernel found, halting */
243                 halt();
244         }
245
246         /* compressed kernel is in the partition 0 or 1 */
247         kofs = read_le32(&hdr->offsets[1]);
248         if (kofs == 0 || kofs > 65536) {
249                 klen = kofs-read_le32(&hdr->offsets[0]);
250                 kofs = read_le32(&hdr->offsets[0]);
251         } else {
252                 klen = read_le32(&hdr->offsets[2]);
253                 if (klen > kofs)
254                         klen -= kofs;
255                 else
256                         klen = read_le32(&hdr->len)-kofs;
257         }
258
259         printf("found at %08X, kernel:%08X len:%08X\n", flash_ofs,
260                 kofs, klen);
261
262         flash_ofs += kofs;
263         flash_max = flash_ofs+klen;
264 }
265
266 static int decompress_data(unsigned char *buffer, UInt32 bufferSize,
267         int lc, int lp, int pb, unsigned char *outStream, UInt32 outSize,
268         UInt32 *outSizeProcessed)
269 {
270         return LzmaDecode(buffer, bufferSize, lc, lp, pb, &lzma_callback,
271                 outStream, outSize, outSizeProcessed);
272 }
273 #endif /* !(LZMA_WRAPPER) */
274
275 /* should be the first function */
276 void decompress_entry(unsigned long reg_a0, unsigned long reg_a1,
277         unsigned long reg_a2, unsigned long reg_a3,
278         unsigned long icache_size, unsigned long icache_lsize,
279         unsigned long dcache_size, unsigned long dcache_lsize)
280 {
281         unsigned int i;  /* temp value */
282         unsigned int lc; /* literal context bits */
283         unsigned int lp; /* literal pos state bits */
284         unsigned int pb; /* pos state bits */
285         unsigned int osize; /* uncompressed size */
286         int res;
287
288         board_init();
289
290         printf("\n\nLZMA loader for " CONFIG_BOARD_NAME
291                         ", Copyright (C) 2007 OpenWrt.org\n\n");
292
293         decompress_init();
294
295         /* lzma args */
296         i = get_byte();
297         lc = i % 9, i = i / 9;
298         lp = i % 5, pb = i / 5;
299
300         /* skip rest of the LZMA coder property */
301         for (i = 0; i < 4; i++)
302                 get_byte();
303
304         /* read the lower half of uncompressed size in the header */
305         osize = ((unsigned int)get_byte()) +
306                 ((unsigned int)get_byte() << 8) +
307                 ((unsigned int)get_byte() << 16) +
308                 ((unsigned int)get_byte() << 24);
309
310         /* skip rest of the header (upper half of uncompressed size) */
311         for (i = 0; i < 4; i++)
312                 get_byte();
313
314         printf("decompressing kernel... ");
315
316         /* decompress kernel */
317         res = decompress_data(workspace, ~0, lc, lp, pb,
318                 (unsigned char *)LOADADDR, osize, &i);
319
320         if (res != LZMA_RESULT_OK) {
321                 printf("failed, ");
322                 switch (res) {
323                 case LZMA_RESULT_DATA_ERROR:
324                         printf("data error!\n");
325                         break;
326                 case LZMA_RESULT_NOT_ENOUGH_MEM:
327                         printf("not enough memory!\n");
328                         break;
329                 default:
330                         printf("unknown error %d!\n", res);
331                 }
332                 halt();
333         } else
334                 printf("done!\n");
335
336         blast_dcache(dcache_size, dcache_lsize);
337         blast_icache(icache_size, icache_lsize);
338
339         printf("launching kernel...\n\n");
340
341 #ifdef CONFIG_PASS_KARGS
342         reg_a0 = 0;
343         reg_a1 = 0;
344         reg_a2 = (unsigned long)env_vars;
345         reg_a3 = 0;
346 #endif
347         /* Jump to load address */
348         ((kernel_entry) LOADADDR)(reg_a0, reg_a1, reg_a2, reg_a3);
349 }