diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Kconfig | 5 | ||||
-rw-r--r-- | lib/Makefile | 3 | ||||
-rw-r--r-- | lib/fdtdec.c | 97 | ||||
-rw-r--r-- | lib/gunzip.c | 15 | ||||
-rw-r--r-- | lib/lzo/lzo1x_decompress.c | 21 |
5 files changed, 119 insertions, 22 deletions
diff --git a/lib/Kconfig b/lib/Kconfig index aef940f6b7d..18663badb25 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -180,6 +180,11 @@ config LZO help This enables support for LZO compression algorithm.r +config SPL_LZO + bool "Enable LZO decompression support in SPL" + help + This enables support for LZO compression algorithm in the SPL. + config SPL_GZIP bool "Enable gzip decompression support for SPL build" select SPL_ZLIB diff --git a/lib/Makefile b/lib/Makefile index 80216c2ed6d..8cd779f8cad 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -11,7 +11,6 @@ obj-$(CONFIG_EFI) += efi/ obj-$(CONFIG_EFI_LOADER) += efi_loader/ obj-$(CONFIG_EFI_LOADER) += efi_selftest/ obj-$(CONFIG_LZMA) += lzma/ -obj-$(CONFIG_LZO) += lzo/ obj-$(CONFIG_BZIP2) += bzip2/ obj-$(CONFIG_TIZEN) += tizen/ obj-$(CONFIG_FIT) += libfdt/ @@ -52,6 +51,8 @@ obj-$(CONFIG_SHA256) += sha256.o obj-$(CONFIG_$(SPL_)ZLIB) += zlib/ obj-$(CONFIG_$(SPL_)GZIP) += gunzip.o +obj-$(CONFIG_$(SPL_)LZO) += lzo/ + obj-$(CONFIG_$(SPL_TPL_)SAVEENV) += qsort.o obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += libfdt/ diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 107a892e79c..45f3fe7baf8 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -4,17 +4,18 @@ */ #ifndef USE_HOSTCC -#include <boot_fit.h> #include <common.h> +#include <boot_fit.h> #include <dm.h> +#include <dm/of_extra.h> #include <errno.h> -#include <serial.h> -#include <libfdt.h> -#include <fdt_support.h> #include <fdtdec.h> +#include <fdt_support.h> +#include <libfdt.h> +#include <serial.h> #include <asm/sections.h> -#include <dm/of_extra.h> #include <linux/ctype.h> +#include <linux/lzo.h> DECLARE_GLOBAL_DATA_PTR; @@ -1203,9 +1204,66 @@ int fdtdec_setup_memory_banksize(void) } #endif +#if CONFIG_IS_ENABLED(MULTI_DTB_FIT) +# if CONFIG_IS_ENABLED(MULTI_DTB_FIT_GZIP) ||\ + CONFIG_IS_ENABLED(MULTI_DTB_FIT_LZO) +static int uncompress_blob(const void *src, ulong sz_src, void **dstp) +{ + size_t sz_out = CONFIG_SPL_MULTI_DTB_FIT_UNCOMPRESS_SZ; + ulong sz_in = sz_src; + void *dst; + int rc; + + if (CONFIG_IS_ENABLED(GZIP)) + if (gzip_parse_header(src, sz_in) < 0) + return -1; + if (CONFIG_IS_ENABLED(LZO)) + if (!lzop_is_valid_header(src)) + return -EBADMSG; + + if (CONFIG_IS_ENABLED(MULTI_DTB_FIT_DYN_ALLOC)) { + dst = malloc(sz_out); + if (!dst) { + puts("uncompress_blob: Unable to allocate memory\n"); + return -ENOMEM; + } + } else { +# if CONFIG_IS_ENABLED(MULTI_DTB_FIT_USER_DEFINED_AREA) + dst = (void *)CONFIG_VAL(MULTI_DTB_FIT_USER_DEF_ADDR); +# else + return -ENOTSUPP; +# endif + } + + if (CONFIG_IS_ENABLED(GZIP)) + rc = gunzip(dst, sz_out, (u8 *)src, &sz_in); + else if (CONFIG_IS_ENABLED(LZO)) + rc = lzop_decompress(src, sz_in, dst, &sz_out); + + if (rc < 0) { + /* not a valid compressed blob */ + puts("uncompress_blob: Unable to uncompress\n"); + if (CONFIG_IS_ENABLED(MULTI_DTB_FIT_DYN_ALLOC)) + free(dst); + return -EBADMSG; + } + *dstp = dst; + return 0; +} +# else +static int uncompress_blob(const void *src, ulong sz_src, void **dstp) +{ + return -ENOTSUPP; +} +# endif +#endif + int fdtdec_setup(void) { #if CONFIG_IS_ENABLED(OF_CONTROL) +# if CONFIG_IS_ENABLED(MULTI_DTB_FIT) + void *fdt_blob; +# endif # ifdef CONFIG_OF_EMBED /* Get a pointer to the FDT */ gd->fdt_blob = __dtb_dt_begin; @@ -1216,15 +1274,6 @@ int fdtdec_setup(void) gd->fdt_blob = (ulong *)&_image_binary_end; else gd->fdt_blob = (ulong *)&__bss_end; - -# elif defined CONFIG_FIT_EMBED - gd->fdt_blob = locate_dtb_in_fit(&_end); - - if (gd->fdt_blob == NULL || gd->fdt_blob <= ((void *)&_end)) { - puts("Failed to find proper dtb in embedded FIT Image\n"); - return -1; - } - # else /* FDT is at end of image */ gd->fdt_blob = (ulong *)&_end; @@ -1243,7 +1292,27 @@ int fdtdec_setup(void) gd->fdt_blob = (void *)env_get_ulong("fdtcontroladdr", 16, (uintptr_t)gd->fdt_blob); # endif + +# if CONFIG_IS_ENABLED(MULTI_DTB_FIT) + /* + * Try and uncompress the blob. + * Unfortunately there is no way to know how big the input blob really + * is. So let us set the maximum input size arbitrarily high. 16MB + * ought to be more than enough for packed DTBs. + */ + if (uncompress_blob(gd->fdt_blob, 0x1000000, &fdt_blob) == 0) + gd->fdt_blob = fdt_blob; + + /* + * Check if blob is a FIT images containings DTBs. + * If so, pick the most relevant + */ + fdt_blob = locate_dtb_in_fit(gd->fdt_blob); + if (fdt_blob) + gd->fdt_blob = fdt_blob; +# endif #endif + return fdtdec_prepare_fdt(); } diff --git a/lib/gunzip.c b/lib/gunzip.c index 832b3064e76..adb86c75503 100644 --- a/lib/gunzip.c +++ b/lib/gunzip.c @@ -42,7 +42,7 @@ void gzfree(void *x, void *addr, unsigned nb) free (addr); } -int gunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp) +int gzip_parse_header(const unsigned char *src, unsigned long len) { int i, flags; @@ -63,12 +63,21 @@ int gunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp) ; if ((flags & HEAD_CRC) != 0) i += 2; - if (i >= *lenp) { + if (i >= len) { puts ("Error: gunzip out of data in header\n"); return (-1); } + return i; +} + +int gunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp) +{ + int offset = gzip_parse_header(src, *lenp); + + if (offset < 0) + return offset; - return zunzip(dst, dstlen, src, lenp, 1, i); + return zunzip(dst, dstlen, src, lenp, 1, offset); } #ifdef CONFIG_CMD_UNZIP diff --git a/lib/lzo/lzo1x_decompress.c b/lib/lzo/lzo1x_decompress.c index ccc90b8ee53..65fef0b0eb9 100644 --- a/lib/lzo/lzo1x_decompress.c +++ b/lib/lzo/lzo1x_decompress.c @@ -30,16 +30,29 @@ static const unsigned char lzop_magic[] = { #define HEADER_HAS_FILTER 0x00000800L -static inline const unsigned char *parse_header(const unsigned char *src) + +bool lzop_is_valid_header(const unsigned char *src) { - 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; + return false; } + return true; +} + +static inline const unsigned char *parse_header(const unsigned char *src) +{ + u16 version; + int i; + + if (!lzop_is_valid_header(src)) + return NULL; + + /* skip header */ + src += 9; + /* get version (2bytes), skip library version (2), * 'need to be extracted' version (2) and * method (1) */ |