From: Andreas Arnez Date: Wed, 10 Jul 2024 16:47:07 +0000 (+0200) Subject: s390x: Re-implement STFLE as an extension X-Git-Tag: VALGRIND_3_24_0~86 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=797c4b049e7b49176f4f155e00353837e4197d69;p=thirdparty%2Fvalgrind.git s390x: Re-implement STFLE as an extension The existing implementation of the STFLE instruction does not use the correct operand size when tracking memory effects. Instead of respecting the user-provided maximum number of doublewords and the returned value from the instruction, it assumes a hard coded value (S390_NUM_FACILITY_DW) instead. For example, if an application passes a buffer of 3 doublewords to STFLE while Valgrind assumes a fixed size of 4 doublewords, Valgrind may falsely complain about an invalid write for the last doubleword. Fix this by re-implementing STFLE via the extension mechanism. --- diff --git a/VEX/priv/guest_s390_defs.h b/VEX/priv/guest_s390_defs.h index 1436ce3e8..69e804cce 100644 --- a/VEX/priv/guest_s390_defs.h +++ b/VEX/priv/guest_s390_defs.h @@ -73,7 +73,6 @@ void s390x_dirtyhelper_EX(ULong torun); ULong s390x_dirtyhelper_STCK(ULong *addr); ULong s390x_dirtyhelper_STCKF(ULong *addr); ULong s390x_dirtyhelper_STCKE(ULong *addr); -ULong s390x_dirtyhelper_STFLE(VexGuestS390XState *guest_state, ULong *addr); void s390x_dirtyhelper_CUxy(UChar *addr, ULong data, ULong num_bytes); ULong s390x_dirtyhelper_vec_op(VexGuestS390XState *guest_state, ULong details); diff --git a/VEX/priv/guest_s390_helpers.c b/VEX/priv/guest_s390_helpers.c index 9642a013e..69a7c7d06 100644 --- a/VEX/priv/guest_s390_helpers.c +++ b/VEX/priv/guest_s390_helpers.c @@ -310,129 +310,6 @@ ULong s390x_dirtyhelper_STCKF(ULong *addr) {return 3;} ULong s390x_dirtyhelper_STCKE(ULong *addr) {return 3;} #endif /* VGA_s390x */ -/*------------------------------------------------------------*/ -/*--- Dirty helper for Store Facility instruction ---*/ -/*------------------------------------------------------------*/ -#if defined(VGA_s390x) - -static ULong -s390_stfle_range(UInt lo, UInt hi) -{ - return ((1UL << (hi + 1 - lo)) - 1) << (63 - (hi % 64)); -} - -ULong -s390x_dirtyhelper_STFLE(VexGuestS390XState *guest_state, ULong *addr) -{ - ULong hoststfle[S390_NUM_FACILITY_DW], cc, last_dw, i; - register ULong reg0 asm("0") = guest_state->guest_r0; - last_dw = reg0 & 0xf; - - /* Restrict to facilities that we know about and that we assume to be - compatible with Valgrind. Of course, in this way we may reject features - that Valgrind is not really involved in (and thus would be compatible - with), but quering for such features doesn't seem like a typical use - case. */ - ULong accepted_facility[S390_NUM_FACILITY_DW] = { - /* === 0 .. 63 === */ - (s390_stfle_range(0, 16) - /* 17: message-security-assist, not supported */ - | s390_stfle_range(18, 19) - /* 20: HFP-multiply-and-add/subtract, not supported */ - | s390_stfle_range(21, 22) - /* 23: HFP-unnormalized-extension, not supported */ - | s390_stfle_range(24, 25) - /* 26: parsing-enhancement, not supported */ - | s390_stfle_range(27, 28) - /* 29: unassigned */ - | s390_stfle_range(30, 30) - /* 31: extract-CPU-time, not supported */ - | s390_stfle_range(32, 41) - /* 42-43: DFP, not fully supported */ - /* 44: PFPO, not fully supported */ - | s390_stfle_range(45, 47) - /* 48: DFP zoned-conversion, not supported */ - /* 49: includes PPA, not supported */ - /* 50: constrained transactional-execution, not supported */ - | s390_stfle_range(51, 55) - /* 56: unassigned */ - /* 57: MSA5, not supported */ - | s390_stfle_range(58, 63)), - - /* === 64 .. 127 === */ - (s390_stfle_range(64, 72) - /* 73: transactional-execution, not supported */ - | s390_stfle_range(74, 75) - /* 76: MSA3, not supported */ - /* 77: MSA4, not supported */ - | s390_stfle_range(78, 78) - /* 80: DFP packed-conversion, not supported */ - /* 81: PPA-in-order, not supported */ - | s390_stfle_range(82, 82) - /* 83-127: unassigned */ ), - - /* === 128 .. 191 === */ - (s390_stfle_range(128, 131) - /* 132: unassigned */ - /* 133: guarded-storage, not supported */ - /* 134: vector packed decimal, not supported */ - | s390_stfle_range(135, 135) - /* 136: unassigned */ - /* 137: unassigned */ - | s390_stfle_range(138, 142) - /* 143: unassigned */ - | s390_stfle_range(144, 145) - /* 146: MSA8, not supported */ - | s390_stfle_range(147, 149) - /* 150: unassigned */ - | s390_stfle_range(151, 151) - /* 152: vector packed decimal enhancement, not supported */ - /* 153: unassigned */ - /* 154: unassigned */ - /* 155: MSA9, not supported */ - | s390_stfle_range(156, 156) - /* 157-164: unassigned */ - | s390_stfle_range(165, 165) - /* 166-167: unassigned */ - | s390_stfle_range(168, 168) - /* 168-191: unassigned */ ), - - /* === 192 .. 255 === */ - /* 192: vector-packed-decimal, not supported */ - (s390_stfle_range(193, 194) - /* 195: unassigned */ - | s390_stfle_range(196, 197)), - }; - - asm(".insn s,0xb2b00000,%0\n" /* stfle */ - "ipm %2\n" - "srl %2,28\n" - : "=Q"(hoststfle), "+d"(reg0), "=d"(cc) - : - : "cc"); - - /* Update guest register 0 with what STFLE set r0 to */ - guest_state->guest_r0 = reg0; - - /* VM facilities = host facilities, filtered by acceptance */ - for (i = 0; i <= last_dw; ++i) { - if (i < S390_NUM_FACILITY_DW) - addr[i] = hoststfle[i] & accepted_facility[i]; - else - addr[i] = 0; /* mask out any excess doublewords */ - } - - return cc; -} - -#else - -ULong -s390x_dirtyhelper_STFLE(VexGuestS390XState *guest_state, ULong *addr) -{ - return 3; -} -#endif /* VGA_s390x */ /*------------------------------------------------------------*/ /*--- Dirty helper for the "convert unicode" insn family. ---*/ diff --git a/VEX/priv/guest_s390_toIR.c b/VEX/priv/guest_s390_toIR.c index 0da0b941b..35cba270d 100644 --- a/VEX/priv/guest_s390_toIR.c +++ b/VEX/priv/guest_s390_toIR.c @@ -3528,6 +3528,18 @@ s390_format_S_RD(const HChar *(*irgen)(IRTemp op2addr), s390_disasm(ENC2(MNM, UDXB), mnm, d2, 0, b2); } +static void +s390_format_S_RD_raw(const HChar *(*irgen)(UChar b2, UShort d2), + UChar b2, UShort d2) +{ + const HChar *mnm; + + mnm = irgen(b2, d2); + + if (UNLIKELY(vex_traceflags & VEX_TRACE_FE)) + s390_disasm(ENC2(MNM, UDXB), mnm, d2, 0, b2); +} + static void s390_format_SI_URD(const HChar *(*irgen)(UChar i2, IRTemp op1addr), UChar i2, UChar b1, UShort d1) @@ -15287,37 +15299,13 @@ s390_irgen_STCKE(IRTemp op2addr) } static const HChar * -s390_irgen_STFLE(IRTemp op2addr) +s390_irgen_STFLE(UChar b2, UShort d2) { if (! s390_host_has_stfle) { emulation_failure(EmFail_S390X_stfle); return "stfle"; } - - IRDirty *d; - IRTemp cc = newTemp(Ity_I64); - - /* IRExpr_GSPTR() => Need to pass pointer to guest state to helper */ - d = unsafeIRDirty_1_N(cc, 0, "s390x_dirtyhelper_STFLE", - &s390x_dirtyhelper_STFLE, - mkIRExprVec_2(IRExpr_GSPTR(), mkexpr(op2addr))); - - d->nFxState = 1; - vex_bzero(&d->fxState, sizeof(d->fxState)); - - d->fxState[0].fx = Ifx_Modify; /* read then write */ - d->fxState[0].offset = S390X_GUEST_OFFSET(guest_r0); - d->fxState[0].size = sizeof(ULong); - - d->mAddr = mkexpr(op2addr); - /* Pretend all double words are written */ - d->mSize = S390_NUM_FACILITY_DW * sizeof(ULong); - d->mFx = Ifx_Write; - - stmt(IRStmt_Dirty(d)); - - s390_cc_set(cc); - + extension(S390_EXT_STFLE, b2 | (d2 << 8)); return "stfle"; } @@ -20034,7 +20022,7 @@ s390_decode_4byte_and_irgen(const UChar *bytes) case 0xb2a7: s390_format_RRF_M0RERE(s390_irgen_CU12, RRF3_r3(ovl), RRF3_r1(ovl), RRF3_r2(ovl)); goto ok; - case 0xb2b0: s390_format_S_RD(s390_irgen_STFLE, S_b2(ovl), S_d2(ovl)); + case 0xb2b0: s390_format_S_RD_raw(s390_irgen_STFLE, S_b2(ovl), S_d2(ovl)); goto ok; case 0xb2b1: /* STFL */ goto unimplemented; case 0xb2b2: /* LPSWE */ goto unimplemented; diff --git a/VEX/pub/libvex_s390x_common.h b/VEX/pub/libvex_s390x_common.h index 9b1168a4e..5b03fb7c4 100644 --- a/VEX/pub/libvex_s390x_common.h +++ b/VEX/pub/libvex_s390x_common.h @@ -119,6 +119,7 @@ #define S390_EXT_PRNO 1 #define S390_EXT_NNPA 2 #define S390_EXT_DFLT 3 +#define S390_EXT_STFLE 4 /*--------------------------------------------------------------*/ /*--- Miscellaneous ---*/ diff --git a/coregrind/m_extension/extension-s390x.c b/coregrind/m_extension/extension-s390x.c index e94e7933c..82bd231cf 100644 --- a/coregrind/m_extension/extension-s390x.c +++ b/coregrind/m_extension/extension-s390x.c @@ -79,7 +79,8 @@ union reg_pair { unsigned __int128 pair; }; -#define S390_SETBIT(x) (1UL << (63 - (x % 64))) +#define S390_SETBIT(x) (1UL << (63 - (x % 64))) +#define S390_SETBITS(lo, hi) (((1UL << (hi + 1 - lo)) - 1) << (63 - (hi % 64))) /* Helper routine for query functions: Filter the bit vector `fc' using a given `filter' vector */ @@ -752,6 +753,111 @@ static UWord do_extension_DFLTCC(ThreadState* tst, ULong variant) return ExtErr_OK; } +/*---------------------------------------------------------------*/ +/*--- STFLE (store facility list extended) ---*/ +/*---------------------------------------------------------------*/ + +static enum ExtensionError do_extension_STFLE(ThreadState* tst, ULong variant) +{ + Int cc = 0; + UChar b2 = variant & 0xf; + UShort d2 = (variant >> 8) & 0xfff; + ULong gpr0 = READ_GPR(tst, "STFLE(r0)", 0); + ULong last_dw = gpr0 & 0xff; + ULong addr = READ_GPR(tst, "STFLE(b2)", b2) + d2; + + PRE_MEM_WRITE(tst, "STFLE(bits)", addr, (last_dw + 1) * sizeof(ULong)); + static const ULong accepted_facility[] = { + /* === 0 .. 63 === */ + (S390_SETBITS(0, 16) + /* 17: message-security-assist, not supported */ + | S390_SETBITS(18, 19) + /* 20: HFP-multiply-and-add/subtract, not supported */ + | S390_SETBITS(21, 22) + /* 23: HFP-unnormalized-extension, not supported */ + | S390_SETBITS(24, 25) + /* 26: parsing-enhancement, not supported */ + | S390_SETBITS(27, 28) + /* 29: unassigned */ + | S390_SETBITS(30, 30) + /* 31: extract-CPU-time, not supported */ + | S390_SETBITS(32, 41) + /* 42-43: DFP, not fully supported */ + /* 44: PFPO, not fully supported */ + | S390_SETBITS(45, 47) + /* 48: DFP zoned-conversion, not supported */ + /* 49: includes PPA, not supported */ + /* 50: constrained transactional-execution, not supported */ + | S390_SETBITS(51, 55) + /* 56: unassigned */ + /* 57: MSA5, not supported */ + | S390_SETBITS(58, 63)), + + /* === 64 .. 127 === */ + (S390_SETBITS(64, 72) + /* 73: transactional-execution, not supported */ + | S390_SETBITS(74, 75) + /* 76: MSA3, not supported */ + /* 77: MSA4, not supported */ + | S390_SETBITS(78, 78) + /* 80: DFP packed-conversion, not supported */ + /* 81: PPA-in-order, not supported */ + | S390_SETBITS(82, 82) + /* 83-127: unassigned */), + + /* === 128 .. 191 === */ + (S390_SETBITS(128, 131) + /* 132: unassigned */ + /* 133: guarded-storage, not supported */ + /* 134: vector packed decimal, not supported */ + | S390_SETBITS(135, 135) + /* 136: unassigned */ + /* 137: unassigned */ + | S390_SETBITS(138, 142) + /* 143: unassigned */ + | S390_SETBITS(144, 145) + /* 146: MSA8, not supported */ + | S390_SETBITS(147, 149) + /* 150: unassigned */ + | S390_SETBITS(151, 151) + /* 152: vector packed decimal enhancement, not supported */ + /* 153: unassigned */ + /* 154: unassigned */ + /* 155: MSA9, not supported */ + | S390_SETBITS(156, 156) + /* 157-164: unassigned */ + | S390_SETBITS(165, 165) + /* 166-167: unassigned */ + | S390_SETBITS(168, 168) + /* 168-191: unassigned */), + + /* === 192 .. 255 === */ + /* 192: vector-packed-decimal, not supported */ + (S390_SETBITS(193, 194) + /* 195: unassigned */ + | S390_SETBITS(196, 197)), + }; + asm("lgr 0,%[r0]\n" + ".insn s,0xb2b00000,%[out]\n" /* stfle */ + "lgr %[r0],0\n" + "ipm %[cc]\n" + "srl %[cc],28\n" + : [out] "=Q"(*(ULong(*)[last_dw + 1])(void*)addr), [r0] "+d"(gpr0), + [cc] "=d"(cc) + : + : "cc"); + + WRITE_GPR(tst, 0, gpr0); + if (last_dw > (gpr0 & 0xff)) + last_dw = gpr0 & 0xff; + s390_filter_functions((ULong*)addr, (last_dw + 1) * sizeof(ULong), + accepted_facility, sizeof(accepted_facility)); + POST_MEM_WRITE(tst, addr, (last_dw + 1) * sizeof(ULong)); + + WRITE_CC(tst, cc); + return ExtErr_OK; +} + /*---------------------------------------------------------------*/ /*--- Main function: select and call appropriate extension ---*/ /*---------------------------------------------------------------*/ @@ -769,6 +875,8 @@ enum ExtensionError ML_(do_client_extension)(ThreadState* tst) return do_extension_NNPA(tst, variant); case S390_EXT_DFLT: return do_extension_DFLTCC(tst, variant); + case S390_EXT_STFLE: + return do_extension_STFLE(tst, variant); default: VG_(core_panic)("unknown extension ID"); }