18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci/*
48c2ecf20Sopenharmony_ci * Important notes about in-place decompression
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * At least on x86, the kernel is decompressed in place: the compressed data
78c2ecf20Sopenharmony_ci * is placed to the end of the output buffer, and the decompressor overwrites
88c2ecf20Sopenharmony_ci * most of the compressed data. There must be enough safety margin to
98c2ecf20Sopenharmony_ci * guarantee that the write position is always behind the read position.
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * The safety margin for ZSTD with a 128 KB block size is calculated below.
128c2ecf20Sopenharmony_ci * Note that the margin with ZSTD is bigger than with GZIP or XZ!
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * The worst case for in-place decompression is that the beginning of
158c2ecf20Sopenharmony_ci * the file is compressed extremely well, and the rest of the file is
168c2ecf20Sopenharmony_ci * uncompressible. Thus, we must look for worst-case expansion when the
178c2ecf20Sopenharmony_ci * compressor is encoding uncompressible data.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * The structure of the .zst file in case of a compresed kernel is as follows.
208c2ecf20Sopenharmony_ci * Maximum sizes (as bytes) of the fields are in parenthesis.
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci *    Frame Header: (18)
238c2ecf20Sopenharmony_ci *    Blocks: (N)
248c2ecf20Sopenharmony_ci *    Checksum: (4)
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci * The frame header and checksum overhead is at most 22 bytes.
278c2ecf20Sopenharmony_ci *
288c2ecf20Sopenharmony_ci * ZSTD stores the data in blocks. Each block has a header whose size is
298c2ecf20Sopenharmony_ci * a 3 bytes. After the block header, there is up to 128 KB of payload.
308c2ecf20Sopenharmony_ci * The maximum uncompressed size of the payload is 128 KB. The minimum
318c2ecf20Sopenharmony_ci * uncompressed size of the payload is never less than the payload size
328c2ecf20Sopenharmony_ci * (excluding the block header).
338c2ecf20Sopenharmony_ci *
348c2ecf20Sopenharmony_ci * The assumption, that the uncompressed size of the payload is never
358c2ecf20Sopenharmony_ci * smaller than the payload itself, is valid only when talking about
368c2ecf20Sopenharmony_ci * the payload as a whole. It is possible that the payload has parts where
378c2ecf20Sopenharmony_ci * the decompressor consumes more input than it produces output. Calculating
388c2ecf20Sopenharmony_ci * the worst case for this would be tricky. Instead of trying to do that,
398c2ecf20Sopenharmony_ci * let's simply make sure that the decompressor never overwrites any bytes
408c2ecf20Sopenharmony_ci * of the payload which it is currently reading.
418c2ecf20Sopenharmony_ci *
428c2ecf20Sopenharmony_ci * Now we have enough information to calculate the safety margin. We need
438c2ecf20Sopenharmony_ci *   - 22 bytes for the .zst file format headers;
448c2ecf20Sopenharmony_ci *   - 3 bytes per every 128 KiB of uncompressed size (one block header per
458c2ecf20Sopenharmony_ci *     block); and
468c2ecf20Sopenharmony_ci *   - 128 KiB (biggest possible zstd block size) to make sure that the
478c2ecf20Sopenharmony_ci *     decompressor never overwrites anything from the block it is currently
488c2ecf20Sopenharmony_ci *     reading.
498c2ecf20Sopenharmony_ci *
508c2ecf20Sopenharmony_ci * We get the following formula:
518c2ecf20Sopenharmony_ci *
528c2ecf20Sopenharmony_ci *    safety_margin = 22 + uncompressed_size * 3 / 131072 + 131072
538c2ecf20Sopenharmony_ci *                 <= 22 + (uncompressed_size >> 15) + 131072
548c2ecf20Sopenharmony_ci */
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci/*
578c2ecf20Sopenharmony_ci * Preboot environments #include "path/to/decompress_unzstd.c".
588c2ecf20Sopenharmony_ci * All of the source files we depend on must be #included.
598c2ecf20Sopenharmony_ci * zstd's only source dependeny is xxhash, which has no source
608c2ecf20Sopenharmony_ci * dependencies.
618c2ecf20Sopenharmony_ci *
628c2ecf20Sopenharmony_ci * When UNZSTD_PREBOOT is defined we declare __decompress(), which is
638c2ecf20Sopenharmony_ci * used for kernel decompression, instead of unzstd().
648c2ecf20Sopenharmony_ci *
658c2ecf20Sopenharmony_ci * Define __DISABLE_EXPORTS in preboot environments to prevent symbols
668c2ecf20Sopenharmony_ci * from xxhash and zstd from being exported by the EXPORT_SYMBOL macro.
678c2ecf20Sopenharmony_ci */
688c2ecf20Sopenharmony_ci#ifdef STATIC
698c2ecf20Sopenharmony_ci# define UNZSTD_PREBOOT
708c2ecf20Sopenharmony_ci# include "xxhash.c"
718c2ecf20Sopenharmony_ci# include "zstd/entropy_common.c"
728c2ecf20Sopenharmony_ci# include "zstd/fse_decompress.c"
738c2ecf20Sopenharmony_ci# include "zstd/huf_decompress.c"
748c2ecf20Sopenharmony_ci# include "zstd/zstd_common.c"
758c2ecf20Sopenharmony_ci# include "zstd/decompress.c"
768c2ecf20Sopenharmony_ci#endif
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci#include <linux/decompress/mm.h>
798c2ecf20Sopenharmony_ci#include <linux/kernel.h>
808c2ecf20Sopenharmony_ci#include <linux/zstd.h>
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci/* 128MB is the maximum window size supported by zstd. */
838c2ecf20Sopenharmony_ci#define ZSTD_WINDOWSIZE_MAX	(1 << ZSTD_WINDOWLOG_MAX)
848c2ecf20Sopenharmony_ci/*
858c2ecf20Sopenharmony_ci * Size of the input and output buffers in multi-call mode.
868c2ecf20Sopenharmony_ci * Pick a larger size because it isn't used during kernel decompression,
878c2ecf20Sopenharmony_ci * since that is single pass, and we have to allocate a large buffer for
888c2ecf20Sopenharmony_ci * zstd's window anyway. The larger size speeds up initramfs decompression.
898c2ecf20Sopenharmony_ci */
908c2ecf20Sopenharmony_ci#define ZSTD_IOBUF_SIZE		(1 << 17)
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic int INIT handle_zstd_error(size_t ret, void (*error)(char *x))
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	const int err = ZSTD_getErrorCode(ret);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	if (!ZSTD_isError(ret))
978c2ecf20Sopenharmony_ci		return 0;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	switch (err) {
1008c2ecf20Sopenharmony_ci	case ZSTD_error_memory_allocation:
1018c2ecf20Sopenharmony_ci		error("ZSTD decompressor ran out of memory");
1028c2ecf20Sopenharmony_ci		break;
1038c2ecf20Sopenharmony_ci	case ZSTD_error_prefix_unknown:
1048c2ecf20Sopenharmony_ci		error("Input is not in the ZSTD format (wrong magic bytes)");
1058c2ecf20Sopenharmony_ci		break;
1068c2ecf20Sopenharmony_ci	case ZSTD_error_dstSize_tooSmall:
1078c2ecf20Sopenharmony_ci	case ZSTD_error_corruption_detected:
1088c2ecf20Sopenharmony_ci	case ZSTD_error_checksum_wrong:
1098c2ecf20Sopenharmony_ci		error("ZSTD-compressed data is corrupt");
1108c2ecf20Sopenharmony_ci		break;
1118c2ecf20Sopenharmony_ci	default:
1128c2ecf20Sopenharmony_ci		error("ZSTD-compressed data is probably corrupt");
1138c2ecf20Sopenharmony_ci		break;
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci	return -1;
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci/*
1198c2ecf20Sopenharmony_ci * Handle the case where we have the entire input and output in one segment.
1208c2ecf20Sopenharmony_ci * We can allocate less memory (no circular buffer for the sliding window),
1218c2ecf20Sopenharmony_ci * and avoid some memcpy() calls.
1228c2ecf20Sopenharmony_ci */
1238c2ecf20Sopenharmony_cistatic int INIT decompress_single(const u8 *in_buf, long in_len, u8 *out_buf,
1248c2ecf20Sopenharmony_ci				  long out_len, long *in_pos,
1258c2ecf20Sopenharmony_ci				  void (*error)(char *x))
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	const size_t wksp_size = ZSTD_DCtxWorkspaceBound();
1288c2ecf20Sopenharmony_ci	void *wksp = large_malloc(wksp_size);
1298c2ecf20Sopenharmony_ci	ZSTD_DCtx *dctx = ZSTD_initDCtx(wksp, wksp_size);
1308c2ecf20Sopenharmony_ci	int err;
1318c2ecf20Sopenharmony_ci	size_t ret;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	if (dctx == NULL) {
1348c2ecf20Sopenharmony_ci		error("Out of memory while allocating ZSTD_DCtx");
1358c2ecf20Sopenharmony_ci		err = -1;
1368c2ecf20Sopenharmony_ci		goto out;
1378c2ecf20Sopenharmony_ci	}
1388c2ecf20Sopenharmony_ci	/*
1398c2ecf20Sopenharmony_ci	 * Find out how large the frame actually is, there may be junk at
1408c2ecf20Sopenharmony_ci	 * the end of the frame that ZSTD_decompressDCtx() can't handle.
1418c2ecf20Sopenharmony_ci	 */
1428c2ecf20Sopenharmony_ci	ret = ZSTD_findFrameCompressedSize(in_buf, in_len);
1438c2ecf20Sopenharmony_ci	err = handle_zstd_error(ret, error);
1448c2ecf20Sopenharmony_ci	if (err)
1458c2ecf20Sopenharmony_ci		goto out;
1468c2ecf20Sopenharmony_ci	in_len = (long)ret;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	ret = ZSTD_decompressDCtx(dctx, out_buf, out_len, in_buf, in_len);
1498c2ecf20Sopenharmony_ci	err = handle_zstd_error(ret, error);
1508c2ecf20Sopenharmony_ci	if (err)
1518c2ecf20Sopenharmony_ci		goto out;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	if (in_pos != NULL)
1548c2ecf20Sopenharmony_ci		*in_pos = in_len;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	err = 0;
1578c2ecf20Sopenharmony_ciout:
1588c2ecf20Sopenharmony_ci	if (wksp != NULL)
1598c2ecf20Sopenharmony_ci		large_free(wksp);
1608c2ecf20Sopenharmony_ci	return err;
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic int INIT __unzstd(unsigned char *in_buf, long in_len,
1648c2ecf20Sopenharmony_ci			 long (*fill)(void*, unsigned long),
1658c2ecf20Sopenharmony_ci			 long (*flush)(void*, unsigned long),
1668c2ecf20Sopenharmony_ci			 unsigned char *out_buf, long out_len,
1678c2ecf20Sopenharmony_ci			 long *in_pos,
1688c2ecf20Sopenharmony_ci			 void (*error)(char *x))
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	ZSTD_inBuffer in;
1718c2ecf20Sopenharmony_ci	ZSTD_outBuffer out;
1728c2ecf20Sopenharmony_ci	ZSTD_frameParams params;
1738c2ecf20Sopenharmony_ci	void *in_allocated = NULL;
1748c2ecf20Sopenharmony_ci	void *out_allocated = NULL;
1758c2ecf20Sopenharmony_ci	void *wksp = NULL;
1768c2ecf20Sopenharmony_ci	size_t wksp_size;
1778c2ecf20Sopenharmony_ci	ZSTD_DStream *dstream;
1788c2ecf20Sopenharmony_ci	int err;
1798c2ecf20Sopenharmony_ci	size_t ret;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	/*
1828c2ecf20Sopenharmony_ci	 * ZSTD decompression code won't be happy if the buffer size is so big
1838c2ecf20Sopenharmony_ci	 * that its end address overflows. When the size is not provided, make
1848c2ecf20Sopenharmony_ci	 * it as big as possible without having the end address overflow.
1858c2ecf20Sopenharmony_ci	 */
1868c2ecf20Sopenharmony_ci	if (out_len == 0)
1878c2ecf20Sopenharmony_ci		out_len = UINTPTR_MAX - (uintptr_t)out_buf;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	if (fill == NULL && flush == NULL)
1908c2ecf20Sopenharmony_ci		/*
1918c2ecf20Sopenharmony_ci		 * We can decompress faster and with less memory when we have a
1928c2ecf20Sopenharmony_ci		 * single chunk.
1938c2ecf20Sopenharmony_ci		 */
1948c2ecf20Sopenharmony_ci		return decompress_single(in_buf, in_len, out_buf, out_len,
1958c2ecf20Sopenharmony_ci					 in_pos, error);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	/*
1988c2ecf20Sopenharmony_ci	 * If in_buf is not provided, we must be using fill(), so allocate
1998c2ecf20Sopenharmony_ci	 * a large enough buffer. If it is provided, it must be at least
2008c2ecf20Sopenharmony_ci	 * ZSTD_IOBUF_SIZE large.
2018c2ecf20Sopenharmony_ci	 */
2028c2ecf20Sopenharmony_ci	if (in_buf == NULL) {
2038c2ecf20Sopenharmony_ci		in_allocated = large_malloc(ZSTD_IOBUF_SIZE);
2048c2ecf20Sopenharmony_ci		if (in_allocated == NULL) {
2058c2ecf20Sopenharmony_ci			error("Out of memory while allocating input buffer");
2068c2ecf20Sopenharmony_ci			err = -1;
2078c2ecf20Sopenharmony_ci			goto out;
2088c2ecf20Sopenharmony_ci		}
2098c2ecf20Sopenharmony_ci		in_buf = in_allocated;
2108c2ecf20Sopenharmony_ci		in_len = 0;
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci	/* Read the first chunk, since we need to decode the frame header. */
2138c2ecf20Sopenharmony_ci	if (fill != NULL)
2148c2ecf20Sopenharmony_ci		in_len = fill(in_buf, ZSTD_IOBUF_SIZE);
2158c2ecf20Sopenharmony_ci	if (in_len < 0) {
2168c2ecf20Sopenharmony_ci		error("ZSTD-compressed data is truncated");
2178c2ecf20Sopenharmony_ci		err = -1;
2188c2ecf20Sopenharmony_ci		goto out;
2198c2ecf20Sopenharmony_ci	}
2208c2ecf20Sopenharmony_ci	/* Set the first non-empty input buffer. */
2218c2ecf20Sopenharmony_ci	in.src = in_buf;
2228c2ecf20Sopenharmony_ci	in.pos = 0;
2238c2ecf20Sopenharmony_ci	in.size = in_len;
2248c2ecf20Sopenharmony_ci	/* Allocate the output buffer if we are using flush(). */
2258c2ecf20Sopenharmony_ci	if (flush != NULL) {
2268c2ecf20Sopenharmony_ci		out_allocated = large_malloc(ZSTD_IOBUF_SIZE);
2278c2ecf20Sopenharmony_ci		if (out_allocated == NULL) {
2288c2ecf20Sopenharmony_ci			error("Out of memory while allocating output buffer");
2298c2ecf20Sopenharmony_ci			err = -1;
2308c2ecf20Sopenharmony_ci			goto out;
2318c2ecf20Sopenharmony_ci		}
2328c2ecf20Sopenharmony_ci		out_buf = out_allocated;
2338c2ecf20Sopenharmony_ci		out_len = ZSTD_IOBUF_SIZE;
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci	/* Set the output buffer. */
2368c2ecf20Sopenharmony_ci	out.dst = out_buf;
2378c2ecf20Sopenharmony_ci	out.pos = 0;
2388c2ecf20Sopenharmony_ci	out.size = out_len;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	/*
2418c2ecf20Sopenharmony_ci	 * We need to know the window size to allocate the ZSTD_DStream.
2428c2ecf20Sopenharmony_ci	 * Since we are streaming, we need to allocate a buffer for the sliding
2438c2ecf20Sopenharmony_ci	 * window. The window size varies from 1 KB to ZSTD_WINDOWSIZE_MAX
2448c2ecf20Sopenharmony_ci	 * (8 MB), so it is important to use the actual value so as not to
2458c2ecf20Sopenharmony_ci	 * waste memory when it is smaller.
2468c2ecf20Sopenharmony_ci	 */
2478c2ecf20Sopenharmony_ci	ret = ZSTD_getFrameParams(&params, in.src, in.size);
2488c2ecf20Sopenharmony_ci	err = handle_zstd_error(ret, error);
2498c2ecf20Sopenharmony_ci	if (err)
2508c2ecf20Sopenharmony_ci		goto out;
2518c2ecf20Sopenharmony_ci	if (ret != 0) {
2528c2ecf20Sopenharmony_ci		error("ZSTD-compressed data has an incomplete frame header");
2538c2ecf20Sopenharmony_ci		err = -1;
2548c2ecf20Sopenharmony_ci		goto out;
2558c2ecf20Sopenharmony_ci	}
2568c2ecf20Sopenharmony_ci	if (params.windowSize > ZSTD_WINDOWSIZE_MAX) {
2578c2ecf20Sopenharmony_ci		error("ZSTD-compressed data has too large a window size");
2588c2ecf20Sopenharmony_ci		err = -1;
2598c2ecf20Sopenharmony_ci		goto out;
2608c2ecf20Sopenharmony_ci	}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	/*
2638c2ecf20Sopenharmony_ci	 * Allocate the ZSTD_DStream now that we know how much memory is
2648c2ecf20Sopenharmony_ci	 * required.
2658c2ecf20Sopenharmony_ci	 */
2668c2ecf20Sopenharmony_ci	wksp_size = ZSTD_DStreamWorkspaceBound(params.windowSize);
2678c2ecf20Sopenharmony_ci	wksp = large_malloc(wksp_size);
2688c2ecf20Sopenharmony_ci	dstream = ZSTD_initDStream(params.windowSize, wksp, wksp_size);
2698c2ecf20Sopenharmony_ci	if (dstream == NULL) {
2708c2ecf20Sopenharmony_ci		error("Out of memory while allocating ZSTD_DStream");
2718c2ecf20Sopenharmony_ci		err = -1;
2728c2ecf20Sopenharmony_ci		goto out;
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	/*
2768c2ecf20Sopenharmony_ci	 * Decompression loop:
2778c2ecf20Sopenharmony_ci	 * Read more data if necessary (error if no more data can be read).
2788c2ecf20Sopenharmony_ci	 * Call the decompression function, which returns 0 when finished.
2798c2ecf20Sopenharmony_ci	 * Flush any data produced if using flush().
2808c2ecf20Sopenharmony_ci	 */
2818c2ecf20Sopenharmony_ci	if (in_pos != NULL)
2828c2ecf20Sopenharmony_ci		*in_pos = 0;
2838c2ecf20Sopenharmony_ci	do {
2848c2ecf20Sopenharmony_ci		/*
2858c2ecf20Sopenharmony_ci		 * If we need to reload data, either we have fill() and can
2868c2ecf20Sopenharmony_ci		 * try to get more data, or we don't and the input is truncated.
2878c2ecf20Sopenharmony_ci		 */
2888c2ecf20Sopenharmony_ci		if (in.pos == in.size) {
2898c2ecf20Sopenharmony_ci			if (in_pos != NULL)
2908c2ecf20Sopenharmony_ci				*in_pos += in.pos;
2918c2ecf20Sopenharmony_ci			in_len = fill ? fill(in_buf, ZSTD_IOBUF_SIZE) : -1;
2928c2ecf20Sopenharmony_ci			if (in_len < 0) {
2938c2ecf20Sopenharmony_ci				error("ZSTD-compressed data is truncated");
2948c2ecf20Sopenharmony_ci				err = -1;
2958c2ecf20Sopenharmony_ci				goto out;
2968c2ecf20Sopenharmony_ci			}
2978c2ecf20Sopenharmony_ci			in.pos = 0;
2988c2ecf20Sopenharmony_ci			in.size = in_len;
2998c2ecf20Sopenharmony_ci		}
3008c2ecf20Sopenharmony_ci		/* Returns zero when the frame is complete. */
3018c2ecf20Sopenharmony_ci		ret = ZSTD_decompressStream(dstream, &out, &in);
3028c2ecf20Sopenharmony_ci		err = handle_zstd_error(ret, error);
3038c2ecf20Sopenharmony_ci		if (err)
3048c2ecf20Sopenharmony_ci			goto out;
3058c2ecf20Sopenharmony_ci		/* Flush all of the data produced if using flush(). */
3068c2ecf20Sopenharmony_ci		if (flush != NULL && out.pos > 0) {
3078c2ecf20Sopenharmony_ci			if (out.pos != flush(out.dst, out.pos)) {
3088c2ecf20Sopenharmony_ci				error("Failed to flush()");
3098c2ecf20Sopenharmony_ci				err = -1;
3108c2ecf20Sopenharmony_ci				goto out;
3118c2ecf20Sopenharmony_ci			}
3128c2ecf20Sopenharmony_ci			out.pos = 0;
3138c2ecf20Sopenharmony_ci		}
3148c2ecf20Sopenharmony_ci	} while (ret != 0);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	if (in_pos != NULL)
3178c2ecf20Sopenharmony_ci		*in_pos += in.pos;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	err = 0;
3208c2ecf20Sopenharmony_ciout:
3218c2ecf20Sopenharmony_ci	if (in_allocated != NULL)
3228c2ecf20Sopenharmony_ci		large_free(in_allocated);
3238c2ecf20Sopenharmony_ci	if (out_allocated != NULL)
3248c2ecf20Sopenharmony_ci		large_free(out_allocated);
3258c2ecf20Sopenharmony_ci	if (wksp != NULL)
3268c2ecf20Sopenharmony_ci		large_free(wksp);
3278c2ecf20Sopenharmony_ci	return err;
3288c2ecf20Sopenharmony_ci}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci#ifndef UNZSTD_PREBOOT
3318c2ecf20Sopenharmony_ciSTATIC int INIT unzstd(unsigned char *buf, long len,
3328c2ecf20Sopenharmony_ci		       long (*fill)(void*, unsigned long),
3338c2ecf20Sopenharmony_ci		       long (*flush)(void*, unsigned long),
3348c2ecf20Sopenharmony_ci		       unsigned char *out_buf,
3358c2ecf20Sopenharmony_ci		       long *pos,
3368c2ecf20Sopenharmony_ci		       void (*error)(char *x))
3378c2ecf20Sopenharmony_ci{
3388c2ecf20Sopenharmony_ci	return __unzstd(buf, len, fill, flush, out_buf, 0, pos, error);
3398c2ecf20Sopenharmony_ci}
3408c2ecf20Sopenharmony_ci#else
3418c2ecf20Sopenharmony_ciSTATIC int INIT __decompress(unsigned char *buf, long len,
3428c2ecf20Sopenharmony_ci			     long (*fill)(void*, unsigned long),
3438c2ecf20Sopenharmony_ci			     long (*flush)(void*, unsigned long),
3448c2ecf20Sopenharmony_ci			     unsigned char *out_buf, long out_len,
3458c2ecf20Sopenharmony_ci			     long *pos,
3468c2ecf20Sopenharmony_ci			     void (*error)(char *x))
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	return __unzstd(buf, len, fill, flush, out_buf, out_len, pos, error);
3498c2ecf20Sopenharmony_ci}
3508c2ecf20Sopenharmony_ci#endif
351