cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dfltcc_deflate.c (9273B)


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