| // 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 <kyungsik.lee@lge.com> |
| */ |
| |
| #include <amlogic/unlz4_android.h> |
| #include <common.h> |
| #include <compiler.h> |
| #include <linux/kernel.h> |
| #include <linux/types.h> |
| #include <amlogic/lz4.h> |
| |
| 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; |
| size -= chunksize; |
| |
| if (size == 0) { |
| break; |
| } else if (size < 0) { |
| printf("data corrupted\n"); |
| goto exit; |
| } |
| inp += chunksize; |
| } |
| |
| exit1: |
| ret = 0; |
| |
| exit: |
| return ret; |
| } |