Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: Zlib
0002 
0003 #include "../zlib_deflate/defutil.h"
0004 #include "dfltcc_util.h"
0005 #include "dfltcc.h"
0006 #include <asm/setup.h>
0007 #include <linux/export.h>
0008 #include <linux/zutil.h>
0009 
0010 /*
0011  * Compress.
0012  */
0013 int dfltcc_can_deflate(
0014     z_streamp strm
0015 )
0016 {
0017     deflate_state *state = (deflate_state *)strm->state;
0018     struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state);
0019 
0020     /* Check for kernel dfltcc command line parameter */
0021     if (zlib_dfltcc_support == ZLIB_DFLTCC_DISABLED ||
0022             zlib_dfltcc_support == ZLIB_DFLTCC_INFLATE_ONLY)
0023         return 0;
0024 
0025     /* Unsupported compression settings */
0026     if (!dfltcc_are_params_ok(state->level, state->w_bits, state->strategy,
0027                               dfltcc_state->level_mask))
0028         return 0;
0029 
0030     /* Unsupported hardware */
0031     if (!is_bit_set(dfltcc_state->af.fns, DFLTCC_GDHT) ||
0032             !is_bit_set(dfltcc_state->af.fns, DFLTCC_CMPR) ||
0033             !is_bit_set(dfltcc_state->af.fmts, DFLTCC_FMT0))
0034         return 0;
0035 
0036     return 1;
0037 }
0038 EXPORT_SYMBOL(dfltcc_can_deflate);
0039 
0040 static void dfltcc_gdht(
0041     z_streamp strm
0042 )
0043 {
0044     deflate_state *state = (deflate_state *)strm->state;
0045     struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param;
0046     size_t avail_in = avail_in = strm->avail_in;
0047 
0048     dfltcc(DFLTCC_GDHT,
0049            param, NULL, NULL,
0050            &strm->next_in, &avail_in, NULL);
0051 }
0052 
0053 static dfltcc_cc dfltcc_cmpr(
0054     z_streamp strm
0055 )
0056 {
0057     deflate_state *state = (deflate_state *)strm->state;
0058     struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param;
0059     size_t avail_in = strm->avail_in;
0060     size_t avail_out = strm->avail_out;
0061     dfltcc_cc cc;
0062 
0063     cc = dfltcc(DFLTCC_CMPR | HBT_CIRCULAR,
0064                 param, &strm->next_out, &avail_out,
0065                 &strm->next_in, &avail_in, state->window);
0066     strm->total_in += (strm->avail_in - avail_in);
0067     strm->total_out += (strm->avail_out - avail_out);
0068     strm->avail_in = avail_in;
0069     strm->avail_out = avail_out;
0070     return cc;
0071 }
0072 
0073 static void send_eobs(
0074     z_streamp strm,
0075     const struct dfltcc_param_v0 *param
0076 )
0077 {
0078     deflate_state *state = (deflate_state *)strm->state;
0079 
0080     zlib_tr_send_bits(
0081           state,
0082           bi_reverse(param->eobs >> (15 - param->eobl), param->eobl),
0083           param->eobl);
0084     flush_pending(strm);
0085     if (state->pending != 0) {
0086         /* The remaining data is located in pending_out[0:pending]. If someone
0087          * calls put_byte() - this might happen in deflate() - the byte will be
0088          * placed into pending_buf[pending], which is incorrect. Move the
0089          * remaining data to the beginning of pending_buf so that put_byte() is
0090          * usable again.
0091          */
0092         memmove(state->pending_buf, state->pending_out, state->pending);
0093         state->pending_out = state->pending_buf;
0094     }
0095 #ifdef ZLIB_DEBUG
0096     state->compressed_len += param->eobl;
0097 #endif
0098 }
0099 
0100 int dfltcc_deflate(
0101     z_streamp strm,
0102     int flush,
0103     block_state *result
0104 )
0105 {
0106     deflate_state *state = (deflate_state *)strm->state;
0107     struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state);
0108     struct dfltcc_param_v0 *param = &dfltcc_state->param;
0109     uInt masked_avail_in;
0110     dfltcc_cc cc;
0111     int need_empty_block;
0112     int soft_bcc;
0113     int no_flush;
0114 
0115     if (!dfltcc_can_deflate(strm))
0116         return 0;
0117 
0118 again:
0119     masked_avail_in = 0;
0120     soft_bcc = 0;
0121     no_flush = flush == Z_NO_FLUSH;
0122 
0123     /* Trailing empty block. Switch to software, except when Continuation Flag
0124      * is set, which means that DFLTCC has buffered some output in the
0125      * parameter block and needs to be called again in order to flush it.
0126      */
0127     if (flush == Z_FINISH && strm->avail_in == 0 && !param->cf) {
0128         if (param->bcf) {
0129             /* A block is still open, and the hardware does not support closing
0130              * blocks without adding data. Thus, close it manually.
0131              */
0132             send_eobs(strm, param);
0133             param->bcf = 0;
0134         }
0135         return 0;
0136     }
0137 
0138     if (strm->avail_in == 0 && !param->cf) {
0139         *result = need_more;
0140         return 1;
0141     }
0142 
0143     /* There is an open non-BFINAL block, we are not going to close it just
0144      * yet, we have compressed more than DFLTCC_BLOCK_SIZE bytes and we see
0145      * more than DFLTCC_DHT_MIN_SAMPLE_SIZE bytes. Open a new block with a new
0146      * DHT in order to adapt to a possibly changed input data distribution.
0147      */
0148     if (param->bcf && no_flush &&
0149             strm->total_in > dfltcc_state->block_threshold &&
0150             strm->avail_in >= dfltcc_state->dht_threshold) {
0151         if (param->cf) {
0152             /* We need to flush the DFLTCC buffer before writing the
0153              * End-of-block Symbol. Mask the input data and proceed as usual.
0154              */
0155             masked_avail_in += strm->avail_in;
0156             strm->avail_in = 0;
0157             no_flush = 0;
0158         } else {
0159             /* DFLTCC buffer is empty, so we can manually write the
0160              * End-of-block Symbol right away.
0161              */
0162             send_eobs(strm, param);
0163             param->bcf = 0;
0164             dfltcc_state->block_threshold =
0165                 strm->total_in + dfltcc_state->block_size;
0166             if (strm->avail_out == 0) {
0167                 *result = need_more;
0168                 return 1;
0169             }
0170         }
0171     }
0172 
0173     /* The caller gave us too much data. Pass only one block worth of
0174      * uncompressed data to DFLTCC and mask the rest, so that on the next
0175      * iteration we start a new block.
0176      */
0177     if (no_flush && strm->avail_in > dfltcc_state->block_size) {
0178         masked_avail_in += (strm->avail_in - dfltcc_state->block_size);
0179         strm->avail_in = dfltcc_state->block_size;
0180     }
0181 
0182     /* When we have an open non-BFINAL deflate block and caller indicates that
0183      * the stream is ending, we need to close an open deflate block and open a
0184      * BFINAL one.
0185      */
0186     need_empty_block = flush == Z_FINISH && param->bcf && !param->bhf;
0187 
0188     /* Translate stream to parameter block */
0189     param->cvt = CVT_ADLER32;
0190     if (!no_flush)
0191         /* We need to close a block. Always do this in software - when there is
0192          * no input data, the hardware will not nohor BCC. */
0193         soft_bcc = 1;
0194     if (flush == Z_FINISH && !param->bcf)
0195         /* We are about to open a BFINAL block, set Block Header Final bit
0196          * until the stream ends.
0197          */
0198         param->bhf = 1;
0199     /* DFLTCC-CMPR will write to next_out, so make sure that buffers with
0200      * higher precedence are empty.
0201      */
0202     Assert(state->pending == 0, "There must be no pending bytes");
0203     Assert(state->bi_valid < 8, "There must be less than 8 pending bits");
0204     param->sbb = (unsigned int)state->bi_valid;
0205     if (param->sbb > 0)
0206         *strm->next_out = (Byte)state->bi_buf;
0207     if (param->hl)
0208         param->nt = 0; /* Honor history */
0209     param->cv = strm->adler;
0210 
0211     /* When opening a block, choose a Huffman-Table Type */
0212     if (!param->bcf) {
0213         if (strm->total_in == 0 && dfltcc_state->block_threshold > 0) {
0214             param->htt = HTT_FIXED;
0215         }
0216         else {
0217             param->htt = HTT_DYNAMIC;
0218             dfltcc_gdht(strm);
0219         }
0220     }
0221 
0222     /* Deflate */
0223     do {
0224         cc = dfltcc_cmpr(strm);
0225         if (strm->avail_in < 4096 && masked_avail_in > 0)
0226             /* We are about to call DFLTCC with a small input buffer, which is
0227              * inefficient. Since there is masked data, there will be at least
0228              * one more DFLTCC call, so skip the current one and make the next
0229              * one handle more data.
0230              */
0231             break;
0232     } while (cc == DFLTCC_CC_AGAIN);
0233 
0234     /* Translate parameter block to stream */
0235     strm->msg = oesc_msg(dfltcc_state->msg, param->oesc);
0236     state->bi_valid = param->sbb;
0237     if (state->bi_valid == 0)
0238         state->bi_buf = 0; /* Avoid accessing next_out */
0239     else
0240         state->bi_buf = *strm->next_out & ((1 << state->bi_valid) - 1);
0241     strm->adler = param->cv;
0242 
0243     /* Unmask the input data */
0244     strm->avail_in += masked_avail_in;
0245     masked_avail_in = 0;
0246 
0247     /* If we encounter an error, it means there is a bug in DFLTCC call */
0248     Assert(cc != DFLTCC_CC_OP2_CORRUPT || param->oesc == 0, "BUG");
0249 
0250     /* Update Block-Continuation Flag. It will be used to check whether to call
0251      * GDHT the next time.
0252      */
0253     if (cc == DFLTCC_CC_OK) {
0254         if (soft_bcc) {
0255             send_eobs(strm, param);
0256             param->bcf = 0;
0257             dfltcc_state->block_threshold =
0258                 strm->total_in + dfltcc_state->block_size;
0259         } else
0260             param->bcf = 1;
0261         if (flush == Z_FINISH) {
0262             if (need_empty_block)
0263                 /* Make the current deflate() call also close the stream */
0264                 return 0;
0265             else {
0266                 bi_windup(state);
0267                 *result = finish_done;
0268             }
0269         } else {
0270             if (flush == Z_FULL_FLUSH)
0271                 param->hl = 0; /* Clear history */
0272             *result = flush == Z_NO_FLUSH ? need_more : block_done;
0273         }
0274     } else {
0275         param->bcf = 1;
0276         *result = need_more;
0277     }
0278     if (strm->avail_in != 0 && strm->avail_out != 0)
0279         goto again; /* deflate() must use all input or all output */
0280     return 1;
0281 }
0282 EXPORT_SYMBOL(dfltcc_deflate);