From: Julian Seward Date: Tue, 24 Jul 2018 08:10:40 +0000 (+0200) Subject: Bug 385412 - s390x: new non-vector z13 instructions not implemented X-Git-Tag: VALGRIND_3_14_0~82 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d44563c49e55f47016e23591f708c7aa57f7a098;p=thirdparty%2Fvalgrind.git Bug 385412 - s390x: new non-vector z13 instructions not implemented 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). --- diff --git a/.gitignore b/.gitignore index 305bbb2362..72b7c3d46b 100644 --- a/.gitignore +++ b/.gitignore @@ -1875,6 +1875,8 @@ /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 diff --git a/VEX/priv/guest_s390_defs.h b/VEX/priv/guest_s390_defs.h index d3dede7a81..4f9e962d3a 100644 --- a/VEX/priv/guest_s390_defs.h +++ b/VEX/priv/guest_s390_defs.h @@ -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, diff --git a/VEX/priv/guest_s390_helpers.c b/VEX/priv/guest_s390_helpers.c index 77772fe104..52e4ce9368 100644 --- a/VEX/priv/guest_s390_helpers.c +++ b/VEX/priv/guest_s390_helpers.c @@ -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 ---*/ /*---------------------------------------------------------------*/ diff --git a/VEX/priv/guest_s390_toIR.c b/VEX/priv/guest_s390_toIR.c index cca684a8e2..1697e9744b 100644 --- a/VEX/priv/guest_s390_toIR.c +++ b/VEX/priv/guest_s390_toIR.c @@ -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, diff --git a/VEX/priv/host_s390_defs.c b/VEX/priv/host_s390_defs.c index d03ed5f07c..d41093eb01 100644 --- a/VEX/priv/host_s390_defs.c +++ b/VEX/priv/host_s390_defs.c @@ -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; diff --git a/VEX/priv/host_s390_defs.h b/VEX/priv/host_s390_defs.h index de1ab19ae9..c88075d5f0 100644 --- a/VEX/priv/host_s390_defs.h +++ b/VEX/priv/host_s390_defs.h @@ -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 */ /*---------------------------------------------------------------*/ diff --git a/VEX/priv/s390_defs.h b/VEX/priv/s390_defs.h index 4c2de40606..56886dbe44 100644 --- a/VEX/priv/s390_defs.h +++ b/VEX/priv/s390_defs.h @@ -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 diff --git a/VEX/priv/s390_disasm.c b/VEX/priv/s390_disasm.c index a7305c9546..f95d7ec3b2 100644 --- a/VEX/priv/s390_disasm.c +++ b/VEX/priv/s390_disasm.c @@ -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)); diff --git a/VEX/priv/s390_disasm.h b/VEX/priv/s390_disasm.h index e7898981c5..9d29b9600f 100644 --- a/VEX/priv/s390_disasm.h +++ b/VEX/priv/s390_disasm.h @@ -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, ...); diff --git a/VEX/pub/libvex.h b/VEX/pub/libvex.h index 93aaf43e24..e6c19744d5 100644 --- a/VEX/pub/libvex.h +++ b/VEX/pub/libvex.h @@ -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) diff --git a/VEX/pub/libvex_emnote.h b/VEX/pub/libvex_emnote.h index 4aaeac8fc9..2feb4bad41 100644 --- a/VEX/pub/libvex_emnote.h +++ b/VEX/pub/libvex_emnote.h @@ -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; diff --git a/VEX/pub/libvex_s390x_common.h b/VEX/pub/libvex_s390x_common.h index 40185c2d9f..a8a66b96b9 100644 --- a/VEX/pub/libvex_s390x_common.h +++ b/VEX/pub/libvex_s390x_common.h @@ -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 diff --git a/coregrind/m_machine.c b/coregrind/m_machine.c index f6ec7d52dc..31b0e1b6b4 100644 --- a/coregrind/m_machine.c +++ b/coregrind/m_machine.c @@ -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 */ diff --git a/none/tests/s390x/Makefile.am b/none/tests/s390x/Makefile.am index fb6adbb62c..cb11df901a 100644 --- a/none/tests/s390x/Makefile.am +++ b/none/tests/s390x/Makefile.am @@ -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 index 0000000000..c3bfacec73 --- /dev/null +++ b/none/tests/s390x/lsc2.c @@ -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 index 0000000000..139597f9cb --- /dev/null +++ b/none/tests/s390x/lsc2.stderr.exp @@ -0,0 +1,2 @@ + + diff --git a/none/tests/s390x/lsc2.stdout.exp b/none/tests/s390x/lsc2.stdout.exp new file mode 100644 index 0000000000..3692ca591b --- /dev/null +++ b/none/tests/s390x/lsc2.stdout.exp @@ -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 index 0000000000..911294c51b --- /dev/null +++ b/none/tests/s390x/lsc2.vgtest @@ -0,0 +1 @@ +prog: lsc2 diff --git a/none/tests/s390x/ppno.c b/none/tests/s390x/ppno.c new file mode 100644 index 0000000000..6bf4cab551 --- /dev/null +++ b/none/tests/s390x/ppno.c @@ -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) █ + 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) █ + 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 index 0000000000..139597f9cb --- /dev/null +++ b/none/tests/s390x/ppno.stderr.exp @@ -0,0 +1,2 @@ + + diff --git a/none/tests/s390x/ppno.stdout.exp b/none/tests/s390x/ppno.stdout.exp new file mode 100644 index 0000000000..3c6ebeb415 --- /dev/null +++ b/none/tests/s390x/ppno.stdout.exp @@ -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 index 0000000000..618fe1e981 --- /dev/null +++ b/none/tests/s390x/ppno.vgtest @@ -0,0 +1,2 @@ +prog: ppno +prereq: test -e ppno && ../../../tests/s390x_features s390x-msa5 diff --git a/tests/s390x_features.c b/tests/s390x_features.c index 0da80b5d3c..25734abb1c 100644 --- a/tests/s390x_features.c +++ b/tests/s390x_features.c @@ -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. }