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