diff options
| author | juhosg <juhosg@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2011-12-05 14:52:25 +0000 | 
|---|---|---|
| committer | juhosg <juhosg@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2011-12-05 14:52:25 +0000 | 
| commit | 057c5990c9a0ef67c3f4dcfcf026cf41ccaec881 (patch) | |
| tree | 17a433e6227a99a23927df83e369c2fd81b8aab9 /target/linux/ar71xx/image/lzma-loader/src/loader.c | |
| parent | f5ac3a13ec9b452ed357ef95299f26549945d1c7 (diff) | |
ar71xx: add lzma loader
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@29443 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/ar71xx/image/lzma-loader/src/loader.c')
| -rw-r--r-- | target/linux/ar71xx/image/lzma-loader/src/loader.c | 263 | 
1 files changed, 263 insertions, 0 deletions
diff --git a/target/linux/ar71xx/image/lzma-loader/src/loader.c b/target/linux/ar71xx/image/lzma-loader/src/loader.c new file mode 100644 index 000000000..5c674ae5f --- /dev/null +++ b/target/linux/ar71xx/image/lzma-loader/src/loader.c @@ -0,0 +1,263 @@ +/* + * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards + * + * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> + * + * Some parts of this code was based on the OpenWrt specific lzma-loader + * for the BCM47xx and ADM5120 based boards: + *	Copyright (C) 2004 Manuel Novoa III (mjn3@codepoet.org) + *	Copyright (C) 2005 Mineharu Takahara <mtakahar@yahoo.com> + *	Copyright (C) 2005 by Oleg I. Vdovikin <oleg@cs.msu.su> + * + * The image_header structure has been taken from the U-Boot project. + *	(C) Copyright 2008 Semihalf + *	(C) Copyright 2000-2005 + *	Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include <stddef.h> +#include <stdint.h> + +#include "config.h" +#include "cache.h" +#include "printf.h" +#include "LzmaDecode.h" + +#define AR71XX_FLASH_START	0x1f000000 +#define AR71XX_FLASH_END	0x1fe00000 + +#define KSEG0			0x80000000 +#define KSEG1			0xa0000000 + +#define KSEG1ADDR(a)		((((unsigned)(a)) & 0x1fffffffU) | KSEG1) + +#undef LZMA_DEBUG + +#ifdef LZMA_DEBUG +#  define DBG(f, a...)	printf(f, ## a) +#else +#  define DBG(f, a...)	do {} while (0) +#endif + +#define IH_MAGIC_OKLI		0x4f4b4c49	/* 'OKLI' */ + +#define IH_NMLEN		32	/* Image Name Length		*/ + +typedef struct image_header { +	uint32_t	ih_magic;	/* Image Header Magic Number	*/ +	uint32_t	ih_hcrc;	/* Image Header CRC Checksum	*/ +	uint32_t	ih_time;	/* Image Creation Timestamp	*/ +	uint32_t	ih_size;	/* Image Data Size		*/ +	uint32_t	ih_load;	/* Data	 Load  Address		*/ +	uint32_t	ih_ep;		/* Entry Point Address		*/ +	uint32_t	ih_dcrc;	/* Image Data CRC Checksum	*/ +	uint8_t		ih_os;		/* Operating System		*/ +	uint8_t		ih_arch;	/* CPU architecture		*/ +	uint8_t		ih_type;	/* Image Type			*/ +	uint8_t		ih_comp;	/* Compression Type		*/ +	uint8_t		ih_name[IH_NMLEN];	/* Image Name		*/ +} image_header_t; + +/* beyond the image end, size not known in advance */ +extern unsigned char workspace[]; +extern void board_init(void); + +static CLzmaDecoderState lzma_state; +static unsigned char *lzma_data; +static unsigned long lzma_datasize; +static unsigned long lzma_outsize; +static unsigned long kernel_la; + +#ifdef CONFIG_KERNEL_CMDLINE +#define kernel_argc	1 +static const char kernel_cmdline[] = CONFIG_KERNEL_CMDLINE; +static const char *kernel_argv[] = { +	kernel_cmdline, +	NULL, +}; +#endif /* CONFIG_KERNEL_CMDLINE */ + +static void halt(void) +{ +	printf("\nSystem halted!\n"); +	for(;;); +} + +static __inline__ unsigned long get_be32(void *buf) +{ +	unsigned char *p = buf; + +	return (((unsigned long) p[0] << 24) + +	        ((unsigned long) p[1] << 16) + +	        ((unsigned long) p[2] << 8) + +	        (unsigned long) p[3]); +} + +static __inline__ unsigned char lzma_get_byte(void) +{ +	unsigned char c; + +	lzma_datasize--; +	c = *lzma_data++; + +	return c; +} + +static int lzma_init_props(void) +{ +	unsigned char props[LZMA_PROPERTIES_SIZE]; +	int res; +	int i; + +	/* read lzma properties */ +	for (i = 0; i < LZMA_PROPERTIES_SIZE; i++) +		props[i] = lzma_get_byte(); + +	/* read the lower half of uncompressed size in the header */ +	lzma_outsize = ((SizeT) lzma_get_byte()) + +		       ((SizeT) lzma_get_byte() << 8) + +		       ((SizeT) lzma_get_byte() << 16) + +		       ((SizeT) lzma_get_byte() << 24); + +	/* skip rest of the header (upper half of uncompressed size) */ +	for (i = 0; i < 4; i++) +		lzma_get_byte(); + +	res = LzmaDecodeProperties(&lzma_state.Properties, props, +					LZMA_PROPERTIES_SIZE); +	return res; +} + +static int lzma_decompress(unsigned char *outStream) +{ +	SizeT ip, op; +	int ret; + +	lzma_state.Probs = (CProb *) workspace; + +	ret = LzmaDecode(&lzma_state, lzma_data, lzma_datasize, &ip, outStream, +			 lzma_outsize, &op); + +	if (ret != LZMA_RESULT_OK) { +		int i; + +		DBG("LzmaDecode error %d at %08x, osize:%d ip:%d op:%d\n", +		    ret, lzma_data + ip, lzma_outsize, ip, op); + +		for (i = 0; i < 16; i++) +			DBG("%02x ", lzma_data[ip + i]); + +		DBG("\n"); +	} + +	return ret; +} + +#if (LZMA_WRAPPER) +static void lzma_init_data(void) +{ +	extern unsigned char _lzma_data_start[]; +	extern unsigned char _lzma_data_end[]; + +	kernel_la = LOADADDR; +	lzma_data = _lzma_data_start; +	lzma_datasize = _lzma_data_end - _lzma_data_start; +} +#else +static void lzma_init_data(void) +{ +	struct image_header *hdr = NULL; +	unsigned char *flash_base; +	unsigned long flash_ofs; +	unsigned long kernel_ofs; +	unsigned long kernel_size; + +	flash_base = (unsigned char *) KSEG1ADDR(AR71XX_FLASH_START); + +	printf("Looking for OpenWrt image... "); + +	for (flash_ofs = CONFIG_FLASH_OFFS; +	     flash_ofs <= (CONFIG_FLASH_OFFS + CONFIG_FLASH_MAX); +	     flash_ofs += CONFIG_FLASH_STEP) { +		unsigned long magic; +		unsigned char *p; + +		p = flash_base + flash_ofs; +		magic = get_be32(p); +		if (magic == IH_MAGIC_OKLI) { +			hdr = (struct image_header *) p; +			break; +		} +	} + +	if (hdr == NULL) { +		printf("not found!\n"); +		halt(); +	} + +	printf("found at 0x%08x\n", flash_base + flash_ofs); + +	kernel_ofs = sizeof(struct image_header); +	kernel_size = get_be32(&hdr->ih_size); +	kernel_la = get_be32(&hdr->ih_load); + +	lzma_data = flash_base + flash_ofs + kernel_ofs; +	lzma_datasize = kernel_size; +} +#endif /* (LZMA_WRAPPER) */ + +void loader_main(unsigned long reg_a0, unsigned long reg_a1, +		 unsigned long reg_a2, unsigned long reg_a3) +{ +	void (*kernel_entry) (unsigned long, unsigned long, unsigned long, +			      unsigned long); +	int res; + +	board_init(); + +	printf("\n\nOpenWrt kernel loader for AR7XXX/AR9XXX\n"); +	printf("Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>\n"); + +	lzma_init_data(); + +	res = lzma_init_props(); +	if (res != LZMA_RESULT_OK) { +		printf("Incorrect LZMA stream properties!\n"); +		halt(); +	} + +	printf("Decompressing kernel... "); + +	res = lzma_decompress((unsigned char *) kernel_la); +	if (res != LZMA_RESULT_OK) { +		printf("failed, "); +		switch (res) { +		case LZMA_RESULT_DATA_ERROR: +			printf("data error!\n"); +			break; +		default: +			printf("unknown error %d!\n", res); +		} +		halt(); +	} else { +		printf("done!\n"); +	} + +	flush_cache(kernel_la, lzma_outsize); + +	printf("Starting kernel at %08x...\n\n", kernel_la); + +#ifdef CONFIG_KERNEL_CMDLINE +	reg_a0 = kernel_argc; +	reg_a1 = (unsigned long) kernel_argv; +	reg_a2 = 0; +	reg_a3 = 0; +#endif + +	kernel_entry = (void *) kernel_la; +	kernel_entry(reg_a0, reg_a1, reg_a2, reg_a3); +}  | 
