3f3a1b
* configure.ac (AC_CHECK_HEADERS_ONCE): Add feature detection for
3f3a1b
sys/sdt.h probes.
3f3a1b
* dfltcc.c (dfltcc_cc): Minor formatting improvements.
3f3a1b
(HB_BITS): Remove.
3f3a1b
(HB_SIZE): Likewise.
3f3a1b
(is_dfltcc_enabled): Fix buffer overrun on newer models and incomplete
3f3a1b
initialization on older models.
3f3a1b
Add machine mode hint.
3f3a1b
(dfltcc): Use sys/sdt.h feature detection.
3f3a1b
(bi_load): New function.
3f3a1b
(bi_close_block): Use bi_load.
3f3a1b
(close_stream): Fix overwriting the End-of-block Symbol.
3f3a1b
(dfltcc_deflate): Fix losing partial byte on flush.
3f3a1b
Fix setting Block-Continuation Flag when DFLTCC-CMPR outputs 0 bits and
3f3a1b
requests a retry.
3f3a1b
Minor formatting improvements.
3f3a1b
(dfltcc_inflate): Retry immediately if requested.
3f3a1b
Print the hardware error code and flush the output buffer on error.
3f3a1b
Minor formatting improvements.
3f3a1b
* tests/hufts: Ignore the hardware error code.
3f3a1b
---
3f3a1b
 configure.ac |  2 +-
3f3a1b
 dfltcc.c     | 76 ++++++++++++++++++++++++++++++++++++----------------
3f3a1b
 tests/hufts  |  2 ++
3f3a1b
 3 files changed, 56 insertions(+), 24 deletions(-)
3f3a1b
3f3a1b
diff --git a/configure.ac b/configure.ac
3f3a1b
index 76ac26f..b4aea34 100644
3f3a1b
--- a/configure.ac
3f3a1b
+++ b/configure.ac
3f3a1b
@@ -263,7 +263,7 @@ AC_SUBST([ASFLAGS_config])
3f3a1b
 AC_ISC_POSIX
3f3a1b
 AC_C_CONST
3f3a1b
 AC_HEADER_STDC
3f3a1b
-AC_CHECK_HEADERS_ONCE(fcntl.h limits.h memory.h time.h)
3f3a1b
+AC_CHECK_HEADERS_ONCE(fcntl.h limits.h memory.h time.h sys/sdt.h)
3f3a1b
 AC_CHECK_FUNCS_ONCE([chown fchmod fchown lstat siginterrupt])
3f3a1b
 AC_HEADER_DIRENT
3f3a1b
 AC_TYPE_SIGNAL
3f3a1b
diff --git a/dfltcc.c b/dfltcc.c
3f3a1b
index ba62968..ed3be8d 100644
3f3a1b
--- a/dfltcc.c
3f3a1b
+++ b/dfltcc.c
3f3a1b
@@ -22,7 +22,7 @@
3f3a1b
 #include <stdbool.h>
3f3a1b
 #include <stdlib.h>
3f3a1b
 
3f3a1b
-#ifdef DFLTCC_USDT
3f3a1b
+#ifdef HAVE_SYS_SDT_H
3f3a1b
 # include <sys/sdt.h>
3f3a1b
 #endif
3f3a1b
 
3f3a1b
@@ -39,11 +39,11 @@
3f3a1b
 
3f3a1b
 typedef enum
3f3a1b
 {
3f3a1b
- DFLTCC_CC_OK = 0,
3f3a1b
- DFLTCC_CC_OP1_TOO_SHORT = 1,
3f3a1b
- DFLTCC_CC_OP2_TOO_SHORT = 2,
3f3a1b
- DFLTCC_CC_OP2_CORRUPT = 2,
3f3a1b
- DFLTCC_CC_AGAIN = 3,
3f3a1b
+  DFLTCC_CC_OK = 0,
3f3a1b
+  DFLTCC_CC_OP1_TOO_SHORT = 1,
3f3a1b
+  DFLTCC_CC_OP2_TOO_SHORT = 2,
3f3a1b
+  DFLTCC_CC_OP2_CORRUPT = 2,
3f3a1b
+  DFLTCC_CC_AGAIN = 3,
3f3a1b
 } dfltcc_cc;
3f3a1b
 
3f3a1b
 #define DFLTCC_QAF 0
3f3a1b
@@ -51,8 +51,6 @@ typedef enum
3f3a1b
 #define DFLTCC_CMPR 2
3f3a1b
 #define DFLTCC_XPND 4
3f3a1b
 #define HBT_CIRCULAR (1 << 7)
3f3a1b
-/* #define HB_BITS 15 */
3f3a1b
-/* #define HB_SIZE (1 << HB_BITS) */
3f3a1b
 #define DFLTCC_FACILITY 151
3f3a1b
 #define DFLTCC_FMT0 0
3f3a1b
 #define CVT_CRC32 0
3f3a1b
@@ -155,9 +153,16 @@ is_dfltcc_enabled (void)
3f3a1b
   if (env && !strcmp (env, "0"))
3f3a1b
     return 0;
3f3a1b
 
3f3a1b
-  register int r0 __asm__ ("r0") = sizeof facilities / 8;
3f3a1b
-  __asm__ ("stfle %[facilities]\n"
3f3a1b
-           : [facilities] "=Q"(facilities) : [r0] "r"(r0) : "cc", "memory");
3f3a1b
+  memset (facilities, 0, sizeof facilities);
3f3a1b
+  register char r0 __asm__ ("r0") = sizeof facilities / 8 - 1;
3f3a1b
+  /* STFLE is supported since z9-109 and only in z/Architecture mode.  When
3f3a1b
+   * compiling with -m31, gcc defaults to ESA mode, however, since the kernel
3f3a1b
+   * is 64-bit, it's always z/Architecture mode at runtime.  */
3f3a1b
+  __asm__ (".machinemode push\n"
3f3a1b
+           ".machinemode zarch\n"
3f3a1b
+           "stfle %[facilities]\n"
3f3a1b
+           ".machinemode pop\n"
3f3a1b
+           : [facilities] "=Q"(facilities), [r0] "+r"(r0) :: "cc");
3f3a1b
   return is_bit_set (facilities, DFLTCC_FACILITY);
3f3a1b
 }
3f3a1b
 
3f3a1b
@@ -180,12 +185,12 @@ dfltcc (int fn, void *param,
3f3a1b
   int cc;
3f3a1b
 
3f3a1b
   __asm__ volatile (
3f3a1b
-#ifdef DFLTCC_USDT
3f3a1b
+#ifdef HAVE_SYS_SDT_H
3f3a1b
                     STAP_PROBE_ASM (zlib, dfltcc_entry,
3f3a1b
                                     STAP_PROBE_ASM_TEMPLATE (5))
3f3a1b
 #endif
3f3a1b
                     ".insn rrf,0xb9390000,%[r2],%[r4],%[hist],0\n"
3f3a1b
-#ifdef DFLTCC_USDT
3f3a1b
+#ifdef HAVE_SYS_SDT_H
3f3a1b
                     STAP_PROBE_ASM (zlib, dfltcc_exit,
3f3a1b
                                     STAP_PROBE_ASM_TEMPLATE (5))
3f3a1b
 #endif
3f3a1b
@@ -198,7 +203,7 @@ dfltcc (int fn, void *param,
3f3a1b
                     : [r0] "r" (r0)
3f3a1b
                       , [r1] "r" (r1)
3f3a1b
                       , [hist] "r" (hist)
3f3a1b
-#ifdef DFLTCC_USDT
3f3a1b
+#ifdef HAVE_SYS_SDT_H
3f3a1b
                       , STAP_PROBE_ASM_OPERANDS (5, r2, r3, r4, r5, hist)
3f3a1b
 #endif
3f3a1b
                     : "cc", "memory");
3f3a1b
@@ -264,10 +269,16 @@ init_param (union aligned_dfltcc_param_v0 *ctx)
3f3a1b
 }
3f3a1b
 
3f3a1b
 static void
3f3a1b
-bi_close_block (struct dfltcc_param_v0 *param)
3f3a1b
+bi_load (struct dfltcc_param_v0 *param)
3f3a1b
 {
3f3a1b
   bi_valid = param->sbb;
3f3a1b
   bi_buf = bi_valid == 0 ? 0 : outbuf[outcnt] & ((1 << bi_valid) - 1);
3f3a1b
+}
3f3a1b
+
3f3a1b
+static void
3f3a1b
+bi_close_block (struct dfltcc_param_v0 *param)
3f3a1b
+{
3f3a1b
+  bi_load (param);
3f3a1b
   send_bits (bi_reverse (param->eobs >> (15 - param->eobl), param->eobl),
3f3a1b
              param->eobl);
3f3a1b
   param->bcf = 0;
3f3a1b
@@ -278,6 +289,7 @@ close_block (struct dfltcc_param_v0 *param)
3f3a1b
 {
3f3a1b
   bi_close_block (param);
3f3a1b
   bi_windup ();
3f3a1b
+  /* bi_windup has written out a possibly partial byte, fix up the position */
3f3a1b
   param->sbb = (param->sbb + param->eobl) % 8;
3f3a1b
   if (param->sbb != 0)
3f3a1b
     {
3f3a1b
@@ -291,6 +303,8 @@ close_stream (struct dfltcc_param_v0 *param)
3f3a1b
 {
3f3a1b
   if (param->bcf)
3f3a1b
     bi_close_block (param);
3f3a1b
+  else
3f3a1b
+    bi_load (param);
3f3a1b
   send_bits (1, 3); /* BFINAL=1, BTYPE=00 */
3f3a1b
   bi_windup ();
3f3a1b
   put_short (0x0000);
3f3a1b
@@ -334,7 +348,16 @@ dfltcc_deflate (int pack_level)
3f3a1b
     {
3f3a1b
       /* Flush the output data.  */
3f3a1b
       if (outcnt > OUTBUFSIZ - 8)
3f3a1b
-        flush_outbuf ();
3f3a1b
+        {
3f3a1b
+          if (param->sbb == 0)
3f3a1b
+            flush_outbuf ();
3f3a1b
+          else
3f3a1b
+            {
3f3a1b
+              uch partial = outbuf[outcnt];
3f3a1b
+              flush_outbuf ();
3f3a1b
+              outbuf[outcnt] = partial;
3f3a1b
+            }
3f3a1b
+        }
3f3a1b
 
3f3a1b
       /* Close the block.  */
3f3a1b
       if (param->bcf && total_in == block_threshold && !param->cf)
3f3a1b
@@ -360,14 +383,16 @@ dfltcc_deflate (int pack_level)
3f3a1b
         {
3f3a1b
           if (total_in == 0 && block_threshold > 0)
3f3a1b
             param->htt = HTT_FIXED;
3f3a1b
-          else {
3f3a1b
-            param->htt = HTT_DYNAMIC;
3f3a1b
-            dfltcc_gdht (param);
3f3a1b
-          }
3f3a1b
+          else
3f3a1b
+            {
3f3a1b
+              param->htt = HTT_DYNAMIC;
3f3a1b
+              dfltcc_gdht (param);
3f3a1b
+            }
3f3a1b
         }
3f3a1b
 
3f3a1b
       /* Compress inbuf into outbuf.  */
3f3a1b
-      dfltcc_cmpr_xpnd (param, DFLTCC_CMPR);
3f3a1b
+      while (dfltcc_cmpr_xpnd (param, DFLTCC_CMPR) == DFLTCC_CC_AGAIN)
3f3a1b
+        ;
3f3a1b
 
3f3a1b
       /* Unmask the input data.  */
3f3a1b
       insize += extra;
3f3a1b
@@ -413,7 +438,9 @@ dfltcc_inflate (void)
3f3a1b
         }
3f3a1b
 
3f3a1b
         /* Decompress inbuf into outbuf.  */
3f3a1b
-        dfltcc_cc cc = dfltcc_cmpr_xpnd (param, DFLTCC_XPND);
3f3a1b
+        dfltcc_cc cc;
3f3a1b
+        while ((cc = dfltcc_cmpr_xpnd (param, DFLTCC_XPND)) == DFLTCC_CC_AGAIN)
3f3a1b
+          ;
3f3a1b
         if (cc == DFLTCC_CC_OK)
3f3a1b
           {
3f3a1b
             /* The entire deflate stream has been successfully decompressed.  */
3f3a1b
@@ -422,6 +449,9 @@ dfltcc_inflate (void)
3f3a1b
         if (cc == DFLTCC_CC_OP2_CORRUPT && param->oesc != 0)
3f3a1b
           {
3f3a1b
             /* The deflate stream is corrupted.  */
3f3a1b
+            fprintf (stderr, "Operation-Ending-Supplemental Code 0x%x\n",
3f3a1b
+                     param->oesc);
3f3a1b
+            flush_outbuf ();
3f3a1b
             return 2;
3f3a1b
           }
3f3a1b
         /* There must be more data to decompress.  */