root/lib/decompress_unlz4.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. unlz4
  2. __decompress

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Wrapper for decompressing LZ4-compressed kernel, initramfs, and initrd
   4  *
   5  * Copyright (C) 2013, LG Electronics, Kyungsik Lee <kyungsik.lee@lge.com>
   6  */
   7 
   8 #ifdef STATIC
   9 #define PREBOOT
  10 #include "lz4/lz4_decompress.c"
  11 #else
  12 #include <linux/decompress/unlz4.h>
  13 #endif
  14 #include <linux/types.h>
  15 #include <linux/lz4.h>
  16 #include <linux/decompress/mm.h>
  17 #include <linux/compiler.h>
  18 
  19 #include <asm/unaligned.h>
  20 
  21 /*
  22  * Note: Uncompressed chunk size is used in the compressor side
  23  * (userspace side for compression).
  24  * It is hardcoded because there is not proper way to extract it
  25  * from the binary stream which is generated by the preliminary
  26  * version of LZ4 tool so far.
  27  */
  28 #define LZ4_DEFAULT_UNCOMPRESSED_CHUNK_SIZE (8 << 20)
  29 #define ARCHIVE_MAGICNUMBER 0x184C2102
  30 
  31 STATIC inline int INIT unlz4(u8 *input, long in_len,
  32                                 long (*fill)(void *, unsigned long),
  33                                 long (*flush)(void *, unsigned long),
  34                                 u8 *output, long *posp,
  35                                 void (*error) (char *x))
  36 {
  37         int ret = -1;
  38         size_t chunksize = 0;
  39         size_t uncomp_chunksize = LZ4_DEFAULT_UNCOMPRESSED_CHUNK_SIZE;
  40         u8 *inp;
  41         u8 *inp_start;
  42         u8 *outp;
  43         long size = in_len;
  44 #ifdef PREBOOT
  45         size_t out_len = get_unaligned_le32(input + in_len);
  46 #endif
  47         size_t dest_len;
  48 
  49 
  50         if (output) {
  51                 outp = output;
  52         } else if (!flush) {
  53                 error("NULL output pointer and no flush function provided");
  54                 goto exit_0;
  55         } else {
  56                 outp = large_malloc(uncomp_chunksize);
  57                 if (!outp) {
  58                         error("Could not allocate output buffer");
  59                         goto exit_0;
  60                 }
  61         }
  62 
  63         if (input && fill) {
  64                 error("Both input pointer and fill function provided,");
  65                 goto exit_1;
  66         } else if (input) {
  67                 inp = input;
  68         } else if (!fill) {
  69                 error("NULL input pointer and missing fill function");
  70                 goto exit_1;
  71         } else {
  72                 inp = large_malloc(LZ4_compressBound(uncomp_chunksize));
  73                 if (!inp) {
  74                         error("Could not allocate input buffer");
  75                         goto exit_1;
  76                 }
  77         }
  78         inp_start = inp;
  79 
  80         if (posp)
  81                 *posp = 0;
  82 
  83         if (fill) {
  84                 size = fill(inp, 4);
  85                 if (size < 4) {
  86                         error("data corrupted");
  87                         goto exit_2;
  88                 }
  89         }
  90 
  91         chunksize = get_unaligned_le32(inp);
  92         if (chunksize == ARCHIVE_MAGICNUMBER) {
  93                 if (!fill) {
  94                         inp += 4;
  95                         size -= 4;
  96                 }
  97         } else {
  98                 error("invalid header");
  99                 goto exit_2;
 100         }
 101 
 102         if (posp)
 103                 *posp += 4;
 104 
 105         for (;;) {
 106 
 107                 if (fill) {
 108                         size = fill(inp, 4);
 109                         if (size == 0)
 110                                 break;
 111                         if (size < 4) {
 112                                 error("data corrupted");
 113                                 goto exit_2;
 114                         }
 115                 }
 116 
 117                 chunksize = get_unaligned_le32(inp);
 118                 if (chunksize == ARCHIVE_MAGICNUMBER) {
 119                         if (!fill) {
 120                                 inp += 4;
 121                                 size -= 4;
 122                         }
 123                         if (posp)
 124                                 *posp += 4;
 125                         continue;
 126                 }
 127 
 128 
 129                 if (posp)
 130                         *posp += 4;
 131 
 132                 if (!fill) {
 133                         inp += 4;
 134                         size -= 4;
 135                 } else {
 136                         if (chunksize > LZ4_compressBound(uncomp_chunksize)) {
 137                                 error("chunk length is longer than allocated");
 138                                 goto exit_2;
 139                         }
 140                         size = fill(inp, chunksize);
 141                         if (size < chunksize) {
 142                                 error("data corrupted");
 143                                 goto exit_2;
 144                         }
 145                 }
 146 #ifdef PREBOOT
 147                 if (out_len >= uncomp_chunksize) {
 148                         dest_len = uncomp_chunksize;
 149                         out_len -= dest_len;
 150                 } else
 151                         dest_len = out_len;
 152 
 153                 ret = LZ4_decompress_fast(inp, outp, dest_len);
 154                 chunksize = ret;
 155 #else
 156                 dest_len = uncomp_chunksize;
 157 
 158                 ret = LZ4_decompress_safe(inp, outp, chunksize, dest_len);
 159                 dest_len = ret;
 160 #endif
 161                 if (ret < 0) {
 162                         error("Decoding failed");
 163                         goto exit_2;
 164                 }
 165 
 166                 ret = -1;
 167                 if (flush && flush(outp, dest_len) != dest_len)
 168                         goto exit_2;
 169                 if (output)
 170                         outp += dest_len;
 171                 if (posp)
 172                         *posp += chunksize;
 173 
 174                 if (!fill) {
 175                         size -= chunksize;
 176 
 177                         if (size == 0)
 178                                 break;
 179                         else if (size < 0) {
 180                                 error("data corrupted");
 181                                 goto exit_2;
 182                         }
 183                         inp += chunksize;
 184                 }
 185         }
 186 
 187         ret = 0;
 188 exit_2:
 189         if (!input)
 190                 large_free(inp_start);
 191 exit_1:
 192         if (!output)
 193                 large_free(outp);
 194 exit_0:
 195         return ret;
 196 }
 197 
 198 #ifdef PREBOOT
 199 STATIC int INIT __decompress(unsigned char *buf, long in_len,
 200                               long (*fill)(void*, unsigned long),
 201                               long (*flush)(void*, unsigned long),
 202                               unsigned char *output, long out_len,
 203                               long *posp,
 204                               void (*error)(char *x)
 205         )
 206 {
 207         return unlz4(buf, in_len - 4, fill, flush, output, posp, error);
 208 }
 209 #endif

/* [<][>][^][v][top][bottom][index][help] */