add lzop decompression support
Add lzop decompression support to the existing lzo bitstream handling (think gzip versus zlib), and support it for uImage decompression if CONFIG_LZO is enabled. Lzop doesn't compress as good as gzip (~10% worse), but decompression is very fast (~0.7s faster here on a slow ppc). The lzop decompression code is based on Albin Tonnerre's recent ARM Linux lzo support patch. Cc: albin.tonnerre@free-electrons.com Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
This commit is contained in:
		
							parent
							
								
									3eb90bad65
								
							
						
					
					
						commit
						20dde48bca
					
				|  | @ -57,6 +57,10 @@ | ||||||
| #include <lzma/LzmaTools.h> | #include <lzma/LzmaTools.h> | ||||||
| #endif /* CONFIG_LZMA */ | #endif /* CONFIG_LZMA */ | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_LZO | ||||||
|  | #include <linux/lzo.h> | ||||||
|  | #endif /* CONFIG_LZO */ | ||||||
|  | 
 | ||||||
| DECLARE_GLOBAL_DATA_PTR; | DECLARE_GLOBAL_DATA_PTR; | ||||||
| 
 | 
 | ||||||
| extern int gunzip (void *dst, int dstlen, unsigned char *src, unsigned long *lenp); | extern int gunzip (void *dst, int dstlen, unsigned char *src, unsigned long *lenp); | ||||||
|  | @ -405,6 +409,24 @@ static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress) | ||||||
| 		*load_end = load + unc_len; | 		*load_end = load + unc_len; | ||||||
| 		break; | 		break; | ||||||
| #endif /* CONFIG_LZMA */ | #endif /* CONFIG_LZMA */ | ||||||
|  | #ifdef CONFIG_LZO | ||||||
|  | 	case IH_COMP_LZO: | ||||||
|  | 		printf ("   Uncompressing %s ... ", type_name); | ||||||
|  | 
 | ||||||
|  | 		int ret = lzop_decompress((const unsigned char *)image_start, | ||||||
|  | 					  image_len, (unsigned char *)load, | ||||||
|  | 					  &unc_len); | ||||||
|  | 		if (ret != LZO_E_OK) { | ||||||
|  | 			printf ("LZO: uncompress or overwrite error %d " | ||||||
|  | 			      "- must RESET board to recover\n", ret); | ||||||
|  | 			if (boot_progress) | ||||||
|  | 				show_boot_progress (-6); | ||||||
|  | 			return BOOTM_ERR_RESET; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		*load_end = load + unc_len; | ||||||
|  | 		break; | ||||||
|  | #endif /* CONFIG_LZO */ | ||||||
| 	default: | 	default: | ||||||
| 		printf ("Unimplemented compression type %d\n", comp); | 		printf ("Unimplemented compression type %d\n", comp); | ||||||
| 		return BOOTM_ERR_UNIMPLEMENTED; | 		return BOOTM_ERR_UNIMPLEMENTED; | ||||||
|  |  | ||||||
|  | @ -148,6 +148,7 @@ static table_entry_t uimage_comp[] = { | ||||||
| 	{	IH_COMP_BZIP2,	"bzip2",	"bzip2 compressed",	}, | 	{	IH_COMP_BZIP2,	"bzip2",	"bzip2 compressed",	}, | ||||||
| 	{	IH_COMP_GZIP,	"gzip",		"gzip compressed",	}, | 	{	IH_COMP_GZIP,	"gzip",		"gzip compressed",	}, | ||||||
| 	{	IH_COMP_LZMA,	"lzma",		"lzma compressed",	}, | 	{	IH_COMP_LZMA,	"lzma",		"lzma compressed",	}, | ||||||
|  | 	{	IH_COMP_LZO,	"lzo",		"lzo compressed",	}, | ||||||
| 	{	-1,		"",		"",			}, | 	{	-1,		"",		"",			}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -164,6 +164,7 @@ | ||||||
| #define IH_COMP_GZIP		1	/* gzip	 Compression Used	*/ | #define IH_COMP_GZIP		1	/* gzip	 Compression Used	*/ | ||||||
| #define IH_COMP_BZIP2		2	/* bzip2 Compression Used	*/ | #define IH_COMP_BZIP2		2	/* bzip2 Compression Used	*/ | ||||||
| #define IH_COMP_LZMA		3	/* lzma  Compression Used	*/ | #define IH_COMP_LZMA		3	/* lzma  Compression Used	*/ | ||||||
|  | #define IH_COMP_LZO		4	/* lzo   Compression Used	*/ | ||||||
| 
 | 
 | ||||||
| #define IH_MAGIC	0x27051956	/* Image Magic Number		*/ | #define IH_MAGIC	0x27051956	/* Image Magic Number		*/ | ||||||
| #define IH_NMLEN		32	/* Image Name Length		*/ | #define IH_NMLEN		32	/* Image Name Length		*/ | ||||||
|  |  | ||||||
|  | @ -27,6 +27,10 @@ int lzo1x_1_compress(const unsigned char *src, size_t src_len, | ||||||
| int lzo1x_decompress_safe(const unsigned char *src, size_t src_len, | int lzo1x_decompress_safe(const unsigned char *src, size_t src_len, | ||||||
| 			unsigned char *dst, size_t *dst_len); | 			unsigned char *dst, size_t *dst_len); | ||||||
| 
 | 
 | ||||||
|  | /* decompress lzop format */ | ||||||
|  | int lzop_decompress(const unsigned char *src, size_t src_len, | ||||||
|  | 		    unsigned char *dst, size_t *dst_len); | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Return values (< 0 = Error) |  * Return values (< 0 = Error) | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
|  | @ -24,6 +24,93 @@ | ||||||
| #define COPY4(dst, src)	\ | #define COPY4(dst, src)	\ | ||||||
| 		put_unaligned(get_unaligned((const u32 *)(src)), (u32 *)(dst)) | 		put_unaligned(get_unaligned((const u32 *)(src)), (u32 *)(dst)) | ||||||
| 
 | 
 | ||||||
|  | static const unsigned char lzop_magic[] = { | ||||||
|  | 	0x89, 0x4c, 0x5a, 0x4f, 0x00, 0x0d, 0x0a, 0x1a, 0x0a | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #define HEADER_HAS_FILTER	0x00000800L | ||||||
|  | 
 | ||||||
|  | static inline const unsigned char *parse_header(const unsigned char *src) | ||||||
|  | { | ||||||
|  | 	u8 level = 0; | ||||||
|  | 	u16 version; | ||||||
|  | 	int i; | ||||||
|  | 
 | ||||||
|  | 	/* read magic: 9 first bytes */ | ||||||
|  | 	for (i = 0; i < ARRAY_SIZE(lzop_magic); i++) { | ||||||
|  | 		if (*src++ != lzop_magic[i]) | ||||||
|  | 			return NULL; | ||||||
|  | 	} | ||||||
|  | 	/* get version (2bytes), skip library version (2),
 | ||||||
|  | 	 * 'need to be extracted' version (2) and | ||||||
|  | 	 * method (1) */ | ||||||
|  | 	version = get_unaligned_be16(src); | ||||||
|  | 	src += 7; | ||||||
|  | 	if (version >= 0x0940) | ||||||
|  | 		level = *src++; | ||||||
|  | 	if (get_unaligned_be32(src) & HEADER_HAS_FILTER) | ||||||
|  | 		src += 4; /* filter info */ | ||||||
|  | 
 | ||||||
|  | 	/* skip flags, mode and mtime_low */ | ||||||
|  | 	src += 12; | ||||||
|  | 	if (version >= 0x0940) | ||||||
|  | 		src += 4;	/* skip mtime_high */ | ||||||
|  | 
 | ||||||
|  | 	i = *src++; | ||||||
|  | 	/* don't care about the file name, and skip checksum */ | ||||||
|  | 	src += i + 4; | ||||||
|  | 
 | ||||||
|  | 	return src; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int lzop_decompress(const unsigned char *src, size_t src_len, | ||||||
|  | 		    unsigned char *dst, size_t *dst_len) | ||||||
|  | { | ||||||
|  | 	unsigned char *start = dst; | ||||||
|  | 	const unsigned char *send = src + src_len; | ||||||
|  | 	u32 slen, dlen; | ||||||
|  | 	size_t tmp; | ||||||
|  | 	int r; | ||||||
|  | 
 | ||||||
|  | 	src = parse_header(src); | ||||||
|  | 	if (!src) | ||||||
|  | 		return LZO_E_ERROR; | ||||||
|  | 
 | ||||||
|  | 	while (src < send) { | ||||||
|  | 		/* read uncompressed block size */ | ||||||
|  | 		dlen = get_unaligned_be32(src); | ||||||
|  | 		src += 4; | ||||||
|  | 
 | ||||||
|  | 		/* exit if last block */ | ||||||
|  | 		if (dlen == 0) { | ||||||
|  | 			*dst_len = dst - start; | ||||||
|  | 			return LZO_E_OK; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		/* read compressed block size, and skip block checksum info */ | ||||||
|  | 		slen = get_unaligned_be32(src); | ||||||
|  | 		src += 8; | ||||||
|  | 
 | ||||||
|  | 		if (slen <= 0 || slen > dlen) | ||||||
|  | 			return LZO_E_ERROR; | ||||||
|  | 
 | ||||||
|  | 		/* decompress */ | ||||||
|  | 		tmp = dlen; | ||||||
|  | 		r = lzo1x_decompress_safe((u8 *) src, slen, dst, &tmp); | ||||||
|  | 
 | ||||||
|  | 		if (r != LZO_E_OK) | ||||||
|  | 			return r; | ||||||
|  | 
 | ||||||
|  | 		if (dlen != tmp) | ||||||
|  | 			return LZO_E_ERROR; | ||||||
|  | 
 | ||||||
|  | 		src += slen; | ||||||
|  | 		dst += dlen; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return LZO_E_INPUT_OVERRUN; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, | int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, | ||||||
| 			unsigned char *out, size_t *out_len) | 			unsigned char *out, size_t *out_len) | ||||||
| { | { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue