]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
s390x: Support the deflate-conversion facility (DFLTCC)
authorAndreas Arnez <arnez@linux.ibm.com>
Wed, 15 May 2024 12:32:42 +0000 (14:32 +0200)
committerAndreas Arnez <arnez@linux.ibm.com>
Wed, 15 May 2024 12:32:42 +0000 (14:32 +0200)
So far the DFLTCC (deflate conversion call) instruction is not supported
by Valgrind.  Similar to PRNO and NNPA, it is a "complex" instruction
whose memory effects cannot be adequately expressed with a dirty helper.

Add support for the DFLTCC instruction using the new "extension" mechanism
and reflect this accordingly in the supported facilities and HWCAPs.

12 files changed:
NEWS
VEX/priv/guest_s390_helpers.c
VEX/priv/guest_s390_toIR.c
VEX/priv/host_s390_defs.h
VEX/priv/main_main.c
VEX/pub/libvex.h
VEX/pub/libvex_s390x_common.h
coregrind/m_extension/extension-s390x.c
coregrind/m_initimg/initimg-linux.c
coregrind/m_machine.c
docs/internals/s390-opcodes.csv
include/vki/vki-s390x-linux.h

diff --git a/NEWS b/NEWS
index 9dbb03216c7921c33bbd81ca6e10895b7e4a9317..f6ed179952d375c6b41a77ea96b0aa78d84ff89d 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,9 @@ AMD64/macOS 10.13 and nanoMIPS/Linux.
 
 * ================== PLATFORM CHANGES =================
 
+* S390X added support for the DFLTCC instruction provided by the
+  deflate-conversion facility (z15/arch13).
+
 * ==================== TOOL CHANGES ===================
 
 * ==================== FIXED BUGS ====================
index bb5e9c9396ba978d1fd46968c127843a3501ed07..9642a013e6a5e3d112103944a0af6b5b9330dd32 100644 (file)
@@ -385,7 +385,7 @@ s390x_dirtyhelper_STFLE(VexGuestS390XState *guest_state, ULong *addr)
        /* 146: MSA8, not supported */
        | s390_stfle_range(147, 149)
        /* 150: unassigned */
-       /* 151: DEFLATE-conversion, not supported */
+       | s390_stfle_range(151, 151)
        /* 152: vector packed decimal enhancement, not supported */
        /* 153: unassigned */
        /* 154: unassigned */
index 7e836faf3e0ef24bbad6a9e27d138ac1d88a4f56..0da0b941bb3f3fd3cd421deb4491a24e69adc2d8 100644 (file)
@@ -17105,6 +17105,19 @@ s390_irgen_PPNO(UChar r1, UChar r2)
    return "ppno";
 }
 
+static const HChar *
+s390_irgen_DFLTCC(UChar r3, UChar r1, UChar r2)
+{
+   s390_insn_assert("dfltcc", s390_host_has_dflt);
+
+   /* Check for obvious specification exceptions */
+   s390_insn_assert("dfltcc", r1 % 2 == 0 && r1 != 0 &&
+                    r2 % 2 == 0 && r2 != 0 && r3 >= 2);
+
+   extension(S390_EXT_DFLT, r1 | (r2 << 4) | (r3 << 8));
+   return "dfltcc";
+}
+
 enum s390_VStrX {
    s390_VStrX_VSTRC,
    s390_VStrX_VFAE,
@@ -20452,7 +20465,8 @@ s390_decode_4byte_and_irgen(const UChar *bytes)
    case 0xb931: s390_format_RRE_RR(s390_irgen_CLGFR, RRE_r1(ovl),
                                    RRE_r2(ovl));  goto ok;
    case 0xb938: /* SORTL */ goto unimplemented;
-   case 0xb939: /* DFLTCC */ goto unimplemented;
+   case 0xb939: s390_format_RRF_R0RR2(s390_irgen_DFLTCC, RRF4_r3(ovl),
+                                      RRF4_r1(ovl), RRF4_r2(ovl)); goto ok;
    case 0xb93a: /* KDSA */ goto unimplemented;
    case 0xb93b: s390_format_E(s390_irgen_NNPA);  goto ok;
    case 0xb93c: s390_format_RRE_RR(s390_irgen_PPNO, RRE_r1(ovl),
index 912db61041424b9094594a38b0ff1a80249c16d8..9d844beeedfdbeecb8a4bdf6ce36bd7f3cb990ea 100644 (file)
@@ -945,6 +945,8 @@ extern UInt s390_host_hwcaps;
                       (s390_host_hwcaps & (VEX_HWCAPS_S390X_VXE))
 #define s390_host_has_nnpa \
                       (s390_host_hwcaps & (VEX_HWCAPS_S390X_NNPA))
+#define s390_host_has_dflt \
+                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_DFLT))
 #endif /* ndef __VEX_HOST_S390_DEFS_H */
 
 /*---------------------------------------------------------------*/
index 4d0551c281775baa7eca47c6cdc8ed7092c8b89b..e6c788d0cb1dcba3b9f7c7453113ef1669181d07 100644 (file)
@@ -1824,7 +1824,8 @@ static const HChar* show_hwcaps_s390x ( UInt hwcaps )
       { VEX_HWCAPS_S390X_MSA5,  "msa5" },
       { VEX_HWCAPS_S390X_MI2,   "mi2" },
       { VEX_HWCAPS_S390X_LSC2,  "lsc2" },
-      { VEX_HWCAPS_S390X_LSC2,  "vxe" },
+      { VEX_HWCAPS_S390X_VXE,   "vxe" },
+      { VEX_HWCAPS_S390X_DFLT,  "dflt" },
    };
    /* Allocate a large enough buffer */
    static HChar buf[sizeof prefix + 
index 544cf034890c922dbd3000f994a666aac8f8df77..16810773435e2ada2a57a757c3cfcde1b5ac7bd9 100644 (file)
@@ -178,6 +178,7 @@ typedef
 #define VEX_HWCAPS_S390X_LSC2  (1<<21)  /* Conditional load/store facility2 */
 #define VEX_HWCAPS_S390X_VXE   (1<<22)  /* Vector-enhancements facility */
 #define VEX_HWCAPS_S390X_NNPA  (1<<23)  /* NNPA facility */
+#define VEX_HWCAPS_S390X_DFLT  (1<<24)  /* Deflate-conversion facility */
 
 /* Special value representing all available s390x hwcaps */
 #define VEX_HWCAPS_S390X_ALL   (VEX_HWCAPS_S390X_LDISP | \
@@ -197,7 +198,8 @@ typedef
                                 VEX_HWCAPS_S390X_MI2   | \
                                 VEX_HWCAPS_S390X_LSC2  | \
                                 VEX_HWCAPS_S390X_VXE   | \
-                                VEX_HWCAPS_S390X_NNPA)
+                                VEX_HWCAPS_S390X_NNPA  | \
+                                VEX_HWCAPS_S390X_DFLT)
 
 #define VEX_HWCAPS_S390X(x)  ((x) & ~VEX_S390X_MODEL_MASK)
 #define VEX_S390X_MODEL(x)   ((x) &  VEX_S390X_MODEL_MASK)
index 4ed848c5c19aa831ea11c54f51a6af73509fdd81..9b1168a4e6c7ec6146f2b8cb82bdb28013ea5194 100644 (file)
 
 #define S390_EXT_PRNO    1
 #define S390_EXT_NNPA    2
+#define S390_EXT_DFLT    3
 
 /*--------------------------------------------------------------*/
 /*--- Miscellaneous                                          ---*/
index 735406e6e4c59a3ad62b75bed48824a195ea6bc1..95116587c5216257cc3f226f765499c8f10ae9d2 100644 (file)
@@ -585,6 +585,172 @@ static enum ExtensionError do_extension_NNPA(ThreadState* tst, ULong variant)
    return ExtErr_OK;
 }
 
+/*---------------------------------------------------------------*/
+/*--- DFLTCC (deflate conversion call)                        ---*/
+/*---------------------------------------------------------------*/
+
+static Int do_DFLTCC_insn(UChar  func,
+                          ULong  parms,
+                          ULong* addr1,
+                          ULong* len1,
+                          ULong* addr2,
+                          ULong* len2,
+                          ULong  addr3)
+{
+   register UChar reg0 asm("0") = func;
+   register void* reg1 asm("1") = (void*)parms;
+   union reg_pair op1           = {{*addr1, *len1}};
+   union reg_pair op2           = {{*addr2, *len2}};
+   Int            cc;
+
+   asm volatile(".insn rrf, 0xb9390000, %[op1], %[op2], %[op3], 0\n"
+                "ipm %[cc]\n"
+                "srl %[cc], 28\n"
+                : [cc] "=d"(cc), [op1] "+a"(op1.pair), [op2] "+a"(op2.pair)
+                : "d"(reg0), "d"(reg1), [op3] "d"(addr3)
+                : "cc", "memory");
+   *addr1 = op1.a;
+   *len1  = op1.b;
+   *addr2 = op2.a;
+   *len2  = op2.b;
+   return cc;
+}
+
+struct s390_DFLTCC_parms0 {
+   UShort pbvn;
+   UChar  mvn;
+   UChar  ribm[3];
+   UShort reserved0 : 15;
+   UShort cf : 1;
+   ULong  reserved1;
+   UShort nt : 1;
+   UShort reserved2 : 1;
+   UShort cvt : 1;
+   UShort reserved3 : 1;
+   UShort htt : 1;
+   UShort bcf : 1;
+   UShort bcc : 1;
+   UShort bhf : 1;
+   UShort reserved4 : 1;
+   UShort reserved5 : 1;
+   UShort dhtgc : 1;
+   UShort reserved6 : 5;
+   UChar  reserved7 : 5;
+   UChar  sbb : 3;
+   UChar  oesc : 8;
+   UShort reserved8 : 12;
+   UShort ifs : 4;
+   UShort ifl;
+   UChar  reserved9[20];
+   UShort hl;
+   UShort reserved10 : 1;
+   UShort ho : 15;
+   UChar  data[1488];
+};
+
+/* DFLTCC functions that we support if the hardware does. */
+static const ULong DFLTCC_functions[] = {
+   (S390_SETBIT(0)     // Query
+    | S390_SETBIT(1)   // GDHT
+    | S390_SETBIT(2)   // CMPR
+    | S390_SETBIT(4)), // XPND
+};
+
+static UWord do_extension_DFLTCC(ThreadState* tst, ULong variant)
+{
+   enum { circ_hist_len = 32768 };
+   UChar r1    = variant & 0xf;
+   UChar r2    = (variant >> 4) & 0xf;
+   UChar r3    = (variant >> 8) & 0xf;
+   UChar func  = READ_FUNCTION_CODE(tst, "DFLTCC");
+   UChar fc    = func & 0x7f;
+   Bool  hbt   = (func & 128) != 0;
+   ULong parms = READ_GPR(tst, "DFLTCC(r1)", 1);
+   ULong parms_len;
+   Int   cc         = 0;
+   ULong orig_addr1 = 0, orig_len1 = 0;
+   ULong addr1 = 0, len1 = 0, addr2 = 0, len2 = 0, addr3 = 0;
+   Bool  do_compress = 0;
+
+   switch (fc) {
+   case 0: // Query
+      parms_len = 32;
+      PRE_MEM_WRITE(tst, "DFLTCC(parms)", parms, parms_len);
+      cc = do_DFLTCC_insn(func, parms, &addr1, &len1, &addr2, &len2, addr3);
+      s390_filter_functions((ULong*)parms, 16, DFLTCC_functions,
+                            sizeof(DFLTCC_functions));
+      POST_MEM_WRITE(tst, parms, parms_len);
+      break;
+   case 1: // GDHT
+      parms_len = 384;
+      PRE_MEM_READ(tst, "DFLTCC(parms)", parms, parms_len);
+      PRE_MEM_WRITE(tst, "DFLTCC(parms)", parms, parms_len);
+      addr2 = READ_GPR(tst, "DFLTCC(op2_addr)", r2);
+      len2  = READ_GPR(tst, "DFLTCC(op2_len)", r2 + 1);
+      if (len2 > 32768)
+         len2 = 32768;
+      PRE_MEM_READ(tst, "DFLTCC(parms)", addr2, len2);
+      cc = do_DFLTCC_insn(func, parms, &addr1, &len1, &addr2, &len2, addr3);
+      POST_MEM_WRITE(tst, parms, parms_len);
+      break;
+   case 2: // CMPR
+      do_compress = 1;
+      /* fallthrough */
+   case 4: // XPND
+   {
+      struct s390_DFLTCC_parms0* p;
+      parms_len = 1536;
+      PRE_MEM_READ(tst, "DFLTCC(parms)", parms, parms_len);
+      p     = (void*)parms;
+      addr1 = orig_addr1 = READ_GPR(tst, "DFLTCC(op1_addr)", r1);
+      len1 = orig_len1 = READ_GPR(tst, "DFLTCC(op1_len)", r1 + 1);
+      PRE_MEM_WRITE(tst, "DFLTCC(op1)", addr1, len1);
+      addr2 = READ_GPR(tst, "DFLTCC(op2_addr)", r2);
+      len2  = READ_GPR(tst, "DFLTCC(op2_len)", r2 + 1);
+      PRE_MEM_READ(tst, "DFLTCC(op2)", addr2, len2);
+      addr3 = READ_GPR(tst, "DFLTCC(op3)", r3);
+      if (hbt) {
+         PRE_MEM_WRITE(tst, "DFLTCC(op3)", addr3, circ_hist_len);
+      }
+      if (!p->nt) {
+         if (hbt) {
+            ULong hl1 = circ_hist_len - p->ho;
+            if (hl1 >= p->hl) {
+               hl1 = p->hl;
+            } else {
+               PRE_MEM_READ(tst, "DFLTCC(op3)", addr3, p->hl - hl1);
+            }
+            PRE_MEM_READ(tst, "DFLTCC(op3)", addr3 + p->ho, hl1);
+         } else {
+            PRE_MEM_READ(tst, "DFLTCC(op2.hist)", addr2 - p->hl, p->hl);
+         }
+      }
+      cc = do_DFLTCC_insn(func, parms, &addr1, &len1, &addr2, &len2, addr3);
+      POST_MEM_WRITE(tst, parms, parms_len);
+      POST_MEM_WRITE(tst, orig_addr1,
+                     orig_len1 - len1 + (do_compress && p->sbb ? 1 : 0));
+      if (hbt) {
+         ULong hl1 = circ_hist_len - p->ho;
+         if (hl1 >= p->hl) {
+            hl1 = p->hl;
+         } else {
+            POST_MEM_WRITE(tst, addr3, p->hl - hl1);
+         }
+         POST_MEM_WRITE(tst, addr3 + p->ho, hl1);
+      }
+      WRITE_GPR(tst, r1, addr1);
+      WRITE_GPR(tst, r1 + 1, len1);
+      WRITE_GPR(tst, r2, addr2);
+      WRITE_GPR(tst, r2 + 1, len2);
+      break;
+   }
+   default:
+      return INSN_ERR("DFLTCC: unknown function code\n");
+   }
+   WRITE_CC(tst, cc);
+   return ExtErr_OK;
+}
+
 /*---------------------------------------------------------------*/
 /*--- Main function: select and call appropriate extension    ---*/
 /*---------------------------------------------------------------*/
@@ -600,6 +766,8 @@ enum ExtensionError ML_(do_client_extension)(ThreadState* tst)
       return do_extension_PRNO(tst, variant);
    case S390_EXT_NNPA:
       return do_extension_NNPA(tst, variant);
+   case S390_EXT_DFLT:
+      return do_extension_DFLTCC(tst, variant);
    default:
       VG_(core_panic)("unknown extension ID");
    }
index c92c3cfb2600e6f8c5eec8d1a8f0b61fbe93496c..5f35637d757d94b10e866ff7e18f5c638f7181de 100644 (file)
@@ -722,6 +722,7 @@ Addr setup_client_stack( void*  init_sp,
                                  | VKI_HWCAP_S390_VXRS
                                  | VKI_HWCAP_S390_VXRS_EXT
                                  | VKI_HWCAP_S390_VXRS_EXT2
+                                 | VKI_HWCAP_S390_DFLT
                                  | VKI_HWCAP_S390_NNPA);
             }
 #           elif defined(VGP_arm64_linux)
index 36db3ab9cfe0fc31e8b592166e60d4d0ef8640ec..234efb312d2c4a7c863ff8ad6b059354ade86a7a 100644 (file)
@@ -1597,6 +1597,7 @@ Bool VG_(machine_get_hwcaps)( void )
         { False, S390_FAC_MI2,   VEX_HWCAPS_S390X_MI2,   "MI2"   },
         { False, S390_FAC_LSC2,  VEX_HWCAPS_S390X_LSC2,  "LSC2"  },
         { False, S390_FAC_VXE,   VEX_HWCAPS_S390X_VXE,   "VXE"   },
+        { False, S390_FAC_DFLT,  VEX_HWCAPS_S390X_DFLT,  "DFLT"  },
         { False, S390_FAC_NNPA,  VEX_HWCAPS_S390X_NNPA,  "NNPA"  },
      };
 
index a65ceea315c68b967cbbf7d547e4c43a27b27225..97eb66beea50671096ddfb1c1a265666936bb581 100644 (file)
@@ -1743,7 +1743,7 @@ wcfeb,"vector fp convert to fixed 32 bit",implemented,arch13
 vclfp,"vector fp convert to logical",implemented,arch13
 vclfeb,"vector fp convert to logical 32 bit",implemented,arch13
 wclfeb,"vector fp convert to logical 32 bit",implemented,arch13
-dfltcc,"deflate conversion call","not implemented",arch13
+dfltcc,"deflate conversion call",implemented,arch13
 sortl,"sort lists","not implemented",arch13
 kdsa,"compute digital signature authentication","not implemented",arch13
 vschp,"decimal scale and convert to hfp","not implemented",arch14
index 829382f7b2b6e8b7b99b520610d613abbe10f922..726f068a0a18cd40c2e3b0b95aaa81f6d86a40e4 100644 (file)
@@ -809,6 +809,7 @@ typedef vki_s390_regs vki_elf_gregset_t;
 #define VKI_HWCAP_S390_VXRS         2048
 #define VKI_HWCAP_S390_VXRS_EXT     8192
 #define VKI_HWCAP_S390_VXRS_EXT2   32768
+#define VKI_HWCAP_S390_DFLT       (1<<18)
 #define VKI_HWCAP_S390_NNPA       (1<<20)