// SPDX-License-Identifier: GPL 2.0+ OR BSD-3-Clause /* * Wrapper for decompressing LZ4-compressed kernel, initramfs, and initrd * * Copyright (C) 2013, LG Electronics, Kyungsik Lee */ #include #include #include #include #include #include static u16 LZ4_readLE16(const void *src) { return le16_to_cpu(*(u16 *)src); } static void LZ4_copy4(void *dst, const void *src) { *(u32 *)dst = *(u32 *)src; } static void LZ4_copy8(void *dst, const void *src) { *(u64 *)dst = *(u64 *)src; } typedef uint8_t BYTE; typedef uint16_t U16; typedef uint32_t U32; typedef int32_t S32; typedef uint64_t U64; #define FORCE_INLINE static inline __attribute__((always_inline)) /* Unaltered (except removing unrelated code) from github.com/Cyan4973/lz4. */ #include "lz4.c" /* #include for inlining, do not link! */ /* * Note: Uncompressed chunk size is used in the compressor side * (userspace side for compression). * It is hardcoded because there is not proper way to extract it * from the binary stream which is generated by the preliminary * version of LZ4 tool so far. */ #define LZ4_DEFAULT_UNCOMPRESSED_CHUNK_SIZE (8 << 20) #define ARCHIVE_MAGICNUMBER 0x184C2102 int unlz4(const void *src, size_t srcn, void *dst, size_t *dstn) { int ret = -1; size_t chunksize = 0; size_t uncomp_chunksize = LZ4_DEFAULT_UNCOMPRESSED_CHUNK_SIZE; long size = srcn; size_t dest_len; const void *inp = src; void *outp = dst; *dstn = 0; chunksize = le32_to_cpu(*(u32 *)inp); printf("magic: 0x%lX, LZ4F_MAGIC: 0x%X\n", chunksize, ARCHIVE_MAGICNUMBER); if (chunksize == ARCHIVE_MAGICNUMBER) { inp += 4; size -= 4; } else { printf("invalid header\n"); goto exit; } for (;;) { if (size < 4) { /* empty or end-of-file */ printf("empty or end-of-file\n"); goto exit1; } chunksize = le32_to_cpu(*(u32 *)inp); if (chunksize == ARCHIVE_MAGICNUMBER) { inp += 4; size -= 4; continue; } if (chunksize == 0) { /* empty or end-of-file */ printf("empty or end-of-file\n"); goto exit1; } inp += 4; size -= 4; dest_len = uncomp_chunksize; ret = LZ4_decompress_generic(inp, outp, chunksize, dest_len, endOnInputSize, full, 0, noDict, outp, NULL, 0); dest_len = ret; if (ret < 0) { printf("Decoding failed\n"); goto exit; } ret = -1; outp += dest_len; *dstn += dest_len; size -= chunksize; if (size == 0) { break; } else if (size < 0) { printf("data corrupted\n"); goto exit; } inp += chunksize; } exit1: ret = 0; exit: return ret; }