From e1d7e6dc9698968a8536b00ebd9e9b4e429b4306 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Wed, 27 Apr 2022 14:37:24 +0200 Subject: [PATCH] zlib-1.2.12-IBM-Z-hw-accelrated-deflate-s390x.patch --- Makefile.in | 8 + compress.c | 14 +- configure | 24 + contrib/README.contrib | 4 + contrib/s390/README.txt | 17 + contrib/s390/dfltcc.c | 996 ++++++++++++++++++++++++++++++++++ contrib/s390/dfltcc.h | 81 +++ contrib/s390/dfltcc_deflate.h | 55 ++ deflate.c | 81 ++- deflate.h | 12 + gzguts.h | 4 + inflate.c | 87 ++- inflate.h | 2 + test/infcover.c | 4 +- test/minigzip.c | 4 + trees.c | 13 +- zutil.h | 2 + 17 files changed, 1348 insertions(+), 60 deletions(-) create mode 100644 contrib/s390/README.txt create mode 100644 contrib/s390/dfltcc.c create mode 100644 contrib/s390/dfltcc.h create mode 100644 contrib/s390/dfltcc_deflate.h Index: zlib-1.2.12/Makefile.in =================================================================== --- zlib-1.2.12.orig/Makefile.in +++ zlib-1.2.12/Makefile.in @@ -143,6 +143,14 @@ match.lo: match.S mv _match.o match.lo rm -f _match.s +dfltcc.o: $(SRCDIR)contrib/s390/dfltcc.c $(SRCDIR)zlib.h zconf.h + $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)contrib/s390/dfltcc.c + +dfltcc.lo: $(SRCDIR)contrib/s390/dfltcc.c $(SRCDIR)zlib.h zconf.h + -@mkdir objs 2>/dev/null || test -d objs + $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/dfltcc.o $(SRCDIR)contrib/s390/dfltcc.c + -@mv objs/dfltcc.o $@ + example.o: $(SRCDIR)test/example.c $(SRCDIR)zlib.h zconf.h $(CC) $(CFLAGS) $(ZINCOUT) -c -o $@ $(SRCDIR)test/example.c Index: zlib-1.2.12/compress.c =================================================================== --- zlib-1.2.12.orig/compress.c +++ zlib-1.2.12/compress.c @@ -5,9 +5,15 @@ /* @(#) $Id$ */ -#define ZLIB_INTERNAL +#include "zutil.h" #include "zlib.h" +#ifdef DFLTCC +# include "contrib/s390/dfltcc.h" +#else +#define DEFLATE_BOUND_COMPLEN(source_len) 0 +#endif + /* =========================================================================== Compresses the source buffer into the destination buffer. The level parameter has the same meaning as in deflateInit. sourceLen is the byte @@ -81,6 +87,12 @@ int ZEXPORT compress (dest, destLen, sou uLong ZEXPORT compressBound (sourceLen) uLong sourceLen; { + uLong complen = DEFLATE_BOUND_COMPLEN(sourceLen); + + if (complen > 0) + /* Architecture-specific code provided an upper bound. */ + return complen + ZLIB_WRAPLEN; + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13; } Index: zlib-1.2.12/configure =================================================================== --- zlib-1.2.12.orig/configure +++ zlib-1.2.12/configure @@ -115,6 +115,7 @@ case "$1" in echo ' configure [--const] [--zprefix] [--prefix=PREFIX] [--eprefix=EXPREFIX]' | tee -a configure.log echo ' [--static] [--64] [--libdir=LIBDIR] [--sharedlibdir=LIBDIR]' | tee -a configure.log echo ' [--includedir=INCLUDEDIR] [--archs="-arch i386 -arch x86_64"]' | tee -a configure.log + echo ' [--dfltcc] [--dfltcc-level-mask=MASK]' | tee -a configure.log exit 0 ;; -p*=* | --prefix=*) prefix=`echo $1 | sed 's/.*=//'`; shift ;; -e*=* | --eprefix=*) exec_prefix=`echo $1 | sed 's/.*=//'`; shift ;; @@ -139,6 +140,16 @@ case "$1" in -w* | --warn) warn=1; shift ;; -d* | --debug) debug=1; shift ;; --sanitize) sanitize=1; shift ;; + --dfltcc) + CFLAGS="$CFLAGS -DDFLTCC" + OBJC="$OBJC dfltcc.o" + PIC_OBJC="$PIC_OBJC dfltcc.lo" + shift + ;; + --dfltcc-level-mask=*) + CFLAGS="$CFLAGS -DDFLTCC_LEVEL_MASK=`echo $1 | sed 's/.*=//'`" + shift + ;; *) echo "unknown option: $1" | tee -a configure.log echo "$0 --help for help" | tee -a configure.log @@ -833,6 +844,19 @@ EOF fi fi +# Check whether sys/sdt.h is available +cat > $test.c << EOF +#include +int main() { return 0; } +EOF +if try $CC -c $CFLAGS $test.c; then + echo "Checking for sys/sdt.h ... Yes." | tee -a configure.log + CFLAGS="$CFLAGS -DHAVE_SYS_SDT_H" + SFLAGS="$SFLAGS -DHAVE_SYS_SDT_H" +else + echo "Checking for sys/sdt.h ... No." | tee -a configure.log +fi + # show the results in the log echo >> configure.log echo ALL = $ALL >> configure.log Index: zlib-1.2.12/contrib/README.contrib =================================================================== --- zlib-1.2.12.orig/contrib/README.contrib +++ zlib-1.2.12/contrib/README.contrib @@ -46,6 +46,10 @@ puff/ by Mark Adler + Hardware-accelerated deflate on IBM Z with DEFLATE CONVERSION CALL + instruction. + testzlib/ by Gilles Vollant Example of the use of zlib Index: zlib-1.2.12/contrib/s390/README.txt =================================================================== --- /dev/null +++ zlib-1.2.12/contrib/s390/README.txt @@ -0,0 +1,17 @@ +IBM Z mainframes starting from version z15 provide DFLTCC instruction, +which implements deflate algorithm in hardware with estimated +compression and decompression performance orders of magnitude faster +than the current zlib and ratio comparable with that of level 1. + +This directory adds DFLTCC support. In order to enable it, the following +build commands should be used: + + $ ./configure --dfltcc + $ make + +When built like this, zlib would compress in hardware on level 1, and in +software on all other levels. Decompression will always happen in +hardware. In order to enable DFLTCC compression for levels 1-6 (i.e. to +make it used by default) one could either configure with +--dfltcc-level-mask=0x7e or set the environment variable +DFLTCC_LEVEL_MASK to 0x7e at run time. Index: zlib-1.2.12/contrib/s390/dfltcc.c =================================================================== --- /dev/null +++ zlib-1.2.12/contrib/s390/dfltcc.c @@ -0,0 +1,996 @@ +/* dfltcc.c - SystemZ DEFLATE CONVERSION CALL support. */ + +/* + Use the following commands to build zlib with DFLTCC support: + + $ ./configure --dfltcc + $ make +*/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include "../../zutil.h" +#include "../../deflate.h" +#include "../../inftrees.h" +#include "../../inflate.h" +#include "dfltcc.h" +#include "dfltcc_deflate.h" +#ifdef HAVE_SYS_SDT_H +#include +#endif + +/* + C wrapper for the DEFLATE CONVERSION CALL instruction. + */ +typedef enum { + DFLTCC_CC_OK = 0, + DFLTCC_CC_OP1_TOO_SHORT = 1, + DFLTCC_CC_OP2_TOO_SHORT = 2, + DFLTCC_CC_OP2_CORRUPT = 2, + DFLTCC_CC_AGAIN = 3, +} dfltcc_cc; + +#define DFLTCC_QAF 0 +#define DFLTCC_GDHT 1 +#define DFLTCC_CMPR 2 +#define DFLTCC_XPND 4 +#define HBT_CIRCULAR (1 << 7) +#define HB_BITS 15 +#define HB_SIZE (1 << HB_BITS) +#define DFLTCC_FACILITY 151 + +local inline dfltcc_cc dfltcc OF((int fn, void *param, + Bytef **op1, size_t *len1, + z_const Bytef **op2, size_t *len2, + void *hist)); +local inline dfltcc_cc dfltcc(fn, param, op1, len1, op2, len2, hist) + int fn; + void *param; + Bytef **op1; + size_t *len1; + z_const Bytef **op2; + size_t *len2; + void *hist; +{ + Bytef *t2 = op1 ? *op1 : NULL; + size_t t3 = len1 ? *len1 : 0; + z_const Bytef *t4 = op2 ? *op2 : NULL; + size_t t5 = len2 ? *len2 : 0; + register int r0 __asm__("r0") = fn; + register void *r1 __asm__("r1") = param; + register Bytef *r2 __asm__("r2") = t2; + register size_t r3 __asm__("r3") = t3; + register z_const Bytef *r4 __asm__("r4") = t4; + register size_t r5 __asm__("r5") = t5; + int cc; + + __asm__ volatile( +#ifdef HAVE_SYS_SDT_H + STAP_PROBE_ASM(zlib, dfltcc_entry, + STAP_PROBE_ASM_TEMPLATE(5)) +#endif + ".insn rrf,0xb9390000,%[r2],%[r4],%[hist],0\n" +#ifdef HAVE_SYS_SDT_H + STAP_PROBE_ASM(zlib, dfltcc_exit, + STAP_PROBE_ASM_TEMPLATE(5)) +#endif + "ipm %[cc]\n" + : [r2] "+r" (r2) + , [r3] "+r" (r3) + , [r4] "+r" (r4) + , [r5] "+r" (r5) + , [cc] "=r" (cc) + : [r0] "r" (r0) + , [r1] "r" (r1) + , [hist] "r" (hist) +#ifdef HAVE_SYS_SDT_H + , STAP_PROBE_ASM_OPERANDS(5, r2, r3, r4, r5, hist) +#endif + : "cc", "memory"); + t2 = r2; t3 = r3; t4 = r4; t5 = r5; + + if (op1) + *op1 = t2; + if (len1) + *len1 = t3; + if (op2) + *op2 = t4; + if (len2) + *len2 = t5; + return (cc >> 28) & 3; +} + +/* + Parameter Block for Query Available Functions. + */ +#define static_assert(c, msg) \ + __attribute__((unused)) \ + static char static_assert_failed_ ## msg[c ? 1 : -1] + +struct dfltcc_qaf_param { + char fns[16]; + char reserved1[8]; + char fmts[2]; + char reserved2[6]; +}; + +static_assert(sizeof(struct dfltcc_qaf_param) == 32, + sizeof_struct_dfltcc_qaf_param_is_32); + +local inline int is_bit_set OF((const char *bits, int n)); +local inline int is_bit_set(bits, n) + const char *bits; + int n; +{ + return bits[n / 8] & (1 << (7 - (n % 8))); +} + +local inline void clear_bit OF((char *bits, int n)); +local inline void clear_bit(bits, n) + char *bits; + int n; +{ + bits[n / 8] &= ~(1 << (7 - (n % 8))); +} + +#define DFLTCC_FMT0 0 + +/* + Parameter Block for Generate Dynamic-Huffman Table, Compress and Expand. + */ +#define CVT_CRC32 0 +#define CVT_ADLER32 1 +#define HTT_FIXED 0 +#define HTT_DYNAMIC 1 + +struct dfltcc_param_v0 { + uint16_t pbvn; /* Parameter-Block-Version Number */ + uint8_t mvn; /* Model-Version Number */ + uint8_t ribm; /* Reserved for IBM use */ + unsigned reserved32 : 31; + unsigned cf : 1; /* Continuation Flag */ + uint8_t reserved64[8]; + unsigned nt : 1; /* New Task */ + unsigned reserved129 : 1; + unsigned cvt : 1; /* Check Value Type */ + unsigned reserved131 : 1; + unsigned htt : 1; /* Huffman-Table Type */ + unsigned bcf : 1; /* Block-Continuation Flag */ + unsigned bcc : 1; /* Block Closing Control */ + unsigned bhf : 1; /* Block Header Final */ + unsigned reserved136 : 1; + unsigned reserved137 : 1; + unsigned dhtgc : 1; /* DHT Generation Control */ + unsigned reserved139 : 5; + unsigned reserved144 : 5; + unsigned sbb : 3; /* Sub-Byte Boundary */ + uint8_t oesc; /* Operation-Ending-Supplemental Code */ + unsigned reserved160 : 12; + unsigned ifs : 4; /* Incomplete-Function Status */ + uint16_t ifl; /* Incomplete-Function Length */ + uint8_t reserved192[8]; + uint8_t reserved256[8]; + uint8_t reserved320[4]; + uint16_t hl; /* History Length */ + unsigned reserved368 : 1; + uint16_t ho : 15; /* History Offset */ + uint32_t cv; /* Check Value */ + unsigned eobs : 15; /* End-of-block Symbol */ + unsigned reserved431: 1; + uint8_t eobl : 4; /* End-of-block Length */ + unsigned reserved436 : 12; + unsigned reserved448 : 4; + uint16_t cdhtl : 12; /* Compressed-Dynamic-Huffman Table + Length */ + uint8_t reserved464[6]; + uint8_t cdht[288]; + uint8_t reserved[32]; + uint8_t csb[1152]; +}; + +static_assert(sizeof(struct dfltcc_param_v0) == 1536, + sizeof_struct_dfltcc_param_v0_is_1536); + +local z_const char *oesc_msg OF((char *buf, int oesc)); +local z_const char *oesc_msg(buf, oesc) + char *buf; + int oesc; +{ + if (oesc == 0x00) + return NULL; /* Successful completion */ + else { + sprintf(buf, "Operation-Ending-Supplemental Code is 0x%.2X", oesc); + return buf; + } +} + +/* + Extension of inflate_state and deflate_state. Must be doubleword-aligned. +*/ +struct dfltcc_state { + struct dfltcc_param_v0 param; /* Parameter block. */ + struct dfltcc_qaf_param af; /* Available functions. */ + uLong level_mask; /* Levels on which to use DFLTCC */ + uLong block_size; /* New block each X bytes */ + uLong block_threshold; /* New block after total_in > X */ + uLong dht_threshold; /* New block only if avail_in >= X */ + char msg[64]; /* Buffer for strm->msg */ +}; + +#define ALIGN_UP(p, size) \ + (__typeof__(p))(((uintptr_t)(p) + ((size) - 1)) & ~((size) - 1)) + +#define GET_DFLTCC_STATE(state) ((struct dfltcc_state FAR *)( \ + (char FAR *)(state) + ALIGN_UP(sizeof(*state), 8))) + +/* + Compress. + */ +local inline int dfltcc_can_deflate_with_params(z_streamp strm, + int level, + uInt window_bits, + int strategy); +local inline int dfltcc_can_deflate_with_params(strm, + level, + window_bits, + strategy) + z_streamp strm; + int level; + uInt window_bits; + int strategy; +{ + deflate_state FAR *state = (deflate_state FAR *)strm->state; + struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state); + + /* Unsupported compression settings */ + if ((dfltcc_state->level_mask & (1 << level)) == 0) + return 0; + if (window_bits != HB_BITS) + return 0; + if (strategy != Z_FIXED && strategy != Z_DEFAULT_STRATEGY) + return 0; + + /* Unsupported hardware */ + if (!is_bit_set(dfltcc_state->af.fns, DFLTCC_GDHT) || + !is_bit_set(dfltcc_state->af.fns, DFLTCC_CMPR) || + !is_bit_set(dfltcc_state->af.fmts, DFLTCC_FMT0)) + return 0; + + return 1; +} + +int ZLIB_INTERNAL dfltcc_can_deflate(strm) + z_streamp strm; +{ + deflate_state FAR *state = (deflate_state FAR *)strm->state; + + return dfltcc_can_deflate_with_params(strm, + state->level, + state->w_bits, + state->strategy); +} + +local void dfltcc_gdht OF((z_streamp strm)); +local void dfltcc_gdht(strm) + z_streamp strm; +{ + deflate_state FAR *state = (deflate_state FAR *)strm->state; + struct dfltcc_param_v0 FAR *param = &GET_DFLTCC_STATE(state)->param; + size_t avail_in = avail_in = strm->avail_in; + + dfltcc(DFLTCC_GDHT, + param, NULL, NULL, + &strm->next_in, &avail_in, NULL); +} + +local dfltcc_cc dfltcc_cmpr OF((z_streamp strm)); +local dfltcc_cc dfltcc_cmpr(strm) + z_streamp strm; +{ + deflate_state FAR *state = (deflate_state FAR *)strm->state; + struct dfltcc_param_v0 FAR *param = &GET_DFLTCC_STATE(state)->param; + size_t avail_in = strm->avail_in; + size_t avail_out = strm->avail_out; + dfltcc_cc cc; + + cc = dfltcc(DFLTCC_CMPR | HBT_CIRCULAR, + param, &strm->next_out, &avail_out, + &strm->next_in, &avail_in, state->window); + strm->total_in += (strm->avail_in - avail_in); + strm->total_out += (strm->avail_out - avail_out); + strm->avail_in = avail_in; + strm->avail_out = avail_out; + return cc; +} + +local void send_eobs OF((z_streamp strm, + z_const struct dfltcc_param_v0 FAR *param)); +local void send_eobs(strm, param) + z_streamp strm; + z_const struct dfltcc_param_v0 FAR *param; +{ + deflate_state FAR *state = (deflate_state FAR *)strm->state; + + _tr_send_bits( + state, + bi_reverse(param->eobs >> (15 - param->eobl), param->eobl), + param->eobl); + flush_pending(strm); + if (state->pending != 0) { + /* The remaining data is located in pending_out[0:pending]. If someone + * calls put_byte() - this might happen in deflate() - the byte will be + * placed into pending_buf[pending], which is incorrect. Move the + * remaining data to the beginning of pending_buf so that put_byte() is + * usable again. + */ + memmove(state->pending_buf, state->pending_out, state->pending); + state->pending_out = state->pending_buf; + } +#ifdef ZLIB_DEBUG + state->compressed_len += param->eobl; +#endif +} + +int ZLIB_INTERNAL dfltcc_deflate(strm, flush, result) + z_streamp strm; + int flush; + block_state *result; +{ + deflate_state FAR *state = (deflate_state FAR *)strm->state; + struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state); + struct dfltcc_param_v0 FAR *param = &dfltcc_state->param; + uInt masked_avail_in; + dfltcc_cc cc; + int need_empty_block; + int soft_bcc; + int no_flush; + + if (!dfltcc_can_deflate(strm)) { + /* Clear history. */ + if (flush == Z_FULL_FLUSH) + param->hl = 0; + return 0; + } + +again: + masked_avail_in = 0; + soft_bcc = 0; + no_flush = flush == Z_NO_FLUSH; + + /* No input data. Return, except when Continuation Flag is set, which means + * that DFLTCC has buffered some output in the parameter block and needs to + * be called again in order to flush it. + */ + if (strm->avail_in == 0 && !param->cf) { + /* A block is still open, and the hardware does not support closing + * blocks without adding data. Thus, close it manually. + */ + if (!no_flush && param->bcf) { + send_eobs(strm, param); + param->bcf = 0; + } + /* Let one of deflate_* functions write a trailing empty block. */ + if (flush == Z_FINISH) + return 0; + /* Clear history. */ + if (flush == Z_FULL_FLUSH) + param->hl = 0; + /* Trigger block post-processing if necessary. */ + *result = no_flush ? need_more : block_done; + return 1; + } + + /* There is an open non-BFINAL block, we are not going to close it just + * yet, we have compressed more than DFLTCC_BLOCK_SIZE bytes and we see + * more than DFLTCC_DHT_MIN_SAMPLE_SIZE bytes. Open a new block with a new + * DHT in order to adapt to a possibly changed input data distribution. + */ + if (param->bcf && no_flush && + strm->total_in > dfltcc_state->block_threshold && + strm->avail_in >= dfltcc_state->dht_threshold) { + if (param->cf) { + /* We need to flush the DFLTCC buffer before writing the + * End-of-block Symbol. Mask the input data and proceed as usual. + */ + masked_avail_in += strm->avail_in; + strm->avail_in = 0; + no_flush = 0; + } else { + /* DFLTCC buffer is empty, so we can manually write the + * End-of-block Symbol right away. + */ + send_eobs(strm, param); + param->bcf = 0; + dfltcc_state->block_threshold = + strm->total_in + dfltcc_state->block_size; + } + } + + /* No space for compressed data. If we proceed, dfltcc_cmpr() will return + * DFLTCC_CC_OP1_TOO_SHORT without buffering header bits, but we will still + * set BCF=1, which is wrong. Avoid complications and return early. + */ + if (strm->avail_out == 0) { + *result = need_more; + return 1; + } + + /* The caller gave us too much data. Pass only one block worth of + * uncompressed data to DFLTCC and mask the rest, so that on the next + * iteration we start a new block. + */ + if (no_flush && strm->avail_in > dfltcc_state->block_size) { + masked_avail_in += (strm->avail_in - dfltcc_state->block_size); + strm->avail_in = dfltcc_state->block_size; + } + + /* When we have an open non-BFINAL deflate block and caller indicates that + * the stream is ending, we need to close an open deflate block and open a + * BFINAL one. + */ + need_empty_block = flush == Z_FINISH && param->bcf && !param->bhf; + + /* Translate stream to parameter block */ + param->cvt = state->wrap == 2 ? CVT_CRC32 : CVT_ADLER32; + if (!no_flush) + /* We need to close a block. Always do this in software - when there is + * no input data, the hardware will not honor BCC. */ + soft_bcc = 1; + if (flush == Z_FINISH && !param->bcf) + /* We are about to open a BFINAL block, set Block Header Final bit + * until the stream ends. + */ + param->bhf = 1; + /* DFLTCC-CMPR will write to next_out, so make sure that buffers with + * higher precedence are empty. + */ + Assert(state->pending == 0, "There must be no pending bytes"); + Assert(state->bi_valid < 8, "There must be less than 8 pending bits"); + param->sbb = (unsigned int)state->bi_valid; + if (param->sbb > 0) + *strm->next_out = (Bytef)state->bi_buf; + /* Honor history and check value */ + param->nt = 0; + param->cv = state->wrap == 2 ? ZSWAP32(strm->adler) : strm->adler; + + /* When opening a block, choose a Huffman-Table Type */ + if (!param->bcf) { + if (state->strategy == Z_FIXED || + (strm->total_in == 0 && dfltcc_state->block_threshold > 0)) + param->htt = HTT_FIXED; + else { + param->htt = HTT_DYNAMIC; + dfltcc_gdht(strm); + } + } + + /* Deflate */ + do { + cc = dfltcc_cmpr(strm); + if (strm->avail_in < 4096 && masked_avail_in > 0) + /* We are about to call DFLTCC with a small input buffer, which is + * inefficient. Since there is masked data, there will be at least + * one more DFLTCC call, so skip the current one and make the next + * one handle more data. + */ + break; + } while (cc == DFLTCC_CC_AGAIN); + + /* Translate parameter block to stream */ + strm->msg = oesc_msg(dfltcc_state->msg, param->oesc); + state->bi_valid = param->sbb; + if (state->bi_valid == 0) + state->bi_buf = 0; /* Avoid accessing next_out */ + else + state->bi_buf = *strm->next_out & ((1 << state->bi_valid) - 1); + strm->adler = state->wrap == 2 ? ZSWAP32(param->cv) : param->cv; + + /* Unmask the input data */ + strm->avail_in += masked_avail_in; + masked_avail_in = 0; + + /* If we encounter an error, it means there is a bug in DFLTCC call */ + Assert(cc != DFLTCC_CC_OP2_CORRUPT || param->oesc == 0, "BUG"); + + /* Update Block-Continuation Flag. It will be used to check whether to call + * GDHT the next time. + */ + if (cc == DFLTCC_CC_OK) { + if (soft_bcc) { + send_eobs(strm, param); + param->bcf = 0; + dfltcc_state->block_threshold = + strm->total_in + dfltcc_state->block_size; + } else + param->bcf = 1; + if (flush == Z_FINISH) { + if (need_empty_block) + /* Make the current deflate() call also close the stream */ + return 0; + else { + bi_windup(state); + *result = finish_done; + } + } else { + if (flush == Z_FULL_FLUSH) + param->hl = 0; /* Clear history */ + *result = flush == Z_NO_FLUSH ? need_more : block_done; + } + } else { + param->bcf = 1; + *result = need_more; + } + if (strm->avail_in != 0 && strm->avail_out != 0) + goto again; /* deflate() must use all input or all output */ + return 1; +} + +/* + Expand. + */ +int ZLIB_INTERNAL dfltcc_can_inflate(strm) + z_streamp strm; +{ + struct inflate_state FAR *state = (struct inflate_state FAR *)strm->state; + struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state); + + /* Unsupported compression settings */ + if (state->wbits != HB_BITS) + return 0; + + /* Unsupported hardware */ + return is_bit_set(dfltcc_state->af.fns, DFLTCC_XPND) && + is_bit_set(dfltcc_state->af.fmts, DFLTCC_FMT0); +} + +local dfltcc_cc dfltcc_xpnd OF((z_streamp strm)); +local dfltcc_cc dfltcc_xpnd(strm) + z_streamp strm; +{ + struct inflate_state FAR *state = (struct inflate_state FAR *)strm->state; + struct dfltcc_param_v0 FAR *param = &GET_DFLTCC_STATE(state)->param; + size_t avail_in = strm->avail_in; + size_t avail_out = strm->avail_out; + dfltcc_cc cc; + + cc = dfltcc(DFLTCC_XPND | HBT_CIRCULAR, + param, &strm->next_out, &avail_out, + &strm->next_in, &avail_in, state->window); + strm->avail_in = avail_in; + strm->avail_out = avail_out; + return cc; +} + +dfltcc_inflate_action ZLIB_INTERNAL dfltcc_inflate(strm, flush, ret) + z_streamp strm; + int flush; + int *ret; +{ + struct inflate_state FAR *state = (struct inflate_state FAR *)strm->state; + struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state); + struct dfltcc_param_v0 FAR *param = &dfltcc_state->param; + dfltcc_cc cc; + + if (flush == Z_BLOCK || flush == Z_TREES) { + /* DFLTCC does not support stopping on block boundaries */ + if (dfltcc_inflate_disable(strm)) { + *ret = Z_STREAM_ERROR; + return DFLTCC_INFLATE_BREAK; + } else + return DFLTCC_INFLATE_SOFTWARE; + } + + if (state->last) { + if (state->bits != 0) { + strm->next_in++; + strm->avail_in--; + state->bits = 0; + } + state->mode = CHECK; + return DFLTCC_INFLATE_CONTINUE; + } + + if (strm->avail_in == 0 && !param->cf) + return DFLTCC_INFLATE_BREAK; + + if (inflate_ensure_window(state)) { + state->mode = MEM; + return DFLTCC_INFLATE_CONTINUE; + } + + /* Translate stream to parameter block */ + param->cvt = state->flags ? CVT_CRC32 : CVT_ADLER32; + param->sbb = state->bits; + param->hl = state->whave; /* Software and hardware history formats match */ + param->ho = (state->wnext - state->whave) & ((1 << HB_BITS) - 1); + if (param->hl) + param->nt = 0; /* Honor history for the first block */ + param->cv = state->flags ? ZSWAP32(state->check) : state->check; + + /* Inflate */ + do { + cc = dfltcc_xpnd(strm); + } while (cc == DFLTCC_CC_AGAIN); + + /* Translate parameter block to stream */ + strm->msg = oesc_msg(dfltcc_state->msg, param->oesc); + state->last = cc == DFLTCC_CC_OK; + state->bits = param->sbb; + state->whave = param->hl; + state->wnext = (param->ho + param->hl) & ((1 << HB_BITS) - 1); + state->check = state->flags ? ZSWAP32(param->cv) : param->cv; + if (cc == DFLTCC_CC_OP2_CORRUPT && param->oesc != 0) { + /* Report an error if stream is corrupted */ + state->mode = BAD; + return DFLTCC_INFLATE_CONTINUE; + } + state->mode = TYPEDO; + /* Break if operands are exhausted, otherwise continue looping */ + return (cc == DFLTCC_CC_OP1_TOO_SHORT || cc == DFLTCC_CC_OP2_TOO_SHORT) ? + DFLTCC_INFLATE_BREAK : DFLTCC_INFLATE_CONTINUE; +} + +int ZLIB_INTERNAL dfltcc_was_inflate_used(strm) + z_streamp strm; +{ + struct inflate_state FAR *state = (struct inflate_state FAR *)strm->state; + struct dfltcc_param_v0 FAR *param = &GET_DFLTCC_STATE(state)->param; + + return !param->nt; +} + +int ZLIB_INTERNAL dfltcc_inflate_disable(strm) + z_streamp strm; +{ + struct inflate_state FAR *state = (struct inflate_state FAR *)strm->state; + struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state); + + if (!dfltcc_can_inflate(strm)) + return 0; + if (dfltcc_was_inflate_used(strm)) + /* DFLTCC has already decompressed some data. Since there is not + * enough information to resume decompression in software, the call + * must fail. + */ + return 1; + /* DFLTCC was not used yet - decompress in software */ + memset(&dfltcc_state->af, 0, sizeof(dfltcc_state->af)); + return 0; +} + +local int env_dfltcc_disabled; +local int env_source_date_epoch; +local unsigned long env_level_mask; +local unsigned long env_block_size; +local unsigned long env_block_threshold; +local unsigned long env_dht_threshold; +local unsigned long env_ribm; +local uint64_t cpu_facilities[(DFLTCC_FACILITY / 64) + 1]; +local struct dfltcc_qaf_param cpu_af __attribute__((aligned(8))); + +local inline int is_dfltcc_enabled OF((void)); +local inline int is_dfltcc_enabled(void) +{ + if (env_dfltcc_disabled) + /* User has explicitly disabled DFLTCC. */ + return 0; + + return is_bit_set((const char *)cpu_facilities, DFLTCC_FACILITY); +} + +local unsigned long xstrtoul OF((const char *s, unsigned long _default)); +local unsigned long xstrtoul(s, _default) + const char *s; + unsigned long _default; +{ + char *endptr; + unsigned long result; + + if (!(s && *s)) + return _default; + errno = 0; + result = strtoul(s, &endptr, 0); + return (errno || *endptr) ? _default : result; +} + +__attribute__((constructor)) local void init_globals OF((void)); +__attribute__((constructor)) local void init_globals(void) +{ + const char *endptr; + const char *env; + register char r0 __asm__("r0"); + + env = secure_getenv("DFLTCC"); + env_dfltcc_disabled = env && !strcmp(env, "0"); + + env = secure_getenv("SOURCE_DATE_EPOCH"); + env_source_date_epoch = !!env; + +#ifndef DFLTCC_LEVEL_MASK +#define DFLTCC_LEVEL_MASK 0x2 +#endif + env_level_mask = xstrtoul(secure_getenv("DFLTCC_LEVEL_MASK"), + DFLTCC_LEVEL_MASK); + +#ifndef DFLTCC_BLOCK_SIZE +#define DFLTCC_BLOCK_SIZE 1048576 +#endif + env_block_size = xstrtoul(secure_getenv("DFLTCC_BLOCK_SIZE"), + DFLTCC_BLOCK_SIZE); + +#ifndef DFLTCC_FIRST_FHT_BLOCK_SIZE +#define DFLTCC_FIRST_FHT_BLOCK_SIZE 4096 +#endif + env_block_threshold = xstrtoul(secure_getenv("DFLTCC_FIRST_FHT_BLOCK_SIZE"), + DFLTCC_FIRST_FHT_BLOCK_SIZE); + +#ifndef DFLTCC_DHT_MIN_SAMPLE_SIZE +#define DFLTCC_DHT_MIN_SAMPLE_SIZE 4096 +#endif + env_dht_threshold = xstrtoul(secure_getenv("DFLTCC_DHT_MIN_SAMPLE_SIZE"), + DFLTCC_DHT_MIN_SAMPLE_SIZE); + +#ifndef DFLTCC_RIBM +#define DFLTCC_RIBM 0 +#endif + env_ribm = xstrtoul(secure_getenv("DFLTCC_RIBM"), DFLTCC_RIBM); + + memset(cpu_facilities, 0, sizeof(cpu_facilities)); + r0 = sizeof(cpu_facilities) / sizeof(cpu_facilities[0]) - 1; + /* STFLE is supported since z9-109 and only in z/Architecture mode. When + * compiling with -m31, gcc defaults to ESA mode, however, since the kernel + * is 64-bit, it's always z/Architecture mode at runtime. + */ + __asm__ volatile( +#ifndef __clang__ + ".machinemode push\n" + ".machinemode zarch\n" +#endif + "stfle %[facilities]\n" +#ifndef __clang__ + ".machinemode pop\n" +#endif + : [facilities] "=Q" (cpu_facilities) + , [r0] "+r" (r0) + : + : "cc"); + + /* Initialize available functions */ + if (is_dfltcc_enabled()) + dfltcc(DFLTCC_QAF, &cpu_af, NULL, NULL, NULL, NULL, NULL); + else + memset(&cpu_af, 0, sizeof(cpu_af)); +} + +/* + Memory management. + + DFLTCC requires parameter blocks and window to be aligned. zlib allows + users to specify their own allocation functions, so using e.g. + `posix_memalign' is not an option. Thus, we overallocate and take the + aligned portion of the buffer. +*/ +void ZLIB_INTERNAL dfltcc_reset(strm, size) + z_streamp strm; + uInt size; +{ + struct dfltcc_state *dfltcc_state = + (struct dfltcc_state *)((char FAR *)strm->state + ALIGN_UP(size, 8)); + + memcpy(&dfltcc_state->af, &cpu_af, sizeof(dfltcc_state->af)); + + if (env_source_date_epoch) + /* User needs reproducible results, but the output of DFLTCC_CMPR + * depends on buffers' page offsets. + */ + clear_bit(dfltcc_state->af.fns, DFLTCC_CMPR); + + /* Initialize parameter block */ + memset(&dfltcc_state->param, 0, sizeof(dfltcc_state->param)); + dfltcc_state->param.nt = 1; + + /* Initialize tuning parameters */ + dfltcc_state->level_mask = env_level_mask; + dfltcc_state->block_size = env_block_size; + dfltcc_state->block_threshold = env_block_threshold; + dfltcc_state->dht_threshold = env_dht_threshold; + dfltcc_state->param.ribm = env_ribm; +} + +voidpf ZLIB_INTERNAL dfltcc_alloc_state(strm, items, size) + z_streamp strm; + uInt items; + uInt size; +{ + return ZALLOC(strm, + ALIGN_UP(items * size, 8) + sizeof(struct dfltcc_state), + sizeof(unsigned char)); +} + +void ZLIB_INTERNAL dfltcc_copy_state(dst, src, size) + voidpf dst; + const voidpf src; + uInt size; +{ + zmemcpy(dst, src, ALIGN_UP(size, 8) + sizeof(struct dfltcc_state)); +} + +static const int PAGE_ALIGN = 0x1000; + +voidpf ZLIB_INTERNAL dfltcc_alloc_window(strm, items, size) + z_streamp strm; + uInt items; + uInt size; +{ + voidpf p, w; + + /* To simplify freeing, we store the pointer to the allocated buffer right + * before the window. + */ + p = ZALLOC(strm, sizeof(voidpf) + items * size + PAGE_ALIGN, + sizeof(unsigned char)); + if (p == NULL) + return NULL; + w = ALIGN_UP((char FAR *)p + sizeof(voidpf), PAGE_ALIGN); + *(voidpf *)((char FAR *)w - sizeof(voidpf)) = p; + return w; +} + +void ZLIB_INTERNAL dfltcc_free_window(strm, w) + z_streamp strm; + voidpf w; +{ + if (w) + ZFREE(strm, *(voidpf *)((unsigned char FAR *)w - sizeof(voidpf))); +} + +/* + Switching between hardware and software compression. + + DFLTCC does not support all zlib settings, e.g. generation of non-compressed + blocks or alternative window sizes. When such settings are applied on the + fly with deflateParams, we need to convert between hardware and software + window formats. +*/ +int ZLIB_INTERNAL dfltcc_deflate_params(strm, level, strategy, flush) + z_streamp strm; + int level; + int strategy; + int *flush; +{ + deflate_state FAR *state = (deflate_state FAR *)strm->state; + struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state); + struct dfltcc_param_v0 FAR *param = &dfltcc_state->param; + int could_deflate = dfltcc_can_deflate(strm); + int can_deflate = dfltcc_can_deflate_with_params(strm, + level, + state->w_bits, + strategy); + + if (can_deflate == could_deflate) + /* We continue to work in the same mode - no changes needed */ + return Z_OK; + + if (strm->total_in == 0 && param->nt == 1 && param->hl == 0) + /* DFLTCC was not used yet - no changes needed */ + return Z_OK; + + /* For now, do not convert between window formats - simply get rid of the + * old data instead. + */ + *flush = Z_FULL_FLUSH; + return Z_OK; +} + +int ZLIB_INTERNAL dfltcc_deflate_done(strm, flush) + z_streamp strm; + int flush; +{ + deflate_state FAR *state = (deflate_state FAR *)strm->state; + struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state); + struct dfltcc_param_v0 FAR *param = &dfltcc_state->param; + + /* When deflate(Z_FULL_FLUSH) is called with small avail_out, it might + * close the block without resetting the compression state. Detect this + * situation and return that deflation is not done. + */ + if (flush == Z_FULL_FLUSH && strm->avail_out == 0) + return 0; + + /* Return that deflation is not done if DFLTCC is used and either it + * buffered some data (Continuation Flag is set), or has not written EOBS + * yet (Block-Continuation Flag is set). + */ + return !dfltcc_can_deflate(strm) || (!param->cf && !param->bcf); +} + +/* + Preloading history. +*/ +local void append_history OF((struct dfltcc_param_v0 FAR *param, + Bytef *history, + const Bytef *buf, + uInt count)); +local void append_history(param, history, buf, count) + struct dfltcc_param_v0 FAR *param; + Bytef *history; + const Bytef *buf; + uInt count; +{ + size_t offset; + size_t n; + + /* Do not use more than 32K */ + if (count > HB_SIZE) { + buf += count - HB_SIZE; + count = HB_SIZE; + } + offset = (param->ho + param->hl) % HB_SIZE; + if (offset + count <= HB_SIZE) + /* Circular history buffer does not wrap - copy one chunk */ + zmemcpy(history + offset, buf, count); + else { + /* Circular history buffer wraps - copy two chunks */ + n = HB_SIZE - offset; + zmemcpy(history + offset, buf, n); + zmemcpy(history, buf + n, count - n); + } + n = param->hl + count; + if (n <= HB_SIZE) + /* All history fits into buffer - no need to discard anything */ + param->hl = n; + else { + /* History does not fit into buffer - discard extra bytes */ + param->ho = (param->ho + (n - HB_SIZE)) % HB_SIZE; + param->hl = HB_SIZE; + } +} + +int ZLIB_INTERNAL dfltcc_deflate_set_dictionary(strm, dictionary, dict_length) + z_streamp strm; + const Bytef *dictionary; + uInt dict_length; +{ + deflate_state FAR *state = (deflate_state FAR *)strm->state; + struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state); + struct dfltcc_param_v0 FAR *param = &dfltcc_state->param; + + append_history(param, state->window, dictionary, dict_length); + state->strstart = 1; /* Add FDICT to zlib header */ + state->block_start = state->strstart; /* Make deflate_stored happy */ + return Z_OK; +} + +int ZLIB_INTERNAL dfltcc_deflate_get_dictionary(strm, dictionary, dict_length) + z_streamp strm; + Bytef *dictionary; + uInt *dict_length; +{ + deflate_state FAR *state = (deflate_state FAR *)strm->state; + struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state); + struct dfltcc_param_v0 FAR *param = &dfltcc_state->param; + + if (dictionary) { + if (param->ho + param->hl <= HB_SIZE) + /* Circular history buffer does not wrap - copy one chunk */ + zmemcpy(dictionary, state->window + param->ho, param->hl); + else { + /* Circular history buffer wraps - copy two chunks */ + zmemcpy(dictionary, + state->window + param->ho, + HB_SIZE - param->ho); + zmemcpy(dictionary + HB_SIZE - param->ho, + state->window, + param->ho + param->hl - HB_SIZE); + } + } + if (dict_length) + *dict_length = param->hl; + return Z_OK; +} Index: zlib-1.2.12/contrib/s390/dfltcc.h =================================================================== --- /dev/null +++ zlib-1.2.12/contrib/s390/dfltcc.h @@ -0,0 +1,81 @@ +#ifndef DFLTCC_H +#define DFLTCC_H + +#include "../../zlib.h" +#include "../../zutil.h" + +voidpf ZLIB_INTERNAL dfltcc_alloc_state OF((z_streamp strm, uInt items, + uInt size)); +void ZLIB_INTERNAL dfltcc_copy_state OF((voidpf dst, const voidpf src, + uInt size)); +void ZLIB_INTERNAL dfltcc_reset OF((z_streamp strm, uInt size)); +voidpf ZLIB_INTERNAL dfltcc_alloc_window OF((z_streamp strm, uInt items, + uInt size)); +void ZLIB_INTERNAL dfltcc_free_window OF((z_streamp strm, voidpf w)); +#define DFLTCC_BLOCK_HEADER_BITS 3 +#define DFLTCC_HLITS_COUNT_BITS 5 +#define DFLTCC_HDISTS_COUNT_BITS 5 +#define DFLTCC_HCLENS_COUNT_BITS 4 +#define DFLTCC_MAX_HCLENS 19 +#define DFLTCC_HCLEN_BITS 3 +#define DFLTCC_MAX_HLITS 286 +#define DFLTCC_MAX_HDISTS 30 +#define DFLTCC_MAX_HLIT_HDIST_BITS 7 +#define DFLTCC_MAX_SYMBOL_BITS 16 +#define DFLTCC_MAX_EOBS_BITS 15 +#define DFLTCC_MAX_PADDING_BITS 7 +#define DEFLATE_BOUND_COMPLEN(source_len) \ + ((DFLTCC_BLOCK_HEADER_BITS + \ + DFLTCC_HLITS_COUNT_BITS + \ + DFLTCC_HDISTS_COUNT_BITS + \ + DFLTCC_HCLENS_COUNT_BITS + \ + DFLTCC_MAX_HCLENS * DFLTCC_HCLEN_BITS + \ + (DFLTCC_MAX_HLITS + DFLTCC_MAX_HDISTS) * DFLTCC_MAX_HLIT_HDIST_BITS + \ + (source_len) * DFLTCC_MAX_SYMBOL_BITS + \ + DFLTCC_MAX_EOBS_BITS + \ + DFLTCC_MAX_PADDING_BITS) >> 3) +int ZLIB_INTERNAL dfltcc_can_inflate OF((z_streamp strm)); +typedef enum { + DFLTCC_INFLATE_CONTINUE, + DFLTCC_INFLATE_BREAK, + DFLTCC_INFLATE_SOFTWARE, +} dfltcc_inflate_action; +dfltcc_inflate_action ZLIB_INTERNAL dfltcc_inflate OF((z_streamp strm, + int flush, int *ret)); +int ZLIB_INTERNAL dfltcc_was_inflate_used OF((z_streamp strm)); +int ZLIB_INTERNAL dfltcc_inflate_disable OF((z_streamp strm)); + +#define ZALLOC_STATE dfltcc_alloc_state +#define ZFREE_STATE ZFREE +#define ZCOPY_STATE dfltcc_copy_state +#define ZALLOC_WINDOW dfltcc_alloc_window +#define ZFREE_WINDOW dfltcc_free_window +#define TRY_FREE_WINDOW dfltcc_free_window +#define INFLATE_RESET_KEEP_HOOK(strm) \ + dfltcc_reset((strm), sizeof(struct inflate_state)) +#define INFLATE_PRIME_HOOK(strm, bits, value) \ + do { if (dfltcc_inflate_disable((strm))) return Z_STREAM_ERROR; } while (0) +#define INFLATE_TYPEDO_HOOK(strm, flush) \ + if (dfltcc_can_inflate((strm))) { \ + dfltcc_inflate_action action; \ +\ + RESTORE(); \ + action = dfltcc_inflate((strm), (flush), &ret); \ + LOAD(); \ + if (action == DFLTCC_INFLATE_CONTINUE) \ + break; \ + else if (action == DFLTCC_INFLATE_BREAK) \ + goto inf_leave; \ + } +#define INFLATE_NEED_CHECKSUM(strm) (!dfltcc_can_inflate((strm))) +#define INFLATE_NEED_UPDATEWINDOW(strm) (!dfltcc_can_inflate((strm))) +#define INFLATE_MARK_HOOK(strm) \ + do { \ + if (dfltcc_was_inflate_used((strm))) return -(1L << 16); \ + } while (0) +#define INFLATE_SYNC_POINT_HOOK(strm) \ + do { \ + if (dfltcc_was_inflate_used((strm))) return Z_STREAM_ERROR; \ + } while (0) + +#endif Index: zlib-1.2.12/contrib/s390/dfltcc_deflate.h =================================================================== --- /dev/null +++ zlib-1.2.12/contrib/s390/dfltcc_deflate.h @@ -0,0 +1,55 @@ +#ifndef DFLTCC_DEFLATE_H +#define DFLTCC_DEFLATE_H + +#include "dfltcc.h" + +int ZLIB_INTERNAL dfltcc_can_deflate OF((z_streamp strm)); +int ZLIB_INTERNAL dfltcc_deflate OF((z_streamp strm, + int flush, + block_state *result)); +int ZLIB_INTERNAL dfltcc_deflate_params OF((z_streamp strm, + int level, + int strategy, + int *flush)); +int ZLIB_INTERNAL dfltcc_deflate_done OF((z_streamp strm, int flush)); +int ZLIB_INTERNAL dfltcc_deflate_set_dictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dict_length)); +int ZLIB_INTERNAL dfltcc_deflate_get_dictionary OF((z_streamp strm, + Bytef *dictionary, + uInt* dict_length)); + +#define DEFLATE_SET_DICTIONARY_HOOK(strm, dict, dict_len) \ + do { \ + if (dfltcc_can_deflate((strm))) \ + return dfltcc_deflate_set_dictionary((strm), (dict), (dict_len)); \ + } while (0) +#define DEFLATE_GET_DICTIONARY_HOOK(strm, dict, dict_len) \ + do { \ + if (dfltcc_can_deflate((strm))) \ + return dfltcc_deflate_get_dictionary((strm), (dict), (dict_len)); \ + } while (0) +#define DEFLATE_RESET_KEEP_HOOK(strm) \ + dfltcc_reset((strm), sizeof(deflate_state)) +#define DEFLATE_PARAMS_HOOK(strm, level, strategy, hook_flush) \ + do { \ + int err; \ +\ + err = dfltcc_deflate_params((strm), \ + (level), \ + (strategy), \ + (hook_flush)); \ + if (err == Z_STREAM_ERROR) \ + return err; \ + } while (0) +#define DEFLATE_DONE dfltcc_deflate_done +#define DEFLATE_BOUND_ADJUST_COMPLEN(strm, complen, source_len) \ + do { \ + if (dfltcc_can_deflate((strm))) \ + (complen) = DEFLATE_BOUND_COMPLEN(source_len); \ + } while (0) +#define DEFLATE_NEED_CONSERVATIVE_BOUND(strm) (dfltcc_can_deflate((strm))) +#define DEFLATE_HOOK dfltcc_deflate +#define DEFLATE_NEED_CHECKSUM(strm) (!dfltcc_can_deflate((strm))) + +#endif Index: zlib-1.2.12/deflate.c =================================================================== --- zlib-1.2.12.orig/deflate.c +++ zlib-1.2.12/deflate.c @@ -61,15 +61,30 @@ const char deflate_copyright[] = */ /* =========================================================================== - * Function prototypes. + * Architecture-specific bits. */ -typedef enum { - need_more, /* block not completed, need more input or more output */ - block_done, /* block flush performed */ - finish_started, /* finish started, need only more output at next deflate */ - finish_done /* finish done, accept no more input or output */ -} block_state; +#ifdef DFLTCC +# include "contrib/s390/dfltcc_deflate.h" +#else +#define ZALLOC_STATE ZALLOC +#define ZFREE_STATE ZFREE +#define ZCOPY_STATE zmemcpy +#define ZALLOC_WINDOW ZALLOC +#define TRY_FREE_WINDOW TRY_FREE +#define DEFLATE_SET_DICTIONARY_HOOK(strm, dict, dict_len) do {} while (0) +#define DEFLATE_GET_DICTIONARY_HOOK(strm, dict, dict_len) do {} while (0) +#define DEFLATE_RESET_KEEP_HOOK(strm) do {} while (0) +#define DEFLATE_PARAMS_HOOK(strm, level, strategy, hook_flush) do {} while (0) +#define DEFLATE_DONE(strm, flush) 1 +#define DEFLATE_BOUND_ADJUST_COMPLEN(strm, complen, sourceLen) do {} while (0) +#define DEFLATE_NEED_CONSERVATIVE_BOUND(strm) 0 +#define DEFLATE_HOOK(strm, flush, bstate) 0 +#define DEFLATE_NEED_CHECKSUM(strm) 1 +#endif +/* =========================================================================== + * Function prototypes. + */ typedef block_state (*compress_func) OF((deflate_state *s, int flush)); /* Compression function. Returns the block state after the call. */ @@ -85,7 +100,6 @@ local block_state deflate_rle OF((def local block_state deflate_huff OF((deflate_state *s, int flush)); local void lm_init OF((deflate_state *s)); local void putShortMSB OF((deflate_state *s, uInt b)); -local void flush_pending OF((z_streamp strm)); local unsigned read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); #ifdef ASMV # pragma message("Assembler code may have bugs -- use at your own risk") @@ -294,7 +308,7 @@ int ZEXPORT deflateInit2_(strm, level, m return Z_STREAM_ERROR; } if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ - s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + s = (deflate_state *) ZALLOC_STATE(strm, 1, sizeof(deflate_state)); if (s == Z_NULL) return Z_MEM_ERROR; strm->state = (struct internal_state FAR *)s; s->strm = strm; @@ -311,7 +325,7 @@ int ZEXPORT deflateInit2_(strm, level, m s->hash_mask = s->hash_size - 1; s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); - s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->window = (Bytef *) ZALLOC_WINDOW(strm, s->w_size, 2*sizeof(Byte)); s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); @@ -429,6 +443,7 @@ int ZEXPORT deflateSetDictionary (strm, /* when using zlib wrappers, compute Adler-32 for provided dictionary */ if (wrap == 1) strm->adler = adler32(strm->adler, dictionary, dictLength); + DEFLATE_SET_DICTIONARY_HOOK(strm, dictionary, dictLength); s->wrap = 0; /* avoid computing Adler-32 in read_buf */ /* if dictionary would fill window, just replace the history */ @@ -487,6 +502,7 @@ int ZEXPORT deflateGetDictionary (strm, if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + DEFLATE_GET_DICTIONARY_HOOK(strm, dictionary, dictLength); s = strm->state; len = s->strstart + s->lookahead; if (len > s->w_size) @@ -533,6 +549,8 @@ int ZEXPORT deflateResetKeep (strm) _tr_init(s); + DEFLATE_RESET_KEEP_HOOK(strm); + return Z_OK; } @@ -608,6 +626,7 @@ int ZEXPORT deflateParams(strm, level, s { deflate_state *s; compress_func func; + int hook_flush = Z_NO_FLUSH; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; @@ -620,15 +639,18 @@ int ZEXPORT deflateParams(strm, level, s if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { return Z_STREAM_ERROR; } + DEFLATE_PARAMS_HOOK(strm, level, strategy, &hook_flush); func = configuration_table[s->level].func; - if ((strategy != s->strategy || func != configuration_table[level].func) && - s->last_flush != -2) { + if (((strategy != s->strategy || func != configuration_table[level].func) && + s->last_flush != -2) || hook_flush != Z_NO_FLUSH) { /* Flush the last buffer: */ - int err = deflate(strm, Z_BLOCK); + int flush = RANK(hook_flush) > RANK(Z_BLOCK) ? hook_flush : Z_BLOCK; + int err = deflate(strm, flush); if (err == Z_STREAM_ERROR) return err; - if (strm->avail_in || (s->strstart - s->block_start) + s->lookahead) + if (strm->avail_in || (s->strstart - s->block_start) + s->lookahead || + !DEFLATE_DONE(strm, flush)) return Z_BUF_ERROR; } if (s->level != level) { @@ -695,6 +717,7 @@ uLong ZEXPORT deflateBound(strm, sourceL /* conservative upper bound for compressed data */ complen = sourceLen + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; + DEFLATE_BOUND_ADJUST_COMPLEN(strm, complen, sourceLen); /* if can't get parameters, return conservative bound plus zlib wrapper */ if (deflateStateCheck(strm)) @@ -736,7 +759,8 @@ uLong ZEXPORT deflateBound(strm, sourceL } /* if not default parameters, return conservative bound */ - if (s->w_bits != 15 || s->hash_bits != 8 + 7) + if (DEFLATE_NEED_CONSERVATIVE_BOUND(strm) || + s->w_bits != 15 || s->hash_bits != 8 + 7) return complen + wraplen; /* default settings: return tight bound for that case */ @@ -763,7 +787,7 @@ local void putShortMSB (s, b) * applications may wish to modify it to avoid allocating a large * strm->next_out buffer and copying into it. (See also read_buf()). */ -local void flush_pending(strm) +void ZLIB_INTERNAL flush_pending(strm) z_streamp strm; { unsigned len; @@ -1035,7 +1059,8 @@ int ZEXPORT deflate (strm, flush) (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { block_state bstate; - bstate = s->level == 0 ? deflate_stored(s, flush) : + bstate = DEFLATE_HOOK(strm, flush, &bstate) ? bstate : + s->level == 0 ? deflate_stored(s, flush) : s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : s->strategy == Z_RLE ? deflate_rle(s, flush) : (*(configuration_table[s->level].func))(s, flush); @@ -1082,7 +1107,6 @@ int ZEXPORT deflate (strm, flush) } if (flush != Z_FINISH) return Z_OK; - if (s->wrap <= 0) return Z_STREAM_END; /* Write the trailer */ #ifdef GZIP @@ -1098,7 +1122,7 @@ int ZEXPORT deflate (strm, flush) } else #endif - { + if (s->wrap == 1) { putShortMSB(s, (uInt)(strm->adler >> 16)); putShortMSB(s, (uInt)(strm->adler & 0xffff)); } @@ -1107,7 +1131,11 @@ int ZEXPORT deflate (strm, flush) * to flush the rest. */ if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ - return s->pending != 0 ? Z_OK : Z_STREAM_END; + if (s->pending == 0) { + Assert(s->bi_valid == 0, "bi_buf not flushed"); + return Z_STREAM_END; + } + return Z_OK; } /* ========================================================================= */ @@ -1124,9 +1152,9 @@ int ZEXPORT deflateEnd (strm) TRY_FREE(strm, strm->state->pending_buf); TRY_FREE(strm, strm->state->head); TRY_FREE(strm, strm->state->prev); - TRY_FREE(strm, strm->state->window); + TRY_FREE_WINDOW(strm, strm->state->window); - ZFREE(strm, strm->state); + ZFREE_STATE(strm, strm->state); strm->state = Z_NULL; return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; @@ -1156,13 +1184,13 @@ int ZEXPORT deflateCopy (dest, source) zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); - ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + ds = (deflate_state *) ZALLOC_STATE(dest, 1, sizeof(deflate_state)); if (ds == Z_NULL) return Z_MEM_ERROR; dest->state = (struct internal_state FAR *) ds; - zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state)); + ZCOPY_STATE((voidpf)ds, (voidpf)ss, sizeof(deflate_state)); ds->strm = dest; - ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->window = (Bytef *) ZALLOC_WINDOW(dest, ds->w_size, 2*sizeof(Byte)); ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, 4); @@ -1209,7 +1237,8 @@ local unsigned read_buf(strm, buf, size) strm->avail_in -= len; zmemcpy(buf, strm->next_in, len); - if (strm->state->wrap == 1) { + if (!DEFLATE_NEED_CHECKSUM(strm)) {} + else if (strm->state->wrap == 1) { strm->adler = adler32(strm->adler, buf, len); } #ifdef GZIP Index: zlib-1.2.12/deflate.h =================================================================== --- zlib-1.2.12.orig/deflate.h +++ zlib-1.2.12/deflate.h @@ -299,6 +299,7 @@ void ZLIB_INTERNAL _tr_flush_bits OF((de void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, int last)); +void ZLIB_INTERNAL _tr_send_bits OF((deflate_state *s, int value, int length)); #define d_code(dist) \ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) @@ -343,4 +344,15 @@ void ZLIB_INTERNAL _tr_stored_block OF(( flush = _tr_tally(s, distance, length) #endif +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +unsigned ZLIB_INTERNAL bi_reverse OF((unsigned code, int len)); +void ZLIB_INTERNAL bi_windup OF((deflate_state *s)); +void ZLIB_INTERNAL flush_pending OF((z_streamp strm)); + #endif /* DEFLATE_H */ Index: zlib-1.2.12/gzguts.h =================================================================== --- zlib-1.2.12.orig/gzguts.h +++ zlib-1.2.12/gzguts.h @@ -153,7 +153,11 @@ /* default i/o buffer size -- double this for output when reading (this and twice this must be able to fit in an unsigned type) */ +#ifdef DFLTCC +#define GZBUFSIZE 131072 +#else #define GZBUFSIZE 8192 +#endif /* gzip modes, also provide a little integrity check on the passed structure */ #define GZ_NONE 0 Index: zlib-1.2.12/inflate.c =================================================================== --- zlib-1.2.12.orig/inflate.c +++ zlib-1.2.12/inflate.c @@ -85,6 +85,24 @@ #include "inflate.h" #include "inffast.h" +/* architecture-specific bits */ +#ifdef DFLTCC +# include "contrib/s390/dfltcc.h" +#else +#define ZALLOC_STATE ZALLOC +#define ZFREE_STATE ZFREE +#define ZCOPY_STATE zmemcpy +#define ZALLOC_WINDOW ZALLOC +#define ZFREE_WINDOW ZFREE +#define INFLATE_RESET_KEEP_HOOK(strm) do {} while (0) +#define INFLATE_PRIME_HOOK(strm, bits, value) do {} while (0) +#define INFLATE_TYPEDO_HOOK(strm, flush) do {} while (0) +#define INFLATE_NEED_CHECKSUM(strm) 1 +#define INFLATE_NEED_UPDATEWINDOW(strm) 1 +#define INFLATE_MARK_HOOK(strm) do {} while (0) +#define INFLATE_SYNC_POINT_HOOK(strm) do {} while (0) +#endif + #ifdef MAKEFIXED # ifndef BUILDFIXED # define BUILDFIXED @@ -138,6 +156,7 @@ z_streamp strm; state->lencode = state->distcode = state->next = state->codes; state->sane = 1; state->back = -1; + INFLATE_RESET_KEEP_HOOK(strm); Tracev((stderr, "inflate: reset\n")); return Z_OK; } @@ -183,7 +202,7 @@ int windowBits; if (windowBits && (windowBits < 8 || windowBits > 15)) return Z_STREAM_ERROR; if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { - ZFREE(strm, state->window); + ZFREE_WINDOW(strm, state->window); state->window = Z_NULL; } @@ -219,7 +238,7 @@ int stream_size; strm->zfree = zcfree; #endif state = (struct inflate_state FAR *) - ZALLOC(strm, 1, sizeof(struct inflate_state)); + ZALLOC_STATE(strm, 1, sizeof(struct inflate_state)); if (state == Z_NULL) return Z_MEM_ERROR; Tracev((stderr, "inflate: allocated\n")); strm->state = (struct internal_state FAR *)state; @@ -228,7 +247,7 @@ int stream_size; state->mode = HEAD; /* to pass state test in inflateReset2() */ ret = inflateReset2(strm, windowBits); if (ret != Z_OK) { - ZFREE(strm, state); + ZFREE_STATE(strm, state); strm->state = Z_NULL; } return ret; @@ -250,6 +269,7 @@ int value; struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + INFLATE_PRIME_HOOK(strm, bits, value); state = (struct inflate_state FAR *)strm->state; if (bits < 0) { state->hold = 0; @@ -377,6 +397,27 @@ void makefixed() } #endif /* MAKEFIXED */ +int ZLIB_INTERNAL inflate_ensure_window(state) + struct inflate_state *state; +{ + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC_WINDOW(state->strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->wnext = 0; + state->whave = 0; + } + + return 0; +} + /* Update the window with the last wsize (normally 32K) bytes written before returning. If window does not exist yet, create it. This is only called @@ -401,20 +442,7 @@ unsigned copy; state = (struct inflate_state FAR *)strm->state; - /* if it hasn't been done already, allocate space for the window */ - if (state->window == Z_NULL) { - state->window = (unsigned char FAR *) - ZALLOC(strm, 1U << state->wbits, - sizeof(unsigned char)); - if (state->window == Z_NULL) return 1; - } - - /* if window not in use yet, initialize */ - if (state->wsize == 0) { - state->wsize = 1U << state->wbits; - state->wnext = 0; - state->whave = 0; - } + if (inflate_ensure_window(state)) return 1; /* copy state->wsize or less output bytes into the circular window */ if (copy >= state->wsize) { @@ -857,6 +885,7 @@ int flush; if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; /* fallthrough */ case TYPEDO: + INFLATE_TYPEDO_HOOK(strm, flush); if (state->last) { BYTEBITS(); state->mode = CHECK; @@ -1218,7 +1247,7 @@ int flush; out -= left; strm->total_out += out; state->total += out; - if ((state->wrap & 4) && out) + if (INFLATE_NEED_CHECKSUM(strm) && (state->wrap & 4) && out) strm->adler = state->check = UPDATE_CHECK(state->check, put - out, out); out = left; @@ -1273,8 +1302,9 @@ int flush; */ inf_leave: RESTORE(); - if (state->wsize || (out != strm->avail_out && state->mode < BAD && - (state->mode < CHECK || flush != Z_FINISH))) + if (INFLATE_NEED_UPDATEWINDOW(strm) && + (state->wsize || (out != strm->avail_out && state->mode < BAD && + (state->mode < CHECK || flush != Z_FINISH)))) if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { state->mode = MEM; return Z_MEM_ERROR; @@ -1284,7 +1314,7 @@ int flush; strm->total_in += in; strm->total_out += out; state->total += out; - if ((state->wrap & 4) && out) + if (INFLATE_NEED_CHECKSUM(strm) && (state->wrap & 4) && out) strm->adler = state->check = UPDATE_CHECK(state->check, strm->next_out - out, out); strm->data_type = (int)state->bits + (state->last ? 64 : 0) + @@ -1302,8 +1332,8 @@ z_streamp strm; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; - if (state->window != Z_NULL) ZFREE(strm, state->window); - ZFREE(strm, strm->state); + if (state->window != Z_NULL) ZFREE_WINDOW(strm, state->window); + ZFREE_STATE(strm, strm->state); strm->state = Z_NULL; Tracev((stderr, "inflate: end\n")); return Z_OK; @@ -1482,6 +1512,7 @@ z_streamp strm; struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + INFLATE_SYNC_POINT_HOOK(strm); state = (struct inflate_state FAR *)strm->state; return state->mode == STORED && state->bits == 0; } @@ -1502,21 +1533,22 @@ z_streamp source; /* allocate space */ copy = (struct inflate_state FAR *) - ZALLOC(source, 1, sizeof(struct inflate_state)); + ZALLOC_STATE(source, 1, sizeof(struct inflate_state)); if (copy == Z_NULL) return Z_MEM_ERROR; window = Z_NULL; if (state->window != Z_NULL) { window = (unsigned char FAR *) - ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + ZALLOC_WINDOW(source, 1U << state->wbits, + sizeof(unsigned char)); if (window == Z_NULL) { - ZFREE(source, copy); + ZFREE_STATE(source, copy); return Z_MEM_ERROR; } } /* copy state */ zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); - zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); + ZCOPY_STATE((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); copy->strm = dest; if (state->lencode >= state->codes && state->lencode <= state->codes + ENOUGH - 1) { @@ -1573,6 +1605,7 @@ z_streamp strm; if (inflateStateCheck(strm)) return -(1L << 16); + INFLATE_MARK_HOOK(strm); state = (struct inflate_state FAR *)strm->state; return (long)(((unsigned long)((long)state->back)) << 16) + (state->mode == COPY ? state->length : Index: zlib-1.2.12/inflate.h =================================================================== --- zlib-1.2.12.orig/inflate.h +++ zlib-1.2.12/inflate.h @@ -124,3 +124,5 @@ struct inflate_state { int back; /* bits back of last unprocessed length/lit */ unsigned was; /* initial length of match */ }; + +int ZLIB_INTERNAL inflate_ensure_window OF((struct inflate_state *state)); Index: zlib-1.2.12/test/infcover.c =================================================================== --- zlib-1.2.12.orig/test/infcover.c +++ zlib-1.2.12/test/infcover.c @@ -373,7 +373,7 @@ local void cover_support(void) mem_setup(&strm); strm.avail_in = 0; strm.next_in = Z_NULL; - ret = inflateInit_(&strm, ZLIB_VERSION - 1, (int)sizeof(z_stream)); + ret = inflateInit_(&strm, &ZLIB_VERSION[1], (int)sizeof(z_stream)); assert(ret == Z_VERSION_ERROR); mem_done(&strm, "wrong version"); @@ -444,7 +444,7 @@ local void cover_wrap(void) } /* input and output functions for inflateBack() */ -local unsigned pull(void *desc, unsigned char **buf) +local unsigned pull(void *desc, z_const unsigned char **buf) { static unsigned int next = 0; static unsigned char dat[] = {0x63, 0, 2, 0}; Index: zlib-1.2.12/test/minigzip.c =================================================================== --- zlib-1.2.12.orig/test/minigzip.c +++ zlib-1.2.12/test/minigzip.c @@ -132,7 +132,11 @@ static void pwinerror (s) #endif #define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1) +#ifdef DFLTCC +#define BUFLEN 262144 +#else #define BUFLEN 16384 +#endif #define MAX_NAME_LEN 1024 #ifdef MAXSEG_64K Index: zlib-1.2.12/trees.c =================================================================== --- zlib-1.2.12.orig/trees.c +++ zlib-1.2.12/trees.c @@ -149,8 +149,6 @@ local void send_all_trees OF((deflate_st local void compress_block OF((deflate_state *s, const ct_data *ltree, const ct_data *dtree)); local int detect_data_type OF((deflate_state *s)); -local unsigned bi_reverse OF((unsigned code, int len)); -local void bi_windup OF((deflate_state *s)); local void bi_flush OF((deflate_state *s)); #ifdef GEN_TREES_H @@ -223,6 +221,13 @@ local void send_bits(s, value, length) } #endif /* ZLIB_DEBUG */ +void ZLIB_INTERNAL _tr_send_bits(s, value, length) + deflate_state *s; + int value; + int length; +{ + send_bits(s, value, length); +} /* the arguments must not have side effects */ @@ -1134,7 +1139,7 @@ local int detect_data_type(s) * method would use a table) * IN assertion: 1 <= len <= 15 */ -local unsigned bi_reverse(code, len) +unsigned ZLIB_INTERNAL bi_reverse(code, len) unsigned code; /* the value to invert */ int len; /* its bit length */ { @@ -1166,7 +1171,7 @@ local void bi_flush(s) /* =========================================================================== * Flush the bit buffer and align the output on a byte boundary */ -local void bi_windup(s) +void ZLIB_INTERNAL bi_windup(s) deflate_state *s; { if (s->bi_valid > 8) { Index: zlib-1.2.12/zutil.h =================================================================== --- zlib-1.2.12.orig/zutil.h +++ zlib-1.2.12/zutil.h @@ -87,6 +87,8 @@ extern z_const char * const z_errmsg[10] #define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ +#define ZLIB_WRAPLEN 6 /* zlib format overhead */ + /* target dependencies */ #if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))