2 * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
4 * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
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>
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.
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.
24 #include <sys/types.h>
29 #include "LzmaDecode.h"
31 #define KSEG0 0x80000000
32 #define KSEG1 0xa0000000
34 #define KSEG1ADDR(a) ((((unsigned)(a)) & 0x1fffffffU) | KSEG1)
39 # define DBG(f, a...) printf(f, ## a)
41 # define DBG(f, a...) do {} while (0)
44 #define IH_MAGIC_OKLI 0x4f4b4c49 /* 'OKLI' */
46 #define IH_NMLEN 32 /* Image Name Length */
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 */
63 /* beyond the image end, size not known in advance */
64 extern unsigned char workspace
[];
65 extern void board_init(void);
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
;
73 #ifdef CONFIG_KERNEL_CMDLINE
75 static const char kernel_cmdline
[] = CONFIG_KERNEL_CMDLINE
;
76 static const char *kernel_argv
[] = {
81 #endif /* CONFIG_KERNEL_CMDLINE */
83 static void halt(void)
85 printf("\nSystem halted!\n");
89 static __inline__
unsigned long get_be32(void *buf
)
91 unsigned char *p
= buf
;
93 return (((unsigned long) p
[0] << 24) +
94 ((unsigned long) p
[1] << 16) +
95 ((unsigned long) p
[2] << 8) +
96 (unsigned long) p
[3]);
99 static __inline__
unsigned char lzma_get_byte(void)
109 static int lzma_init_props(void)
111 unsigned char props
[LZMA_PROPERTIES_SIZE
];
115 /* read lzma properties */
116 for (i
= 0; i
< LZMA_PROPERTIES_SIZE
; i
++)
117 props
[i
] = lzma_get_byte();
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);
125 /* skip rest of the header (upper half of uncompressed size) */
126 for (i
= 0; i
< 4; i
++)
129 res
= LzmaDecodeProperties(&lzma_state
.Properties
, props
,
130 LZMA_PROPERTIES_SIZE
);
134 static int lzma_decompress(unsigned char *outStream
)
139 lzma_state
.Probs
= (CProb
*) workspace
;
141 ret
= LzmaDecode(&lzma_state
, lzma_data
, lzma_datasize
, &ip
, outStream
,
144 if (ret
!= LZMA_RESULT_OK
) {
147 DBG("LzmaDecode error %d at %08x, osize:%d ip:%d op:%d\n",
148 ret
, lzma_data
+ ip
, lzma_outsize
, ip
, op
);
150 for (i
= 0; i
< 16; i
++)
151 DBG("%02x ", lzma_data
[ip
+ i
]);
160 static void lzma_init_data(void)
162 extern unsigned char _lzma_data_start
[];
163 extern unsigned char _lzma_data_end
[];
165 kernel_la
= LOADADDR
;
166 lzma_data
= _lzma_data_start
;
167 lzma_datasize
= _lzma_data_end
- _lzma_data_start
;
170 static void lzma_init_data(void)
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
;
178 flash_base
= (unsigned char *) KSEG1ADDR(CONFIG_FLASH_START
);
180 printf("Looking for OpenWrt image... ");
182 for (flash_ofs
= CONFIG_FLASH_OFFS
;
183 flash_ofs
<= (CONFIG_FLASH_OFFS
+ CONFIG_FLASH_MAX
);
184 flash_ofs
+= CONFIG_FLASH_STEP
) {
188 p
= flash_base
+ flash_ofs
;
190 if (magic
== IH_MAGIC_OKLI
) {
191 hdr
= (struct image_header
*) p
;
197 printf("not found!\n");
201 printf("found at 0x%08x\n", flash_base
+ flash_ofs
);
203 kernel_ofs
= sizeof(struct image_header
);
204 kernel_size
= get_be32(&hdr
->ih_size
);
205 kernel_la
= get_be32(&hdr
->ih_load
);
207 lzma_data
= flash_base
+ flash_ofs
+ kernel_ofs
;
208 lzma_datasize
= kernel_size
;
210 #endif /* (LZMA_WRAPPER) */
212 void loader_main(unsigned long reg_a0
, unsigned long reg_a1
,
213 unsigned long reg_a2
, unsigned long reg_a3
)
215 void (*kernel_entry
) (unsigned long, unsigned long, unsigned long,
221 printf("\n\nOpenWrt kernel loader for MIPS based SoC\n");
222 printf("Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>\n");
226 res
= lzma_init_props();
227 if (res
!= LZMA_RESULT_OK
) {
228 printf("Incorrect LZMA stream properties!\n");
232 printf("Decompressing kernel... ");
234 res
= lzma_decompress((unsigned char *) kernel_la
);
235 if (res
!= LZMA_RESULT_OK
) {
238 case LZMA_RESULT_DATA_ERROR
:
239 printf("data error!\n");
242 printf("unknown error %d!\n", res
);
249 flush_cache(kernel_la
, lzma_outsize
);
251 printf("Starting kernel at %08x...\n\n", kernel_la
);
253 #ifdef CONFIG_KERNEL_CMDLINE
254 reg_a0
= kernel_argc
;
255 reg_a1
= (unsigned long) kernel_argv
;
260 kernel_entry
= (void *) kernel_la
;
261 kernel_entry(reg_a0
, reg_a1
, reg_a2
, reg_a3
);