]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
PPC64: Add support for copy, cpabort, paste instructions
authorCarl Love <cel@us.ibm.com>
Thu, 27 May 2021 16:54:22 +0000 (11:54 -0500)
committerCarl Love <cel@us.ibm.com>
Thu, 3 Jun 2021 15:35:36 +0000 (10:35 -0500)
NEWS
VEX/priv/guest_ppc_defs.h
VEX/priv/guest_ppc_helpers.c
VEX/priv/guest_ppc_toIR.c
none/tests/ppc64/Makefile.am
none/tests/ppc64/test_copy_paste.c [new file with mode: 0644]
none/tests/ppc64/test_copy_paste.stderr.exp [new file with mode: 0644]
none/tests/ppc64/test_copy_paste.stdout.exp [new file with mode: 0644]
none/tests/ppc64/test_copy_paste.vgtest [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 4cf932d3032e9c65583f1cb05d849b5196f01539..c109b765ddfc3ce89bacf5e20251ed63397d7cd3 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -20,6 +20,7 @@ support for X86/macOS 10.13, AMD64/macOS 10.13 and nanoMIPS/Linux.
   - ISA 3.1 support is now complete
   - ISA 3.0 support for the darn instruction added.
   - ISA 3.0 support for the vector system call instruction scv added.
+  - ISA 3.0 support for the copy, paste and cpabort instructions added.
 
 * ==================== TOOL CHANGES ====================
 
@@ -40,6 +41,7 @@ are not entered into bugzilla tend to get forgotten about or ignored.
 434840  PPC64 darn instruction not supported
 434296  s390x: False-positive memcheck diagnostics from vector string
         instructions
+435665  PPC ISA 3.0 copy, paste, cpabort instructions are not supported 
 435908  valgrind tries to fetch from deubginfod for files which already
         have debug information
 
index 7c50f8581999b135d8184ac6277678c67595687a..93ada1ba988cb52a31e2e0ebe0fd4bb2ff238005 100644 (file)
@@ -219,6 +219,11 @@ extern void vector_gen_pvc_dword_mask_dirty_helper( VexGuestPPC64State* gst,
 #define XVF64GERNP     0b01111010
 #define XVF64GERNN     0b11111010
 
+#define INVALD_INST    1
+#define COPY_INST      2
+#define PASTE_INST     3
+#define CPABORT_INST   4
+
 /* --- DIRTY HELPERS --- */
 
 extern ULong ppcg_dirtyhelper_MFTB ( void );
@@ -273,6 +278,7 @@ extern void vsx_matrix_64bit_float_ger_dirty_helper( VexGuestPPC64State* gst,
                                                      ULong srcY_lo,
                                                      UInt masks_inst );
 extern ULong darn_dirty_helper ( UInt L );
+extern UInt copy_paste_abort_dirty_helper(UInt addr, UInt op);
 
 #endif /* ndef __VEX_GUEST_PPC_DEFS_H */
 
index c7557399898e19c2d2838782758c05665dfd94ba..6c8191a474c6a0e5caaa40a28d0920128433f0b6 100644 (file)
@@ -3163,6 +3163,35 @@ VexGuestLayout
             }
         };
 
+UInt copy_paste_abort_dirty_helper(UInt addr, UInt op) {
+#  if defined(__powerpc__)
+   ULong ret;
+   UInt cr;
+
+   if (op == COPY_INST)
+      __asm__ __volatile__ ("copy 0,%0" :: "r" (addr));
+
+   else if (op == PASTE_INST)
+      __asm__ __volatile__ ("paste. 0,%0" :: "r" (addr));
+
+   else if (op == CPABORT_INST)
+      __asm__ __volatile__ ("cpabort");
+
+   else
+      /* Unknown operation */
+      vassert(0);
+
+   /* Return the CR0 value. Contains status for the paste instruction. */
+   __asm__ __volatile__ ("mfocrf %0,128" : "=r" (cr));
+   __asm__ __volatile__ ("srawi %0,%1,28" : "=r" (ret) : "r" (cr));
+   /* Make sure the upper bits of the return value are zero per the hack
+      described in function dis_copy_paste().  */
+   return 0xFF & ret;
+# else
+   return 0;
+# endif
+}
+
 /*---------------------------------------------------------------*/
 /*--- end                                 guest_ppc_helpers.c ---*/
 /*---------------------------------------------------------------*/
index 1ed6f8d6f7dc1bf03c6f6f71c0de9d785cb50217..f223fe94568f23b6b388adc2e972afba221cb8b9 100644 (file)
@@ -35603,6 +35603,151 @@ static Bool dis_vector_generate_pvc_from_mask ( UInt prefix,
    return True;
 }
 
+static Int dis_copy_paste ( UInt prefix, UInt theInstr,
+                           const VexAbiInfo* vbi )
+{
+   IRType ty = mode64 ? Ity_I64 : Ity_I32;
+   Bool L = IFIELD( theInstr, 21, 1 );
+   UInt bit0 = IFIELD( theInstr, 0, 1 );
+   UInt opc2 = ifieldOPClo10( theInstr );
+   UChar rA_addr = ifieldRegA(theInstr);
+   UChar rB_addr = ifieldRegB(theInstr);
+   IRTemp cr0 = newTemp( Ity_I8 );
+   UInt operation = INVALD_INST;
+   IRTemp EA_base = newTemp(ty);
+   IRExpr** args;
+   IRDirty* d;
+   UInt mFx = Ifx_None;
+   IRTemp helper_rtn = newTemp(Ity_I32);
+
+   /* There is no prefixed version of these instructions.  */
+   PREFIX_CHECK
+
+   assign( EA_base, ea_rAor0_idxd(rA_addr, rB_addr) );
+
+   if (ty != Ity_I64) {
+      vpanic( "ERROR PPC: copy, paste, cpabort only supported on 64-bit systems");
+      return False;
+   }
+
+   /* The dirty helper is passed the EA_bse for the 128-byte buffer and
+      and operation, i.e. which instruction to issue on the host.  It returns
+      uint32_t result.  The result is condition code CR0.  Only for the paste
+      instruction is the return value relevant and must be used to update the
+      guest state.  */
+
+   if (( opc2 == 0x306 ) && ( L == 1 )) {         // copy
+      DIP("copy %u,%u\n", rA_addr, rB_addr);
+      operation = COPY_INST;
+      mFx = Ifx_Read;
+
+   } else if ( opc2 == 0x346 ) {  // cpabort
+      DIP("cpabort\n");
+      operation = CPABORT_INST;
+      /* Abort data transfer if one is in progress.  */
+      /* cpabort does nothing to the guest state, just resets operation
+         on the host.  */
+
+   } else if (( opc2 == 0x386 ) && ( bit0 == 1 )) {  // paste.
+
+      /*   The Ifx_write will cause Memcheck will instrument the buffer, if
+           there is any undefinedness in the inputs, then all of the outputs
+           will be undefined.  Hence:
+
+              if    EA_base or operation contain any undefined bits
+
+              then  the return value is undefined and the specified 128-byte
+                    memory area are undefined after the call
+
+              else  the return value is undefined and the specified 128-byte
+                    memory area are defined after the call  */
+      DIP("paste %u,%u\n", rA_addr, rB_addr);
+      operation = PASTE_INST;
+      mFx = Ifx_Write;
+
+   } else {
+      /* Unknown instruction, should never get here.  */
+      return False;
+   }
+
+   /* Call dirty helper to issue the copy, paste or cpabort instruction on the
+      host.  */
+   args = mkIRExprVec_2( mkexpr(EA_base), mkU32(operation) );
+
+   /* The dirty helper needs to return the 8-bit condition code result from
+      the copy/paste instructions run on the host.  The follwoing hack is used
+      to get Memcheck to return an error if any of the bits in the 128-byte
+      copy-paste buffer are uninitialized.  The bottom 8-bits of helper_rtn
+      contain the condition code CR0.  The upper bits must all be zero.   */
+
+   d = unsafeIRDirty_1_N (
+      helper_rtn,
+      0/*regparms*/,
+      "copy_paste_abort_dirty_helper",
+      fnptr_to_fnentry( vbi, &copy_paste_abort_dirty_helper ),
+      args );
+
+   /* As part of the hack, we must set mFx/mAddr/mSize so as to declare the
+      memory area used by the copy/paste instructions.  */
+   d->mAddr = NULL;
+
+   if (mFx != Ifx_None) {
+      d->mFx = mFx;
+      d->mAddr = mkexpr(EA_base);
+      d->mSize = 128;  /* 128 byte memory region */
+   }
+
+   stmt( IRStmt_Dirty(d) );
+
+   /* The following Exit state is inserted with a test that the IR
+      optimization cannot remove.  */
+   stmt( IRStmt_Exit(
+            binop(Iop_CmpNE32, binop( Iop_And32, mkexpr(helper_rtn),
+                                      mkU32(0xFF00)),
+                  mkU32(0)),
+            Ijk_SigTRAP,
+            mode64 ? IRConst_U64(guest_CIA_curr_instr) :
+            IRConst_U32((UInt) guest_CIA_curr_instr),
+            OFFB_CIA
+      ));
+   /*  The effects of this hack are as follows:
+
+       (1) the above stmt() asks the IR to exit, asking Valgrind to hand
+       the program a SIGTRAP at this point, if the fake return value is
+       nonzero, however ..
+
+       (2) .. that never happens, because the actual return value is maked
+       out and the upper bits of the return are always zero.
+
+       (3) Memcheck will believe that any undefinedness in the copy/paste
+       area read by the helper will be propagated through to the helper_rtn
+       value, and will generate instrumentation to cause that to happen.
+
+       (4) Memcheck will instrument the IRStmt_Exit to check the definedness
+       computed by (3) and emit an error if helper_rtn value contains any
+       undefined bits.  Hence Memcheck will generate a warning for undefined
+       bits in the copy/paste buffer.
+
+       (5) Note that the IR optimisation passes do not know what value the
+       helper call will return.  Hence we are guaranteed that they can't
+       optimise away the IRStmt_Exit and its associated check.  */
+
+   /* Need to extract the actual return value and put it into the guest
+      state.  */
+   assign( cr0, unop(Iop_16to8,
+                     unop(Iop_32to16, mkexpr(helper_rtn))));
+
+   if (( opc2 == 0x386 ) && (bit0 == 1 )) {
+      /* Only the paste instruction sets CR0.
+         Update CR0 bits [3:1] with the copy/paste result with the host CR0
+         result value.  CR0 bit 0 must match the guest XER_OV value.  */
+      putCR0  ( 0, binop(Iop_And8, mkU8( 1  ), getXER_OV() ) );
+      putCR321( 0, binop(Iop_And8, mkU8( 0xE ), mkexpr(cr0) ) );
+   }
+
+   return True;
+}
+
 static Int dis_nop_prefix ( UInt prefix, UInt theInstr )
 {
    Bool is_prefix   = prefix_instruction( prefix );
@@ -37533,6 +37678,21 @@ DisResult disInstr_PPC_WRK (
          if (dis_int_logic( prefix, theInstr )) goto decode_success;
          goto decode_failure;
 
+      case 0x306:  // copy
+         if ( !mode64 || !allow_isa_3_0 ) goto decode_failure;
+         if (dis_copy_paste( prefix, theInstr, abiinfo )) goto decode_success;
+         goto decode_failure;
+
+      case 0x346:  // cpabort
+         if ( !mode64 || !allow_isa_3_0 ) goto decode_failure;
+         if (dis_copy_paste( prefix, theInstr, abiinfo )) goto decode_success;
+         goto decode_failure;
+
+      case 0x386:  // paste.
+         if ( !mode64 || !allow_isa_3_0 ) goto decode_failure;
+         if (dis_copy_paste( prefix, theInstr, abiinfo )) goto decode_success;
+         goto decode_failure;
+
       default:
          /* Deal with some other cases that we would otherwise have
             punted on. */
index 1636613345318bf5f3370d2922c1de6847df9903..5c2ee87d58efb867e32c62e2ffaabf270d47e9ec 100644 (file)
@@ -59,7 +59,10 @@ EXTRA_DIST = \
        subnormal_test.stderr.exp  subnormal_test.stdout.exp \
        subnormal_test.vgtest test_darn_inst.stderr.exp \
        test_darn_inst.stdout.exp test_darn_inst.vgtest \
-       scv_test.stderr.exp scv_test.stdout.exp scv_test.vgtest
+       scv_test.stderr.exp scv_test.stdout.exp scv_test.vgtest \
+       test_copy_paste.stderr.exp test_copy_paste.stdout.exp \
+       test_copy_paste.vgtest
+
 
 check_PROGRAMS = \
        allexec \
@@ -70,7 +73,7 @@ check_PROGRAMS = \
        test_isa_3_0 test_mod_instructions \
        test_isa_3_1_RT test_isa_3_1_XT test_isa_3_1_VRT \
        test_isa_3_1_Misc test_isa_3_1_AT \
-       subnormal_test test_darn_inst \
+       subnormal_test test_darn_inst test_copy_paste \
        test_tm test_touch_tm data-cache-instructions \
        power6_mf_gpr std_reg_imm \
        twi_tdi tw_td power6_bcmp scv_test
@@ -204,6 +207,9 @@ test_isa_3_1_AT_CFLAGS = $(test_isa_3_1_CFLAGS)
 subnormal_test_CFLAGS = $(AM_CFLAGS) -Winline -Wall -O -g -mregnames $(VSX_FLAG) $(ISA_2_06_FLAG) \
                        @FLAG_M64@ $(ALTIVEC_FLAG) $(BUILD_FLAG_VSX) $(BUILD_FLAGS_ISA_2_06)
 
+test_copy_paste_CFLAGS = $(AM_CFLAGS) -Winline -Wall -O -g -mregnames $(VSX_FLAG) $(ISA_3_1_FLAG) \
+                       @FLAG_M64@ $(ALTIVEC_FLAG) $(BUILD_FLAG_VSX) $(BUILD_FLAGS_ISA_3_1)
+
 test_isa_2_06_part3_LDADD = -lm
 test_dfp1_LDADD = -lm
 test_dfp2_LDADD = -lm
diff --git a/none/tests/ppc64/test_copy_paste.c b/none/tests/ppc64/test_copy_paste.c
new file mode 100644 (file)
index 0000000..0f4659e
--- /dev/null
@@ -0,0 +1,110 @@
+/* The copy, paste, cpabort are ISA 3.0 instructions.  However, the memory
+   to memory copy is only supported on ISA 3.1 era machines.  */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include <altivec.h>
+
+/* return CR0 in least significant bits */
+#define GET_CR0(_lval)                                  \
+   __asm__ __volatile__ ("mfcr %0"  : "=b"(_lval) );    \
+   __asm__ __volatile__ ("srawi %0,%1,28" : "=r" (_lval) : "r" (_lval));
+
+void test_copy (uint8_t *reg)
+{
+  __asm__ __volatile__ ("copy 0,%0" : : "r" (reg));
+}
+
+void test_paste (uint8_t *reg)
+{
+  __asm__ __volatile__ ("paste. 0,%0" : : "r" (reg));
+}
+
+void test_cpabort (void)
+{
+  __asm__ __volatile__ ("cpabort");
+}
+
+#define NUM_ELEMENTS 128
+#define SUCCESS 1
+#define FAILURE 2
+#define DEBUG 0
+#define PASTE_ERROR 0
+
+int main()
+{
+   int i;
+   unsigned int cc_value;
+   int result = SUCCESS;
+
+   /* buffers must be 128 bytes long and aligned to 128 bytes */
+   uint8_t src_buffer[NUM_ELEMENTS] __attribute__ ((aligned (128)));
+   uint8_t dst_buffer[NUM_ELEMENTS] __attribute__ ((aligned (128)));
+
+   for (i=0; i<NUM_ELEMENTS; i++) {
+     src_buffer[i] = 10 + i;
+     dst_buffer[i] = i;
+   }
+
+#if DEBUG
+   printf("Initial contents of src/dst buffer\n");
+   for (i=0; i<NUM_ELEMENTS; i++) {
+      printf("src_buffer[%d] = 0x%x  ", i, src_buffer[i]);
+      printf("dst_buffer[%d] = 0x%x\n", i, dst_buffer[i]);
+   }
+#endif
+
+    /* Test correct copy past sequence. */
+   test_copy (src_buffer);
+   test_paste (dst_buffer);
+   GET_CR0(cc_value);
+
+#if DEBUG
+   printf("AFTER COPY/PASTE Contents of src/dst buffer\n");
+   for (i=0; i<NUM_ELEMENTS; i++) {
+      printf("src_buffer[%d] = 0x%x  ", i, src_buffer[i]);
+      printf("dst_buffer[%d] = 0x%x\n", i, dst_buffer[i]);
+   }
+#endif
+
+   /* Check if result matches initial values. */
+   for (i=0; i<NUM_ELEMENTS; i++) {
+      if (src_buffer[i] != dst_buffer[i]) {
+         result = FAILURE;
+      printf("ERROR: dst_buffer[%d] = 0x%x\n", i, dst_buffer[i]);
+      printf("    not equal to src_buffer[%d] = 0x%x\n", i, src_buffer[i]);
+      }
+   }
+
+   if (cc_value == PASTE_ERROR) {
+      result = FAILURE;
+      printf("ERROR: result code wrong for correct copy/paste sequence.\n");
+   }
+
+   /* Test out of order paste.  */
+   for (i=0; i<NUM_ELEMENTS; i++) {
+     dst_buffer[i] = i;
+   }
+
+   test_paste (dst_buffer);
+   GET_CR0(cc_value);
+
+   if (cc_value != PASTE_ERROR) {
+      result = FAILURE;
+      printf("ERROR: out of order past result 0x%x is wrong.\n", cc_value);
+   }
+
+   /* Issue cpabort instruction just to see if we get a segmentation fault or
+      other catastrophic failure.  No specific result to check for failure.  */
+   test_cpabort ();
+
+   if (result == SUCCESS)
+      printf("SUCCESS.\n");
+   else
+      printf("FAILURE.\n");
+
+   return 0;
+}
diff --git a/none/tests/ppc64/test_copy_paste.stderr.exp b/none/tests/ppc64/test_copy_paste.stderr.exp
new file mode 100644 (file)
index 0000000..139597f
--- /dev/null
@@ -0,0 +1,2 @@
+
+
diff --git a/none/tests/ppc64/test_copy_paste.stdout.exp b/none/tests/ppc64/test_copy_paste.stdout.exp
new file mode 100644 (file)
index 0000000..6dbfe86
--- /dev/null
@@ -0,0 +1 @@
+SUCCESS.
diff --git a/none/tests/ppc64/test_copy_paste.vgtest b/none/tests/ppc64/test_copy_paste.vgtest
new file mode 100644 (file)
index 0000000..fd7ebc3
--- /dev/null
@@ -0,0 +1,2 @@
+prereq: ../../../tests/check_ppc64_auxv_cap arch_3_1
+prog: test_copy_paste