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 */ |
41 | static unsigned long decompressed_bytes; |
42 | static unsigned long limit; |
43 | static unsigned long skip; |
44 | static char *output_buffer; |
45 | |
46 | /* |
47 | * flush() is called by __decompress() when the decompressor's scratch buffer is |
48 | * full. |
49 | */ |
50 | static 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(dest: out, src: in, n: size); |
84 | decompressed_bytes += size; |
85 | |
86 | return buffer_size; |
87 | } |
88 | |
89 | static 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(fmt: "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 | */ |
116 | long 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 | |