[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