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