decompress.c (3719B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Wrapper around the kernel's pre-boot decompression library. 4 * 5 * Copyright (C) IBM Corporation 2016. 6 */ 7 8#include "elf.h" 9#include "page.h" 10#include "string.h" 11#include "stdio.h" 12#include "ops.h" 13#include "reg.h" 14#include "types.h" 15 16/* 17 * The decompressor_*.c files play #ifdef games so they can be used in both 18 * pre-boot and regular kernel code. We need these definitions to make the 19 * includes work. 20 */ 21 22#define STATIC static 23#define INIT 24 25/* 26 * The build process will copy the required zlib source files and headers 27 * out of lib/ and "fix" the includes so they do not pull in other kernel 28 * headers. 29 */ 30 31#ifdef CONFIG_KERNEL_GZIP 32# include "decompress_inflate.c" 33#endif 34 35#ifdef CONFIG_KERNEL_XZ 36# include "xz_config.h" 37# include "../../../lib/decompress_unxz.c" 38#endif 39 40/* globals for tracking the state of the decompression */ 41static unsigned long decompressed_bytes; 42static unsigned long limit; 43static unsigned long skip; 44static char *output_buffer; 45 46/* 47 * flush() is called by __decompress() when the decompressor's scratch buffer is 48 * full. 49 */ 50static long flush(void *v, unsigned long buffer_size) 51{ 52 unsigned long end = decompressed_bytes + buffer_size; 53 unsigned long size = buffer_size; 54 unsigned long offset = 0; 55 char *in = v; 56 char *out; 57 58 /* 59 * if we hit our decompression limit, we need to fake an error to abort 60 * the in-progress decompression. 61 */ 62 if (decompressed_bytes >= limit) 63 return -1; 64 65 /* skip this entire block */ 66 if (end <= skip) { 67 decompressed_bytes += buffer_size; 68 return buffer_size; 69 } 70 71 /* skip some data at the start, but keep the rest of the block */ 72 if (decompressed_bytes < skip && end > skip) { 73 offset = skip - decompressed_bytes; 74 75 in += offset; 76 size -= offset; 77 decompressed_bytes += offset; 78 } 79 80 out = &output_buffer[decompressed_bytes - skip]; 81 size = min(decompressed_bytes + size, limit) - decompressed_bytes; 82 83 memcpy(out, in, size); 84 decompressed_bytes += size; 85 86 return buffer_size; 87} 88 89static void print_err(char *s) 90{ 91 /* suppress the "error" when we terminate the decompressor */ 92 if (decompressed_bytes >= limit) 93 return; 94 95 printf("Decompression error: '%s'\n\r", s); 96} 97 98/** 99 * partial_decompress - decompresses part or all of a compressed buffer 100 * @inbuf: input buffer 101 * @input_size: length of the input buffer 102 * @outbuf: output buffer 103 * @output_size: length of the output buffer 104 * @skip number of output bytes to ignore 105 * 106 * This function takes compressed data from inbuf, decompresses and write it to 107 * outbuf. Once output_size bytes are written to the output buffer, or the 108 * stream is exhausted the function will return the number of bytes that were 109 * decompressed. Otherwise it will return whatever error code the decompressor 110 * reported (NB: This is specific to each decompressor type). 111 * 112 * The skip functionality is mainly there so the program and discover 113 * the size of the compressed image so that it can ask firmware (if present) 114 * for an appropriately sized buffer. 115 */ 116long partial_decompress(void *inbuf, unsigned long input_size, 117 void *outbuf, unsigned long output_size, unsigned long _skip) 118{ 119 int ret; 120 121 /* 122 * The skipped bytes needs to be included in the size of data we want 123 * to decompress. 124 */ 125 output_size += _skip; 126 127 decompressed_bytes = 0; 128 output_buffer = outbuf; 129 limit = output_size; 130 skip = _skip; 131 132 ret = __decompress(inbuf, input_size, NULL, flush, outbuf, 133 output_size, NULL, print_err); 134 135 /* 136 * If decompression was aborted due to an actual error rather than 137 * a fake error that we used to abort, then we should report it. 138 */ 139 if (decompressed_bytes < limit) 140 return ret; 141 142 return decompressed_bytes - skip; 143}