1// SPDX-License-Identifier: GPL 2.0+ OR BSD-3-Clause 2/* 3 * Copyright 2015 Google Inc. 4 */ 5 6#include <compiler.h> 7#include <image.h> 8#include <linux/kernel.h> 9#include <linux/types.h> 10#include <asm/unaligned.h> 11#include <u-boot/lz4.h> 12 13/* lz4.c is unaltered (except removing unrelated code) from github.com/Cyan4973/lz4. */ 14#include "lz4.c" /* #include for inlining, do not link! */ 15 16#define LZ4F_BLOCKUNCOMPRESSED_FLAG 0x80000000U 17 18int ulz4fn(const void *src, size_t srcn, void *dst, size_t *dstn) 19{ 20 const void *end = dst + *dstn; 21 const void *in = src; 22 void *out = dst; 23 int has_block_checksum; 24 int ret; 25 *dstn = 0; 26 27 { /* With in-place decompression the header may become invalid later. */ 28 u32 magic; 29 u8 flags, version, independent_blocks, has_content_size; 30 u8 block_desc; 31 32 if (srcn < sizeof(u32) + 3*sizeof(u8)) 33 return -EINVAL; /* input overrun */ 34 35 magic = get_unaligned_le32(in); 36 in += sizeof(u32); 37 flags = *(u8 *)in; 38 in += sizeof(u8); 39 block_desc = *(u8 *)in; 40 in += sizeof(u8); 41 42 version = (flags >> 6) & 0x3; 43 independent_blocks = (flags >> 5) & 0x1; 44 has_block_checksum = (flags >> 4) & 0x1; 45 has_content_size = (flags >> 3) & 0x1; 46 47 /* We assume there's always only a single, standard frame. */ 48 if (magic != LZ4F_MAGIC || version != 1) 49 return -EPROTONOSUPPORT; /* unknown format */ 50 if ((flags & 0x03) || (block_desc & 0x8f)) 51 return -EINVAL; /* reserved bits must be zero */ 52 if (!independent_blocks) 53 return -EPROTONOSUPPORT; /* we can't support this yet */ 54 55 if (has_content_size) { 56 if (srcn < sizeof(u32) + 3*sizeof(u8) + sizeof(u64)) 57 return -EINVAL; /* input overrun */ 58 in += sizeof(u64); 59 } 60 /* Header checksum byte */ 61 in += sizeof(u8); 62 } 63 64 while (1) { 65 u32 block_header, block_size; 66 67 block_header = get_unaligned_le32(in); 68 in += sizeof(u32); 69 block_size = block_header & ~LZ4F_BLOCKUNCOMPRESSED_FLAG; 70 71 if (in - src + block_size > srcn) { 72 ret = -EINVAL; /* input overrun */ 73 break; 74 } 75 76 if (!block_size) { 77 ret = 0; /* decompression successful */ 78 break; 79 } 80 81 if (block_header & LZ4F_BLOCKUNCOMPRESSED_FLAG) { 82 size_t size = min((ptrdiff_t)block_size, (ptrdiff_t)(end - out)); 83 memcpy(out, in, size); 84 out += size; 85 if (size < block_size) { 86 ret = -ENOBUFS; /* output overrun */ 87 break; 88 } 89 } else { 90 /* constant folding essential, do not touch params! */ 91 ret = LZ4_decompress_generic(in, out, block_size, 92 end - out, endOnInputSize, 93 decode_full_block, noDict, out, NULL, 0); 94 if (ret < 0) { 95 ret = -EPROTO; /* decompression error */ 96 break; 97 } 98 out += ret; 99 } 100 101 in += block_size; 102 if (has_block_checksum) 103 in += sizeof(u32); 104 } 105 106 *dstn = out - dst; 107 return ret; 108} 109