lantiq: bring back okli loader
[openwrt/staging/dedeckeh.git] / target / linux / lantiq / image / lzma-loader / src / loader.c
1 /*
2 * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
3 *
4 * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
5 *
6 * Some parts of this code was based on the OpenWrt specific lzma-loader
7 * for the BCM47xx and ADM5120 based boards:
8 * Copyright (C) 2004 Manuel Novoa III (mjn3@codepoet.org)
9 * Copyright (C) 2005 Mineharu Takahara <mtakahar@yahoo.com>
10 * Copyright (C) 2005 by Oleg I. Vdovikin <oleg@cs.msu.su>
11 *
12 * The image_header structure has been taken from the U-Boot project.
13 * (C) Copyright 2008 Semihalf
14 * (C) Copyright 2000-2005
15 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
16 *
17 * This program is free software; you can redistribute it and/or modify it
18 * under the terms of the GNU General Public License version 2 as published
19 * by the Free Software Foundation.
20 */
21
22 #include <stddef.h>
23 #include <stdint.h>
24
25 #include "config.h"
26 #include "cache.h"
27 #include "printf.h"
28 #include "LzmaDecode.h"
29
30
31 #define KSEG0 0x80000000
32 #define KSEG1 0xa0000000
33
34 #define KSEG1ADDR(a) ((((unsigned)(a)) & 0x1fffffffU) | KSEG1)
35
36 #undef LZMA_DEBUG
37
38 #ifdef LZMA_DEBUG
39 # define DBG(f, a...) printf(f, ## a)
40 #else
41 # define DBG(f, a...) do {} while (0)
42 #endif
43
44 #define IH_MAGIC_OKLI 0x4f4b4c49 /* 'OKLI' */
45
46 #define IH_NMLEN 32 /* Image Name Length */
47
48 typedef struct image_header {
49 uint32_t ih_magic; /* Image Header Magic Number */
50 uint32_t ih_hcrc; /* Image Header CRC Checksum */
51 uint32_t ih_time; /* Image Creation Timestamp */
52 uint32_t ih_size; /* Image Data Size */
53 uint32_t ih_load; /* Data Load Address */
54 uint32_t ih_ep; /* Entry Point Address */
55 uint32_t ih_dcrc; /* Image Data CRC Checksum */
56 uint8_t ih_os; /* Operating System */
57 uint8_t ih_arch; /* CPU architecture */
58 uint8_t ih_type; /* Image Type */
59 uint8_t ih_comp; /* Compression Type */
60 uint8_t ih_name[IH_NMLEN]; /* Image Name */
61 } image_header_t;
62
63 /* beyond the image end, size not known in advance */
64 extern unsigned char workspace[];
65 extern void board_init(void);
66
67 static CLzmaDecoderState lzma_state;
68 static unsigned char *lzma_data;
69 static unsigned long lzma_datasize;
70 static unsigned long lzma_outsize;
71 static unsigned long kernel_la;
72
73 #ifdef CONFIG_KERNEL_CMDLINE
74 #define kernel_argc 2
75 static const char kernel_cmdline[] = CONFIG_KERNEL_CMDLINE;
76 static const char *const kernel_argv[] = {
77 NULL,
78 kernel_cmdline,
79 NULL,
80 };
81 #endif /* CONFIG_KERNEL_CMDLINE */
82
83 static void halt(void)
84 {
85 printf("\nSystem halted!\n");
86 for(;;);
87 }
88
89 static __inline__ unsigned long get_be32(void *buf)
90 {
91 unsigned char *p = buf;
92
93 return (((unsigned long) p[0] << 24) +
94 ((unsigned long) p[1] << 16) +
95 ((unsigned long) p[2] << 8) +
96 (unsigned long) p[3]);
97 }
98
99 static __inline__ unsigned char lzma_get_byte(void)
100 {
101 unsigned char c;
102
103 lzma_datasize--;
104 c = *lzma_data++;
105
106 return c;
107 }
108
109 static int lzma_init_props(void)
110 {
111 unsigned char props[LZMA_PROPERTIES_SIZE];
112 int res;
113 int i;
114
115 /* read lzma properties */
116 for (i = 0; i < LZMA_PROPERTIES_SIZE; i++)
117 props[i] = lzma_get_byte();
118
119 /* read the lower half of uncompressed size in the header */
120 lzma_outsize = ((SizeT) lzma_get_byte()) +
121 ((SizeT) lzma_get_byte() << 8) +
122 ((SizeT) lzma_get_byte() << 16) +
123 ((SizeT) lzma_get_byte() << 24);
124
125 /* skip rest of the header (upper half of uncompressed size) */
126 for (i = 0; i < 4; i++)
127 lzma_get_byte();
128
129 res = LzmaDecodeProperties(&lzma_state.Properties, props,
130 LZMA_PROPERTIES_SIZE);
131 return res;
132 }
133
134 static int lzma_decompress(unsigned char *outStream)
135 {
136 SizeT ip, op;
137 int ret;
138
139 lzma_state.Probs = (CProb *) workspace;
140
141 ret = LzmaDecode(&lzma_state, lzma_data, lzma_datasize, &ip, outStream,
142 lzma_outsize, &op);
143
144 if (ret != LZMA_RESULT_OK) {
145 int i;
146
147 DBG("LzmaDecode error %d at %08x, osize:%d ip:%d op:%d\n",
148 ret, lzma_data + ip, lzma_outsize, ip, op);
149
150 for (i = 0; i < 16; i++)
151 DBG("%02x ", lzma_data[ip + i]);
152
153 DBG("\n");
154 }
155
156 return ret;
157 }
158
159 #if (LZMA_WRAPPER)
160 static void lzma_init_data(void)
161 {
162 extern unsigned char _lzma_data_start[];
163 extern unsigned char _lzma_data_end[];
164
165 kernel_la = LOADADDR;
166 lzma_data = _lzma_data_start;
167 lzma_datasize = _lzma_data_end - _lzma_data_start;
168 }
169 #else
170 static void lzma_init_data(void)
171 {
172 struct image_header *hdr = NULL;
173 unsigned char *flash_base;
174 unsigned long flash_ofs;
175 unsigned long kernel_ofs;
176 unsigned long kernel_size;
177
178 flash_base = (unsigned char *) KSEG1ADDR(CONFIG_FLASH_START);
179
180 printf("Looking for OpenWrt image... ");
181
182 for (flash_ofs = CONFIG_FLASH_OFFS;
183 flash_ofs <= (CONFIG_FLASH_OFFS + CONFIG_FLASH_MAX);
184 flash_ofs += CONFIG_FLASH_STEP) {
185 unsigned long magic;
186 unsigned char *p;
187
188 p = flash_base + flash_ofs;
189 magic = get_be32(p);
190 #ifdef CONFIG_KERNEL_MAGIC
191 if (magic == CONFIG_KERNEL_MAGIC) {
192 #else
193 if (magic == IH_MAGIC_OKLI) {
194 #endif
195 hdr = (struct image_header *) p;
196 break;
197 }
198 }
199
200 if (hdr == NULL) {
201 printf("not found!\n");
202 halt();
203 }
204
205 printf("found at 0x%08x\n", flash_base + flash_ofs);
206
207 kernel_ofs = sizeof(struct image_header);
208 kernel_size = get_be32(&hdr->ih_size);
209 kernel_la = get_be32(&hdr->ih_load);
210
211 lzma_data = flash_base + flash_ofs + kernel_ofs;
212 lzma_datasize = kernel_size;
213 }
214 #endif /* (LZMA_WRAPPER) */
215
216 void loader_main(unsigned long reg_a0, unsigned long reg_a1,
217 unsigned long reg_a2, unsigned long reg_a3)
218 {
219 void (*kernel_entry) (unsigned long, unsigned long, unsigned long,
220 unsigned long);
221 int res;
222
223 board_init();
224
225 printf("\n\nOpenWrt kernel loader for MIPS based SoC\n");
226 printf("Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>\n");
227
228 lzma_init_data();
229
230 res = lzma_init_props();
231 if (res != LZMA_RESULT_OK) {
232 printf("Incorrect LZMA stream properties!\n");
233 halt();
234 }
235
236 printf("Decompressing kernel... ");
237
238 res = lzma_decompress((unsigned char *) kernel_la);
239 if (res != LZMA_RESULT_OK) {
240 printf("failed, ");
241 switch (res) {
242 case LZMA_RESULT_DATA_ERROR:
243 printf("data error!\n");
244 break;
245 default:
246 printf("unknown error %d!\n", res);
247 }
248 halt();
249 } else {
250 printf("done!\n");
251 }
252
253 flush_cache(kernel_la, lzma_outsize);
254
255 printf("Starting kernel at %08x...\n\n", kernel_la);
256
257 #ifdef CONFIG_KERNEL_CMDLINE
258 reg_a0 = kernel_argc;
259 reg_a1 = (unsigned long) kernel_argv;
260 reg_a2 = 0;
261 reg_a3 = 0;
262 #endif
263
264 kernel_entry = (void *) kernel_la;
265 kernel_entry(reg_a0, reg_a1, reg_a2, reg_a3);
266 }