linux/arch/powerpc/boot/decompress.c
<<
>>
Prefs
   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}
 144