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