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).
This commit is contained in:
Julian Seward 2018-07-24 10:10:40 +02:00
parent 53cf5739b3
commit d44563c49e
23 changed files with 1551 additions and 41 deletions

2
.gitignore vendored
View File

@ -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

View 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,

View 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 ---*/
/*---------------------------------------------------------------*/

View 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,

View 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);
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:
*/
/* 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:
...
*/
// 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;

View 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 */
/*---------------------------------------------------------------*/

View 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

View 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));

View 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, ...);

View 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)

View 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;

View 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

View 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 */

View 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

490
none/tests/s390x/lsc2.c Normal file
View File

@ -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;
}

View File

@ -0,0 +1,2 @@

View File

@ -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.

View File

@ -0,0 +1 @@
prog: lsc2

127
none/tests/s390x/ppno.c Normal file
View File

@ -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;
}

View File

@ -0,0 +1,2 @@

View File

@ -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.

View File

@ -0,0 +1,2 @@
prog: ppno
prereq: test -e ppno && ../../../tests/s390x_features s390x-msa5

View 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.
}