/coregrind/m_dispatch/Makefile
/coregrind/m_dispatch/Makefile.in
+# /coregrind/m_extension/
+/coregrind/m_extension/*.a
+/coregrind/m_extension/.deps
+/coregrind/m_extension/.dirstamp
+/coregrind/m_extension/Makefile
+/coregrind/m_extension/Makefile.in
+
# /coregrind/m_gdbserver/
/coregrind/m_gdbserver/.deps
/coregrind/m_gdbserver/.dirstamp
This file is part of Valgrind, a dynamic binary instrumentation
framework.
- Copyright IBM Corp. 2010-2021
+ Copyright IBM Corp. 2010-2024
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
dis_res->jk_StopHere = Ijk_Sys_syscall;
}
+/* An extension */
+static void
+extension(ULong id, ULong variant)
+{
+ vassert(id < (1 << S390_EXT_ID_NBITS));
+ vassert(variant <= ~((ULong) 0) >> S390_EXT_ID_NBITS);
+
+ /* Store the extension ID in the pseudo register. */
+ ULong ext_id = id | (variant << S390_EXT_ID_NBITS);
+ stmt(IRStmt_Put(S390X_GUEST_OFFSET(guest_SYSNO), mkU64(ext_id)));
+
+ /* Store the current IA into guest_IP_AT_SYSCALL. */
+ stmt(IRStmt_Put(S390X_GUEST_OFFSET(guest_IP_AT_SYSCALL),
+ mkU64(guest_IA_curr_instr)));
+
+ put_IA(mkaddr_expr(guest_IA_next_instr));
+
+ dis_res->whatNext = Dis_StopHere;
+ dis_res->jk_StopHere = Ijk_Extension;
+}
+
/* A side exit that branches back to the current insn if CONDITION is
true. Does not set DisResult. */
static void
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.
- */
+/* Also known as "PRNO" */
static const HChar *
s390_irgen_PPNO(UChar r1, UChar r2)
{
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));
+ /* Check for obvious specification exceptions */
+ s390_insn_assert("ppno", r1 % 2 == 0 && r2 % 2 == 0 && r1 != 0 && r2 != 0);
+ extension(S390_EXT_PRNO, r1 | (r2 << 4));
return "ppno";
}
case Ijk_SigSEGV: return "SigSEGV";
case Ijk_SigBUS: return "SigBUS";
case Ijk_Sys_syscall: return "Sys_syscall";
+ case Ijk_Extension: return "Extension";
default:
vpanic("s390_jump_kind_as_string");
}
switch (insn->variant.xassisted.kind) {
case Ijk_ClientReq: trcval = VEX_TRC_JMP_CLIENTREQ; break;
case Ijk_Sys_syscall: trcval = VEX_TRC_JMP_SYS_SYSCALL; break;
+ case Ijk_Extension: trcval = VEX_TRC_JMP_EXTENSION; break;
case Ijk_Yield: trcval = VEX_TRC_JMP_YIELD; break;
case Ijk_EmWarn: trcval = VEX_TRC_JMP_EMWARN; break;
case Ijk_EmFail: trcval = VEX_TRC_JMP_EMFAIL; break;
case Ijk_NoDecode:
case Ijk_InvalICache:
case Ijk_Sys_syscall:
+ case Ijk_Extension:
case Ijk_ClientReq:
case Ijk_NoRedir:
case Ijk_Yield:
case Ijk_NoDecode:
case Ijk_InvalICache:
case Ijk_Sys_syscall:
+ case Ijk_Extension:
case Ijk_ClientReq:
case Ijk_NoRedir:
case Ijk_Yield:
case Ijk_Sys_int145: vex_printf("Sys_int145"); break;
case Ijk_Sys_int210: vex_printf("Sys_int210"); break;
case Ijk_Sys_sysenter: vex_printf("Sys_sysenter"); break;
+ case Ijk_Extension: vex_printf("Extension"); break;
default: vpanic("ppIRJumpKind");
}
}
executed kernel-entering (system call) instruction. This makes it
very much easier (viz, actually possible at all) to back up the
guest to restart a syscall that has been interrupted by a signal.
+
+ Re Ijk_Extension: the guest state must have the pseudo-register
+ guest_IP_AT_SYSCALL, which is also used for Ijk_Sys_*. Front ends
+ must set this to the current instruction address before jumping to
+ an extension handler.
*/
typedef
enum {
Ijk_Sys_int130, /* amd64/x86 'int $0x82' */
Ijk_Sys_int145, /* amd64/x86 'int $0x91' */
Ijk_Sys_int210, /* amd64/x86 'int $0xD2' */
- Ijk_Sys_sysenter /* x86 'sysenter'. guest_EIP becomes
+ Ijk_Sys_sysenter, /* x86 'sysenter'. guest_EIP becomes
invalid at the point this happens. */
+ Ijk_Extension, /* invoke guest-specific extension */
}
IRJumpKind;
#define S390_FAC_DFLT 151 // deflate-conversion facility
#define S390_FAC_NNPA 165 // NNPA facility
+/*--------------------------------------------------------------*/
+/*--- Extensions ---*/
+/*--------------------------------------------------------------*/
+
+/* The extension ID is stored in the low 16 bits of the guest_SYSNO pseudo
+ register. */
+#define S390_EXT_ID_NBITS 16
+
+#define S390_EXT_PRNO 1
/*--------------------------------------------------------------*/
/*--- Miscellaneous ---*/
#define VEX_TRC_JMP_NODECODE 69 /* next instruction is not decodable */
#define VEX_TRC_JMP_MAPFAIL 71 /* address translation failed */
+#define VEX_TRC_JMP_EXTENSION 114 /* invoke extension before continuing */
+
#define VEX_TRC_JMP_SYS_SYSCALL 73 /* do syscall before continuing */
#define VEX_TRC_JMP_SYS_INT32 75 /* do syscall before continuing */
#define VEX_TRC_JMP_SYS_INT128 77 /* do syscall before continuing */
m_demangle/demangle.h \
m_demangle/safe-ctype.h \
m_demangle/vg_libciface.h \
+ m_extension/priv_extension.h \
+ m_extension/priv_types_n_macros.h \
m_gdbserver/regcache.h \
m_gdbserver/regdef.h \
m_gdbserver/server.h \
m_dispatch/dispatch-amd64-darwin.S \
m_dispatch/dispatch-x86-solaris.S \
m_dispatch/dispatch-amd64-solaris.S \
+ m_extension/extension-main.c \
+ m_extension/extension-s390x.c \
m_gdbserver/inferiors.c \
m_gdbserver/regcache.c \
m_gdbserver/remote-utils.c \
--- /dev/null
+
+/*--------------------------------------------------------------------*/
+/*--- Handle extensions. extension-main.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) IBM Corp. 2024
+
+ 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, see <http://www.gnu.org/licenses/>.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+/* Contributed by Andreas Arnez */
+
+#include "libvex_guest_offsets.h"
+#include "pub_core_extension.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_threadstate.h"
+#include "priv_extension.h"
+
+/* This is the top-level of the extension handler module. Extensions provide a
+ means of executing instructions whose register and memory effects are too
+ complex to be expressed with dirty helpers.
+ */
+
+#if defined(VGP_s390x_linux)
+
+/* --- This is the main function of this file. --- */
+
+enum ExtensionError VG_(client_extension)(ThreadId tid)
+{
+ ThreadState* tst;
+
+ vg_assert(VG_(is_valid_tid)(tid));
+ vg_assert(tid >= 1 && tid < VG_N_THREADS);
+ vg_assert(VG_(is_running_thread)(tid));
+
+ tst = VG_(get_ThreadState)(tid);
+
+ return ML_(do_client_extension)(tst);
+}
+
+#else
+
+enum ExtensionError VG_(client_extension)(ThreadId tid)
+{
+ VG_(core_panic)("Extension handler not implemented for this architecture");
+}
+
+#endif
--- /dev/null
+
+/*--------------------------------------------------------------------*/
+/*--- Handle s390x-specific extensions. extension-s390x.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) IBM Corp. 2024
+
+ 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, see <http://www.gnu.org/licenses/>.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+/* Contributed by Andreas Arnez */
+
+#if defined(VGP_s390x_linux)
+
+#include "libvex_s390x_common.h"
+#include "priv_extension.h"
+#include "priv_types_n_macros.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_threadstate.h"
+
+#undef SYSNO
+
+#define READ_FUNCTION_CODE(tst) \
+ ({ \
+ PRE_REG_READ(tst, "func_code", r0, 7, sizeof(UChar)); \
+ tst->arch.vex.guest_r0 & 0xff; \
+ })
+
+#define READ_GPR(tst, name, regno) \
+ ({ \
+ PRE_REG_READ(tst, name, r0, sizeof(ULong) * (regno), sizeof(ULong)); \
+ *((&tst->arch.vex.guest_r0) + (regno)); \
+ })
+
+#define WRITE_GPR(tst, regno, value) \
+ ({ \
+ *((&tst->arch.vex.guest_r0) + (regno)) = value; \
+ POST_REG_WRITE(tst, r0, sizeof(ULong) * (regno), sizeof(ULong)); \
+ })
+
+#define S390_CC_OP_SET 35
+
+#define WRITE_CC(tst, value) \
+ ({ \
+ tst->arch.vex.guest_CC_OP = S390_CC_OP_SET; \
+ tst->arch.vex.guest_CC_DEP1 = value; \
+ tst->arch.vex.guest_CC_DEP2 = 0; \
+ tst->arch.vex.guest_CC_NDEP = 0; \
+ POST_REG_WRITE(tst, CC_OP, 0, sizeof(ULong) * 4); \
+ })
+
+#define INSN_ERR(msg) \
+ ({ \
+ VG_(umsg)("Illegal operation: "); \
+ VG_(umsg)(msg); \
+ ExtErr_Illop; \
+ })
+
+union reg_pair {
+ struct {
+ ULong a, b;
+ };
+ unsigned __int128 pair;
+};
+
+#define S390_SETBIT(x) (1UL << (63 - (x % 64)))
+
+/* Helper routine for query functions: Filter the bit vector `fc' using a given
+ `filter' vector */
+static void s390_filter_functions(ULong* fc,
+ ULong fc_len,
+ const ULong* filter,
+ ULong filter_len)
+{
+ ULong n_fc = fc_len / sizeof(ULong);
+ ULong n_filter = filter_len / sizeof(ULong);
+
+ for (ULong i = 0; i < n_fc; i++) {
+ if (i < n_filter)
+ fc[i] &= filter[i];
+ else
+ fc[i] = 0;
+ }
+}
+
+/*---------------------------------------------------------------*/
+/*--- PRNO (perform random number operation) ---*/
+/*---------------------------------------------------------------*/
+
+static Int do_PRNO_insn(UChar func,
+ ULong parms,
+ ULong* addr1,
+ ULong* len1,
+ ULong* addr2,
+ ULong* len2)
+{
+ register UChar reg0 asm("0") = func;
+ register void* reg1 asm("1") = (void*)parms;
+ union reg_pair op1 = {{*addr1, *len1}};
+ union reg_pair op2 = {{*addr2, *len2}};
+ Int cc;
+
+ asm volatile(".insn rre, 0xb93c0000, %[op1], %[op2]\n"
+ "ipm %[cc]\n"
+ "srl %[cc], 28\n"
+ : [cc] "=d"(cc), [op1] "+a"(op1.pair), [op2] "+a"(op2.pair)
+ : "d"(reg0), "d"(reg1)
+ : "cc", "memory");
+ *addr1 = op1.a;
+ *len1 = op1.b;
+ *addr2 = op2.a;
+ *len2 = op2.b;
+ return cc;
+}
+
+/* PRNO functions that we support if the hardware does. */
+static const ULong PRNO_functions[] = {
+ (S390_SETBIT(0) // Query
+ | S390_SETBIT(3)), // SHA-512-DRNG
+ (S390_SETBIT(112) // TRNG-Query-Raw-to-Conditioned-Ratio
+ | S390_SETBIT(114)), // TRNG
+};
+
+static UWord do_extension_PRNO(ThreadState* tst, ULong variant)
+{
+ UChar r1 = variant & 0xf;
+ UChar r2 = (variant >> 4) & 0xf;
+ UChar func = READ_FUNCTION_CODE(tst);
+ UChar fc = func & 0x7f;
+ UChar mflag = func & 128;
+ ULong parms = READ_GPR(tst, "r1", 1);
+ ULong parms_len;
+ Int cc = 0;
+ ULong orig_addr1 = 0, orig_len1 = 0, orig_addr2 = 0, orig_len2 = 0;
+ ULong addr1 = 0, len1 = 0, addr2 = 0, len2 = 0;
+
+ switch (fc) {
+ case 0: // Query
+ parms_len = 16;
+ PRE_MEM_WRITE(tst, "parms", parms, parms_len);
+ cc = do_PRNO_insn(func, parms, &addr1, &len1, &addr2, &len2);
+ s390_filter_functions((ULong*)parms, parms_len, PRNO_functions,
+ sizeof(PRNO_functions));
+ POST_MEM_WRITE(tst, parms, parms_len);
+ break;
+ case 112: // TRNG-Query-Raw-to-Conditioned-Ratio
+ parms_len = 8;
+ PRE_MEM_WRITE(tst, "parms", parms, parms_len);
+ cc = do_PRNO_insn(func, parms, &addr1, &len1, &addr2, &len2);
+ POST_MEM_WRITE(tst, parms, parms_len);
+ break;
+ case 3: // SHA-512-DRNG
+ parms_len = 240;
+ PRE_MEM_READ(tst, "parms", parms, parms_len);
+ if (mflag == 0) {
+ // Generate operation
+ addr1 = orig_addr1 = READ_GPR(tst, "op1_addr", r1);
+ len1 = orig_len1 = READ_GPR(tst, "op1_len", r1 + 1);
+ PRE_MEM_WRITE(tst, "operand1", addr1, len1);
+ } else {
+ // Seed operation
+ addr2 = orig_addr2 = READ_GPR(tst, "op2_addr", r2);
+ len2 = orig_len2 = READ_GPR(tst, "op2_len", r2 + 1);
+ PRE_MEM_READ(tst, "operand2", addr2, len2);
+ }
+ PRE_MEM_WRITE(tst, "parms", parms, parms_len);
+ cc = do_PRNO_insn(func, parms, &addr1, &len1, &addr2, &len2);
+ POST_MEM_WRITE(tst, parms, parms_len);
+ if (mflag == 0) {
+ WRITE_GPR(tst, r2 + 1, len1);
+ POST_MEM_WRITE(tst, orig_addr1, orig_len1 - len1);
+ }
+ break;
+ case 114: // TRNG
+ addr1 = orig_addr1 = READ_GPR(tst, "op1_addr", r1);
+ len1 = orig_len1 = READ_GPR(tst, "op1_len", r1 + 1);
+ PRE_MEM_WRITE(tst, "operand1", addr1, len1);
+ addr2 = orig_addr2 = READ_GPR(tst, "op2_addr", r2);
+ len2 = orig_len2 = READ_GPR(tst, "op2_len", r2 + 1);
+ PRE_MEM_WRITE(tst, "operand2", addr2, len2);
+ cc = do_PRNO_insn(func, parms, &addr1, &len1, &addr2, &len2);
+ WRITE_GPR(tst, r1, addr1);
+ WRITE_GPR(tst, r1 + 1, len1);
+ WRITE_GPR(tst, r2, addr2);
+ WRITE_GPR(tst, r2 + 1, len2);
+ POST_MEM_WRITE(tst, orig_addr1, orig_len1 - len1);
+ POST_MEM_WRITE(tst, orig_addr2, orig_len2 - len2);
+ break;
+ default:
+ return INSN_ERR("PRNO: unknown function code\n");
+ }
+ WRITE_CC(tst, cc);
+ return ExtErr_OK;
+}
+
+enum ExtensionError ML_(do_client_extension)(ThreadState* tst)
+{
+ ULong code = REG_READ(tst, SYSNO);
+ ULong id = code & ((1ULL << S390_EXT_ID_NBITS) - 1);
+ ULong variant = code >> S390_EXT_ID_NBITS;
+
+ switch (id) {
+ case S390_EXT_PRNO:
+ return do_extension_PRNO(tst, variant);
+ default:
+ VG_(core_panic)("unknown extension ID");
+ }
+}
+
+#endif
--- /dev/null
+
+/*--------------------------------------------------------------------*/
+/*--- Private extensions header. priv_extension.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) IBM Corp. 2024
+
+ 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, see <http://www.gnu.org/licenses/>.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+/* Contributed by Andreas Arnez */
+
+#ifndef __PRIV_EXTENSION_H
+#define __PRIV_EXTENSION_H
+
+#include "pub_core_extension.h"
+#include "pub_core_threadstate.h"
+
+enum ExtensionError ML_(do_client_extension)(ThreadState* thread_state);
+
+#endif
--- /dev/null
+
+/*--------------------------------------------------------------------*/
+/*--- Types and macros for writing extensions. ---*/
+/*--- priv_types_n_macros.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) IBM Corp. 2024
+
+ 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, see <http://www.gnu.org/licenses/>.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+/* Contributed by Andreas Arnez */
+
+#ifndef __PRIV_TYPES_N_MACROS_H
+#define __PRIV_TYPES_N_MACROS_H
+
+#include "pub_core_basics.h" // Addr
+#include "pub_core_libcprint.h"
+#include "pub_core_signals.h"
+#include "pub_core_tooliface.h"
+#include "pub_tool_tooliface.h"
+
+#define PRE_REG_READ(tst, name, reg, offset, len) \
+ if (VG_(tdict).track_pre_reg_read) { \
+ VexGuestArchState* gst = &tst->arch.vex; \
+ VG_(tdict).track_pre_reg_read( \
+ Vg_CoreSysCall, tst->tid, name, \
+ (UChar*)&gst->guest_##reg - (UChar*)gst + (offset), len); \
+ }
+
+#define POST_REG_WRITE(tst, reg, offset, len) \
+ if (VG_(tdict).track_post_reg_write) { \
+ VexGuestArchState* gst = &tst->arch.vex; \
+ VG_(tdict).track_post_reg_write( \
+ Vg_CoreSysCall, tst->tid, \
+ (UChar*)&gst->guest_##reg - (UChar*)gst + offset, len); \
+ }
+
+#define PRE_MEM_READ(tst, name, addr, len) \
+ if (VG_(tdict).track_pre_mem_read) { \
+ VG_(tdict).track_pre_mem_read(Vg_CoreSysCall, tst->tid, name, addr, \
+ len); \
+ }
+
+#define PRE_MEM_WRITE(tst, name, addr, len) \
+ if (VG_(tdict).track_pre_mem_write) { \
+ VG_(tdict).track_pre_mem_write(Vg_CoreSysCall, tst->tid, name, addr, \
+ len); \
+ }
+
+#define POST_MEM_WRITE(tst, addr, len) \
+ if (VG_(tdict).track_post_mem_write) { \
+ VG_(tdict).track_post_mem_write(Vg_CoreSysCall, tst->tid, addr, len); \
+ }
+
+#define REG_READ(tst, reg) \
+ ({ \
+ PRE_REG_READ(tst, #reg, reg, 0, sizeof(tst->arch.vex.guest_##reg)); \
+ tst->arch.vex.guest_##reg; \
+ })
+
+
+#endif
#include "pub_core_clreq.h" // for VG_USERREQ__*
#include "pub_core_dispatch.h"
#include "pub_core_errormgr.h" // For VG_(get_n_errs_found)()
+#include "pub_core_extension.h"
#include "pub_core_gdbserver.h" // for VG_(gdbserver)/VG_(gdbserver_activity)
#include "pub_core_libcbase.h"
#include "pub_core_libcassert.h"
case VEX_TRC_JMP_YIELD: return "YIELD";
case VEX_TRC_JMP_NODECODE: return "NODECODE";
case VEX_TRC_JMP_MAPFAIL: return "MAPFAIL";
+ case VEX_TRC_JMP_EXTENSION: return "EXTENSION";
case VEX_TRC_JMP_SYS_SYSCALL: return "SYSCALL";
case VEX_TRC_JMP_SYS_INT32: return "INT32";
case VEX_TRC_JMP_SYS_INT128: return "INT128";
}
}
+static void handle_extension(ThreadId tid)
+{
+ volatile UWord jumped;
+ enum ExtensionError err;
+
+ SCHEDSETJMP(tid, jumped, err = VG_(client_extension)(tid));
+ vg_assert(VG_(is_running_thread)(tid));
+
+ if (err != ExtErr_OK) {
+ ThreadState* tst = VG_(get_ThreadState)(tid);
+ Addr addr = tst->arch.vex.guest_IP_AT_SYSCALL;
+ switch (err) {
+ case ExtErr_Illop:
+ VG_(synth_sigill)(tid, addr);
+ break;
+ default:
+ VG_(core_panic)("scheduler: bad return code from extension");
+ }
+ }
+
+ if (jumped != (UWord)0) {
+ block_signals();
+ VG_(poll_signals)(tid);
+ }
+}
+
/* tid just requested a jump to the noredir version of its current
program counter. So make up that translation if needed, run it,
and return the resulting thread return code in two_words[]. */
do_client_request(tid);
break;
+ case VEX_TRC_JMP_EXTENSION: {
+ handle_extension(tid);
+ break;
+ }
+
case VEX_TRC_JMP_SYS_INT128: /* x86-linux */
case VEX_TRC_JMP_SYS_INT129: /* x86-darwin */
case VEX_TRC_JMP_SYS_INT130: /* x86-darwin */
--- /dev/null
+/*--------------------------------------------------------------------*/
+/*--- Extensions pub_core_extension.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) IBM Corp. 2024
+
+ 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, see <http://www.gnu.org/licenses/>.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+/* Contributed by Andreas Arnez */
+
+#ifndef __PUB_CORE_EXTENSION_H
+#define __PUB_CORE_EXTENSION_H
+
+#include "pub_core_basics.h" // VG_ macro
+
+//--------------------------------------------------------------------
+// PURPOSE: This module contains the extension handling stuff
+//--------------------------------------------------------------------
+
+enum ExtensionError {
+ ExtErr_OK,
+ ExtErr_Illop,
+};
+
+extern enum ExtensionError VG_(client_extension) ( ThreadId tid );
+
+#endif