dfltcc_inflate.c 4.4 KB

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