brintos

brintos / linux-shallow public Read only

0
0
Text · 4.2 KiB · c0dbb3c Raw
218 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Wrapper for decompressing LZ4-compressed kernel, initramfs, and initrd4 *5 * Copyright (C) 2013, LG Electronics, Kyungsik Lee <kyungsik.lee@lge.com>6 */7 8#ifdef STATIC9#define PREBOOT10#include "lz4/lz4_decompress.c"11#else12#include <linux/decompress/unlz4.h>13#endif14#include <linux/types.h>15#include <linux/lz4.h>16#include <linux/decompress/mm.h>17#include <linux/compiler.h>18 19#include <linux/unaligned.h>20 21/*22 * Note: Uncompressed chunk size is used in the compressor side23 * (userspace side for compression).24 * It is hardcoded because there is not proper way to extract it25 * from the binary stream which is generated by the preliminary26 * version of LZ4 tool so far.27 */28#define LZ4_DEFAULT_UNCOMPRESSED_CHUNK_SIZE (8 << 20)29#define ARCHIVE_MAGICNUMBER 0x184C210230 31STATIC 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 PREBOOT45	size_t out_len = get_unaligned_le32(input + in_len);46#endif47	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		} else if (size < 4) {116			/* empty or end-of-file */117			goto exit_3;118		}119 120		chunksize = get_unaligned_le32(inp);121		if (chunksize == ARCHIVE_MAGICNUMBER) {122			if (!fill) {123				inp += 4;124				size -= 4;125			}126			if (posp)127				*posp += 4;128			continue;129		}130 131		if (!fill && chunksize == 0) {132			/* empty or end-of-file */133			goto exit_3;134		}135 136		if (posp)137			*posp += 4;138 139		if (!fill) {140			inp += 4;141			size -= 4;142		} else {143			if (chunksize > LZ4_compressBound(uncomp_chunksize)) {144				error("chunk length is longer than allocated");145				goto exit_2;146			}147			size = fill(inp, chunksize);148			if (size < chunksize) {149				error("data corrupted");150				goto exit_2;151			}152		}153#ifdef PREBOOT154		if (out_len >= uncomp_chunksize) {155			dest_len = uncomp_chunksize;156			out_len -= dest_len;157		} else158			dest_len = out_len;159 160		ret = LZ4_decompress_fast(inp, outp, dest_len);161		chunksize = ret;162#else163		dest_len = uncomp_chunksize;164 165		ret = LZ4_decompress_safe(inp, outp, chunksize, dest_len);166		dest_len = ret;167#endif168		if (ret < 0) {169			error("Decoding failed");170			goto exit_2;171		}172 173		ret = -1;174		if (flush && flush(outp, dest_len) != dest_len)175			goto exit_2;176		if (output)177			outp += dest_len;178		if (posp)179			*posp += chunksize;180 181		if (!fill) {182			size -= chunksize;183 184			if (size == 0)185				break;186			else if (size < 0) {187				error("data corrupted");188				goto exit_2;189			}190			inp += chunksize;191		}192	}193 194exit_3:195	ret = 0;196exit_2:197	if (!input)198		large_free(inp_start);199exit_1:200	if (!output)201		large_free(outp);202exit_0:203	return ret;204}205 206#ifdef PREBOOT207STATIC int INIT __decompress(unsigned char *buf, long in_len,208			      long (*fill)(void*, unsigned long),209			      long (*flush)(void*, unsigned long),210			      unsigned char *output, long out_len,211			      long *posp,212			      void (*error)(char *x)213	)214{215	return unlz4(buf, in_len - 4, fill, flush, output, posp, error);216}217#endif218