[U-Boot] [PATCH] add lzop decompression support

Peter Korsgaard jacmet at sunsite.dk
Thu Nov 19 11:37:51 CET 2009


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 at free-electrons.com
Signed-off-by: Peter Korsgaard <jacmet at sunsite.dk>
---
 common/cmd_bootm.c                 |   22 +++++++++
 common/image.c                     |    1 +
 include/image.h                    |    1 +
 include/linux/lzo.h                |    4 ++
 lib_generic/lzo/lzo1x_decompress.c |   87 ++++++++++++++++++++++++++++++++++++
 5 files changed, 115 insertions(+), 0 deletions(-)

diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
index 8f83598..aa85faf 100644
--- a/common/cmd_bootm.c
+++ b/common/cmd_bootm.c
@@ -57,6 +57,10 @@
 #include <lzma/LzmaTools.h>
 #endif /* CONFIG_LZMA */
 
+#ifdef CONFIG_LZO
+#include <linux/lzo.h>
+#endif /* CONFIG_LZO */
+
 DECLARE_GLOBAL_DATA_PTR;
 
 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;
 		break;
 #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:
 		printf ("Unimplemented compression type %d\n", comp);
 		return BOOTM_ERR_UNIMPLEMENTED;
diff --git a/common/image.c b/common/image.c
index 6eaf41e..5cc3ab4 100644
--- a/common/image.c
+++ b/common/image.c
@@ -148,6 +148,7 @@ static table_entry_t uimage_comp[] = {
 	{	IH_COMP_BZIP2,	"bzip2",	"bzip2 compressed",	},
 	{	IH_COMP_GZIP,	"gzip",		"gzip compressed",	},
 	{	IH_COMP_LZMA,	"lzma",		"lzma compressed",	},
+	{	IH_COMP_LZO,	"lzo",		"lzo compressed",	},
 	{	-1,		"",		"",			},
 };
 
diff --git a/include/image.h b/include/image.h
index 5a424e6..cc38eae 100644
--- a/include/image.h
+++ b/include/image.h
@@ -164,6 +164,7 @@
 #define IH_COMP_GZIP		1	/* gzip	 Compression Used	*/
 #define IH_COMP_BZIP2		2	/* bzip2 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_NMLEN		32	/* Image Name Length		*/
diff --git a/include/linux/lzo.h b/include/linux/lzo.h
index d793497..88687fa 100644
--- a/include/linux/lzo.h
+++ b/include/linux/lzo.h
@@ -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,
 			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)
  */
diff --git a/lib_generic/lzo/lzo1x_decompress.c b/lib_generic/lzo/lzo1x_decompress.c
index 2780e11..09bdc8f 100644
--- a/lib_generic/lzo/lzo1x_decompress.c
+++ b/lib_generic/lzo/lzo1x_decompress.c
@@ -24,6 +24,93 @@
 #define COPY4(dst, src)	\
 		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,
 			unsigned char *out, size_t *out_len)
 {
-- 
1.6.3.3



More information about the U-Boot mailing list