Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Wrapper around the kernel's pre-boot decompression library.
0004  *
0005  * Copyright (C) IBM Corporation 2016.
0006  */
0007 
0008 #include "elf.h"
0009 #include "page.h"
0010 #include "string.h"
0011 #include "stdio.h"
0012 #include "ops.h"
0013 #include "reg.h"
0014 #include "types.h"
0015 
0016 /*
0017  * The decompressor_*.c files play #ifdef games so they can be used in both
0018  * pre-boot and regular kernel code. We need these definitions to make the
0019  * includes work.
0020  */
0021 
0022 #define STATIC static
0023 #define INIT
0024 
0025 /*
0026  * The build process will copy the required zlib source files and headers
0027  * out of lib/ and "fix" the includes so they do not pull in other kernel
0028  * headers.
0029  */
0030 
0031 #ifdef CONFIG_KERNEL_GZIP
0032 #   include "decompress_inflate.c"
0033 #endif
0034 
0035 #ifdef CONFIG_KERNEL_XZ
0036 #   include "xz_config.h"
0037 #   include "../../../lib/decompress_unxz.c"
0038 #endif
0039 
0040 /* globals for tracking the state of the decompression */
0041 static unsigned long decompressed_bytes;
0042 static unsigned long limit;
0043 static unsigned long skip;
0044 static char *output_buffer;
0045 
0046 /*
0047  * flush() is called by __decompress() when the decompressor's scratch buffer is
0048  * full.
0049  */
0050 static long flush(void *v, unsigned long buffer_size)
0051 {
0052     unsigned long end = decompressed_bytes + buffer_size;
0053     unsigned long size = buffer_size;
0054     unsigned long offset = 0;
0055     char *in = v;
0056     char *out;
0057 
0058     /*
0059      * if we hit our decompression limit, we need to fake an error to abort
0060      * the in-progress decompression.
0061      */
0062     if (decompressed_bytes >= limit)
0063         return -1;
0064 
0065     /* skip this entire block */
0066     if (end <= skip) {
0067         decompressed_bytes += buffer_size;
0068         return buffer_size;
0069     }
0070 
0071     /* skip some data at the start, but keep the rest of the block */
0072     if (decompressed_bytes < skip && end > skip) {
0073         offset = skip - decompressed_bytes;
0074 
0075         in += offset;
0076         size -= offset;
0077         decompressed_bytes += offset;
0078     }
0079 
0080     out = &output_buffer[decompressed_bytes - skip];
0081     size = min(decompressed_bytes + size, limit) - decompressed_bytes;
0082 
0083     memcpy(out, in, size);
0084     decompressed_bytes += size;
0085 
0086     return buffer_size;
0087 }
0088 
0089 static void print_err(char *s)
0090 {
0091     /* suppress the "error" when we terminate the decompressor */
0092     if (decompressed_bytes >= limit)
0093         return;
0094 
0095     printf("Decompression error: '%s'\n\r", s);
0096 }
0097 
0098 /**
0099  * partial_decompress - decompresses part or all of a compressed buffer
0100  * @inbuf:       input buffer
0101  * @input_size:  length of the input buffer
0102  * @outbuf:      output buffer
0103  * @output_size: length of the output buffer
0104  * @skip         number of output bytes to ignore
0105  *
0106  * This function takes compressed data from inbuf, decompresses and write it to
0107  * outbuf. Once output_size bytes are written to the output buffer, or the
0108  * stream is exhausted the function will return the number of bytes that were
0109  * decompressed. Otherwise it will return whatever error code the decompressor
0110  * reported (NB: This is specific to each decompressor type).
0111  *
0112  * The skip functionality is mainly there so the program and discover
0113  * the size of the compressed image so that it can ask firmware (if present)
0114  * for an appropriately sized buffer.
0115  */
0116 long partial_decompress(void *inbuf, unsigned long input_size,
0117     void *outbuf, unsigned long output_size, unsigned long _skip)
0118 {
0119     int ret;
0120 
0121     /*
0122      * The skipped bytes needs to be included in the size of data we want
0123      * to decompress.
0124      */
0125     output_size += _skip;
0126 
0127     decompressed_bytes = 0;
0128     output_buffer = outbuf;
0129     limit = output_size;
0130     skip = _skip;
0131 
0132     ret = __decompress(inbuf, input_size, NULL, flush, outbuf,
0133         output_size, NULL, print_err);
0134 
0135     /*
0136      * If decompression was aborted due to an actual error rather than
0137      * a fake error that we used to abort, then we should report it.
0138      */
0139     if (decompressed_bytes < limit)
0140         return ret;
0141 
0142     return decompressed_bytes - skip;
0143 }