]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
PPC64: add support for the vectored system call instruction scv.
authorCarl Love <cel@us.ibm.com>
Tue, 4 May 2021 19:49:49 +0000 (14:49 -0500)
committerCarl Love <cel@us.ibm.com>
Tue, 4 May 2021 20:34:43 +0000 (15:34 -0500)
21 files changed:
NEWS
VEX/priv/guest_ppc_defs.h
VEX/priv/guest_ppc_toIR.c
VEX/pub/libvex.h
VEX/pub/libvex_guest_ppc32.h
VEX/pub/libvex_guest_ppc64.h
coregrind/m_initimg/initimg-linux.c
coregrind/m_machine.c
coregrind/m_signals.c
coregrind/m_syscall.c
coregrind/m_syswrap/priv_types_n_macros.h
coregrind/m_syswrap/syscall-ppc64le-linux.S
coregrind/m_syswrap/syswrap-linux.c
coregrind/m_syswrap/syswrap-main.c
coregrind/pub_core_syscall.h
memcheck/mc_machine.c
none/tests/ppc64/Makefile.am
none/tests/ppc64/scv_test.c [new file with mode: 0644]
none/tests/ppc64/scv_test.stderr.exp [new file with mode: 0644]
none/tests/ppc64/scv_test.stdout.exp [new file with mode: 0644]
none/tests/ppc64/scv_test.vgtest [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 4b4d33309cc63762b77b2be69f23fbf24dc4cec9..a84ee6b730c6f18366f6a753c3590a818d550429 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -19,6 +19,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.
 
 * ==================== TOOL CHANGES ====================
 
@@ -33,6 +34,7 @@ are not entered into bugzilla tend to get forgotten about or ignored.
 
 423963  Error in child thread when CLONE_PIDFD is used
 429375  PPC ISA 3.1 support is missing, part 9
+431157  PPC_FEATURE2_SCV needs to be masked in AT_HWCAP2
 433801  PPC ISA 3.1 support is missing, part 10 (ISA 3.1 support complete)
 433863  s390x: memcheck/tests/s390x/{cds,cs,csg} failures
 434840  PPC64 darn instruction not supported
index 3c22096673be819ae073ecb156bc5e60e5de678a..7c50f8581999b135d8184ac6277678c67595687a 100644 (file)
@@ -276,6 +276,13 @@ extern ULong darn_dirty_helper ( UInt L );
 
 #endif /* ndef __VEX_GUEST_PPC_DEFS_H */
 
+/* SCV flag defines.  Must be consistently defined here and in
+   coregrind/pub_core_syscall.h,in the do_syscall_WRK() assembly code in
+   coregrind/m_syscall.c and coregrind/m_syswrap/syscall-ppc64le-linux.S
+   code.  */
+#define SC_FLAG  1
+#define SCV_FLAG 2
+
 /*---------------------------------------------------------------*/
 /*--- end                                    guest_ppc_defs.h ---*/
 /*---------------------------------------------------------------*/
index 09e9c490873b31fc55ea912ccfb153d745855904..1ed6f8d6f7dc1bf03c6f6f71c0de9d785cb50217 100644 (file)
@@ -375,6 +375,7 @@ static Bool OV32_CA32_supported = False;
 #define OFFB_ACC_7_r1    offsetofPPCGuestState(guest_ACC_7_r1)
 #define OFFB_ACC_7_r2    offsetofPPCGuestState(guest_ACC_7_r2)
 #define OFFB_ACC_7_r3    offsetofPPCGuestState(guest_ACC_7_r3)
+#define OFFB_syscall_flag  offsetofPPCGuestState(guest_syscall_flag)
 
 
 /*------------------------------------------------------------*/
@@ -4068,6 +4069,18 @@ static IRExpr* /* ::Ity_I32 */  getFPCC ( void )
    return mkexpr(val);
 }
 
+static void put_syscall_flag( IRExpr* src )
+{
+   /* Need to pass a flag indicating if the system call is using the sc or
+      scv instructions.  Because Valgrind does an end-of-block after the
+      system call, the contents of a gpr can not be saved and restored after
+      the system call.  A custom guest state register guest_syscall_flag is
+      used to pass the flag so the guest state is not disturbed.  */
+
+   stmt( IRStmt_Put( offsetofPPCGuestState(guest_syscall_flag), src ) );
+}
+
+
 /*-----------------------------------------------------------*/
 /* Helpers to access VSX Accumulator register file
  *-----------------------------------------------------------*/
@@ -11011,6 +11024,7 @@ static Bool dis_trap ( UInt prefix, UInt theInstr,
 /*
   System Linkage Instructions
 */
+
 static Bool dis_syslink ( UInt prefix, UInt theInstr,
                           const VexAbiInfo* abiinfo, DisResult* dres )
 {
@@ -11019,14 +11033,27 @@ static Bool dis_syslink ( UInt prefix, UInt theInstr,
    /* There is no prefixed version of these instructions.  */
    PREFIX_CHECK
 
-   if (theInstr != 0x44000002) { // sc
-      if (theInstr != 0x44000001) // scv
-         vex_printf("dis_syslink(ppc)(theInstr)\n");
+   if ((theInstr != 0x44000002)       // sc
+       && (theInstr != 0x44000001)) { // scv
+       vex_printf("dis_syslink(ppc)(theInstr)\n");
       return False;
    }
 
-   // sc  (System Call, PPC32 p504)
-   DIP("sc\n");
+   /* The PPC syscall uses guest_GPR9 to pass a flag to indicate which
+      system call instruction is to be used.  Arg7 = SC_FLAG for the sc
+      instruction; Arg7 = SCV_FLAG for the scv instruction.  */
+   if (theInstr == 0x44000002) {
+      // sc  (System Call, PPC32 p504)
+      DIP("sc\n");
+      put_syscall_flag( mkU32(SC_FLAG) );
+   } else if (theInstr == 0x44000001) {
+      // scv
+      DIP("scv\n");
+      put_syscall_flag( mkU32(SCV_FLAG) );
+   } else {
+      /* Unknown instruction */
+      return False;
+   }
 
    /* Copy CIA into the IP_AT_SYSCALL pseudo-register, so that on Darwin
       Valgrind can back the guest up to this instruction if it needs
@@ -36113,8 +36140,9 @@ DisResult disInstr_PPC_WRK (
       goto decode_failure;
 
    /* System Linkage Instructions */
-   case 0x11: // sc
-      if (dis_syslink( prefix, theInstr, abiinfo, &dres)) goto decode_success;
+   case 0x11: // sc, scv
+      if (dis_syslink( prefix, theInstr, abiinfo, &dres))
+         goto decode_success;
       goto decode_failure;
 
    /* Trap Instructions */
index 46a7a5553e4edaaa63baf10fbc67b5e61f534f90..dcf022159b8d1d7d69efe614361440124f7995d9 100644 (file)
@@ -125,6 +125,8 @@ typedef
 #define VEX_HWCAPS_PPC64_ISA2_07   (1<<20) /* ISA 2.07 -- e.g., mtvsrd */
 #define VEX_HWCAPS_PPC64_ISA3_0    (1<<22) /* ISA 3.0  -- e.g., cnttzw */
 #define VEX_HWCAPS_PPC64_ISA3_1    (1<<23) /* ISA 3.1  -- e.g., brh */
+#define VEX_HWCAPS_PPC64_SCV       (1<<24) /* ISA 3.0, Kernel supports scv
+                                              instruction. */
 
 /* s390x: Hardware capability encoding
 
index eb1f728b747f842c67c43612fb0e3e2eedcaf333..9457e9bc0f679deed502f68da61f35f20be0d981 100644 (file)
@@ -290,9 +290,8 @@ typedef
       /* 1924 */   U128  guest_ACC_7_r3;
 
    /* Padding to make it have an 16-aligned size */
-      /* 1940 */ UInt  padding2;
-//      /* 1944 */ UInt  padding3;
-//      /* 1948 */ UInt  padding4;
+      /* 1940 */   UInt guest_syscall_flag;
+      /* 1944 *    UInt  padding2; */
    }
    VexGuestPPC32State;
 
index c8c9d072d484b557724695e8e86e9e944f84b3cc..92e93cb881ab02d1ffd7d3661e0750894408a778 100644 (file)
@@ -328,6 +328,10 @@ typedef
       /* 2192 */   U128  guest_ACC_7_r2;
       /* 2208 */   U128  guest_ACC_7_r3;
 
+      /* 2224 */   UInt guest_syscall_flag;
+      /* 2228 */   UInt padding1;
+      /* 2232 */   UInt padding2;
+      /* 2236 */   UInt padding3;
       /* Padding to make it have an 16-aligned size */
       /* 2222    UInt  padding0; */
    }
index 55559b492344c24e5bc8876ab2d60553cc09a74c..fc1a32ecf8eff99ff2b1cfa1967abc8fbb5c9f8f 100644 (file)
@@ -726,6 +726,7 @@ Addr setup_client_stack( void*  init_sp,
             Bool auxv_2_07, hw_caps_2_07;
             Bool auxv_3_0, hw_caps_3_0;
             Bool auxv_3_1, hw_caps_3_1;
+            Bool auxv_scv_supported, hw_caps_scv_supported;
 
            /* The HWCAP2 field may contain an arch_2_07 entry that indicates
              * if the processor is compliant with the 2.07 ISA. (i.e. Power 8
@@ -796,6 +797,19 @@ Addr setup_client_stack( void*  init_sp,
 
                 ADD PUBLIC LINK WHEN AVAILABLE
             */
+
+            /* Check for SCV support */
+            auxv_scv_supported = (auxv->u.a_val & 0x00100000ULL)
+               == 0x00100000ULL;
+            hw_caps_scv_supported =
+               (vex_archinfo->hwcaps & VEX_HWCAPS_PPC64_SCV)
+               == VEX_HWCAPS_PPC64_SCV;
+
+            /* Verify the scv_supported setting in HWCAP2 matches the setting
+               in VEX HWCAPS.
+             */
+            vg_assert(auxv_scv_supported == hw_caps_scv_supported);
+
             /* ISA 3.1 */
             auxv_3_1 = (auxv->u.a_val & 0x00040000ULL) == 0x00040000ULL;
             hw_caps_3_1 = (vex_archinfo->hwcaps & VEX_HWCAPS_PPC64_ISA3_1)
@@ -820,6 +834,7 @@ Addr setup_client_stack( void*  init_sp,
                               | 0x04000000ULL   /* TAR */
                               | 0x04000000ULL   /* VEC_CRYPTO */
                               | 0x00800000ULL   /* ARCH_3_00 */
+                              | 0x00100000ULL   /* PPC_FEATURE2_SCV */
                               | 0x00400000ULL   /* HAS_IEEE128 */
                               | 0x00200000ULL   /* PPC_FEATURE2_DARN */
                               | 0x00040000ULL); /* ARCH_3_1 */
index 1bf50846d2d9dbeeea9221969d0d2dcdd2492f77..ab436aec6e062446d2c8f1689ed0d4b76f849c61 100644 (file)
@@ -1291,6 +1291,7 @@ Bool VG_(machine_get_hwcaps)( void )
 
      volatile Bool have_F, have_V, have_FX, have_GX, have_VX, have_DFP;
      volatile Bool have_isa_2_07, have_isa_3_0, have_isa_3_1;
+     volatile Bool have_scv_support;
      Int r;
 
      /* This is a kludge.  Really we ought to back-convert saved_act
@@ -1401,6 +1402,18 @@ Bool VG_(machine_get_hwcaps)( void )
         __asm__ __volatile__(".long 0x7f1401b6"); /* brh  RA, RS */
      }
 
+     /* Check if Host supports scv instruction */
+     have_scv_support = True;
+     if (VG_MINIMAL_SETJMP(env_unsup_insn)) {
+        have_scv_support = False;
+     } else {
+        /* Set r0 to 13 for the system time call.  Don't want to make a random
+           system call.  */
+        __asm__ __volatile__(".long 0x7c000278"); /* clear r0 */
+        __asm__ __volatile__(".long 0x6009000d"); /* set r0 to 13 */
+        __asm__ __volatile__(".long 0x44000001"); /* scv */
+     }
+
      /* determine dcbz/dcbzl sizes while we still have the signal
       * handlers registered */
      find_ppc_dcbz_sz(&vai);
@@ -1436,6 +1449,7 @@ Bool VG_(machine_get_hwcaps)( void )
      if (have_isa_2_07) vai.hwcaps |= VEX_HWCAPS_PPC64_ISA2_07;
      if (have_isa_3_0) vai.hwcaps |= VEX_HWCAPS_PPC64_ISA3_0;
      if (have_isa_3_1) vai.hwcaps |= VEX_HWCAPS_PPC64_ISA3_1;
+     if (have_scv_support) vai.hwcaps |= VEX_HWCAPS_PPC64_SCV;
 
      VG_(machine_get_cache_info)(&vai);
 
index 720fb5f661221cf72e945177461abb053ab6e448..b45afe59923245352ac17fdd1eeeb5e220f912be 100644 (file)
@@ -359,8 +359,12 @@ typedef struct SigQueue {
    {
       ULong err = (uc->uc_mcontext.gp_regs[VKI_PT_CCR] >> 28) & 1;
       ULong r3  = uc->uc_mcontext.gp_regs[VKI_PT_R3];
+      ThreadId tid = VG_(lwpid_to_vgtid)(VG_(gettid)());
+      ThreadState *tst = VG_(get_ThreadState)(tid);
+
       if (err) r3 &= 0xFF;
-      return VG_(mk_SysRes_ppc64_linux)( r3, err );
+      return VG_(mk_SysRes_ppc64_linux)( r3, err,
+                                         tst->arch.vex.guest_syscall_flag);
    }
 #  define VG_UCONTEXT_TO_UnwindStartRegs(srP, uc)                       \
       { (srP)->r_pc = (uc)->uc_mcontext.gp_regs[VKI_PT_NIP];            \
index 4053d402474fe89986e1ae6aa62b75934c9bca91..80e2af439714472e43f9e2b4c81e6075794c8214 100644 (file)
@@ -145,11 +145,29 @@ SysRes VG_(mk_SysRes_ppc32_linux) ( UInt val, UInt cr0so ) {
    return res;
 }
 
-/* As per ppc32 version, cr0.so must be in l.s.b. of 2nd arg */
-SysRes VG_(mk_SysRes_ppc64_linux) ( ULong val, ULong cr0so ) {
+/* As per ppc32 version, for the sc instruction cr0.so must be in
+   l.s.b. of 2nd arg.
+   For the scv 0 instruction, the return value indicates failure if
+   it is -4095..-1 (i.e., it is >= -MAX_ERRNO (-4095) as an unsigned
+   comparison), in which case the error value is the negated return value. */
+SysRes VG_(mk_SysRes_ppc64_linux) ( ULong val, ULong cr0so, UInt flag ) {
    SysRes res;
-   res._isError = (cr0so & 1) != 0;
-   res._val     = val;
+
+   if (flag == SC_FLAG) {
+      /* sc instruction */
+      res._isError = (cr0so & 1) != 0;
+      res._val     = val;
+   } else if (flag == SCV_FLAG) {
+      /* scv instruction */
+      if ( (Long)val >= -4095 && (Long)val <= -1) {
+         res._isError = True;
+         res._val = (ULong)(-val);
+      } else {
+         res._isError = False;
+         res._val = (ULong)(val);
+      }
+   } else
+      vg_assert(0);
    return res;
 }
 
@@ -541,6 +559,12 @@ asm(
 "        addi         2,2,.TOC.-0b@l\n"
 "        .localentry do_syscall_WRK, .-do_syscall_WRK\n"
 "#endif"                            "\n"
+/* Check which system call instruction to issue*/
+"        ld   8, 56(3)\n"  /* arg 7 holds sc/scv flag */
+"        cmpdi 8,1\n"      /* check sc/scv flag not equal to SC_FLAG*/
+"        bne  issue_scv\n"
+
+/* setup and issue the sc instruction */
 "        std  3,-16(1)\n"  /* stash arg */
 "        ld   8, 48(3)\n"  /* sc arg 6 */
 "        ld   7, 40(3)\n"  /* sc arg 5 */
@@ -556,6 +580,34 @@ asm(
 "        srwi 3,3,28\n"
 "        andi. 3,3,1\n"
 "        std  3,8(5)\n"    /* argblock[1] = cr0.s0 & 1 */
+"        blr\n"            /* return */
+
+/*  setup to do scv instruction */
+"issue_scv: "
+/* The scv instruction requires a new stack frame */
+"        stdu    1,-80(1)\n"
+"        std     27,40(1)\n" /* save r27 to stack frame */
+"        mflr    27\n"       /* Get link register */
+"        std     27,16(1)\n" /* Save link register */
+
+/* setup and issue the scv instruction */
+"        std  3,-16(1)\n"  /* stash arg */
+"        ld   8, 48(3)\n"  /* sc arg 6 */
+"        ld   7, 40(3)\n"  /* sc arg 5 */
+"        ld   6, 32(3)\n"  /* sc arg 4 */
+"        ld   5, 24(3)\n"  /* sc arg 3 */
+"        ld   4, 16(3)\n"  /* sc arg 2 */
+"        ld   0,  0(3)\n"  /* sc number */
+"        ld   3,  8(3)\n"  /* sc arg 1 */
+"        scv  0\n"
+"        ld   5,-16(1)\n"  /* reacquire argblock ptr (r5 is caller-save) */
+"        std  3,0(5)\n"    /* argblock[0] = r3 */
+
+/* pop off stack frame */
+"        ld      27,16(1)\n"        /* Fetch LR from frame */
+"        mtlr    27\n"              /* restore LR */
+"        ld      27,40(1)\n"        /* restore r27 from stack frame */
+"        addi    1,1,80\n"
 "        blr\n"
 "        .size do_syscall_WRK, .-do_syscall_WRK\n"
 );
@@ -978,7 +1030,11 @@ SysRes VG_(do_syscall) ( UWord sysno, RegWord a1, RegWord a2, RegWord a3,
    return VG_(mk_SysRes_ppc32_linux)( val, cr0so );
 
 #  elif defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)
-   ULong argblock[7];
+   ULong argblock[8];
+   /* PPC system calls have at most 6 arguments.  The Valgrind infrastructure
+      supports 8 system call arguments.  Argument 7 is used on PPC LE to pass
+      the flag indicating if the sc or scv instruction should be used for the
+      system call.  */
    argblock[0] = sysno;
    argblock[1] = a1;
    argblock[2] = a2;
@@ -986,8 +1042,9 @@ SysRes VG_(do_syscall) ( UWord sysno, RegWord a1, RegWord a2, RegWord a3,
    argblock[4] = a4;
    argblock[5] = a5;
    argblock[6] = a6;
+   argblock[7] = a7;
    do_syscall_WRK( &argblock[0] );
-   return VG_(mk_SysRes_ppc64_linux)( argblock[0], argblock[1] );
+   return VG_(mk_SysRes_ppc64_linux)( argblock[0], argblock[1], a7 );
 
 #  elif defined(VGP_arm_linux)
    UWord val = do_syscall_WRK(a1,a2,a3,a4,a5,a6,sysno);
index 014db76fb6821ee89d3f8fcd50b7906dd5fd437d..7a9fd3260fb90105b9dbd336b36490c736966950 100644 (file)
@@ -89,7 +89,6 @@ typedef
       Int o_sysno;
 #     if defined(VGP_x86_linux) || defined(VGP_amd64_linux) \
          || defined(VGP_ppc32_linux) \
-         || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
          || defined(VGP_arm_linux) || defined(VGP_s390x_linux) \
          || defined(VGP_arm64_linux) \
          || defined(VGP_nanomips_linux)
@@ -101,6 +100,15 @@ typedef
       Int o_arg6;
       Int uu_arg7;
       Int uu_arg8;
+#     elif defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)
+      Int o_arg1;
+      Int o_arg2;
+      Int o_arg3;
+      Int o_arg4;
+      Int o_arg5;
+      Int o_arg6;
+      Int o_arg7;
+      Int uu_arg8;
 #     elif defined(VGP_mips32_linux)
       Int o_arg1;
       Int o_arg2;
index 2eee752a8df8d534996d7a8c577e777e787bb662..e416688e37198ee447f264703c58df89e3e9188c 100644 (file)
                                  Int sigsetSzB)                // r7
 */
 /* from vki_arch.h */
+
+/* SCV flag defines.  Must be consistently defined here and in
+   coregrind/pub_core_syscall.h,in the do_syscall_WRK() assembly code in
+   coregrind/m_syscall.c and coregrind/m_syswrap/syscall-ppcle-linux.S code.
+*/
+#define SC_FLAG  1
+#define SCV_FLAG 2
+
 #define VKI_SIG_SETMASK 2
 
 .align 2
@@ -101,6 +109,10 @@ ML_(do_syscall_for_client_WRK):
         std     30,64(1)
         std     29,56(1)
         std     28,48(1)
+        std     27,40(1)        /* save r27 to stack frame */
+        mflr    27              /* Get link register */
+        std     27,16(1)        /* Save link register */
+        std     9,32(1)         /* save gpr 9 */
         mr      31,3            /* syscall number */
         mr      30,4            /* guest_state */
         mr      29,6            /* postmask */
@@ -123,14 +135,27 @@ ML_(do_syscall_for_client_WRK):
         ld      6,OFFSET_ppc64_GPR6(30)
         ld      7,OFFSET_ppc64_GPR7(30)
         ld      8,OFFSET_ppc64_GPR8(30)
+        ld      9,OFFSET_ppc64_GPR9(30)   /* get flag for sc or scv inst */
         mr      0,31            /* syscall number */
+        cmpdi   9,SC_FLAG
+        bne     8f              /* jump to scv call if gpr9 != 0 */
+        /* If you change the code between labels 2 and 3, you need to update
+           the corresponding ppc64le calculations for blksys_restart and
+           blksys_complete in function getSyscallArgsFromGuestState in file
+           syswrap-main.c.  */
 2:      sc                      /* do the syscall */
+        b       3f              /* jump over scv call */
+8:      scv     0
 
         /* put the result back in the threadstate  */
 3:     std     3,OFFSET_ppc64_GPR3(30)     /* gst->GPR3 = sc result */
+
        /* copy cr0.so back to simulated state */
        mfcr    5                           /* r5 = CR               */
        rlwinm  5,5,4,31,31                 /* r5 = (CR >> 28) & 1   */
+       ld      9,OFFSET_ppc64_GPR9(30)
+       cmpdi   9,SC_FLAG
+       bne     4f                          /* scv does not change CR */
         stb     5,OFFSET_ppc64_CR0_0(30)    /* gst->CR0.SO = cr0.so  */
 
         /* block signals again */
@@ -150,6 +175,10 @@ ML_(do_syscall_for_client_WRK):
         ld      29,56(1)
         ld      30,64(1)
         ld      31,72(1)
+        ld      9,32(1)
+        ld      27,16(1)        /* Fetch LR from frame */
+        mtlr    27              /* restore LR */
+        ld      27,40(1)        /* restore r27 from stack frame */
         addi    1,1,80
         blr
 
index c59d8ee26b3f82d15a6e2b76f7ce99d26e15a8b1..818b11ff6e6c12dd92e55597d674975d22d61970 100644 (file)
@@ -474,6 +474,7 @@ static SysRes clone_new_thread ( Word (*fn)(void *),
 #elif defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)
    ULong        word64;
    UInt old_cr = LibVEX_GuestPPC64_get_CR( &ctst->arch.vex );
+   UInt flag = ctst->arch.vex.guest_syscall_flag;
    /* %r3 = 0 */
    ctst->arch.vex.guest_GPR3 = 0;
    /* %cr0.so = 0 */
@@ -486,7 +487,7 @@ static SysRes clone_new_thread ( Word (*fn)(void *),
    /* VG_(printf)("word64 = 0x%llx\n", word64); */
    res = VG_(mk_SysRes_ppc64_linux)
       (/*val*/(UInt)(word64 & 0xFFFFFFFFULL), 
-       /*errflag*/ (UInt)((word64 >> (32+28)) & 1));
+       /*errflag*/ (UInt)((word64 >> (32+28)) & 1), flag);
 #elif defined(VGP_s390x_linux)
    ULong        r2;
    ctst->arch.vex.guest_r2 = 0;
index cdb2663a2202cbe61b19d2d3a2fd05da04797dd3..1a475422b1dcf8ddadb3a2892e9141eb3a8ff46b 100644 (file)
@@ -504,9 +504,20 @@ void getSyscallArgsFromGuestState ( /*OUT*/SyscallArgs*       canonical,
    canonical->arg4  = gst->guest_GPR6;
    canonical->arg5  = gst->guest_GPR7;
    canonical->arg6  = gst->guest_GPR8;
-   canonical->arg7  = 0;
+   /* ISA 3.0 adds the scv system call instruction.
+      The PPC syscalls have at most 6 args.  Arg 7 is being used to pass a
+      flag to indicate which system call instruction is to be used.
+      Arg7 = SC_FLAG for the sc instruction; Arg7 = SCV_FLAG for the scv
+      instruction.  The guest register guest_syscall_flag was created to pass
+      the flag so the actual guest state would not be changed. */
+   canonical->arg7  = gst->guest_syscall_flag;
    canonical->arg8  = 0;
 
+#if defined(VGP_ppc64be_linux)
+   /* The sc instruction is currently only supported on LE systems. */
+   vg_assert(gst->guest_syscall_flag == SC_FLAG);
+#endif
+
 #elif defined(VGP_arm_linux)
    VexGuestARMState* gst = (VexGuestARMState*)gst_vanilla;
    canonical->sysno = gst->guest_R7;
@@ -829,6 +840,7 @@ void putSyscallArgsIntoGuestState ( /*IN*/ SyscallArgs*       canonical,
    gst->guest_GPR6 = canonical->arg4;
    gst->guest_GPR7 = canonical->arg5;
    gst->guest_GPR8 = canonical->arg6;
+   gst->guest_GPR9 = canonical->arg7;
 
 #elif defined(VGP_arm_linux)
    VexGuestARMState* gst = (VexGuestARMState*)gst_vanilla;
@@ -1004,10 +1016,15 @@ void getSyscallStatusFromGuestState ( /*OUT*/SyscallStatus*     canonical,
    canonical->what = SsComplete;
 
 #  elif defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)
+   /* There is a Valgrind specific guest state register guest_syscall_flag
+      that is set to zero to indicate if the sc instruction was used or one
+      if the scv instruction was used for the system call.  */
    VexGuestPPC64State* gst   = (VexGuestPPC64State*)gst_vanilla;
    UInt                cr    = LibVEX_GuestPPC64_get_CR( gst );
    UInt                cr0so = (cr >> 28) & 1;
-   canonical->sres = VG_(mk_SysRes_ppc64_linux)( gst->guest_GPR3, cr0so );
+   UInt                flag  =  gst->guest_syscall_flag;
+
+   canonical->sres = VG_(mk_SysRes_ppc64_linux)( gst->guest_GPR3, cr0so, flag );
    canonical->what = SsComplete;
 
 #  elif defined(VGP_arm_linux)
@@ -1188,20 +1205,34 @@ void putSyscallStatusIntoGuestState ( /*IN*/ ThreadId tid,
 #  elif defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)
    VexGuestPPC64State* gst = (VexGuestPPC64State*)gst_vanilla;
    UInt old_cr = LibVEX_GuestPPC64_get_CR(gst);
+   UInt flag  =  gst->guest_syscall_flag;
+
    vg_assert(canonical->what == SsComplete);
-   if (sr_isError(canonical->sres)) {
-      /* set CR0.SO */
-      LibVEX_GuestPPC64_put_CR( old_cr | (1<<28), gst );
-      gst->guest_GPR3 = sr_Err(canonical->sres);
+   if (flag == SC_FLAG) {
+      /* sc syscall */
+      if (sr_isError(canonical->sres)) {
+         /* set CR0.SO */
+         LibVEX_GuestPPC64_put_CR( old_cr | (1<<28), gst );
+         gst->guest_GPR3 = sr_Err(canonical->sres);
+      } else {
+         /* clear CR0.SO */
+         LibVEX_GuestPPC64_put_CR( old_cr & ~(1<<28), gst );
+         gst->guest_GPR3 = sr_Res(canonical->sres);
+      }
+      VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
+                OFFSET_ppc64_GPR3, sizeof(UWord) );
+      VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
+                OFFSET_ppc64_CR0_0, sizeof(UChar) );
    } else {
-      /* clear CR0.SO */
-      LibVEX_GuestPPC64_put_CR( old_cr & ~(1<<28), gst );
-      gst->guest_GPR3 = sr_Res(canonical->sres);
+      /* scv system call instruction */
+      if (sr_isError(canonical->sres))
+         gst->guest_GPR3 = - (Long)canonical->sres._val;
+      else
+         gst->guest_GPR3 = canonical->sres._val;
+
+      VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
+                OFFSET_ppc64_GPR3, sizeof(UWord) );
    }
-   VG_TRACK( post_reg_write, Vg_CoreSysCall, tid, 
-             OFFSET_ppc64_GPR3, sizeof(UWord) );
-   VG_TRACK( post_reg_write, Vg_CoreSysCall, tid, 
-             OFFSET_ppc64_CR0_0, sizeof(UChar) );
 
 #  elif defined(VGP_arm_linux)
    VexGuestARMState* gst = (VexGuestARMState*)gst_vanilla;
@@ -1459,7 +1490,7 @@ void getSyscallArgLayout ( /*OUT*/SyscallArgLayout* layout )
    layout->o_arg4   = OFFSET_ppc64_GPR6;
    layout->o_arg5   = OFFSET_ppc64_GPR7;
    layout->o_arg6   = OFFSET_ppc64_GPR8;
-   layout->uu_arg7  = -1; /* impossible value */
+   layout->o_arg7   = OFFSET_ppc64_GPR9;
    layout->uu_arg8  = -1; /* impossible value */
 
 #elif defined(VGP_arm_linux)
@@ -2343,16 +2374,20 @@ void ML_(fixup_guest_state_to_restart_syscall) ( ThreadArchState* arch )
       back over a syscall.
 
       sc == 44 00 00 02
+      or
+      scv == 44 00 00 01
    */
    {
       UChar *p = (UChar *)arch->vex.guest_CIA;
 
-      if (p[3] != 0x44 || p[2] != 0x0 || p[1] != 0x0 || p[0] != 0x02)
+      if (!(p[3] == 0x44 && p[2] == 0x0 && p[1] == 0x0
+            && (p[0] == 0x01 || p[0] == 0x02)))
          VG_(message)(Vg_DebugMsg,
                       "?! restarting over syscall at %#llx %02x %02x %02x %02x\n",
                       arch->vex.guest_CIA, p[3], p[2], p[1], p[0]);
 
-      vg_assert(p[3] == 0x44 && p[2] == 0x0 && p[1] == 0x0 && p[0] == 0x2);
+      vg_assert(p[3] == 0x44 && p[2] == 0x0 && p[1] == 0x0
+                && (p[0] == 0x1 || p[0] == 0x2));
    }
 
 #elif defined(VGP_arm_linux)
@@ -2670,10 +2705,29 @@ VG_(fixup_guest_state_after_syscall_interrupted)( ThreadId tid,
       = ip < ML_(blksys_setup) || ip >= ML_(blksys_finished);
    in_setup_to_restart
       = ip >= ML_(blksys_setup) && ip < ML_(blksys_restart); 
+
+#if  defined(VGP_ppc64le_linux)
+   /* Starting with ISA 3.0, Power supports two system call instructions sc
+      and scv.  The code in file syscall-ppc64[be|le]-linux.S uses an input
+      to call the requested system call.  The definitions for blksys_restart
+      and blksys_complete must account for being at either of the two system
+      calls and account for the branch to lable 3 if the sc instruction was
+      called.  at_restart is true if the ip is at either system call
+      instruction.  in_complete_to_committed is true if the ip is between
+      blksys_complete and blksys_committed OR at the branch after the sc
+      instruction.  The scv instruction is currently only supported on LE. */
+   at_restart
+      = (ip == ML_(blksys_restart)) || ((ip-8) == ML_(blksys_restart));
+   in_complete_to_committed
+      = (ip >= ML_(blksys_complete) && ip < ML_(blksys_committed)) ||
+      ((ip+8) == ML_(blksys_complete));
+#else
    at_restart
       = ip == ML_(blksys_restart); 
    in_complete_to_committed
       = ip >= ML_(blksys_complete) && ip < ML_(blksys_committed); 
+#endif
+
    in_committed_to_finished
       = ip >= ML_(blksys_committed) && ip < ML_(blksys_finished);
 #  elif defined(VGO_darwin)
index 49b8586a80c68e1ea6185d8308940473fab389b3..ddcca3809f24759bcd06cf1a62cfb7127165e112 100644 (file)
 
 #include "pub_core_basics.h"   // VG_ macro
 
+/* PPC64 supports two system call instructions.  The flags are used to
+   identify which of the two system call instructions sc or scv is to be
+   used.  The following flags must be consistently defined here and in
+   VEX/priv/guest_ppc_defs.h, in the do_syscall_WRK() assembly code
+   below and coregrind/m_syswrap/syscall-ppcle-linux.S code.  */
+#define SC_FLAG  1
+#define SCV_FLAG 2
+
 //--------------------------------------------------------------------
 // PURPOSE: This module contains the code for actually executing syscalls.
 //--------------------------------------------------------------------
@@ -51,19 +59,29 @@ extern SysRes VG_(do_syscall) ( UWord sysno,
 
 /* Macros make life easier. */
 
-#define vgPlain_do_syscall0(s)             VG_(do_syscall)((s),0,0,0,0,0,0,0,0)
+#if defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)
+/* PPC64 uses the 7th argument to pass a flag indicating if the sc or scv
+   instruction is to be used for the system call.  Need to set the flag to the
+   sc instruction by default.  */
+#define A7 SC_FLAG
+#else
+#define A7 0
+#endif
+
+#define vgPlain_do_syscall0(s)             VG_(do_syscall)((s),0,0,0,0,0,0,A7,0)
+
 #define vgPlain_do_syscall1(s,a)           VG_(do_syscall)((s),(a),\
-                                                           0,0,0,0,0,0,0)
+                                                           0,0,0,0,0,A7,0)
 #define vgPlain_do_syscall2(s,a,b)         VG_(do_syscall)((s),(a),(b),\
-                                                           0,0,0,0,0,0)
+                                                           0,0,0,0,A7,0)
 #define vgPlain_do_syscall3(s,a,b,c)       VG_(do_syscall)((s),(a),(b),(c),\
-                                                           0,0,0,0,0)
+                                                           0,0,0,A7,0)
 #define vgPlain_do_syscall4(s,a,b,c,d)     VG_(do_syscall)((s),(a),(b),(c),\
-                                                           (d),0,0,0,0)
+                                                           (d),0,0,A7,0)
 #define vgPlain_do_syscall5(s,a,b,c,d,e)   VG_(do_syscall)((s),(a),(b),(c),\
-                                                           (d),(e),0,0,0)
+                                                           (d),(e),0,A7,0)
 #define vgPlain_do_syscall6(s,a,b,c,d,e,f) VG_(do_syscall)((s),(a),(b),(c),\
-                                                           (d),(e),(f),0,0)
+                                                           (d),(e),(f),A7,0)
 #define vgPlain_do_syscall7(s,a,b,c,d,e,f,g) VG_(do_syscall)((s),(a),(b),(c),\
                                                            (d),(e),(f),(g),0)
 #define vgPlain_do_syscall8(s,a,b,c,d,e,f,g,h) VG_(do_syscall)((s),(a),(b),(c),\
@@ -72,7 +90,7 @@ extern SysRes VG_(do_syscall) ( UWord sysno,
 extern SysRes VG_(mk_SysRes_x86_linux)   ( Int  val );
 extern SysRes VG_(mk_SysRes_amd64_linux) ( Long val );
 extern SysRes VG_(mk_SysRes_ppc32_linux) ( UInt  val, UInt  cr0so );
-extern SysRes VG_(mk_SysRes_ppc64_linux) ( ULong val, ULong cr0so );
+extern SysRes VG_(mk_SysRes_ppc64_linux) ( ULong val, ULong cr0so, UInt flag );
 extern SysRes VG_(mk_SysRes_arm_linux)   ( Int val );
 extern SysRes VG_(mk_SysRes_arm64_linux) ( Long val );
 extern SysRes VG_(mk_SysRes_x86_darwin)  ( UChar scclass, Bool isErr,
@@ -104,7 +122,6 @@ extern SysRes VG_(mk_SysRes_SuccessEx)   ( UWord val, UWord valEx );
 
 extern const HChar* VG_(strerror) ( UWord errnum );
 
-
 #endif   // __PUB_CORE_SYSCALL_H
 
 /*--------------------------------------------------------------------*/
index a95bfd9959c460e07fa0ee626aefb5fb2d25fe8d..919c7fae88132988efcf054c015bc6b06b272ed5 100644 (file)
@@ -395,6 +395,7 @@ static Int get_otrack_shadow_offset_wrk ( Int offset, Int szB )
       return 0+ GOF(ACC_7_r2);
    if (o >= GOF(ACC_7_r3) && o+sz <= GOF(ACC_7_r3)+SZB(ACC_7_r3))
       return 0+ GOF(ACC_7_r3);
+   if (o == GOF(syscall_flag) && sz == 4) return -1;
 
    VG_(printf)("MC_(get_otrack_shadow_offset)(ppc64)(off=%d,sz=%d)\n",
                offset,szB);
index 00c65b565402e7d75d739f142c4f65f2f30dc0f1..1636613345318bf5f3370d2922c1de6847df9903 100644 (file)
@@ -58,7 +58,8 @@ EXTRA_DIST = \
        test_isa_3_1_AT.vgtest test_isa_3_1_AT.stderr.exp test_isa_3_1_AT.stdout.exp \
        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
+       test_darn_inst.stdout.exp test_darn_inst.vgtest \
+       scv_test.stderr.exp scv_test.stdout.exp scv_test.vgtest
 
 check_PROGRAMS = \
        allexec \
@@ -72,7 +73,7 @@ check_PROGRAMS = \
        subnormal_test test_darn_inst \
        test_tm test_touch_tm data-cache-instructions \
        power6_mf_gpr std_reg_imm \
-       twi_tdi tw_td power6_bcmp
+       twi_tdi tw_td power6_bcmp scv_test
 
 # lmw, stmw, lswi, lswx, stswi, stswx compile (and run) only on big endian.
 if VGCONF_PLATFORMS_INCLUDE_PPC64BE_LINUX
diff --git a/none/tests/ppc64/scv_test.c b/none/tests/ppc64/scv_test.c
new file mode 100644 (file)
index 0000000..d292c4b
--- /dev/null
@@ -0,0 +1,85 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <asm/unistd.h>
+#include <sys/auxv.h>
+
+
+#define ASM_INPUT_0 "0" (r0)
+
+#define INTERNAL_SYSCALL_SCV(name, nr) \
+  ({                                                                    \
+    register long int r0  __asm__ ("r0");                               \
+    register long int r3  __asm__ ("r3");                               \
+    register long int r4  __asm__ ("r4");                               \
+    register long int r5  __asm__ ("r5");                               \
+    register long int r6  __asm__ ("r6");                               \
+    register long int r7  __asm__ ("r7");                               \
+    register long int r8  __asm__ ("r8");                               \
+    r0=name;                                                            \
+    __asm__ __volatile__                                                \
+      ("scv 0\n\t"                                                      \
+       "0:"                                                             \
+       : "=&r" (r0),                                                    \
+         "=&r" (r3), "=&r" (r4), "=&r" (r5),                            \
+         "=&r" (r6), "=&r" (r7), "=&r" (r8)                             \
+       : ASM_INPUT_##nr                                                 \
+       : "r9", "r10", "r11", "r12",                                     \
+         "cr0", "cr1", "cr5", "cr6", "cr7", "xer",                      \
+         "lr", "ctr", "memory");                                        \
+    r3;                                                                        \
+  })
+
+#define INTERNAL_SYSCALL_SC(name, nr) \
+  ({                                                                    \
+    register long int r0  __asm__ ("r0");                               \
+    register long int r3  __asm__ ("r3");                               \
+    register long int r4  __asm__ ("r4");                               \
+    register long int r5  __asm__ ("r5");                               \
+    register long int r6  __asm__ ("r6");                               \
+    register long int r7  __asm__ ("r7");                               \
+    register long int r8  __asm__ ("r8");                               \
+    r0=name;                                                            \
+    __asm__ __volatile__                                                \
+      ("sc\n\t"                                                         \
+       "mfcr %0\n\t"                                                    \
+       "0:"                                                             \
+       : "=&r" (r0),                                                    \
+         "=&r" (r3), "=&r" (r4), "=&r" (r5),                            \
+         "=&r" (r6), "=&r" (r7), "=&r" (r8)                             \
+       : ASM_INPUT_##nr                                                 \
+       : "r9", "r10", "r11", "r12",                                     \
+         "xer", "cr0", "ctr", "memory");                                \
+    r0 & (1 << 28) ? -r3 : r3; \
+  })
+
+#define PPC_FEATURE2_SCV           0x00100000 /* scv syscall enabled */
+
+int
+main(void)
+{
+  int result;
+  unsigned long hwcaps2_val;
+
+  result = INTERNAL_SYSCALL_SC(__NR_gettid, 0);
+
+  if (result < 0) {
+    printf("The sc instruction test unexpectedly failed\n");
+    exit (-1);
+  }
+
+  hwcaps2_val = getauxval(AT_HWCAP2);
+
+  if ((hwcaps2_val & PPC_FEATURE2_SCV) == PPC_FEATURE2_SCV) {
+    /* system supports the scv instruction */
+    result = INTERNAL_SYSCALL_SCV(__NR_gettid, 0);
+
+    if (result < 0) {
+      printf("The scv instruction test unexpectedly failed\n");
+      exit (-1);
+    }
+  }
+
+  printf("Success\n");
+  return 0;
+}
diff --git a/none/tests/ppc64/scv_test.stderr.exp b/none/tests/ppc64/scv_test.stderr.exp
new file mode 100644 (file)
index 0000000..139597f
--- /dev/null
@@ -0,0 +1,2 @@
+
+
diff --git a/none/tests/ppc64/scv_test.stdout.exp b/none/tests/ppc64/scv_test.stdout.exp
new file mode 100644 (file)
index 0000000..3582111
--- /dev/null
@@ -0,0 +1 @@
+Success
diff --git a/none/tests/ppc64/scv_test.vgtest b/none/tests/ppc64/scv_test.vgtest
new file mode 100644 (file)
index 0000000..163d874
--- /dev/null
@@ -0,0 +1,2 @@
+prereq:
+prog: scv_test