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