// SPDX-License-Identifier: GPL-2.0-or-later1/*2* Wrapper around the kernel's pre-boot decompression library.3*4* Copyright (C) IBM Corporation 2016.5*/67#include "elf.h"8#include "page.h"9#include "string.h"10#include "stdio.h"11#include "ops.h"12#include "reg.h"13#include "types.h"1415/*16* The decompressor_*.c files play #ifdef games so they can be used in both17* pre-boot and regular kernel code. We need these definitions to make the18* includes work.19*/2021#define STATIC static22#define INIT2324/*25* The build process will copy the required zlib source files and headers26* out of lib/ and "fix" the includes so they do not pull in other kernel27* headers.28*/2930#ifdef CONFIG_KERNEL_GZIP31# include "decompress_inflate.c"32#endif3334#ifdef CONFIG_KERNEL_XZ35# include "xz_config.h"36# include "../../../lib/decompress_unxz.c"37#endif3839/* globals for tracking the state of the decompression */40static unsigned long decompressed_bytes;41static unsigned long limit;42static unsigned long skip;43static char *output_buffer;4445/*46* flush() is called by __decompress() when the decompressor's scratch buffer is47* full.48*/49static long flush(void *v, unsigned long buffer_size)50{51unsigned long end = decompressed_bytes + buffer_size;52unsigned long size = buffer_size;53unsigned long offset = 0;54char *in = v;55char *out;5657/*58* if we hit our decompression limit, we need to fake an error to abort59* the in-progress decompression.60*/61if (decompressed_bytes >= limit)62return -1;6364/* skip this entire block */65if (end <= skip) {66decompressed_bytes += buffer_size;67return buffer_size;68}6970/* skip some data at the start, but keep the rest of the block */71if (decompressed_bytes < skip && end > skip) {72offset = skip - decompressed_bytes;7374in += offset;75size -= offset;76decompressed_bytes += offset;77}7879out = &output_buffer[decompressed_bytes - skip];80size = min(decompressed_bytes + size, limit) - decompressed_bytes;8182memcpy(out, in, size);83decompressed_bytes += size;8485return buffer_size;86}8788static void print_err(char *s)89{90/* suppress the "error" when we terminate the decompressor */91if (decompressed_bytes >= limit)92return;9394printf("Decompression error: '%s'\n\r", s);95}9697/**98* partial_decompress - decompresses part or all of a compressed buffer99* @inbuf: input buffer100* @input_size: length of the input buffer101* @outbuf: output buffer102* @output_size: length of the output buffer103* @_skip: number of output bytes to ignore104*105* This function takes compressed data from inbuf, decompresses and write it to106* outbuf. Once output_size bytes are written to the output buffer, or the107* stream is exhausted the function will return the number of bytes that were108* decompressed. Otherwise it will return whatever error code the decompressor109* reported (NB: This is specific to each decompressor type).110*111* The skip functionality is mainly there so the program and discover112* the size of the compressed image so that it can ask firmware (if present)113* for an appropriately sized buffer.114*/115long partial_decompress(void *inbuf, unsigned long input_size,116void *outbuf, unsigned long output_size, unsigned long _skip)117{118int ret;119120/*121* The skipped bytes needs to be included in the size of data we want122* to decompress.123*/124output_size += _skip;125126decompressed_bytes = 0;127output_buffer = outbuf;128limit = output_size;129skip = _skip;130131ret = __decompress(inbuf, input_size, NULL, flush, outbuf,132output_size, NULL, print_err);133134/*135* If decompression was aborted due to an actual error rather than136* a fake error that we used to abort, then we should report it.137*/138if (decompressed_bytes < limit)139return ret;140141return decompressed_bytes - skip;142}143144145