1// SPDX-License-Identifier: Zlib
2
3#include "../zlib_deflate/defutil.h"
4#include "dfltcc_util.h"
5#include "dfltcc_deflate.h"
6#include <asm/setup.h>
7#include <linux/export.h>
8#include <linux/zutil.h>
9
10#define GET_DFLTCC_DEFLATE_STATE(state) ((struct dfltcc_deflate_state *)GET_DFLTCC_STATE(state))
11
12/*
13 * Compress.
14 */
15int dfltcc_can_deflate(
16 z_streamp strm
17)
18{
19 deflate_state *state = (deflate_state *)strm->state;
20 struct dfltcc_deflate_state *dfltcc_state = GET_DFLTCC_DEFLATE_STATE(state);
21
22 /* Check for kernel dfltcc command line parameter */
23 if (zlib_dfltcc_support == ZLIB_DFLTCC_DISABLED ||
24 zlib_dfltcc_support == ZLIB_DFLTCC_INFLATE_ONLY)
25 return 0;
26
27 /* Unsupported compression settings */
28 if (!dfltcc_are_params_ok(level: state->level, window_bits: state->w_bits, strategy: state->strategy,
29 level_mask: dfltcc_state->level_mask))
30 return 0;
31
32 /* Unsupported hardware */
33 if (!is_bit_set(bits: dfltcc_state->common.af.fns, DFLTCC_GDHT) ||
34 !is_bit_set(bits: dfltcc_state->common.af.fns, DFLTCC_CMPR) ||
35 !is_bit_set(bits: dfltcc_state->common.af.fmts, DFLTCC_FMT0))
36 return 0;
37
38 return 1;
39}
40EXPORT_SYMBOL(dfltcc_can_deflate);
41
42void dfltcc_reset_deflate_state(z_streamp strm) {
43 deflate_state *state = (deflate_state *)strm->state;
44 struct dfltcc_deflate_state *dfltcc_state = GET_DFLTCC_DEFLATE_STATE(state);
45
46 dfltcc_reset_state(dfltcc_state: &dfltcc_state->common);
47
48 /* Initialize tuning parameters */
49 if (zlib_dfltcc_support == ZLIB_DFLTCC_FULL_DEBUG)
50 dfltcc_state->level_mask = DFLTCC_LEVEL_MASK_DEBUG;
51 else
52 dfltcc_state->level_mask = DFLTCC_LEVEL_MASK;
53 dfltcc_state->block_size = DFLTCC_BLOCK_SIZE;
54 dfltcc_state->block_threshold = DFLTCC_FIRST_FHT_BLOCK_SIZE;
55 dfltcc_state->dht_threshold = DFLTCC_DHT_MIN_SAMPLE_SIZE;
56}
57EXPORT_SYMBOL(dfltcc_reset_deflate_state);
58
59static void dfltcc_gdht(
60 z_streamp strm
61)
62{
63 deflate_state *state = (deflate_state *)strm->state;
64 struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param;
65 size_t avail_in = strm->avail_in;
66
67 dfltcc(DFLTCC_GDHT,
68 param, NULL, NULL,
69 op2: &strm->next_in, len2: &avail_in, NULL);
70}
71
72static dfltcc_cc dfltcc_cmpr(
73 z_streamp strm
74)
75{
76 deflate_state *state = (deflate_state *)strm->state;
77 struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param;
78 size_t avail_in = strm->avail_in;
79 size_t avail_out = strm->avail_out;
80 dfltcc_cc cc;
81
82 cc = dfltcc(DFLTCC_CMPR | HBT_CIRCULAR,
83 param, op1: &strm->next_out, len1: &avail_out,
84 op2: &strm->next_in, len2: &avail_in, hist: state->window);
85 strm->total_in += (strm->avail_in - avail_in);
86 strm->total_out += (strm->avail_out - avail_out);
87 strm->avail_in = avail_in;
88 strm->avail_out = avail_out;
89 return cc;
90}
91
92static void send_eobs(
93 z_streamp strm,
94 const struct dfltcc_param_v0 *param
95)
96{
97 deflate_state *state = (deflate_state *)strm->state;
98
99 zlib_tr_send_bits(
100 s: state,
101 value: bi_reverse(code: param->eobs >> (15 - param->eobl), len: param->eobl),
102 length: param->eobl);
103 flush_pending(strm);
104 if (state->pending != 0) {
105 /* The remaining data is located in pending_out[0:pending]. If someone
106 * calls put_byte() - this might happen in deflate() - the byte will be
107 * placed into pending_buf[pending], which is incorrect. Move the
108 * remaining data to the beginning of pending_buf so that put_byte() is
109 * usable again.
110 */
111 memmove(state->pending_buf, state->pending_out, state->pending);
112 state->pending_out = state->pending_buf;
113 }
114#ifdef ZLIB_DEBUG
115 state->compressed_len += param->eobl;
116#endif
117}
118
119int dfltcc_deflate(
120 z_streamp strm,
121 int flush,
122 block_state *result
123)
124{
125 deflate_state *state = (deflate_state *)strm->state;
126 struct dfltcc_deflate_state *dfltcc_state = GET_DFLTCC_DEFLATE_STATE(state);
127 struct dfltcc_param_v0 *param = &dfltcc_state->common.param;
128 uInt masked_avail_in;
129 dfltcc_cc cc;
130 int need_empty_block;
131 int soft_bcc;
132 int no_flush;
133
134 if (!dfltcc_can_deflate(strm)) {
135 /* Clear history. */
136 if (flush == Z_FULL_FLUSH)
137 param->hl = 0;
138 return 0;
139 }
140
141again:
142 masked_avail_in = 0;
143 soft_bcc = 0;
144 no_flush = flush == Z_NO_FLUSH;
145
146 /* No input data. Return, except when Continuation Flag is set, which means
147 * that DFLTCC has buffered some output in the parameter block and needs to
148 * be called again in order to flush it.
149 */
150 if (strm->avail_in == 0 && !param->cf) {
151 /* A block is still open, and the hardware does not support closing
152 * blocks without adding data. Thus, close it manually.
153 */
154 if (!no_flush && param->bcf) {
155 send_eobs(strm, param);
156 param->bcf = 0;
157 }
158 /* Let one of deflate_* functions write a trailing empty block. */
159 if (flush == Z_FINISH)
160 return 0;
161 /* Clear history. */
162 if (flush == Z_FULL_FLUSH)
163 param->hl = 0;
164 /* Trigger block post-processing if necessary. */
165 *result = no_flush ? need_more : block_done;
166 return 1;
167 }
168
169 /* There is an open non-BFINAL block, we are not going to close it just
170 * yet, we have compressed more than DFLTCC_BLOCK_SIZE bytes and we see
171 * more than DFLTCC_DHT_MIN_SAMPLE_SIZE bytes. Open a new block with a new
172 * DHT in order to adapt to a possibly changed input data distribution.
173 */
174 if (param->bcf && no_flush &&
175 strm->total_in > dfltcc_state->block_threshold &&
176 strm->avail_in >= dfltcc_state->dht_threshold) {
177 if (param->cf) {
178 /* We need to flush the DFLTCC buffer before writing the
179 * End-of-block Symbol. Mask the input data and proceed as usual.
180 */
181 masked_avail_in += strm->avail_in;
182 strm->avail_in = 0;
183 no_flush = 0;
184 } else {
185 /* DFLTCC buffer is empty, so we can manually write the
186 * End-of-block Symbol right away.
187 */
188 send_eobs(strm, param);
189 param->bcf = 0;
190 dfltcc_state->block_threshold =
191 strm->total_in + dfltcc_state->block_size;
192 }
193 }
194
195 /* No space for compressed data. If we proceed, dfltcc_cmpr() will return
196 * DFLTCC_CC_OP1_TOO_SHORT without buffering header bits, but we will still
197 * set BCF=1, which is wrong. Avoid complications and return early.
198 */
199 if (strm->avail_out == 0) {
200 *result = need_more;
201 return 1;
202 }
203
204 /* The caller gave us too much data. Pass only one block worth of
205 * uncompressed data to DFLTCC and mask the rest, so that on the next
206 * iteration we start a new block.
207 */
208 if (no_flush && strm->avail_in > dfltcc_state->block_size) {
209 masked_avail_in += (strm->avail_in - dfltcc_state->block_size);
210 strm->avail_in = dfltcc_state->block_size;
211 }
212
213 /* When we have an open non-BFINAL deflate block and caller indicates that
214 * the stream is ending, we need to close an open deflate block and open a
215 * BFINAL one.
216 */
217 need_empty_block = flush == Z_FINISH && param->bcf && !param->bhf;
218
219 /* Translate stream to parameter block */
220 param->cvt = CVT_ADLER32;
221 if (!no_flush)
222 /* We need to close a block. Always do this in software - when there is
223 * no input data, the hardware will not hohor BCC. */
224 soft_bcc = 1;
225 if (flush == Z_FINISH && !param->bcf)
226 /* We are about to open a BFINAL block, set Block Header Final bit
227 * until the stream ends.
228 */
229 param->bhf = 1;
230 /* DFLTCC-CMPR will write to next_out, so make sure that buffers with
231 * higher precedence are empty.
232 */
233 Assert(state->pending == 0, "There must be no pending bytes");
234 Assert(state->bi_valid < 8, "There must be less than 8 pending bits");
235 param->sbb = (unsigned int)state->bi_valid;
236 if (param->sbb > 0)
237 *strm->next_out = (Byte)state->bi_buf;
238 /* Honor history and check value */
239 param->nt = 0;
240 param->cv = strm->adler;
241
242 /* When opening a block, choose a Huffman-Table Type */
243 if (!param->bcf) {
244 if (strm->total_in == 0 && dfltcc_state->block_threshold > 0) {
245 param->htt = HTT_FIXED;
246 }
247 else {
248 param->htt = HTT_DYNAMIC;
249 dfltcc_gdht(strm);
250 }
251 }
252
253 /* Deflate */
254 do {
255 cc = dfltcc_cmpr(strm);
256 if (strm->avail_in < 4096 && masked_avail_in > 0)
257 /* We are about to call DFLTCC with a small input buffer, which is
258 * inefficient. Since there is masked data, there will be at least
259 * one more DFLTCC call, so skip the current one and make the next
260 * one handle more data.
261 */
262 break;
263 } while (cc == DFLTCC_CC_AGAIN);
264
265 /* Translate parameter block to stream */
266 strm->msg = oesc_msg(buf: dfltcc_state->common.msg, oesc: param->oesc);
267 state->bi_valid = param->sbb;
268 if (state->bi_valid == 0)
269 state->bi_buf = 0; /* Avoid accessing next_out */
270 else
271 state->bi_buf = *strm->next_out & ((1 << state->bi_valid) - 1);
272 strm->adler = param->cv;
273
274 /* Unmask the input data */
275 strm->avail_in += masked_avail_in;
276 masked_avail_in = 0;
277
278 /* If we encounter an error, it means there is a bug in DFLTCC call */
279 Assert(cc != DFLTCC_CC_OP2_CORRUPT || param->oesc == 0, "BUG");
280
281 /* Update Block-Continuation Flag. It will be used to check whether to call
282 * GDHT the next time.
283 */
284 if (cc == DFLTCC_CC_OK) {
285 if (soft_bcc) {
286 send_eobs(strm, param);
287 param->bcf = 0;
288 dfltcc_state->block_threshold =
289 strm->total_in + dfltcc_state->block_size;
290 } else
291 param->bcf = 1;
292 if (flush == Z_FINISH) {
293 if (need_empty_block)
294 /* Make the current deflate() call also close the stream */
295 return 0;
296 else {
297 bi_windup(s: state);
298 *result = finish_done;
299 }
300 } else {
301 if (flush == Z_FULL_FLUSH)
302 param->hl = 0; /* Clear history */
303 *result = flush == Z_NO_FLUSH ? need_more : block_done;
304 }
305 } else {
306 param->bcf = 1;
307 *result = need_more;
308 }
309 if (strm->avail_in != 0 && strm->avail_out != 0)
310 goto again; /* deflate() must use all input or all output */
311 return 1;
312}
313EXPORT_SYMBOL(dfltcc_deflate);
314

source code of linux/lib/zlib_dfltcc/dfltcc_deflate.c