Add support for the s390's TROO insn. These are the valgrind bits.
Detect ETF2 enhancement facility using STFLE. Add testcases.
Patch by Divya Vyas (divyvyas@linux.vnet.ibm.com) with
modifications. Partial fix of #273114
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@12335 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/m_machine.c b/coregrind/m_machine.c
index 5df9e04..bbfaa1f 100644
--- a/coregrind/m_machine.c
+++ b/coregrind/m_machine.c
@@ -999,6 +999,7 @@
vki_sigaction_toK_t tmp_sigill_act;
volatile Bool have_LDISP, have_EIMM, have_GIE, have_DFP, have_FGX;
+ volatile Bool have_STFLE, have_ETF2;
Int r, model;
/* Unblock SIGILL and stash away the old action for that signal */
@@ -1066,6 +1067,24 @@
__asm__ __volatile__(".long 0xb3cd0000" : : : "r0"); /* lgdr r0,f0 */
}
+ /* Detect presence of the ETF2-enhancement facility using the
+ STFLE insn. Note, that STFLE and ETF2 were introduced at the same
+ time, so the absence of STLFE implies the absence of ETF2. */
+ have_STFLE = True;
+ have_ETF2 = False;
+ if (VG_MINIMAL_SETJMP(env_unsup_insn)) {
+ have_STFLE = False;
+ } else {
+ ULong hoststfle[1];
+ register ULong reg0 asm("0") = 0; /* one double word available */
+
+ __asm__ __volatile__(" .insn s,0xb2b00000,%0\n" /* stfle */
+ : "=m" (hoststfle), "+d"(reg0)
+ : : "cc", "memory");
+ if (hoststfle[0] & (1ULL << (63 - 24)))
+ have_ETF2 = True;
+ }
+
/* Restore signals */
r = VG_(sigaction)(VKI_SIGILL, &saved_sigill_act, NULL);
vg_assert(r == 0);
@@ -1076,8 +1095,8 @@
model = VG_(get_machine_model)();
VG_(debugLog)(1, "machine", "machine %d LDISP %d EIMM %d GIE %d DFP %d "
- "FGX %d\n", model, have_LDISP, have_EIMM, have_GIE,
- have_DFP, have_FGX);
+ "FGX %d STFLE %d ETF2 %d\n", model, have_LDISP, have_EIMM,
+ have_GIE, have_DFP, have_FGX, have_STFLE, have_ETF2);
if (model == VEX_S390X_MODEL_INVALID) return False;
@@ -1092,6 +1111,7 @@
if (have_GIE) vai.hwcaps |= VEX_HWCAPS_S390X_GIE;
if (have_DFP) vai.hwcaps |= VEX_HWCAPS_S390X_DFP;
if (have_FGX) vai.hwcaps |= VEX_HWCAPS_S390X_FGX;
+ if (have_ETF2) vai.hwcaps |= VEX_HWCAPS_S390X_ETF2;
VG_(debugLog)(1, "machine", "hwcaps = 0x%x\n", vai.hwcaps);
diff --git a/none/tests/s390x/Makefile.am b/none/tests/s390x/Makefile.am
index bb0a281..2ede439 100644
--- a/none/tests/s390x/Makefile.am
+++ b/none/tests/s390x/Makefile.am
@@ -5,7 +5,7 @@
INSN_TESTS = clc clcle cvb cvd icm lpr tcxb lam_stam xc mvst add sub mul \
and or xor insert div srst fold_And16 flogr sub_EI add_EI \
and_EI or_EI xor_EI insert_EI mul_GE add_GE condloadstore \
- op_exception fgx stck stckf stcke stfle cksm mvcl clcl
+ op_exception fgx stck stckf stcke stfle cksm mvcl clcl troo
check_PROGRAMS = $(INSN_TESTS) \
allexec \
diff --git a/none/tests/s390x/troo.c b/none/tests/s390x/troo.c
new file mode 100644
index 0000000..925c7a7
--- /dev/null
+++ b/none/tests/s390x/troo.c
@@ -0,0 +1,126 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+
+/* Register contents after executing an TROO insn */
+typedef struct {
+ uint64_t srcaddr;
+ uint64_t len;
+ uint64_t desaddr;
+ uint64_t tabaddr;
+ uint8_t testbyte;
+ uint64_t cc;
+} troo_regs;
+
+uint8_t tran_table[20] = {
+ 0xaa,0xbb,0xcc,0xdd,0xff,0xda,0xbc,0xab,0xca,0xea,0xcc,0xee
+};
+
+uint8_t src[20] = {
+ 0x04,0x01,0x03,0x07,0x08,0x06,0x02,0x05,0x09
+};
+
+uint8_t des[20];
+
+troo_regs tr(uint8_t *addr, uint8_t *codepage, uint8_t *dest, uint64_t len,
+ uint8_t test)
+{
+ troo_regs regs;
+ register uint64_t test_byte asm("0") = test;
+ register uint64_t length asm("3") = len;
+ register uint64_t srcaddr asm("4") = (uint64_t)addr;
+ register uint64_t codepage2 asm("1") = (uint64_t)codepage;
+ register uint64_t desaddr asm("2") = (uint64_t)dest;
+ register uint64_t cc asm("5");
+
+ cc = 2; /* cc result will never be 2 */
+ asm volatile(
+ " troo %1,%2\n"
+ " ipm %0\n"
+ " srl %0,28\n"
+ : "=d"(cc),"+&d"(desaddr)
+ : "d" (srcaddr),"d"(test_byte),"d" (codepage2),"d"(length)
+ : "memory" );
+
+ regs.srcaddr = srcaddr;
+ regs.len = length;
+ regs.desaddr = desaddr;
+ regs.tabaddr = codepage2;
+ regs.testbyte = test_byte;
+ regs.cc = cc;
+ return regs;
+}
+
+int run_test(void *srcaddr, void *tableaddr, void *desaddr, uint64_t len,
+ uint8_t testbyte)
+{
+ troo_regs regs;
+ int i;
+
+ assert(len <= sizeof src);
+
+ if ((testbyte & 0xff) != testbyte)
+ printf("testbyte should be 1 byte only\n");
+
+ regs = tr(srcaddr, tableaddr, desaddr, len, testbyte);
+
+ if ((uint64_t)tableaddr != regs.tabaddr)
+ printf("translation table address changed\n");
+ if ((uint64_t)srcaddr + (len - regs.len) != regs.srcaddr)
+ printf("source address/length not updated properly\n");
+ if ((uint64_t)desaddr + (len - regs.len) != regs.desaddr)
+ printf("destination address/length not updated properly\n");
+ if (regs.cc == 0 && regs.len != 0)
+ printf("length is not zero but cc is zero\n");
+ printf("%u bytes translated\n", (unsigned)(len - regs.len));
+ printf("the translated values are");
+ for (i = 0; i < len - regs.len; i++) {
+ printf(" %x", des[i]);
+ }
+ printf("\n");
+
+ return regs.cc;
+}
+
+int main()
+{
+ int cc;
+
+ assert(sizeof des >= sizeof src);
+
+ /* Test 1 : len == 0 */
+ cc = run_test(NULL, NULL, NULL, 0, 0x0);
+ if (cc != 0)
+ printf("cc not updated properly:%d", cc);
+
+ cc = run_test(&src, &tran_table, &des, 0, 0xca);
+ if (cc != 0)
+ printf("cc not updated properly:%d",cc);
+
+ /* Test 2 : len > 0, testbyte not matching */
+ cc = run_test(&src, &tran_table, &des, 5, 0xee);
+ if (cc != 0)
+ printf("cc not updated properly:%d",cc);
+
+ cc = run_test(&src, &tran_table, &des, 10, 0x00);
+ if (cc != 0)
+ printf("cc not updated properly:%d",cc);
+
+ memset((char *)&des, 0, 10);
+
+ /* Test 3 : len > 0, testbyte matching */
+ cc = run_test(&src, &tran_table, &des, 5, 0xff); /* 1st byte matches */
+ if (cc != 1)
+ printf("cc not updated properly:%d",cc);
+
+ cc = run_test(&src, &tran_table, &des, 5, 0xbb); /* 2nd byte matches */
+ if (cc != 1)
+ printf("cc not updated properly:%d",cc);
+
+ cc = run_test(&src, &tran_table, &des, 10, 0xea);
+ if (cc != 1)
+ printf("cc not updated properly:%d",cc);
+
+ return 0;
+}
diff --git a/none/tests/s390x/troo.stderr.exp b/none/tests/s390x/troo.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/none/tests/s390x/troo.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/none/tests/s390x/troo.stdout.exp b/none/tests/s390x/troo.stdout.exp
new file mode 100644
index 0000000..bebf998
--- /dev/null
+++ b/none/tests/s390x/troo.stdout.exp
@@ -0,0 +1,14 @@
+0 bytes translated
+the translated values are
+0 bytes translated
+the translated values are
+5 bytes translated
+the translated values are ff bb dd ab ca
+10 bytes translated
+the translated values are ff bb dd ab ca bc cc da ea aa
+0 bytes translated
+the translated values are
+1 bytes translated
+the translated values are ff
+8 bytes translated
+the translated values are ff bb dd ab ca bc cc da
diff --git a/none/tests/s390x/troo.vgtest b/none/tests/s390x/troo.vgtest
new file mode 100644
index 0000000..500076e
--- /dev/null
+++ b/none/tests/s390x/troo.vgtest
@@ -0,0 +1 @@
+prog: troo