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