1 // SPDX-License-Identifier: Zlib 2 3 #include "../zlib_inflate/inflate.h" 4 #include "dfltcc_util.h" 5 #include "dfltcc.h" 6 #include <asm/setup.h> 7 #include <linux/zutil.h> 8 9 /* 10 * Expand. 11 */ 12 int dfltcc_can_inflate( 13 z_streamp strm 14 ) 15 { 16 struct inflate_state *state = (struct inflate_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_DEFLATE_ONLY) 22 return 0; 23 24 /* Unsupported compression settings */ 25 if (state->wbits != HB_BITS) 26 return 0; 27 28 /* Unsupported hardware */ 29 return is_bit_set(dfltcc_state->af.fns, DFLTCC_XPND) && 30 is_bit_set(dfltcc_state->af.fmts, DFLTCC_FMT0); 31 } 32 33 static int dfltcc_was_inflate_used( 34 z_streamp strm 35 ) 36 { 37 struct inflate_state *state = (struct inflate_state *)strm->state; 38 struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param; 39 40 return !param->nt; 41 } 42 43 static int dfltcc_inflate_disable( 44 z_streamp strm 45 ) 46 { 47 struct inflate_state *state = (struct inflate_state *)strm->state; 48 struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state); 49 50 if (!dfltcc_can_inflate(strm)) 51 return 0; 52 if (dfltcc_was_inflate_used(strm)) 53 /* DFLTCC has already decompressed some data. Since there is not 54 * enough information to resume decompression in software, the call 55 * must fail. 56 */ 57 return 1; 58 /* DFLTCC was not used yet - decompress in software */ 59 memset(&dfltcc_state->af, 0, sizeof(dfltcc_state->af)); 60 return 0; 61 } 62 63 static dfltcc_cc dfltcc_xpnd( 64 z_streamp strm 65 ) 66 { 67 struct inflate_state *state = (struct inflate_state *)strm->state; 68 struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param; 69 size_t avail_in = strm->avail_in; 70 size_t avail_out = strm->avail_out; 71 dfltcc_cc cc; 72 73 cc = dfltcc(DFLTCC_XPND | HBT_CIRCULAR, 74 param, &strm->next_out, &avail_out, 75 &strm->next_in, &avail_in, state->window); 76 strm->avail_in = avail_in; 77 strm->avail_out = avail_out; 78 return cc; 79 } 80 81 dfltcc_inflate_action dfltcc_inflate( 82 z_streamp strm, 83 int flush, 84 int *ret 85 ) 86 { 87 struct inflate_state *state = (struct inflate_state *)strm->state; 88 struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state); 89 struct dfltcc_param_v0 *param = &dfltcc_state->param; 90 dfltcc_cc cc; 91 92 if (flush == Z_BLOCK) { 93 /* DFLTCC does not support stopping on block boundaries */ 94 if (dfltcc_inflate_disable(strm)) { 95 *ret = Z_STREAM_ERROR; 96 return DFLTCC_INFLATE_BREAK; 97 } else 98 return DFLTCC_INFLATE_SOFTWARE; 99 } 100 101 if (state->last) { 102 if (state->bits != 0) { 103 strm->next_in++; 104 strm->avail_in--; 105 state->bits = 0; 106 } 107 state->mode = CHECK; 108 return DFLTCC_INFLATE_CONTINUE; 109 } 110 111 if (strm->avail_in == 0 && !param->cf) 112 return DFLTCC_INFLATE_BREAK; 113 114 if (!state->window || state->wsize == 0) { 115 state->mode = MEM; 116 return DFLTCC_INFLATE_CONTINUE; 117 } 118 119 /* Translate stream to parameter block */ 120 param->cvt = CVT_ADLER32; 121 param->sbb = state->bits; 122 param->hl = state->whave; /* Software and hardware history formats match */ 123 param->ho = (state->write - state->whave) & ((1 << HB_BITS) - 1); 124 if (param->hl) 125 param->nt = 0; /* Honor history for the first block */ 126 param->cv = state->flags ? REVERSE(state->check) : state->check; 127 128 /* Inflate */ 129 do { 130 cc = dfltcc_xpnd(strm); 131 } while (cc == DFLTCC_CC_AGAIN); 132 133 /* Translate parameter block to stream */ 134 strm->msg = oesc_msg(dfltcc_state->msg, param->oesc); 135 state->last = cc == DFLTCC_CC_OK; 136 state->bits = param->sbb; 137 state->whave = param->hl; 138 state->write = (param->ho + param->hl) & ((1 << HB_BITS) - 1); 139 state->check = state->flags ? REVERSE(param->cv) : param->cv; 140 if (cc == DFLTCC_CC_OP2_CORRUPT && param->oesc != 0) { 141 /* Report an error if stream is corrupted */ 142 state->mode = BAD; 143 return DFLTCC_INFLATE_CONTINUE; 144 } 145 state->mode = TYPEDO; 146 /* Break if operands are exhausted, otherwise continue looping */ 147 return (cc == DFLTCC_CC_OP1_TOO_SHORT || cc == DFLTCC_CC_OP2_TOO_SHORT) ? 148 DFLTCC_INFLATE_BREAK : DFLTCC_INFLATE_CONTINUE; 149 } 150