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