0001
0002
0003
0004
0005
0006
0007
0008 #ifdef STATIC
0009 #define PREBOOT
0010 #include "lz4/lz4_decompress.c"
0011 #else
0012 #include <linux/decompress/unlz4.h>
0013 #endif
0014 #include <linux/types.h>
0015 #include <linux/lz4.h>
0016 #include <linux/decompress/mm.h>
0017 #include <linux/compiler.h>
0018
0019 #include <asm/unaligned.h>
0020
0021
0022
0023
0024
0025
0026
0027
0028 #define LZ4_DEFAULT_UNCOMPRESSED_CHUNK_SIZE (8 << 20)
0029 #define ARCHIVE_MAGICNUMBER 0x184C2102
0030
0031 STATIC inline int INIT unlz4(u8 *input, long in_len,
0032 long (*fill)(void *, unsigned long),
0033 long (*flush)(void *, unsigned long),
0034 u8 *output, long *posp,
0035 void (*error) (char *x))
0036 {
0037 int ret = -1;
0038 size_t chunksize = 0;
0039 size_t uncomp_chunksize = LZ4_DEFAULT_UNCOMPRESSED_CHUNK_SIZE;
0040 u8 *inp;
0041 u8 *inp_start;
0042 u8 *outp;
0043 long size = in_len;
0044 #ifdef PREBOOT
0045 size_t out_len = get_unaligned_le32(input + in_len);
0046 #endif
0047 size_t dest_len;
0048
0049
0050 if (output) {
0051 outp = output;
0052 } else if (!flush) {
0053 error("NULL output pointer and no flush function provided");
0054 goto exit_0;
0055 } else {
0056 outp = large_malloc(uncomp_chunksize);
0057 if (!outp) {
0058 error("Could not allocate output buffer");
0059 goto exit_0;
0060 }
0061 }
0062
0063 if (input && fill) {
0064 error("Both input pointer and fill function provided,");
0065 goto exit_1;
0066 } else if (input) {
0067 inp = input;
0068 } else if (!fill) {
0069 error("NULL input pointer and missing fill function");
0070 goto exit_1;
0071 } else {
0072 inp = large_malloc(LZ4_compressBound(uncomp_chunksize));
0073 if (!inp) {
0074 error("Could not allocate input buffer");
0075 goto exit_1;
0076 }
0077 }
0078 inp_start = inp;
0079
0080 if (posp)
0081 *posp = 0;
0082
0083 if (fill) {
0084 size = fill(inp, 4);
0085 if (size < 4) {
0086 error("data corrupted");
0087 goto exit_2;
0088 }
0089 }
0090
0091 chunksize = get_unaligned_le32(inp);
0092 if (chunksize == ARCHIVE_MAGICNUMBER) {
0093 if (!fill) {
0094 inp += 4;
0095 size -= 4;
0096 }
0097 } else {
0098 error("invalid header");
0099 goto exit_2;
0100 }
0101
0102 if (posp)
0103 *posp += 4;
0104
0105 for (;;) {
0106
0107 if (fill) {
0108 size = fill(inp, 4);
0109 if (size == 0)
0110 break;
0111 if (size < 4) {
0112 error("data corrupted");
0113 goto exit_2;
0114 }
0115 } else if (size < 4) {
0116
0117 goto exit_3;
0118 }
0119
0120 chunksize = get_unaligned_le32(inp);
0121 if (chunksize == ARCHIVE_MAGICNUMBER) {
0122 if (!fill) {
0123 inp += 4;
0124 size -= 4;
0125 }
0126 if (posp)
0127 *posp += 4;
0128 continue;
0129 }
0130
0131 if (!fill && chunksize == 0) {
0132
0133 goto exit_3;
0134 }
0135
0136 if (posp)
0137 *posp += 4;
0138
0139 if (!fill) {
0140 inp += 4;
0141 size -= 4;
0142 } else {
0143 if (chunksize > LZ4_compressBound(uncomp_chunksize)) {
0144 error("chunk length is longer than allocated");
0145 goto exit_2;
0146 }
0147 size = fill(inp, chunksize);
0148 if (size < chunksize) {
0149 error("data corrupted");
0150 goto exit_2;
0151 }
0152 }
0153 #ifdef PREBOOT
0154 if (out_len >= uncomp_chunksize) {
0155 dest_len = uncomp_chunksize;
0156 out_len -= dest_len;
0157 } else
0158 dest_len = out_len;
0159
0160 ret = LZ4_decompress_fast(inp, outp, dest_len);
0161 chunksize = ret;
0162 #else
0163 dest_len = uncomp_chunksize;
0164
0165 ret = LZ4_decompress_safe(inp, outp, chunksize, dest_len);
0166 dest_len = ret;
0167 #endif
0168 if (ret < 0) {
0169 error("Decoding failed");
0170 goto exit_2;
0171 }
0172
0173 ret = -1;
0174 if (flush && flush(outp, dest_len) != dest_len)
0175 goto exit_2;
0176 if (output)
0177 outp += dest_len;
0178 if (posp)
0179 *posp += chunksize;
0180
0181 if (!fill) {
0182 size -= chunksize;
0183
0184 if (size == 0)
0185 break;
0186 else if (size < 0) {
0187 error("data corrupted");
0188 goto exit_2;
0189 }
0190 inp += chunksize;
0191 }
0192 }
0193
0194 exit_3:
0195 ret = 0;
0196 exit_2:
0197 if (!input)
0198 large_free(inp_start);
0199 exit_1:
0200 if (!output)
0201 large_free(outp);
0202 exit_0:
0203 return ret;
0204 }
0205
0206 #ifdef PREBOOT
0207 STATIC int INIT __decompress(unsigned char *buf, long in_len,
0208 long (*fill)(void*, unsigned long),
0209 long (*flush)(void*, unsigned long),
0210 unsigned char *output, long out_len,
0211 long *posp,
0212 void (*error)(char *x)
0213 )
0214 {
0215 return unlz4(buf, in_len - 4, fill, flush, output, posp, error);
0216 }
0217 #endif