add lzop decompression support
authorPeter Korsgaard <jacmet@sunsite.dk>
Thu, 19 Nov 2009 10:37:51 +0000 (11:37 +0100)
committerWolfgang Denk <wd@denx.de>
Sat, 5 Dec 2009 00:30:23 +0000 (01:30 +0100)
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>
common/cmd_bootm.c
common/image.c
include/image.h
include/linux/lzo.h
lib_generic/lzo/lzo1x_decompress.c

index 8f8359856162e47b450c0d41cd779c97981c3778..aa85fafab738b6fdf9bd91bf40bcfe21395bd594 100644 (file)
 #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;
index 6eaf41eb131feb2624421b590c99441bc3a542bf..5cc3ab49d888961b93c4f6b32adf6efefcc7be55 100644 (file)
@@ -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,             "",             "",                     },
 };
 
index 5a424e6a9422c74933494710e1ead02a745a19f1..cc38eae39a4c280adf17eca9c9907515e3390900 100644 (file)
 #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            */
index d793497ec1ca92ddfc0b12ba9854650b64f7beb1..88687faba10bb9ed9d4862142f5161ec0837a8d2 100644 (file)
@@ -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)
  */
index 2780e118a402635b81ae1b2f22b41c1d3a7051ed..09bdc8f6ca00324f8b7ec331da7ca58709e42bb9 100644 (file)
 #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)
 {