]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Bug 385412 - s390x: new non-vector z13 instructions not implemented
authorJulian Seward <jseward@acm.org>
Tue, 24 Jul 2018 08:10:40 +0000 (10:10 +0200)
committerJulian Seward <jseward@acm.org>
Tue, 24 Jul 2018 08:10:40 +0000 (10:10 +0200)
Apart from instructions with vector operands, Valgrind does not implement the
additional z/Architecture instructions introduced with z13.

These are:
- load and zero rightmost byte (LZRF, LZRG);
- load logical and zero rightmost byte (LLZRGF);
- load halfword high immediate on condition (LOCHHI);
- load halfword immediate on condition (LOCHI, LOCGHI);
- load high on condition (LOCFHR, LOCFH);
- store high on condition (STOCFH);
- perform pseudorandom number operation (PPNO), with the functions
  PPNO-Query and PPNO-SHA-512-DRNG;
- load count to block boundary (LCBB).

Patches from Vadim Barkov (vbrkov@gmail.com), with coordination, testing
and format cleanups from Andreas Arnez (arnez@linux.ibm.com).

23 files changed:
.gitignore
VEX/priv/guest_s390_defs.h
VEX/priv/guest_s390_helpers.c
VEX/priv/guest_s390_toIR.c
VEX/priv/host_s390_defs.c
VEX/priv/host_s390_defs.h
VEX/priv/s390_defs.h
VEX/priv/s390_disasm.c
VEX/priv/s390_disasm.h
VEX/pub/libvex.h
VEX/pub/libvex_emnote.h
VEX/pub/libvex_s390x_common.h
coregrind/m_machine.c
none/tests/s390x/Makefile.am
none/tests/s390x/lsc2.c [new file with mode: 0644]
none/tests/s390x/lsc2.stderr.exp [new file with mode: 0644]
none/tests/s390x/lsc2.stdout.exp [new file with mode: 0644]
none/tests/s390x/lsc2.vgtest [new file with mode: 0644]
none/tests/s390x/ppno.c [new file with mode: 0644]
none/tests/s390x/ppno.stderr.exp [new file with mode: 0644]
none/tests/s390x/ppno.stdout.exp [new file with mode: 0644]
none/tests/s390x/ppno.vgtest [new file with mode: 0644]
tests/s390x_features.c

index 305bbb2362ef1d0dbe225b35645d54a67800ad1b..72b7c3d46bade8d6a4ea04bffab77d75b4b8a9cf 100644 (file)
 /none/tests/s390x/fixbr
 /none/tests/s390x/popcnt
 /none/tests/s390x/vector
+/none/tests/s390x/lsc2
+/none/tests/s390x/ppno
 
 # /none/tests/scripts/
 /none/tests/scripts/*.dSYM
index d3dede7a810c2209041b1ca49bd4f8f336ce7f99..4f9e962d3aceaae5c8a28c823963e5faaec72e1b 100644 (file)
@@ -95,7 +95,9 @@ UInt  s390_do_cvb(ULong decimal);
 ULong s390_do_cvd(ULong binary);
 ULong s390_do_ecag(ULong op2addr);
 UInt  s390_do_pfpo(UInt gpr0);
-
+void  s390x_dirtyhelper_PPNO_query(VexGuestS390XState *guest_state, ULong r1, ULong r2);
+ULong  s390x_dirtyhelper_PPNO_sha512(VexGuestS390XState *guest_state, ULong r1, ULong r2);
+void  s390x_dirtyhelper_PPNO_sha512_load_param_block( void );
 /* The various ways to compute the condition code. */
 enum {
    S390_CC_OP_BITWISE = 0,
index 77772fe104d7901be4835390a20e4e87f6086464..52e4ce936800e158165f6f2f9d7fde3466a324bf 100644 (file)
@@ -365,6 +365,7 @@ s390x_dirtyhelper_STFLE(VexGuestS390XState *guest_state, ULong *addr)
    s390_set_facility_bit(addr, S390_FAC_GIE,    1);
    s390_set_facility_bit(addr, S390_FAC_EXEXT,  1);
    s390_set_facility_bit(addr, S390_FAC_HIGHW,  1);
+   s390_set_facility_bit(addr, S390_FAC_LSC2,   1);
 
    s390_set_facility_bit(addr, S390_FAC_HFPMAS, 0);
    s390_set_facility_bit(addr, S390_FAC_HFPUNX, 0);
@@ -2525,6 +2526,75 @@ s390x_dirtyhelper_vec_binop(VexGuestS390XState *guest_state, ULong opcode,
 
 #endif
 
+/*-----------------------------------------------------------------*/
+/*--- Dirty helper for Perform Pseudorandom number instruction  ---*/
+/*-----------------------------------------------------------------*/
+
+/* Dummy helper that is needed to indicate load of parameter block.
+   We have to use it because dirty helper cannot have two memory side
+   effects.
+ */
+void s390x_dirtyhelper_PPNO_sha512_load_param_block( void )
+{
+}
+
+#if defined(VGA_s390x)
+
+/* IMPORTANT!
+   We return here bit mask where only supported functions are set to one.
+   If you implement new functions don't forget the supported array.
+ */
+void
+s390x_dirtyhelper_PPNO_query(VexGuestS390XState *guest_state, ULong r1, ULong r2)
+{
+   ULong supported[2] = {0x9000000000000000ULL, 0x0000000000000000ULL};
+   ULong *result = (ULong*) guest_state->guest_r1;
+
+   result[0] = supported[0];
+   result[1] = supported[1];
+}
+
+ULong
+s390x_dirtyhelper_PPNO_sha512(VexGuestS390XState *guest_state, ULong r1, ULong r2)
+{
+   ULong* op1 = (ULong*) (((ULong)(&guest_state->guest_r0)) + r1 * sizeof(ULong));
+   ULong* op2 = (ULong*) (((ULong)(&guest_state->guest_r0)) + r2 * sizeof(ULong));
+
+   register ULong reg0 asm("0") = guest_state->guest_r0;
+   register ULong reg1 asm("1") = guest_state->guest_r1;
+   register ULong reg2 asm("2") = op1[0];
+   register ULong reg3 asm("3") = op1[1];
+   register ULong reg4 asm("4") = op2[0];
+   register ULong reg5 asm("5") = op2[1];
+
+   ULong cc = 0;
+   asm volatile(".insn rre, 0xb93c0000, %%r2, %%r4\n"
+                "ipm %[cc]\n"
+                "srl %[cc], 28\n"
+                : "+d"(reg0), "+d"(reg1),
+                  "+d"(reg2), "+d"(reg3),
+                  "+d"(reg4), "+d"(reg5),
+                  [cc] "=d"(cc)
+                :
+                : "cc", "memory");
+
+   return cc;
+}
+
+#else
+
+void
+s390x_dirtyhelper_PPNO_query(VexGuestS390XState *guest_state, ULong r1, ULong r2)
+{
+}
+
+ULong
+s390x_dirtyhelper_PPNO_sha512(VexGuestS390XState *guest_state, ULong r1, ULong r2)
+{
+   return 0;
+}
+
+#endif /* VGA_s390x */
 /*---------------------------------------------------------------*/
 /*--- end                                guest_s390_helpers.c ---*/
 /*---------------------------------------------------------------*/
index cca684a8e2ee0899d6bbf9af40ee485c3efca585..1697e9744bfc7487b87a207db1b06128394bf6ff 100644 (file)
@@ -2243,6 +2243,18 @@ s390_format_RIE_RUPI(const HChar *(*irgen)(UChar r1, UChar m3, UShort i4,
                   (Int)(Char)i2, m3, (Int)(Short)i4);
 }
 
+static void
+s390_format_RIE_RUPIX(const HChar *(*irgen)(UChar r1, UChar m3, UShort i4,
+                                           UChar i2),
+                     UChar r1, UChar m3, UShort i4, UChar i2, Int xmnm_kind)
+{
+   const HChar *mnm = irgen(r1, m3, i4, i2);
+
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_FE))
+      s390_disasm(ENC5(XMNM, GPR, INT, CABM, PCREL), xmnm_kind, mnm, m3, r1,
+                  (Int)(Char)i2, m3, (Int)(Short)i4);
+}
+
 static void
 s390_format_RIL(const HChar *(*irgen)(UChar r1, UInt i2),
                 UChar r1, UInt i2)
@@ -2787,6 +2799,23 @@ s390_format_RXE_FRRD(const HChar *(*irgen)(UChar r1, IRTemp op2addr),
       s390_disasm(ENC3(MNM, FPR, UDXB), mnm, r1, d2, x2, b2);
 }
 
+static void
+s390_format_RXE_RRRDR(const HChar *(*irgen)(UChar r1, IRTemp op2addr, UChar m3),
+                     UChar r1, UChar x2, UChar b2, UShort d2, UChar m3)
+{
+   const HChar *mnm;
+   IRTemp op2addr = newTemp(Ity_I64);
+
+   assign(op2addr, binop(Iop_Add64, binop(Iop_Add64, mkU64(d2),
+          b2 != 0 ? get_gpr_dw0(b2) : mkU64(0)), x2 != 0 ? get_gpr_dw0(x2) :
+          mkU64(0)));
+
+   mnm = irgen(r1, op2addr, m3);
+
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_FE))
+      s390_disasm(ENC3(MNM, GPR, UDXB), mnm, r1, d2, x2, b2);
+}
+
 static void
 s390_format_RXF_FRRDF(const HChar *(*irgen)(UChar, IRTemp, UChar),
                       UChar r3, UChar x2, UChar b2, UShort d2, UChar r1)
@@ -15699,6 +15728,288 @@ s390_irgen_VNO(UChar v1, UChar v2, UChar v3)
    return "vno";
 }
 
+static const HChar *
+s390_irgen_LZRF(UChar r1, IRTemp op2addr)
+{
+   IRTemp op2 = newTemp(Ity_I32);
+
+   assign(op2, binop(Iop_And32, load(Ity_I32, mkexpr(op2addr)), mkU32(0xffffff00)));
+   put_gpr_w1(r1, mkexpr(op2));
+
+   return "lzrf";
+}
+
+static const HChar *
+s390_irgen_LZRG(UChar r1, IRTemp op2addr)
+{
+   IRTemp op2 = newTemp(Ity_I64);
+
+   assign(op2, binop(Iop_And64, load(Ity_I64, mkexpr(op2addr)), mkU64(0xffffffffffffff00UL)));
+   put_gpr_dw0(r1, mkexpr(op2));
+
+   return "lzrg";
+}
+
+static const HChar *
+s390_irgen_LLZRGF(UChar r1, IRTemp op2addr)
+{
+   IRTemp op2 = newTemp(Ity_I32);
+
+   assign(op2, binop(Iop_And32, load(Ity_I32, mkexpr(op2addr)), mkU32(0xffffff00)));
+   put_gpr_w1(r1, mkexpr(op2));
+   put_gpr_w0(r1, mkU32(0));
+
+   return "llzrgf";
+}
+
+static const HChar *
+s390_irgen_LOCFH(UChar r1, IRTemp op2addr)
+{
+   /* condition is checked in format handler */
+   put_gpr_w0(r1, load(Ity_I32, mkexpr(op2addr)));
+
+   return "locfh";
+}
+
+static const HChar *
+s390_irgen_LOCFHR(UChar m3, UChar r1, UChar r2)
+{
+   next_insn_if(binop(Iop_CmpEQ32, s390_call_calculate_cond(m3), mkU32(0)));
+   put_gpr_w0(r1, get_gpr_w0(r2));
+
+   return "locfhr";
+}
+
+static const HChar *
+s390_irgen_LOCHHI(UChar r1, UChar m3, UShort i2, UChar unused)
+{
+   next_insn_if(binop(Iop_CmpEQ32, s390_call_calculate_cond(m3), mkU32(0)));
+   put_gpr_w0(r1, mkU32(i2));
+
+   return "lochhi";
+}
+
+static const HChar *
+s390_irgen_LOCHI(UChar r1, UChar m3, UShort i2, UChar unused)
+{
+   next_insn_if(binop(Iop_CmpEQ32, s390_call_calculate_cond(m3), mkU32(0)));
+   put_gpr_w1(r1, mkU32(i2));
+
+   return "lochi";
+}
+
+static const HChar *
+s390_irgen_LOCGHI(UChar r1, UChar m3, UShort i2, UChar unused)
+{
+   next_insn_if(binop(Iop_CmpEQ32, s390_call_calculate_cond(m3), mkU32(0)));
+   put_gpr_dw0(r1, mkU64(i2));
+
+   return "locghi";
+}
+
+static const HChar *
+s390_irgen_STOCFH(UChar r1, IRTemp op2addr)
+{
+   /* condition is checked in format handler */
+   store(mkexpr(op2addr), get_gpr_w1(r1));
+
+   return "stocfh";
+}
+
+static const HChar *
+s390_irgen_LCBB(UChar r1, IRTemp op2addr, UChar m3)
+{
+   IRTemp op2 = newTemp(Ity_I32);
+   assign(op2, s390_getCountToBlockBoundary(op2addr, m3));
+   put_gpr_w1(r1, mkexpr(op2));
+
+   IRExpr* cc = mkite(binop(Iop_CmpEQ32, mkexpr(op2), mkU32(16)), mkU64(0), mkU64(3));
+   s390_cc_thunk_fill(mkU64(S390_CC_OP_SET), cc, mkU64(0), mkU64(0));
+
+   return "lcbb";
+}
+
+/* Regarding the use of 
+   // Dummy helper which is used to signal VEX library that memory was loaded
+   sha512_loadparam 
+     = unsafeIRDirty_0_N(0, "s390x_dirtyhelper_PPNO_sha512_load_param_block",
+                             &s390x_dirtyhelper_PPNO_sha512_load_param_block,
+                             mkIRExprVec_0());
+
+   in the following function (s390_irgen_PPNO).  This is a workaround to get
+   around the fact that IRDirty annotations cannot indicate two memory side
+   effects, which are unfortunately necessary here.  It will possibly lead to
+   losing undefinedness (undefinedness in some inputs might not be propagated
+   to the outputs as it shouod, in Memcheck).  The correct fix would be to
+   extend IRDirty to represent two memory side effects, but that's quite a bit
+   of work.
+
+   Here's a summary of what this insn does.
+
+   // getReg(RegisterNumber n) returns the value of GPR number 'n'
+
+   // reg1 and reg2 are even
+   void ppno(RegisterNumber reg1, RegisterNumber reg2) {
+
+       switch(getReg(0)) {
+       case 0x0:
+           // Query mode, ignore reg1 and reg2
+           // Write 16 bytes                    at  getReg(1)
+           break;
+
+       case 0x3:
+           // SHA-512 generate mode, ignore reg2
+
+           // Read 240 bytes                    at  getReg(1)
+           // Write getReg(reg1 + 1) bytes      at  getReg(reg1)
+           // Write some of 240 bytes starting  at  getReg(1)
+           break;
+
+       case 0x83:
+           // SHA-512 seed mode, ignore reg1
+
+           // Read some of 240 bytes starting  at  getReg(1)
+           // Read getReg(reg2 + 1) bytes      at  getReg(reg2)
+           // Write 240 bytes                  at  getReg(1)
+           break;
+
+       default:
+           // Specification exception, abort execution.
+       }
+   }
+*/
+/* Also known as "prno"
+   If you implement new functions please don't forget to update
+   "s390x_dirtyhelper_PPNO_query" function.
+ */
+static const HChar *
+s390_irgen_PPNO(UChar r1, UChar r2)
+{
+   if (!s390_host_has_msa5) {
+      emulation_failure(EmFail_S390X_ppno);
+      return "ppno";
+   }
+
+   /* Theese conditions lead to specification exception */
+   vassert(r1 % 2 == 0);
+   vassert(r2 % 2 == 0);
+   vassert((r1 != 0) && (r2 != 0));
+
+   IRDirty *query, *sha512_gen, *sha512_seed, *sha512_loadparam;
+   IRTemp gpr1num = newTemp(Ity_I64);
+   IRTemp gpr2num = newTemp(Ity_I64);
+
+   IRTemp funcCode = newTemp(Ity_I8);
+   IRTemp is_query = newTemp(Ity_I1);
+   IRTemp is_sha512_gen = newTemp(Ity_I1);
+   IRTemp is_sha512_seed = newTemp(Ity_I1);
+   IRTemp is_sha512 = newTemp(Ity_I1);
+
+   assign(funcCode, unop(Iop_64to8, binop(Iop_And64, get_gpr_dw0(0), mkU64(0xffULL))));
+   assign(gpr1num, mkU64(r1));
+   assign(gpr2num, mkU64(r2));
+
+   assign(is_query, binop(Iop_CmpEQ8, mkexpr(funcCode), mkU8(S390_PPNO_QUERY)));
+   assign(is_sha512_gen, binop(Iop_CmpEQ8, mkexpr(funcCode), mkU8(S390_PPNO_SHA512_GEN)));
+   assign(is_sha512_seed, binop(Iop_CmpEQ8, mkexpr(funcCode), mkU8(S390_PPNO_SHA512_SEED)));
+   assign(is_sha512, binop(Iop_CmpEQ8,
+                           mkU8(S390_PPNO_SHA512_GEN),
+                           binop(Iop_And8,
+                                 mkexpr(funcCode),
+                                 mkU8(S390_PPNO_SHA512_GEN)
+                                 )
+                           ));
+
+   query = unsafeIRDirty_0_N(0, "s390x_dirtyhelper_PPNO_query",
+                             &s390x_dirtyhelper_PPNO_query,
+                             mkIRExprVec_3(IRExpr_GSPTR(), mkexpr(gpr1num), mkexpr(gpr2num)));
+   query->guard = mkexpr(is_query);
+   query->nFxState = 1;
+   vex_bzero(&query->fxState, sizeof(query->fxState));
+   query->fxState[0].fx     = Ifx_Read;
+   query->fxState[0].offset = S390X_GUEST_OFFSET(guest_r0);
+   query->fxState[0].size   = 2 * sizeof(ULong); /* gpr0 and gpr1 are read */
+   query->mAddr = get_gpr_dw0(1);
+   query->mSize = S390_PPNO_PARAM_BLOCK_SIZE_QUERY;
+   query->mFx   = Ifx_Write;
+
+   IRTemp gen_cc = newTemp(Ity_I64);
+   sha512_gen = unsafeIRDirty_1_N(gen_cc, 0, "s390x_dirtyhelper_PPNO_sha512",
+                             &s390x_dirtyhelper_PPNO_sha512,
+                             mkIRExprVec_3(IRExpr_GSPTR(), mkexpr(gpr1num), mkexpr(gpr2num)));
+   sha512_gen->guard = mkexpr(is_sha512_gen);
+   sha512_gen->nFxState = 3;
+   vex_bzero(&sha512_gen->fxState, sizeof(sha512_gen->fxState));
+   sha512_gen->fxState[0].fx     = Ifx_Read;
+   sha512_gen->fxState[0].offset = S390X_GUEST_OFFSET(guest_r0);
+   sha512_gen->fxState[0].size   = 2 * sizeof(ULong); /* gpr0 and gpr1 are read */
+   sha512_gen->fxState[1].fx     = Ifx_Read;
+   sha512_gen->fxState[1].offset = S390X_GUEST_OFFSET(guest_r0) + r1 * sizeof(ULong);
+   sha512_gen->fxState[1].size   = sizeof(ULong);
+   sha512_gen->fxState[2].fx     = Ifx_Modify;
+   sha512_gen->fxState[2].offset = S390X_GUEST_OFFSET(guest_r0) + (r1 + 1) * sizeof(ULong);
+   sha512_gen->fxState[2].size   = sizeof(ULong);
+   sha512_gen->mAddr = get_gpr_dw0(r1);
+   sha512_gen->mSize = S390_PPNO_MAX_SIZE_SHA512_GEN;
+   sha512_gen->mFx   = Ifx_Write;
+
+   IRTemp unused = newTemp(Ity_I64);
+   sha512_seed = unsafeIRDirty_1_N(unused, 0, "s390x_dirtyhelper_PPNO_sha512",
+                             &s390x_dirtyhelper_PPNO_sha512,
+                             mkIRExprVec_3(IRExpr_GSPTR(), mkexpr(gpr1num), mkexpr(gpr2num)));
+   sha512_seed->guard = mkexpr(is_sha512_seed);
+   sha512_seed->nFxState = 2;
+   vex_bzero(&sha512_seed->fxState, sizeof(sha512_seed->fxState));
+   sha512_seed->fxState[0].fx     = Ifx_Read;
+   sha512_seed->fxState[0].offset = S390X_GUEST_OFFSET(guest_r0);
+   sha512_seed->fxState[0].size   = 2 * sizeof(ULong); /* gpr0 and gpr1 are read */
+   sha512_seed->fxState[1].fx     = Ifx_Read;
+   sha512_seed->fxState[1].offset = S390X_GUEST_OFFSET(guest_r0) + r2 * sizeof(ULong);
+   sha512_seed->fxState[1].size   = 2 * sizeof(ULong); /* r2 and r2 + 1 are read */
+   sha512_seed->mAddr = get_gpr_dw0(r2);
+   sha512_seed->mSize = S390_PPNO_MAX_SIZE_SHA512_SEED;
+   sha512_seed->mFx   = Ifx_Write;
+
+   /* Dummy helper which is used to signal VEX library that memory was loaded */
+   sha512_loadparam = unsafeIRDirty_0_N(0, "s390x_dirtyhelper_PPNO_sha512_load_param_block",
+                             &s390x_dirtyhelper_PPNO_sha512_load_param_block,
+                             mkIRExprVec_0());
+   sha512_loadparam->guard = mkexpr(is_sha512);
+   sha512_loadparam->nFxState = 0;
+   vex_bzero(&sha512_loadparam->fxState, sizeof(sha512_loadparam->fxState));
+   sha512_loadparam->mAddr = get_gpr_dw0(1);
+   sha512_loadparam->mSize = S390_PPNO_PARAM_BLOCK_SIZE_SHA512;
+   sha512_loadparam->mFx   = Ifx_Read;
+
+   IRDirty*
+   sha512_saveparam = unsafeIRDirty_0_N(0, "s390x_dirtyhelper_PPNO_sha512_save_param_block",
+                             &s390x_dirtyhelper_PPNO_sha512_load_param_block,
+                             mkIRExprVec_0());
+   sha512_saveparam->guard = mkexpr(is_sha512);
+   sha512_saveparam->nFxState = 0;
+   vex_bzero(&sha512_saveparam->fxState, sizeof(sha512_saveparam->fxState));
+   sha512_saveparam->mAddr = get_gpr_dw0(1);
+   sha512_saveparam->mSize = S390_PPNO_PARAM_BLOCK_SIZE_SHA512;
+   sha512_saveparam->mFx   = Ifx_Write;
+
+   stmt(IRStmt_Dirty(query));
+   stmt(IRStmt_Dirty(sha512_loadparam));
+   stmt(IRStmt_Dirty(sha512_gen));
+   stmt(IRStmt_Dirty(sha512_seed));
+   stmt(IRStmt_Dirty(sha512_saveparam));
+
+   IRTemp cc = newTemp(Ity_I64);
+   assign(cc,
+          mkite(mkexpr(is_sha512_gen),
+                mkexpr(gen_cc),
+                mkU64(0)
+               )
+         );
+
+   s390_cc_thunk_fill(mkU64(S390_CC_OP_SET), mkexpr(cc), mkU64(0), mkU64(0));
+
+   return "ppno";
+}
 
 /* New insns are added here.
    If an insn is contingent on a facility being installed also
@@ -16590,7 +16901,8 @@ s390_decode_4byte_and_irgen(const UChar *bytes)
                                    ovl.fmt.RRE.r2);  goto ok;
    case 0xb931: s390_format_RRE_RR(s390_irgen_CLGFR, ovl.fmt.RRE.r1,
                                    ovl.fmt.RRE.r2);  goto ok;
-   case 0xb93c: /* PPNO */ goto unimplemented;
+   case 0xb93c: s390_format_RRE_RR(s390_irgen_PPNO, ovl.fmt.RRE.r1,
+                                   ovl.fmt.RRE.r2);  goto ok;
    case 0xb93e: /* KIMD */ goto unimplemented;
    case 0xb93f: /* KLMD */ goto unimplemented;
    case 0xb941: s390_format_RRF_UURF(s390_irgen_CFDTR, ovl.fmt.RRF2.m3,
@@ -16733,7 +17045,9 @@ s390_decode_4byte_and_irgen(const UChar *bytes)
                                    ovl.fmt.RRE.r2);  goto ok;
    case 0xb9df: s390_format_RRE_RR(s390_irgen_CLHLR, ovl.fmt.RRE.r1,
                                    ovl.fmt.RRE.r2);  goto ok;
-   case 0xb9e0: /* LOCFHR */ goto unimplemented;
+   case 0xb9e0: s390_format_RRF_U0RR(s390_irgen_LOCFHR, ovl.fmt.RRF3.r3,
+                                     ovl.fmt.RRF3.r1, ovl.fmt.RRF3.r2,
+                                     S390_XMNM_LOCFHR);  goto ok;
    case 0xb9e1: s390_format_RRE_RR(s390_irgen_POPCNT, ovl.fmt.RRE.r1,
                                    ovl.fmt.RRE.r2);  goto ok;
    case 0xb9e2: s390_format_RRF_U0RR(s390_irgen_LOCGR, ovl.fmt.RRF3.r3,
@@ -17310,7 +17624,10 @@ s390_decode_6byte_and_irgen(const UChar *bytes)
                                                 ovl.fmt.RXY.x2, ovl.fmt.RXY.b2,
                                                 ovl.fmt.RXY.dl2,
                                                 ovl.fmt.RXY.dh2);  goto ok;
-   case 0xe3000000002aULL: /* LZRG */ goto unimplemented;
+   case 0xe3000000002aULL: s390_format_RXY_RRRD(s390_irgen_LZRG, ovl.fmt.RXY.r1,
+                                                ovl.fmt.RXY.x2, ovl.fmt.RXY.b2,
+                                                ovl.fmt.RXY.dl2,
+                                                ovl.fmt.RXY.dh2);  goto ok;
    case 0xe3000000002eULL: /* CVDG */ goto unimplemented;
    case 0xe3000000002fULL: s390_format_RXY_RRRD(s390_irgen_STRVG,
                                                 ovl.fmt.RXY.r1, ovl.fmt.RXY.x2,
@@ -17338,8 +17655,14 @@ s390_decode_6byte_and_irgen(const UChar *bytes)
                                                 ovl.fmt.RXY.dh2);  goto ok;
    case 0xe30000000038ULL: /* AGH */ goto unimplemented;
    case 0xe30000000039ULL: /* SGH */ goto unimplemented;
-   case 0xe3000000003aULL: /* LLZRGF */ goto unimplemented;
-   case 0xe3000000003bULL: /* LZRF */ goto unimplemented;
+   case 0xe3000000003aULL: s390_format_RXY_RRRD(s390_irgen_LLZRGF, ovl.fmt.RXY.r1,
+                                                ovl.fmt.RXY.x2, ovl.fmt.RXY.b2,
+                                                ovl.fmt.RXY.dl2,
+                                                ovl.fmt.RXY.dh2);  goto ok;
+   case 0xe3000000003bULL: s390_format_RXY_RRRD(s390_irgen_LZRF, ovl.fmt.RXY.r1,
+                                                ovl.fmt.RXY.x2, ovl.fmt.RXY.b2,
+                                                ovl.fmt.RXY.dl2,
+                                                ovl.fmt.RXY.dh2);  goto ok;
    case 0xe3000000003cULL: /* MGH */ goto unimplemented;
    case 0xe3000000003eULL: s390_format_RXY_RRRD(s390_irgen_STRV, ovl.fmt.RXY.r1,
                                                 ovl.fmt.RXY.x2, ovl.fmt.RXY.b2,
@@ -17665,10 +17988,12 @@ s390_decode_6byte_and_irgen(const UChar *bytes)
    case 0xe70000000021ULL: s390_format_VRS_RRDVM(s390_irgen_VLGV, ovl.fmt.VRS.v1,
                                                 ovl.fmt.VRS.b2, ovl.fmt.VRS.d2, ovl.fmt.VRS.v3,
                                                 ovl.fmt.VRS.m4, ovl.fmt.VRS.rxb);  goto ok;
-   case 0xe70000000027ULL: /* LCBB */ goto unimplemented;
    case 0xe70000000022ULL: s390_format_VRS_VRRDM(s390_irgen_VLVG, ovl.fmt.VRS.v1,
                                                 ovl.fmt.VRS.b2, ovl.fmt.VRS.d2, ovl.fmt.VRS.v3,
                                                 ovl.fmt.VRS.m4, ovl.fmt.VRS.rxb);  goto ok;
+   case 0xe70000000027ULL: s390_format_RXE_RRRDR(s390_irgen_LCBB, ovl.fmt.RXE.r1,
+                                                 ovl.fmt.RXE.x2, ovl.fmt.RXE.b2,
+                                                 ovl.fmt.RXE.d2, ovl.fmt.RXE.m3);  goto ok;
    case 0xe70000000030ULL: /* VESL */ goto unimplemented;
    case 0xe70000000033ULL: /* VERLL */ goto unimplemented;
    case 0xe70000000036ULL: s390_format_VRS_VRDV(s390_irgen_VLM, ovl.fmt.VRS.v1,
@@ -17941,7 +18266,7 @@ s390_decode_6byte_and_irgen(const UChar *bytes)
                                                 ovl.fmt.RSY.dh2);  goto ok;
    case 0xeb000000004cULL: s390_format_RSY_RRRD(s390_irgen_ECAG, ovl.fmt.RSY.r1,
                                                 ovl.fmt.RSY.r3, ovl.fmt.RSY.b2,
-                                                ovl.fmt.RSY.dl2, 
+                                                ovl.fmt.RSY.dl2,
                                                 ovl.fmt.RSY.dh2);  goto ok;
    case 0xeb0000000051ULL: s390_format_SIY_URD(s390_irgen_TMY, ovl.fmt.SIY.i2,
                                                ovl.fmt.SIY.b1, ovl.fmt.SIY.dl1,
@@ -18020,8 +18345,16 @@ s390_decode_6byte_and_irgen(const UChar *bytes)
                                                 ovl.fmt.RSY.r3, ovl.fmt.RSY.b2,
                                                 ovl.fmt.RSY.dl2,
                                                 ovl.fmt.RSY.dh2);  goto ok;
-   case 0xeb00000000e0ULL: /* LOCFH */ goto unimplemented;
-   case 0xeb00000000e1ULL: /* STOCFH */ goto unimplemented;
+   case 0xeb00000000e0ULL: s390_format_RSY_RDRM(s390_irgen_LOCFH, ovl.fmt.RSY.r1,
+                                                ovl.fmt.RSY.r3, ovl.fmt.RSY.b2,
+                                                ovl.fmt.RSY.dl2,
+                                                ovl.fmt.RSY.dh2,
+                                                S390_XMNM_LOCFH);  goto ok;
+   case 0xeb00000000e1ULL: s390_format_RSY_RDRM(s390_irgen_STOCFH, ovl.fmt.RSY.r1,
+                                                ovl.fmt.RSY.r3, ovl.fmt.RSY.b2,
+                                                ovl.fmt.RSY.dl2,
+                                                ovl.fmt.RSY.dh2,
+                                                S390_XMNM_STOCFH);  goto ok;
    case 0xeb00000000e2ULL: s390_format_RSY_RDRM(s390_irgen_LOCG, ovl.fmt.RSY.r1,
                                                 ovl.fmt.RSY.r3, ovl.fmt.RSY.b2,
                                                 ovl.fmt.RSY.dl2,
@@ -18082,15 +18415,30 @@ s390_decode_6byte_and_irgen(const UChar *bytes)
                                                 ovl.fmt.RSY.r3, ovl.fmt.RSY.b2,
                                                 ovl.fmt.RSY.dl2,
                                                 ovl.fmt.RSY.dh2);  goto ok;
-   case 0xec0000000042ULL: /* LOCHI */ goto unimplemented;
+   case 0xec0000000042ULL: s390_format_RIE_RUPIX(s390_irgen_LOCHI,
+                                                 ovl.fmt.RIEv3.r1,
+                                                 ovl.fmt.RIEv3.m3,
+                                                 ovl.fmt.RIEv3.i4,
+                                                 ovl.fmt.RIEv3.i2,
+                                                 S390_XMNM_LOCHI);  goto ok;
    case 0xec0000000044ULL: s390_format_RIE_RRP(s390_irgen_BRXHG, ovl.fmt.RIE.r1,
                                                ovl.fmt.RIE.r3, ovl.fmt.RIE.i2);
                                                goto ok;
    case 0xec0000000045ULL: s390_format_RIE_RRP(s390_irgen_BRXLG, ovl.fmt.RIE.r1,
                                                ovl.fmt.RIE.r3, ovl.fmt.RIE.i2);
                                                goto ok;
-   case 0xec0000000046ULL: /* LOCGHI */ goto unimplemented;
-   case 0xec000000004eULL: /* LOCHHI */ goto unimplemented;
+   case 0xec0000000046ULL: s390_format_RIE_RUPIX(s390_irgen_LOCGHI,
+                                                 ovl.fmt.RIEv3.r1,
+                                                 ovl.fmt.RIEv3.m3,
+                                                 ovl.fmt.RIEv3.i4,
+                                                 ovl.fmt.RIEv3.i2,
+                                                 S390_XMNM_LOCGHI);  goto ok;
+   case 0xec000000004eULL: s390_format_RIE_RUPIX(s390_irgen_LOCHHI,
+                                                 ovl.fmt.RIEv3.r1,
+                                                 ovl.fmt.RIEv3.m3,
+                                                 ovl.fmt.RIEv3.i4,
+                                                 ovl.fmt.RIEv3.i2,
+                                                 S390_XMNM_LOCHHI);  goto ok;
    case 0xec0000000051ULL: s390_format_RIE_RRUUU(s390_irgen_RISBLG,
                                                  ovl.fmt.RIE_RRUUU.r1,
                                                  ovl.fmt.RIE_RRUUU.r2,
index d03ed5f07c953ed4374880a3c5aaefa163a72bd2..d41093eb0133d758acfcbc47ea993b07116218c1 100644 (file)
@@ -9289,36 +9289,37 @@ s390_insn_helper_call_emit(UChar *buf, const s390_insn *insn)
 {
    s390_cc_t cond;
    ULong target;
-   UChar *ptmp = buf;
+   Int delta;
    s390_helper_call *helper_call = insn->variant.helper_call.details;
 
    cond = helper_call->cond;
    target = helper_call->target;
 
-   if (cond != S390_CC_ALWAYS
-       && helper_call->rloc.pri != RLPri_None) {
-      /* The call might not happen (it isn't unconditional) and it
-         returns a result.  In this case we will need to generate a
-         control flow diamond to put 0x555..555 in the return
-         register(s) in the case where the call doesn't happen.  If
-         this ever becomes necessary, maybe copy code from the ARM
-         equivalent.  Until that day, just give up. */
-      return buf; /* To denote failure. */
-   }
+   const Bool not_always = (cond != S390_CC_ALWAYS);
+   const Bool not_void_return = (helper_call->rloc.pri != RLPri_None);
+
+   /* We have this situation:
+      ( *** code in this braces is for  not_always && not_void_return*** )
+         ...
+         before:
+           brc{!cond} else
+           call_helper
+         preElse:
+         ***  j after ***
+         else:
+         *** load_64imm $0x5555555555555555, %%r2  *** // e.g. for Int RetLoc
+         after:
+         ...
+   */
 
-   if (cond != S390_CC_ALWAYS) {
-      /* So we have something like this
-         if (cond) call X;
-         Y: ...
-         We convert this into
-         if (! cond) goto Y;        // BRC opcode; 4 bytes
-         call X;
-         Y:
-      */
+   // before:
+   UChar *pBefore = buf;
+   if (not_always) {
       /* 4 bytes (a BRC insn) to be filled in here */
       buf += 4;
    }
 
+   // call_helper
    /* Load the target address into a register, that
       (a) is not used for passing parameters to the helper and
       (b) can be clobbered by the callee
@@ -9336,12 +9337,45 @@ s390_insn_helper_call_emit(UChar *buf, const s390_insn *insn)
    buf = s390_emit_LFPC(buf, S390_REGNO_STACK_POINTER,          // restore FPC
                         S390_OFFSET_SAVED_FPC_C);
 
-   if (cond != S390_CC_ALWAYS) {
-      Int delta = buf - ptmp;
+   // preElse:
+   UChar* pPreElse = buf;
+   if (not_always && not_void_return) {
+      /* 4 bytes (a BRC insn) to be filled in here */
+      buf += 4;
+   }
+
+   // else:
+   UChar* pElse = buf;
+   if (not_always && not_void_return) {
+      switch (helper_call->rloc.pri) {
+      case RLPri_Int:
+         buf = s390_emit_load_64imm(buf, S390_REGNO_RETURN_VALUE, 0x5555555555555555ULL);
+         break;
+      default:
+         ppS390Instr(insn, True);
+         vpanic("s390_insn_helper_call_emit: invalid conditional RetLoc.");
+      }
+   }
+
+   // after:
+   UChar* pAfter = buf;
 
+   // fill "brc{!cond} else"
+   if(not_always)
+   {
+      delta = pElse - pBefore;
       delta >>= 1;  /* immediate constant is #half-words */
       vassert(delta > 0 && delta < (1 << 16));
-      s390_emit_BRC(ptmp, s390_cc_invert(cond), delta);
+      s390_emit_BRC(pBefore, s390_cc_invert(cond), delta);
+   }
+
+   // fill "brc{ALWAYS} after"
+   if (not_always && not_void_return)
+   {
+      delta = pAfter - pPreElse;
+      delta >>= 1;  /* immediate constant is #half-words */
+      vassert(delta > 0 && delta < (1 << 16));
+      s390_emit_BRC(pPreElse, S390_CC_ALWAYS, delta);
    }
 
    return buf;
index de1ab19ae9510632505ba81f6bbdd14d9c0ad20b..c88075d5f01653a8a3df63efb468a3838540e356 100644 (file)
@@ -873,7 +873,8 @@ extern UInt s390_host_hwcaps;
                       (s390_host_hwcaps & (VEX_HWCAPS_S390X_PFPO))
 #define s390_host_has_vx \
                       (s390_host_hwcaps & (VEX_HWCAPS_S390X_VX))
-
+#define s390_host_has_msa5 \
+                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_MSA5))
 #endif /* ndef __VEX_HOST_S390_DEFS_H */
 
 /*---------------------------------------------------------------*/
index 4c2de40606aa2984822b039314a80fb0a91e7e22..56886dbe44797e0d161542caf69789127a0ff0ea 100644 (file)
@@ -146,6 +146,28 @@ typedef enum {
    S390_PFPO_D128_TO_F128 = 0x01070A
 } s390_pfpo_function_t;
 
+/* PPNO function code as it is encoded in bits [57:63] of GR0
+   when PPNO insn is executed. */
+typedef enum
+{
+   S390_PPNO_QUERY       = 0x00,
+   S390_PPNO_SHA512_GEN  = 0x03,
+   S390_PPNO_SHA512_SEED = 0x83
+} s390_ppno_function_t;
+
+/* Size of parameter block for PPNO functions.
+   All values are in bytes.
+ */
+#define S390_PPNO_PARAM_BLOCK_SIZE_QUERY  16
+#define S390_PPNO_PARAM_BLOCK_SIZE_SHA512 240
+
+/* Maximum length of modified memory for PPNO functions.
+   All values are in bytes.
+*/
+#define S390_PPNO_MAX_SIZE_SHA512_SEED 512
+#define S390_PPNO_MAX_SIZE_SHA512_GEN  64
+
+
 /* The length of the longest mnemonic: locgrnhe */
 #define S390_MAX_MNEMONIC_LEN  8
 
index a7305c954670ba03d3b944a6fc0d53429ebc5cb3..f95d7ec3b2f34874768aea4a406663b973f436ca 100644 (file)
@@ -251,6 +251,12 @@ cls_operand(Int kind, UInt mask)
    case S390_XMNM_LOCG:   prefix = "locg";  break;
    case S390_XMNM_STOC:   prefix = "stoc";  break;
    case S390_XMNM_STOCG:  prefix = "stocg"; break;
+   case S390_XMNM_STOCFH: prefix = "stocfh"; break;
+   case S390_XMNM_LOCFH:  prefix = "locgh"; break;
+   case S390_XMNM_LOCFHR: prefix = "locghr"; break;
+   case S390_XMNM_LOCHI:  prefix = "lochi"; break;
+   case S390_XMNM_LOCGHI: prefix = "locghi"; break;
+   case S390_XMNM_LOCHHI: prefix = "lochhi"; break;
    default:
       vpanic("cls_operand");
    }
@@ -416,6 +422,12 @@ s390_disasm(UInt command, ...)
          case S390_XMNM_LOCG:
          case S390_XMNM_STOC:
          case S390_XMNM_STOCG:
+         case S390_XMNM_STOCFH:
+         case S390_XMNM_LOCFH:
+         case S390_XMNM_LOCFHR:
+         case S390_XMNM_LOCHI:
+         case S390_XMNM_LOCGHI:
+         case S390_XMNM_LOCHHI:
             mask = va_arg(args, UInt);
             mnm = cls_operand(kind, mask);
             p  += vex_sprintf(p, "%s", mnemonic(mnm));
index e7898981c504fc14a3deda0cc05e4db5716a4347..9d29b9600f6e62f97476e688028fb02155db2ff5 100644 (file)
@@ -83,7 +83,13 @@ enum {
    S390_XMNM_LOC = 7,
    S390_XMNM_LOCG = 8,
    S390_XMNM_STOC = 9,
-   S390_XMNM_STOCG = 10
+   S390_XMNM_STOCG = 10,
+   S390_XMNM_STOCFH = 11,
+   S390_XMNM_LOCFH = 12,
+   S390_XMNM_LOCFHR = 13,
+   S390_XMNM_LOCHI = 14,
+   S390_XMNM_LOCGHI = 15,
+   S390_XMNM_LOCHHI = 16
 };
 
 void s390_disasm(UInt command, ...);
index 93aaf43e246c881c65e6e4752b8a0996dedee7f5..e6c19744d5243c7d5b4c0f317eb907d40fa6195d 100644 (file)
@@ -159,6 +159,8 @@ typedef
 #define VEX_HWCAPS_S390X_LSC   (1<<16)  /* Conditional load/store facility */
 #define VEX_HWCAPS_S390X_PFPO  (1<<17)  /* Perform floating point ops facility */
 #define VEX_HWCAPS_S390X_VX    (1<<18)  /* Vector facility */
+#define VEX_HWCAPS_S390X_MSA5  (1<<19)  /* message security assistance facility */
+
 
 /* Special value representing all available s390x hwcaps */
 #define VEX_HWCAPS_S390X_ALL   (VEX_HWCAPS_S390X_LDISP | \
@@ -173,7 +175,8 @@ typedef
                                 VEX_HWCAPS_S390X_ETF3  | \
                                 VEX_HWCAPS_S390X_ETF2  | \
                                 VEX_HWCAPS_S390X_PFPO  | \
-                                VEX_HWCAPS_S390X_VX)
+                                VEX_HWCAPS_S390X_VX    | \
+                                VEX_HWCAPS_S390X_MSA5)
 
 #define VEX_HWCAPS_S390X(x)  ((x) & ~VEX_S390X_MODEL_MASK)
 #define VEX_S390X_MODEL(x)   ((x) &  VEX_S390X_MODEL_MASK)
index 4aaeac8fc9ac00f884e89384b1503492d40b9ba4..2feb4bad4125e92938014a4278203f4a391bdc1e 100644 (file)
@@ -123,6 +123,9 @@ typedef
       /* some insn needs vector facility which is not available on this host */
       EmFail_S390X_vx,
 
+      /* ppno insn is not supported on this host */
+      EmFail_S390X_ppno,
+
       EmNote_NUMBER
    }
    VexEmNote;
index 40185c2d9f8f5cb23ef4f8c86e66f5119e0a040d..a8a66b96b9c9985a40e02d9b6b67d0ad3bf0db0e 100644 (file)
@@ -99,6 +99,8 @@
 #define S390_FAC_DFPZC   48  // DFP zoned-conversion
 #define S390_FAC_MISC    49  // miscellaneous insn
 #define S390_FAC_CTREXE  50  // constrained transactional execution
+#define S390_FAC_LSC2    53  // load/store on condition 2 and load and zero rightmost byte
+#define S390_FAC_MSA5    57  // message-security-assist 5
 #define S390_FAC_TREXE   73  // transactional execution
 #define S390_FAC_MSA4    77  // message-security-assist 4
 #define S390_FAC_VX      128 // vector facility
index f6ec7d52dcdf80b6b0d480433a49dcfc3aa2d780..31b0e1b6b479f41f70350398553a6e01b423a03c 100644 (file)
@@ -1495,7 +1495,8 @@ Bool VG_(machine_get_hwcaps)( void )
         { False, S390_FAC_FPEXT, VEX_HWCAPS_S390X_FPEXT, "FPEXT" },
         { False, S390_FAC_LSC,   VEX_HWCAPS_S390X_LSC,   "LSC"   },
         { False, S390_FAC_PFPO,  VEX_HWCAPS_S390X_PFPO,  "PFPO"  },
-        { False, S390_FAC_VX,    VEX_HWCAPS_S390X_VX,    "VX"    }
+        { False, S390_FAC_VX,    VEX_HWCAPS_S390X_VX,    "VX"    },
+        { False, S390_FAC_MSA5,  VEX_HWCAPS_S390X_MSA5,  "MSA5"  }
      };
 
      /* Set hwcaps according to the detected facilities */
index fb6adbb62c1f64ecc029f3666819bb70ca16614b..cb11df901aa5c684012d54f397532d14741834f3 100644 (file)
@@ -18,7 +18,7 @@ INSN_TESTS = clc clcle cvb cvd icm lpr tcxb lam_stam xc mvst add sub mul \
             spechelper-cr  spechelper-clr  \
             spechelper-ltr spechelper-or   \
             spechelper-icm-1  spechelper-icm-2 spechelper-tmll \
-            spechelper-tm laa vector
+            spechelper-tm laa vector lsc2 ppno
 if BUILD_DFP_TESTS
   INSN_TESTS += dfp-1 dfp-2 dfp-3 dfp-4 dfptest dfpext dfpconv srnmt pfpo
 endif
@@ -65,3 +65,4 @@ fixbr_CFLAGS     = $(AM_CFLAGS) @FLAG_MLONG_DOUBLE_128@
 fpext_CFLAGS     = $(AM_CFLAGS) @FLAG_MLONG_DOUBLE_128@
 ex_clone_LDADD   = -lpthread
 vector_CFLAGS    = $(AM_CFLAGS) -march=z13
+lsc2_CFLAGS       = -march=z13 -DS390_TESTS_NOCOLOR
diff --git a/none/tests/s390x/lsc2.c b/none/tests/s390x/lsc2.c
new file mode 100644 (file)
index 0000000..c3bface
--- /dev/null
@@ -0,0 +1,490 @@
+/*
+ *  s390x z13 instructions test
+ *
+ *  Copyright (c) 2017 Vadim Barkov
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#define _GNU_SOURCE
+#include "assert.h"
+#include "math.h"
+#include "stdbool.h"
+#include "stdint.h"
+#include "stdio.h"
+#include "string.h"
+
+/* Colors for output */
+#ifndef S390_TESTS_NOCOLOR
+#   define RED "\033[31m"
+#   define GREEN "\033[32m"
+#   define RESET "\033[0m"
+#else
+#   define RED
+#   define GREEN
+#   define RESET
+#endif
+
+#define printPassed(insn) \
+   printf(RESET "%15s :\t " GREEN "PASSED" RESET "\n", #insn)
+#define printFailed(insn) \
+   printf(RESET "%15s :\t " RED "FAILED" RESET "\n", #insn)
+
+#define test(insn)          \
+   {                        \
+      if (test_##insn())    \
+         printPassed(insn); \
+      else                  \
+         printFailed(insn); \
+   }
+
+#define SMART_RETURN_R64(insn)                        \
+   bool result = after == expected;                   \
+   if (!result) {                                     \
+      printf("[ERROR] %s:\n", #insn);                 \
+      printf("after: %lx\n", (uint64_t) after);       \
+      printf("expected: %lx\n", (uint64_t) expected); \
+   }                                                  \
+   return result
+
+/* Constant value for immediate instructions' tests */
+#define IMMEDIATE_VALUE 0x0abc
+#define IMMEDIATE_VALUE_STR "0x0abc"
+
+/* Useful macros for testing many input values
+   and printing message after test execution
+ */
+#define test_each(type, var, instruction)                                      \
+   {                                                                           \
+      type##_foreach((var), test_##instruction((var)));                        \
+   }
+
+#define test_range(var, from, to, instruction)                                 \
+   {                                                                           \
+      bool result = true;                                                      \
+      __int_foreach(var, from, to, result &= (test_##instruction((var))));     \
+      if (result)                                                              \
+         printPassed(instruction);                                             \
+      else                                                                     \
+         printFailed(instruction);                                             \
+   }
+
+#define __int_foreach(var, minValue, maxValue, statement)                      \
+   {                                                                           \
+      for (var = minValue; var < maxValue; var++) {                            \
+         statement;                                                            \
+      }                                                                        \
+                                                                               \
+      { statement; }                                                           \
+   }
+
+#define uint32_foreach(var, statement)                                         \
+   __int_foreach(var, 0, UINT32_MAX, statement)
+#define int32_foreach(var, statement)                                          \
+   __int_foreach(var, INT32_MIN, INT32_MAX, statement)
+#define uint64_foreach(var, statement)                                         \
+   __int_foreach(var, 0, UINT64_MAX, statement)
+
+/* load and zero rightmost byte */
+static bool test_lzrf(const uint32_t testedValue)
+{
+   uint32_t after = testedValue;
+   uint32_t expected = testedValue & 0xffffff00;
+   __asm__ volatile("lzrf %%r6, %0\n"
+                    "st %%r6, %0\n"
+                    :
+                    : "g"(after));
+
+   SMART_RETURN_R64(lzrf);
+}
+
+/* load and zero rightmost byte 64bit*/
+static bool test_lzrg(const uint64_t testedValue)
+{
+   uint64_t after = testedValue;
+   uint64_t expected = testedValue & 0xffffffffffffff00UL;
+
+   __asm__ volatile("lzrg %%r6, %0\n"
+                    "stg %%r6, %0\n"
+                    :
+                    : "g"(after));
+
+   SMART_RETURN_R64(lzrg);
+}
+
+/* load logical and zero rightmost byte */
+static bool test_llzrgf(const uint32_t testedValue)
+{
+   uint64_t after = 0;
+   uint64_t expected = ((uint64_t)testedValue << 32) & 0xffffff0000000000UL;
+
+   __asm__ volatile("llzrgf %%r6, %0\n"
+                    "st %%r6, %1\n"
+                    :
+                    : "g"(testedValue), "g"(after));
+
+   SMART_RETURN_R64(llzrgf);
+}
+
+/* compare instructions */
+#define __compare_r "cr"
+#define __compare_m "c"
+
+/* load high on condition */
+#define declare_load_high_on_condition(TESTED_INSTRUCTION, CONDITION_SYMBOL,   \
+                                       ARGUMENT_ASM_TYPE)                      \
+   bool test_##TESTED_INSTRUCTION(const int32_t testedValue)                   \
+   {                                                                           \
+      uint64_t expected;                                                       \
+      const uint64_t valueBeforeTest = 0x6666666699999999UL;                   \
+      const uint64_t overrideValue = 0xeeeeeeeeeeeeeeeeUL;                     \
+      const int32_t invertedValue = testedValue ^ 0xffffffff;                  \
+      uint64_t after = valueBeforeTest;                                        \
+      if (testedValue CONDITION_SYMBOL invertedValue) {                        \
+         expected = 0xeeeeeeee99999999UL;                                      \
+      } else {                                                                 \
+         expected = valueBeforeTest;                                           \
+      }                                                                        \
+                                                                               \
+      __asm__ volatile(                                                        \
+          "cr %[testedValue], %[invertedValue]\n" #TESTED_INSTRUCTION          \
+          " %[after], %[overrideValue]\n"                                      \
+          : [after] "=r"(after)                                                \
+          : [testedValue] "r"(testedValue),                                    \
+            [invertedValue] "r"(invertedValue),                                \
+            [overrideValue] #ARGUMENT_ASM_TYPE(overrideValue),                 \
+            "[after]"(after));                                                 \
+                                                                               \
+      SMART_RETURN_R64(TESTED_INSTRUCTION);                                    \
+   }
+
+declare_load_high_on_condition(locfhre, ==, r)
+declare_load_high_on_condition(locfhrne, !=, r)
+declare_load_high_on_condition(locfhrh, >, r)
+declare_load_high_on_condition(locfhrl, <, r)
+declare_load_high_on_condition(locfhe, ==, m)
+declare_load_high_on_condition(locfhne, !=, m)
+declare_load_high_on_condition(locfhh, >, m)
+declare_load_high_on_condition(locfhl, <, m)
+
+/* store high on condition */
+#define declare_store_high_on_condition(TESTED_INSTRUCTION, CONDITION_SYMBOL,  \
+                                        ARGUMENT_ASM_TYPE)                     \
+   bool test_##TESTED_INSTRUCTION(const int32_t testedValue)                   \
+   {                                                                           \
+      uint64_t expected;                                                       \
+      const uint64_t valueBeforeTest = 0x6666666699999999UL;                   \
+      const uint64_t overrideValue = 0xeeeeeeeeeeeeeeeeUL;                     \
+      const int32_t invertedValue = testedValue ^ 0xffffffff;                  \
+      uint64_t after = valueBeforeTest;                                        \
+      if (testedValue CONDITION_SYMBOL invertedValue) {                        \
+         expected = 0xeeeeeeee99999999UL;                                      \
+      } else {                                                                 \
+         expected = valueBeforeTest;                                           \
+      }                                                                        \
+                                                                               \
+      __asm__ volatile(                                                        \
+          "cr %[testedValue], %[invertedValue]\n" #TESTED_INSTRUCTION          \
+          " %[overrideValue], %[after]\n"                                      \
+          : [after] "=" #ARGUMENT_ASM_TYPE(after)                              \
+          : [testedValue] "r"(testedValue),                                    \
+            [invertedValue] "r"(invertedValue),                                \
+            [overrideValue] "r"(overrideValue));                               \
+                                                                               \
+      SMART_RETURN_R64(TESTED_INSTRUCTION);                                    \
+   }
+
+declare_store_high_on_condition(stocfhe, ==, m)
+declare_store_high_on_condition(stocfhne, !=, m)
+declare_store_high_on_condition(stocfhh, >, m)
+declare_store_high_on_condition(stocfhl, <, m)
+
+#define __format_uint32_t "%x"
+#define __format_uint64_t "%lx"
+#define __halfword_valueBefore_uint32_t 0x66669999
+#define __halfword_valueBefore_uint64_t 0x6666666699999999UL
+/* load halfword immediate on condition */
+#define declare_load_halfword_immediate_on_condition(                          \
+    TESTED_INSTRUCTION, ARGUMENT_TYPE, CONDITION_SYMBOL, ARGUMENT_ASM_TYPE)    \
+   bool test_##TESTED_INSTRUCTION(const int32_t testedValue)                   \
+   {                                                                           \
+      ARGUMENT_TYPE expected;                                                  \
+      const ARGUMENT_TYPE valueBeforeTest =                                    \
+          __halfword_valueBefore_##ARGUMENT_TYPE;                              \
+      const int32_t invertedValue = testedValue ^ 0xffffffff;                  \
+      ARGUMENT_TYPE after = valueBeforeTest;                                   \
+      if (testedValue CONDITION_SYMBOL invertedValue) {                        \
+         expected = IMMEDIATE_VALUE;                                           \
+      } else {                                                                 \
+         expected = valueBeforeTest;                                           \
+      }                                                                        \
+                                                                               \
+      __asm__ volatile(                                                        \
+          "cr %[testedValue], %[invertedValue]\n" #TESTED_INSTRUCTION          \
+          " %[after], " IMMEDIATE_VALUE_STR "\n"                               \
+          : [after] "=r"(after)                                                \
+          : [testedValue] "r"(testedValue),                                    \
+            [invertedValue] "r"(invertedValue),                                \
+            "[after]"(after));                                                 \
+                                                                               \
+      SMART_RETURN_R64(TESTED_INSTRUCTION);                                    \
+   }
+
+declare_load_halfword_immediate_on_condition(lochie, uint32_t, ==, r)
+declare_load_halfword_immediate_on_condition(lochine, uint32_t, !=, r)
+declare_load_halfword_immediate_on_condition(lochih, uint32_t, >, r)
+declare_load_halfword_immediate_on_condition(lochil, uint32_t, <, r)
+declare_load_halfword_immediate_on_condition(locghie, uint64_t, ==, r)
+declare_load_halfword_immediate_on_condition(locghine, uint64_t, !=, r)
+declare_load_halfword_immediate_on_condition(locghih, uint64_t, >, r)
+declare_load_halfword_immediate_on_condition(locghil, uint64_t, <, r)
+
+/* load halfword high immediate on condition */
+#define declare_load_halfword_high_immediate_on_condition(                \
+    TESTED_INSTRUCTION, CONDITION_SYMBOL, ARGUMENT_ASM_TYPE)              \
+   bool test_##TESTED_INSTRUCTION(const int32_t testedValue)              \
+   {                                                                      \
+      uint64_t expected;                                                  \
+      const uint64_t valueBeforeTest = __halfword_valueBefore_uint64_t;   \
+      const int32_t invertedValue = testedValue ^ 0xffffffff;             \
+      uint64_t after = valueBeforeTest;                                   \
+      if (testedValue CONDITION_SYMBOL invertedValue) {                   \
+         expected = IMMEDIATE_VALUE;                                      \
+         expected <<= 32;                                                 \
+         expected +=                                                      \
+             __halfword_valueBefore_uint64_t & 0x00000000ffffffffUL;      \
+      } else {                                                            \
+         expected = valueBeforeTest;                                      \
+      }                                                                   \
+                                                                          \
+      __asm__ volatile(                                                   \
+          "cr %[testedValue], %[invertedValue]\n" #TESTED_INSTRUCTION     \
+          " %[after], " IMMEDIATE_VALUE_STR "\n"                          \
+          : [after] "=r"(after)                                           \
+          : [testedValue] "r"(testedValue),                               \
+            [invertedValue] "r"(invertedValue),                           \
+            "[after]"(after));                                            \
+                                                                          \
+      SMART_RETURN_R64(TESTED_INSTRUCTION);                               \
+   }
+
+declare_load_halfword_high_immediate_on_condition(lochhie, ==, r)
+declare_load_halfword_high_immediate_on_condition(lochhine, !=, r)
+declare_load_halfword_high_immediate_on_condition(lochhih, >, r)
+declare_load_halfword_high_immediate_on_condition(lochhil, <, r)
+
+static void test_all_locfh()
+{
+   int32_t signed32bit = 0;
+
+   test_each(int32, signed32bit, locfhe);
+   test_each(int32, signed32bit, locfhne);
+   test_each(int32, signed32bit, locfhh);
+   test_each(int32, signed32bit, locfhl);
+
+   test_each(int32, signed32bit, locfhre);
+   test_each(int32, signed32bit, locfhrne);
+   test_each(int32, signed32bit, locfhrh);
+   test_each(int32, signed32bit, locfhrl);
+}
+
+/* load count to block boundary */
+#define declare_load_count_to_block_boundary(M_FIELD)                     \
+   bool test_lcbb##M_FIELD(const uint32_t testedValue)                    \
+   {                                                                      \
+      const size_t boundary = 64 * pow(2, M_FIELD);                       \
+      const uint32_t *testedPointer =                                     \
+          (uint32_t *)(boundary -                                         \
+                       ((testedValue < boundary) ? testedValue : 0));     \
+      uint32_t after = 0;                                                 \
+      uint32_t expected = boundary - ((size_t)testedPointer % boundary);  \
+      if (expected > 16)                                                  \
+         expected = 16;                                                   \
+                                                                          \
+      __asm__ volatile("lcbb %[after], %[testedPointer], " #M_FIELD       \
+                       "\n"                                               \
+                       : [after] "=r"(after)                              \
+                       : [testedPointer] "m"(*testedPointer));            \
+                                                                          \
+      SMART_RETURN_R64(lcbb##M_FIELD);                                    \
+   }
+
+declare_load_count_to_block_boundary(0)
+declare_load_count_to_block_boundary(1)
+declare_load_count_to_block_boundary(2)
+declare_load_count_to_block_boundary(3)
+declare_load_count_to_block_boundary(4)
+declare_load_count_to_block_boundary(5)
+declare_load_count_to_block_boundary(6)
+
+static bool test_lcbb0_cc(const uint32_t testedValue)
+{
+   const size_t boundary = 64;
+   const uint32_t *testedPointer =
+       (uint32_t *)(boundary -
+                    ((testedValue < boundary) ? testedValue : 0));
+   uint32_t expectedForLCBB = boundary - ((size_t)testedPointer % boundary);
+
+   uint32_t after = 0;
+   uint32_t expected = (expectedForLCBB >= 16) ? 0 : 3;
+   __asm__ volatile("lcbb %[cc], %[testedPointer], 0 \n"
+                    "ipm %[cc] \n"
+                    "srl %[cc], 28 \n"
+                    : [cc] "=d"(after)
+                    : [testedPointer] "m"(*testedPointer)
+                    : "cc");
+   SMART_RETURN_R64(lcbb0_cc);
+}
+
+
+static void test_all_lzr()
+{
+   uint32_t unsigned32bit = 0;
+
+   test_each(uint32, unsigned32bit, lzrf);
+   test_each(uint32, unsigned32bit, lzrg);
+}
+
+static void test_all_stocfh()
+{
+   int32_t signed32bit = 0;
+
+   test_each(int32, signed32bit, stocfhne);
+   test_each(int32, signed32bit, stocfhe);
+   test_each(int32, signed32bit, stocfhh);
+   test_each(int32, signed32bit, stocfhl);
+}
+
+static void test_all_lochi()
+{
+   int32_t signed32bit = 0;
+
+   test_each(int32, signed32bit, locghine);
+   test_each(int32, signed32bit, locghine);
+   test_each(int32, signed32bit, locghih);
+   test_each(int32, signed32bit, locghil);
+
+   test_each(int32, signed32bit, lochine);
+   test_each(int32, signed32bit, lochie);
+   test_each(int32, signed32bit, lochil);
+   test_each(int32, signed32bit, lochih);
+}
+
+static void test_all_lochhi()
+{
+   int32_t signed32bit = 0;
+
+   test_each(int32, signed32bit, lochhine);
+   test_each(int32, signed32bit, lochhie);
+   test_each(int32, signed32bit, lochhih);
+   test_each(int32, signed32bit, lochhil);
+}
+
+static void test_all_lcbb()
+{
+   size_t tested = 0;
+
+   test_range(tested, 0, 64, lcbb0);
+   test_range(tested, 0, 128, lcbb1);
+   test_range(tested, 0, 256, lcbb2);
+   test_range(tested, 0, 512, lcbb3);
+   test_range(tested, 0, 1024, lcbb4);
+   test_range(tested, 0, 2048, lcbb5);
+   test_range(tested, 0, 4096, lcbb6);
+   test_range(tested, 0, 64, lcbb0_cc);
+}
+
+void test_long_all() {
+   uint64_t unsigned64bit = 0;
+
+   test_all_lcbb();
+   test_all_lochhi();
+   test_all_lochi();
+   test_all_stocfh();
+   test_all_locfh();
+   test_all_lzr();
+   test_each(uint64, unsigned64bit, llzrgf);
+}
+
+#define SHORT_TESTS_UNSIGNED_FROM 0
+#define SHORT_TESTS_SIGNED_FROM -0xffff
+#define SHORT_TESTS_TO 0xffff
+
+void test_short_all()
+{
+   uint32_t unsigned32bit = 0;
+   int32_t signed32bit = 0;
+   uint64_t unsigned64bit = 0;
+
+   test_range(unsigned32bit, SHORT_TESTS_UNSIGNED_FROM, SHORT_TESTS_TO, lzrf);
+   test_range(unsigned64bit, SHORT_TESTS_UNSIGNED_FROM, SHORT_TESTS_TO, lzrg);
+   test_range(unsigned64bit, SHORT_TESTS_UNSIGNED_FROM, SHORT_TESTS_TO, llzrgf);
+
+   /* stocfh */
+   test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, stocfhne);
+   test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, stocfhe);
+   test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, stocfhh);
+   test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, stocfhl);
+
+   /* locfh */
+   test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, locfhe);
+   test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, locfhne);
+   test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, locfhh);
+   test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, locfhl);
+
+   /* locfhr */
+   test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, locfhre);
+   test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, locfhrne);
+   test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, locfhrh);
+   test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, locfhrl);
+
+   /* lochhi */
+   test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, lochhine);
+   test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, lochhie);
+   test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, lochhih);
+   test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, lochhil);
+
+   /* lochi */
+   test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, lochine);
+   test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, lochie);
+   test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, lochih);
+   test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, lochil);
+
+   /* locghi */
+   test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, locghine);
+   test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, locghie);
+   test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, locghih);
+   test_range(signed32bit, SHORT_TESTS_SIGNED_FROM, SHORT_TESTS_TO, locghil);
+
+   test_all_lcbb(); /* These test is not long, so we can run it on all range */
+}
+
+int main(int argc, char *argv[])
+{
+   bool shouldRunLongTests = false;
+
+   /* --long option forces to test all possible values (it is very long)*/
+   if (argc > 1)
+      if (strcmp(argv[1], "--long") == 0)
+         shouldRunLongTests = true;
+
+   printf("Tests started:\n");
+   if (shouldRunLongTests)
+      test_long_all();
+   else
+      test_short_all();
+
+   printf("Tests ended.\n");
+   return 0;
+}
diff --git a/none/tests/s390x/lsc2.stderr.exp b/none/tests/s390x/lsc2.stderr.exp
new file mode 100644 (file)
index 0000000..139597f
--- /dev/null
@@ -0,0 +1,2 @@
+
+
diff --git a/none/tests/s390x/lsc2.stdout.exp b/none/tests/s390x/lsc2.stdout.exp
new file mode 100644 (file)
index 0000000..3692ca5
--- /dev/null
@@ -0,0 +1,37 @@
+Tests started:
+           lzrf :       PASSED
+           lzrg :       PASSED
+         llzrgf :       PASSED
+       stocfhne :       PASSED
+        stocfhe :       PASSED
+        stocfhh :       PASSED
+        stocfhl :       PASSED
+         locfhe :       PASSED
+        locfhne :       PASSED
+         locfhh :       PASSED
+         locfhl :       PASSED
+        locfhre :       PASSED
+       locfhrne :       PASSED
+        locfhrh :       PASSED
+        locfhrl :       PASSED
+       lochhine :       PASSED
+        lochhie :       PASSED
+        lochhih :       PASSED
+        lochhil :       PASSED
+        lochine :       PASSED
+         lochie :       PASSED
+         lochih :       PASSED
+         lochil :       PASSED
+       locghine :       PASSED
+        locghie :       PASSED
+        locghih :       PASSED
+        locghil :       PASSED
+          lcbb0 :       PASSED
+          lcbb1 :       PASSED
+          lcbb2 :       PASSED
+          lcbb3 :       PASSED
+          lcbb4 :       PASSED
+          lcbb5 :       PASSED
+          lcbb6 :       PASSED
+       lcbb0_cc :       PASSED
+Tests ended.
diff --git a/none/tests/s390x/lsc2.vgtest b/none/tests/s390x/lsc2.vgtest
new file mode 100644 (file)
index 0000000..911294c
--- /dev/null
@@ -0,0 +1 @@
+prog: lsc2
diff --git a/none/tests/s390x/ppno.c b/none/tests/s390x/ppno.c
new file mode 100644 (file)
index 0000000..6bf4cab
--- /dev/null
@@ -0,0 +1,127 @@
+#include "stdio.h"
+#include "stdbool.h"
+#include "stdint.h"
+#include "string.h"
+#include "vector.h"
+
+#define S390_PPNO_SHA512_BLOCK_SIZE (240 / 8)
+static uint64_t block[S390_PPNO_SHA512_BLOCK_SIZE];
+#define HASH_COUNT 2 /* exactly two hashes for generate */
+static uint64_t hash[HASH_COUNT];
+
+static void print_sha512_block()
+{
+   printf("Current block state:\n");
+   for(size_t elem = 0; elem < S390_PPNO_SHA512_BLOCK_SIZE; elem++)
+   {
+      print_uint64_t(block[elem]);
+   }
+
+   printf("end of block.\n");
+}
+
+static void print_sha512_hash()
+{
+   printf("Current hash:\n");
+   for(size_t index = 0; index < HASH_COUNT; index++)
+      print_uint64_t(hash[index]);
+
+   printf("end of hash\n");
+}
+
+/* The problem with this test is different results on different architectures.
+   E.g. z13 will return (1 << 0)|(1 << 3) value while more recent versions of CPU
+   can (and will!) add their own operations here. Anyway z13 or any later arch will
+   have "SHA-512-DRNG" (3-rd bit of result) and "Query" (0-th bit) functions
+   so we test only this bits and ignore others.
+*/
+static bool test_ppno_query()
+{
+   uint32_t output[4];
+   register uint64_t functionCode __asm__("0") = 0ULL;
+   register uint64_t paramBlock __asm__("1") = (uint64_t) &output;
+
+   __asm__ volatile (
+         ".insn rre, 0xb93c0000, %%r2, %%r4 \n" // GPR's are ignored here
+         : "+d"(functionCode), "+d"(paramBlock)
+         :
+         : "cc", "memory"
+      );
+
+   /* 0x9 = (1 << 0)|(1 << 3), see explanation above */
+   uint32_t expected = 0x90000000U;
+   uint32_t after = output[0];
+
+   bool result = expected == after;
+   if(!result)
+      printf("ERROR: basic ppno functions are not supported : %d\n", after);
+
+   return result;
+}
+
+static void test_ppno_sha512_seed()
+{
+   /* Important! The program should zero paramBlock for seeding. */
+   memset(block, 0, sizeof(block));
+
+   uint8_t seed[512];
+   for(size_t index = 0; index < 512; index++)
+      seed[index] = random_element();
+   seed[511] = 0;
+   const uint64_t seedLength = strlen((char*)seed);
+
+   register uint64_t functionCode __asm__("0") = 0x83ULL;
+   register uint64_t paramBlock __asm__("1") = (uint64_t) &block;
+   register uint64_t gpr2 __asm__("2") = (uint64_t) &seed;
+   register uint64_t gpr3 __asm__("3") = seedLength;
+   __asm__ volatile (
+         ".insn rre, 0xb93c0000, %%r4, %%r2 \n"
+         :
+         : "d"(functionCode), "d"(paramBlock), "d"(gpr2), "d"(gpr3)
+         : "cc", "memory"
+      );
+
+   printf("seedLength = %ld\n", seedLength);
+   print_sha512_block();
+}
+
+static void test_ppno_sha512_gen()
+{
+   register uint64_t functionCode __asm__("0") = 0x3ULL;
+   register uint64_t paramBlock __asm__("1") = (uint64_t) &block;
+   register uint64_t gpr2 __asm__("2") = (uint64_t) &hash;
+   register uint64_t gpr3 __asm__("3") = HASH_COUNT;
+
+   __asm__ volatile (
+         "0: .insn rre, 0xb93c0000, %%r2, %%r4 \n"
+         "   brc 1, 0 \n" /* handle partial completion */
+         :
+         : "d"(functionCode), "d"(paramBlock), "d"(gpr2), "d"(gpr3)
+         : "cc", "memory"
+      );
+
+   print_sha512_hash();
+   print_sha512_block();
+}
+
+static void test_ppno_sha512()
+{
+   printf(" === sha512_seed: ===\n");
+   test_ppno_sha512_seed();
+   return;
+   printf(" === sha512_gen: ===\n");
+   test_ppno_sha512_gen();
+
+   memset(hash, 0, sizeof(hash));
+}
+
+int main()
+{
+   size_t iteration;
+   if(!test_ppno_query())
+      return 1;
+
+   test(ppno_sha512);
+
+   return 0;
+}
diff --git a/none/tests/s390x/ppno.stderr.exp b/none/tests/s390x/ppno.stderr.exp
new file mode 100644 (file)
index 0000000..139597f
--- /dev/null
@@ -0,0 +1,2 @@
+
+
diff --git a/none/tests/s390x/ppno.stdout.exp b/none/tests/s390x/ppno.stdout.exp
new file mode 100644 (file)
index 0000000..3c6ebeb
--- /dev/null
@@ -0,0 +1,340 @@
+ === sha512_seed: ===
+seedLength = 0
+Current block state:
+0000000000000001
+0000000000000000
+003e226456bf592f
+441da979b2879409
+fc6f0e6192b8e7a7
+4ab3c33ebe6211bc
+4d4e1319fa123ab6
+5d34f1db2a58545c
+56fdbba651cffc31
+93bad6df02b799e3
+aaaa0c62548a2b53
+2621bf68328e3354
+678049ba8d9f1dc4
+ab9b96e348df64d6
+73f6e4aa1e2a772f
+8cd1a86bec20d436
+00f78e432b75bb7a
+60296ca43d1c6a9b
+ab6531522f5c1327
+2ceeb7b13076587a
+7becdef486f4f207
+ce5059ceb74ced11
+7309c2683f68a9d5
+e7458e632be82b57
+83754f8941faf016
+10f6eec6c45b195d
+018034f6220e3728
+9ac61bb9dc8e100c
+3f5e85d5a6537e0d
+8381c3f2ca21f4a5
+end of block.
+ === sha512_seed: ===
+seedLength = 11
+Current block state:
+0000000000000001
+0000000000000000
+004eb1b72a8a5538
+99417cd142461d13
+a4e7fdd4fe5bec3c
+2d84993f3c7dfecd
+81c7a13cd7a2e1dd
+1a72bbca637c9f35
+a9e73691ed4dab56
+2749ba30f6d1f93b
+4152bce5396879b3
+eddda1b12d8d083d
+a385ab81199f7f36
+1cf637397957dfd4
+bde5cab81dd1e412
+72931ea30835862a
+004469806a5b73d8
+aeaf1f9d0cae7c37
+8adf82179d0fca03
+e47741e426d6e305
+b84ebd07593a8225
+7f1c6928f7653501
+d1524486643b460f
+dc6c2402af8aa1af
+86043ac0ac159bb3
+41aaba7230c42a1f
+8be022ac67e2d5b1
+aa3c7ad10bb2f452
+7e91c25bb6bed695
+488c9efa3bedadcf
+end of block.
+ === sha512_seed: ===
+seedLength = 104
+Current block state:
+0000000000000001
+0000000000000000
+0065b7da3facb603
+a39ba35264e352c1
+528ff5b185090e96
+1e23953329b37e51
+ed239bc2b128f806
+f17aea98269226f8
+060c890a3052852c
+5df580976052e63a
+878588f4a8ee6646
+976b9a9768b6e005
+77bbd6d0c9343a00
+0faaa6e742c9dac8
+46a8a5506c2e9401
+9043d2bf21003936
+00a0ae8f2a4cb315
+782760f19dc3092d
+60060ae811f7ebda
+0b1b47143d57a5c2
+b15629bb9162d3cf
+c771535a7d6414b3
+e7e1adfb50e9534a
+bbb340f32c63cf50
+edf209d0db329cbc
+c4f31b47743eecc4
+04c3f5884af60998
+cfea12866218e29e
+5f2363a04592c804
+46d387494a63fec0
+end of block.
+ === sha512_seed: ===
+seedLength = 158
+Current block state:
+0000000000000001
+0000000000000000
+0045781698282993
+4da84904d0e89d9a
+edeaf6024283326f
+527c60b5a7aa2bab
+38e8d26031674b06
+ba0b249df891a67c
+5b364ea73ffea6c0
+e398d258a5ba5917
+c8b87f8f5e33b622
+a49b4ef408e3649e
+3da66fec9b5a6db0
+55d27c3cd383b31c
+5d5150f16c6d7451
+57b9fabe0e028fba
+003613e0f72a16fe
+dbddb109b3c327ba
+197eb5098dc8b240
+04add947f078aead
+6ce9e45c94c1ff24
+ea57dc533fec8520
+41bac59db19c7ac4
+6ebfb7055be23099
+e968ca0ae2f45635
+3a8096f2b2d33744
+c0c43d08f6797136
+c248bf582e5f5c5f
+e79d264972e8dc36
+f3045008abe8a6ca
+end of block.
+ === sha512_seed: ===
+seedLength = 37
+Current block state:
+0000000000000001
+0000000000000000
+00349033d29ca4c9
+dc2d01908a5791be
+c5cf75e0e3ca17cf
+7aed3a3df4990bcd
+87fc573cd5b13ba2
+6fdab83b8464cf82
+1a21797e3a9e7035
+3a06c2b83281705f
+f1d35bf5f068bc49
+a4ad202f6ce656e3
+4c56eb01058ce66d
+0e998ab91d77350a
+767fc3bc6bfa0b20
+07b6e69af6a59bea
+00ba228488e7ac41
+8c2d862fb775f15a
+d669a21dfa69f5b9
+4d134ec98379df9d
+81a2da79e623eca8
+b65a481b7aef0e89
+562a0f4743360402
+bde519a05363cbaf
+82608e5fe7ff8337
+c6030af815307cec
+fcef279b9735498b
+a90c7aebac65655a
+5871203aa8ec538e
+31f5e08b75f40311
+end of block.
+ === sha512_seed: ===
+seedLength = 301
+Current block state:
+0000000000000001
+0000000000000000
+00a2cd9e1108b253
+60f0f515f9436267
+6112b2da9b34e224
+b882cf25f62058f0
+e939aaef747e10f6
+796a3c2c0de9f9b5
+666e3c719678469c
+794413d6cc3ab283
+4d201dbffcbe9d75
+2e7826d27d1fd410
+e591db24ed522dae
+cda5699ea7ff7a10
+5ca19132941d57ed
+64cb80f5965dac83
+00b17bbb282a09b1
+3df5323781179ef5
+fcb78fac7c3e2aab
+88ba2880422809b2
+8d32558e30af18da
+c0030273bffaf70a
+0347475d9d030ce3
+6ce0c491d4a4f74d
+99daef279fdc1b49
+a0a862ab740eb859
+7dd377eaea992d4b
+ef9d973cb7138817
+303998590f022392
+e9a9a39e7ede4eaa
+end of block.
+ === sha512_seed: ===
+seedLength = 185
+Current block state:
+0000000000000001
+0000000000000000
+000108c265da6c80
+0192507c98a4c2c7
+452608dd4fe634a1
+c880a82e782378c7
+c66821bda7472a82
+ab84aa370d9c5dde
+316ce0a0348bc019
+b050cccaf67f178e
+d318738dab56b454
+ae5a95f3f935eb6b
+e77275efef5b7201
+e24690d9039b02b6
+21b3a48bf7ff98e4
+9fef58ec1f88fff7
+003caab18195c6df
+641cd44486e21c8e
+02c18c895dd6cda2
+e23b8cc41c9d0994
+bd7236c9322f655a
+298ee4aa4b23b737
+2c5feadf5cfcfe57
+6bf3bbd877e448eb
+bd1fcf1624ac28be
+041d143f9a9facda
+c9ae1027c3548419
+130e59d52f1d824e
+23af4bf89e504583
+fc017e2eb2a4d28a
+end of block.
+ === sha512_seed: ===
+seedLength = 125
+Current block state:
+0000000000000001
+0000000000000000
+00c4c2ecae21e662
+85b3e6f0042d2baf
+9e484b413ba43943
+9cd159886515ffad
+8cd8a3a5028ed440
+98f350a7b31a397c
+0eb36001904a1384
+07c57472df6c61f1
+a6f3ca8e6675078b
+d9d2325a92030fca
+2a1d516dcae5a8cb
+972cfde019bfcdc0
+74d1e498cb4f4882
+3308b466d31c3023
+00dd0698e4f695a1
+06257726d3b1f4bc
+3b9794261c1401d4
+fd1e82ac81472d04
+0afba5dedbf8003a
+4146305cf5b96e03
+9bb6672bd2ee8acc
+e00d1c05ee4d7639
+8313735518354ab0
+e3f1487cb8f79c96
+bc99d40d7a49afe8
+e8e1139b3864f068
+89ffd2a4948b1967
+e5cf0258f3082fd6
+end of block.
+ === sha512_seed: ===
+seedLength = 30
+Current block state:
+0000000000000001
+0000000000000000
+00b05877ea149ca9
+ddb7203e41de79bd
+f637815de27b89e1
+bda7afbb46634eec
+3f2f329c2509c348
+63a8e954764f99bc
+f0fb5d2ec9f2f996
+7c8cae8651e7b4e0
+4b3e2d33a90095eb
+42b1c6305af4487c
+3e116fc0b9700f1a
+94ac60577d4d1a47
+1c338f226410f72d
+d8231fa60e8f4e53
+0051e3f1e9e02151
+a1d8fc93f9d45b0c
+69e8fef198cb391e
+5952ee22ec3553e7
+fa6ddd6f23387117
+fa71fa2d88b1083d
+2bbc00ae1103daa2
+6eae1e34be4c53d0
+82cb422f047d0758
+f776d289c581ea5f
+b1f0959bef26d7fd
+da4c80f7309a266b
+755f72d68f47c6af
+6d1269427254b971
+end of block.
+ === sha512_seed: ===
+seedLength = 511
+Current block state:
+0000000000000001
+0000000000000000
+002c4bf217887798
+49700ed88f7abec4
+31f331722e562f90
+d3ada9dc23790d8d
+87dac381c4634a22
+5d32c8e62ee3fd4e
+19560e54b7464c02
+da8173723e36b679
+08dc7f22f28c9b8e
+8cfc13e645a13d68
+af4f40f6460007b6
+e98b97ba232b7049
+a8de0efcb7e74212
+187a977bfbe5ad54
+001f54f5715b6e7f
+dc7cec10e2fb028f
+7ff779259762f33f
+1342e9a91ff7015e
+5b12cfa2ab1afd2b
+af95a97ef7cf30ff
+cd5149f31f92a4e4
+c97e4b3af244ce23
+cc74abb567ed5f5b
+4de0d128dce98570
+f097484c991998fe
+3e17f4e5caa21f08
+1e33b2536984cae5
+48ace06455de2fc8
+end of block.
diff --git a/none/tests/s390x/ppno.vgtest b/none/tests/s390x/ppno.vgtest
new file mode 100644 (file)
index 0000000..618fe1e
--- /dev/null
@@ -0,0 +1,2 @@
+prog: ppno
+prereq: test -e ppno && ../../../tests/s390x_features s390x-msa5
index 0da80b5d3c621a8d503168fb4dce7f5fcfa4a1f4..25734abb1cb093dc63d6e07e5439b76ac7c20714 100644 (file)
@@ -245,6 +245,8 @@ static int go(char *feature, char *cpu)
       match = facilities[0] & FAC_BIT(45);
    } else if (strcmp(feature, "s390x-vx") == 0 ) {
       match = facilities[2] & FAC_BIT(0);
+   } else if (strcmp(feature, "s390x-msa5") == 0 ) {
+      match = facilities[0] & FAC_BIT(57); /* message security assist 5 facility */
    } else {
       return 2;          // Unrecognised feature.
    }