cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

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}