12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21b7898eeSOliver O'Halloran /*
31b7898eeSOliver O'Halloran * Wrapper around the kernel's pre-boot decompression library.
41b7898eeSOliver O'Halloran *
51b7898eeSOliver O'Halloran * Copyright (C) IBM Corporation 2016.
61b7898eeSOliver O'Halloran */
71b7898eeSOliver O'Halloran
81b7898eeSOliver O'Halloran #include "elf.h"
91b7898eeSOliver O'Halloran #include "page.h"
101b7898eeSOliver O'Halloran #include "string.h"
111b7898eeSOliver O'Halloran #include "stdio.h"
121b7898eeSOliver O'Halloran #include "ops.h"
131b7898eeSOliver O'Halloran #include "reg.h"
141b7898eeSOliver O'Halloran #include "types.h"
151b7898eeSOliver O'Halloran
161b7898eeSOliver O'Halloran /*
171b7898eeSOliver O'Halloran * The decompressor_*.c files play #ifdef games so they can be used in both
181b7898eeSOliver O'Halloran * pre-boot and regular kernel code. We need these definitions to make the
191b7898eeSOliver O'Halloran * includes work.
201b7898eeSOliver O'Halloran */
211b7898eeSOliver O'Halloran
221b7898eeSOliver O'Halloran #define STATIC static
231b7898eeSOliver O'Halloran #define INIT
241b7898eeSOliver O'Halloran
251b7898eeSOliver O'Halloran /*
261b7898eeSOliver O'Halloran * The build process will copy the required zlib source files and headers
271b7898eeSOliver O'Halloran * out of lib/ and "fix" the includes so they do not pull in other kernel
281b7898eeSOliver O'Halloran * headers.
291b7898eeSOliver O'Halloran */
301b7898eeSOliver O'Halloran
311b7898eeSOliver O'Halloran #ifdef CONFIG_KERNEL_GZIP
321b7898eeSOliver O'Halloran # include "decompress_inflate.c"
331b7898eeSOliver O'Halloran #endif
341b7898eeSOliver O'Halloran
35c762c69eSOliver O'Halloran #ifdef CONFIG_KERNEL_XZ
36c762c69eSOliver O'Halloran # include "xz_config.h"
37c762c69eSOliver O'Halloran # include "../../../lib/decompress_unxz.c"
38c762c69eSOliver O'Halloran #endif
39c762c69eSOliver O'Halloran
401b7898eeSOliver O'Halloran /* globals for tracking the state of the decompression */
411b7898eeSOliver O'Halloran static unsigned long decompressed_bytes;
421b7898eeSOliver O'Halloran static unsigned long limit;
431b7898eeSOliver O'Halloran static unsigned long skip;
441b7898eeSOliver O'Halloran static char *output_buffer;
451b7898eeSOliver O'Halloran
461b7898eeSOliver O'Halloran /*
471b7898eeSOliver O'Halloran * flush() is called by __decompress() when the decompressor's scratch buffer is
481b7898eeSOliver O'Halloran * full.
491b7898eeSOliver O'Halloran */
flush(void * v,unsigned long buffer_size)501b7898eeSOliver O'Halloran static long flush(void *v, unsigned long buffer_size)
511b7898eeSOliver O'Halloran {
521b7898eeSOliver O'Halloran unsigned long end = decompressed_bytes + buffer_size;
531b7898eeSOliver O'Halloran unsigned long size = buffer_size;
541b7898eeSOliver O'Halloran unsigned long offset = 0;
551b7898eeSOliver O'Halloran char *in = v;
561b7898eeSOliver O'Halloran char *out;
571b7898eeSOliver O'Halloran
581b7898eeSOliver O'Halloran /*
591b7898eeSOliver O'Halloran * if we hit our decompression limit, we need to fake an error to abort
601b7898eeSOliver O'Halloran * the in-progress decompression.
611b7898eeSOliver O'Halloran */
621b7898eeSOliver O'Halloran if (decompressed_bytes >= limit)
631b7898eeSOliver O'Halloran return -1;
641b7898eeSOliver O'Halloran
651b7898eeSOliver O'Halloran /* skip this entire block */
661b7898eeSOliver O'Halloran if (end <= skip) {
671b7898eeSOliver O'Halloran decompressed_bytes += buffer_size;
681b7898eeSOliver O'Halloran return buffer_size;
691b7898eeSOliver O'Halloran }
701b7898eeSOliver O'Halloran
711b7898eeSOliver O'Halloran /* skip some data at the start, but keep the rest of the block */
721b7898eeSOliver O'Halloran if (decompressed_bytes < skip && end > skip) {
731b7898eeSOliver O'Halloran offset = skip - decompressed_bytes;
741b7898eeSOliver O'Halloran
751b7898eeSOliver O'Halloran in += offset;
761b7898eeSOliver O'Halloran size -= offset;
771b7898eeSOliver O'Halloran decompressed_bytes += offset;
781b7898eeSOliver O'Halloran }
791b7898eeSOliver O'Halloran
801b7898eeSOliver O'Halloran out = &output_buffer[decompressed_bytes - skip];
811b7898eeSOliver O'Halloran size = min(decompressed_bytes + size, limit) - decompressed_bytes;
821b7898eeSOliver O'Halloran
831b7898eeSOliver O'Halloran memcpy(out, in, size);
841b7898eeSOliver O'Halloran decompressed_bytes += size;
851b7898eeSOliver O'Halloran
861b7898eeSOliver O'Halloran return buffer_size;
871b7898eeSOliver O'Halloran }
881b7898eeSOliver O'Halloran
print_err(char * s)891b7898eeSOliver O'Halloran static void print_err(char *s)
901b7898eeSOliver O'Halloran {
911b7898eeSOliver O'Halloran /* suppress the "error" when we terminate the decompressor */
921b7898eeSOliver O'Halloran if (decompressed_bytes >= limit)
931b7898eeSOliver O'Halloran return;
941b7898eeSOliver O'Halloran
951b7898eeSOliver O'Halloran printf("Decompression error: '%s'\n\r", s);
961b7898eeSOliver O'Halloran }
971b7898eeSOliver O'Halloran
981b7898eeSOliver O'Halloran /**
991b7898eeSOliver O'Halloran * partial_decompress - decompresses part or all of a compressed buffer
1001b7898eeSOliver O'Halloran * @inbuf: input buffer
1011b7898eeSOliver O'Halloran * @input_size: length of the input buffer
102*930a77c3SZhang Jianhua * @outbuf: output buffer
103*930a77c3SZhang Jianhua * @output_size: length of the output buffer
1041b7898eeSOliver O'Halloran * @skip number of output bytes to ignore
1051b7898eeSOliver O'Halloran *
1061b7898eeSOliver O'Halloran * This function takes compressed data from inbuf, decompresses and write it to
1071b7898eeSOliver O'Halloran * outbuf. Once output_size bytes are written to the output buffer, or the
1081b7898eeSOliver O'Halloran * stream is exhausted the function will return the number of bytes that were
1091b7898eeSOliver O'Halloran * decompressed. Otherwise it will return whatever error code the decompressor
1101b7898eeSOliver O'Halloran * reported (NB: This is specific to each decompressor type).
1111b7898eeSOliver O'Halloran *
1121b7898eeSOliver O'Halloran * The skip functionality is mainly there so the program and discover
1131b7898eeSOliver O'Halloran * the size of the compressed image so that it can ask firmware (if present)
1141b7898eeSOliver O'Halloran * for an appropriately sized buffer.
1151b7898eeSOliver O'Halloran */
partial_decompress(void * inbuf,unsigned long input_size,void * outbuf,unsigned long output_size,unsigned long _skip)1161b7898eeSOliver O'Halloran long partial_decompress(void *inbuf, unsigned long input_size,
1171b7898eeSOliver O'Halloran void *outbuf, unsigned long output_size, unsigned long _skip)
1181b7898eeSOliver O'Halloran {
1191b7898eeSOliver O'Halloran int ret;
1201b7898eeSOliver O'Halloran
1211b7898eeSOliver O'Halloran /*
1221b7898eeSOliver O'Halloran * The skipped bytes needs to be included in the size of data we want
1231b7898eeSOliver O'Halloran * to decompress.
1241b7898eeSOliver O'Halloran */
1251b7898eeSOliver O'Halloran output_size += _skip;
1261b7898eeSOliver O'Halloran
1271b7898eeSOliver O'Halloran decompressed_bytes = 0;
1281b7898eeSOliver O'Halloran output_buffer = outbuf;
1291b7898eeSOliver O'Halloran limit = output_size;
1301b7898eeSOliver O'Halloran skip = _skip;
1311b7898eeSOliver O'Halloran
1321b7898eeSOliver O'Halloran ret = __decompress(inbuf, input_size, NULL, flush, outbuf,
1331b7898eeSOliver O'Halloran output_size, NULL, print_err);
1341b7898eeSOliver O'Halloran
1351b7898eeSOliver O'Halloran /*
1361b7898eeSOliver O'Halloran * If decompression was aborted due to an actual error rather than
1371b7898eeSOliver O'Halloran * a fake error that we used to abort, then we should report it.
1381b7898eeSOliver O'Halloran */
1391b7898eeSOliver O'Halloran if (decompressed_bytes < limit)
1401b7898eeSOliver O'Halloran return ret;
1411b7898eeSOliver O'Halloran
1421b7898eeSOliver O'Halloran return decompressed_bytes - skip;
1431b7898eeSOliver O'Halloran }
144