e94d64
commit 306353a8d233c3d7c60e7b02799b8675e745d5c2
e94d64
Author: Julian Seward <jseward@acm.org>
e94d64
Date:   Tue May 16 05:35:23 2017 +0000
e94d64
e94d64
    arm64-linux: detect Cavium CPUs (implementer = 0x43) and enable the
e94d64
    fallback LLSC implementation in that case.  Pertains to bug #369459.
e94d64
    
e94d64
    
e94d64
    
e94d64
    git-svn-id: svn://svn.valgrind.org/valgrind/trunk@16380
e94d64
e94d64
diff --git a/coregrind/m_machine.c b/coregrind/m_machine.c
e94d64
index 93bdd72..eac1c16 100644
e94d64
--- a/coregrind/m_machine.c
e94d64
+++ b/coregrind/m_machine.c
e94d64
@@ -634,7 +634,7 @@ static UInt VG_(get_machine_model)(void)
e94d64
    return model;
e94d64
 }
e94d64
 
e94d64
-#endif /* VGA_s390x */
e94d64
+#endif /* defined(VGA_s390x) */
e94d64
 
e94d64
 #if defined(VGA_mips32) || defined(VGA_mips64)
e94d64
 
e94d64
@@ -755,12 +755,65 @@ static Bool VG_(parse_cpuinfo)(void)
e94d64
    return True;
e94d64
 }
e94d64
 
e94d64
-#endif
e94d64
+#endif /* defined(VGA_mips32) || defined(VGA_mips64) */
e94d64
+
e94d64
+#if defined(VGP_arm64_linux)
e94d64
+
e94d64
+/* Check to see whether we are running on a Cavium core, and if so auto-enable
e94d64
+   the fallback LLSC implementation.  See #369459. */
e94d64
+
e94d64
+static Bool VG_(parse_cpuinfo)(void)
e94d64
+{
e94d64
+   const char *search_Cavium_str = "CPU implementer\t: 0x43";
e94d64
+
e94d64
+   Int    n, fh;
e94d64
+   SysRes fd;
e94d64
+   SizeT  num_bytes, file_buf_size;
e94d64
+   HChar  *file_buf;
e94d64
+
e94d64
+   /* Slurp contents of /proc/cpuinfo into FILE_BUF */
e94d64
+   fd = VG_(open)( "/proc/cpuinfo", 0, VKI_S_IRUSR );
e94d64
+   if ( sr_isError(fd) ) return False;
e94d64
+
e94d64
+   fh  = sr_Res(fd);
e94d64
+
e94d64
+   /* Determine the size of /proc/cpuinfo.
e94d64
+      Work around broken-ness in /proc file system implementation.
e94d64
+      fstat returns a zero size for /proc/cpuinfo although it is
e94d64
+      claimed to be a regular file. */
e94d64
+   num_bytes = 0;
e94d64
+   file_buf_size = 1000;
e94d64
+   file_buf = VG_(malloc)("cpuinfo", file_buf_size + 1);
e94d64
+   while (42) {
e94d64
+      n = VG_(read)(fh, file_buf, file_buf_size);
e94d64
+      if (n < 0) break;
e94d64
+
e94d64
+      num_bytes += n;
e94d64
+      if (n < file_buf_size) break;  /* reached EOF */
e94d64
+   }
e94d64
+
e94d64
+   if (n < 0) num_bytes = 0;   /* read error; ignore contents */
e94d64
+
e94d64
+   if (num_bytes > file_buf_size) {
e94d64
+      VG_(free)( file_buf );
e94d64
+      VG_(lseek)( fh, 0, VKI_SEEK_SET );
e94d64
+      file_buf = VG_(malloc)( "cpuinfo", num_bytes + 1 );
e94d64
+      n = VG_(read)( fh, file_buf, num_bytes );
e94d64
+      if (n < 0) num_bytes = 0;
e94d64
+   }
e94d64
 
e94d64
-/* Determine what insn set and insn set variant the host has, and
e94d64
-   record it.  To be called once at system startup.  Returns False if
e94d64
-   this a CPU incapable of running Valgrind.
e94d64
-   Also determine information about the caches on this host. */
e94d64
+   file_buf[num_bytes] = '\0';
e94d64
+   VG_(close)(fh);
e94d64
+
e94d64
+   /* Parse file */
e94d64
+   if (VG_(strstr)(file_buf, search_Cavium_str) != NULL)
e94d64
+      vai.arm64_requires_fallback_LLSC = True;
e94d64
+
e94d64
+   VG_(free)(file_buf);
e94d64
+   return True;
e94d64
+}
e94d64
+
e94d64
+#endif /* defined(VGP_arm64_linux) */
e94d64
 
e94d64
 Bool VG_(machine_get_hwcaps)( void )
e94d64
 {
e94d64
@@ -1588,6 +1641,11 @@ Bool VG_(machine_get_hwcaps)( void )
e94d64
 
e94d64
      VG_(machine_get_cache_info)(&vai;;
e94d64
 
e94d64
+     /* Check whether we need to use the fallback LLSC implementation.
e94d64
+        If the check fails, give up. */
e94d64
+     if (! VG_(parse_cpuinfo)())
e94d64
+        return False;
e94d64
+
e94d64
      /* 0 denotes 'not set'.  The range of legitimate values here,
e94d64
         after being set that is, is 2 though 17 inclusive. */
e94d64
      vg_assert(vai.arm64_dMinLine_lg2_szB == 0);
e94d64
@@ -1600,6 +1658,8 @@ Bool VG_(machine_get_hwcaps)( void )
e94d64
                       "ctr_el0.iMinLine_szB = %d\n",
e94d64
                    1 << vai.arm64_dMinLine_lg2_szB,
e94d64
                    1 << vai.arm64_iMinLine_lg2_szB);
e94d64
+     VG_(debugLog)(1, "machine", "ARM64: requires_fallback_LLSC: %s\n",
e94d64
+                   vai.arm64_requires_fallback_LLSC ? "yes" : "no");
e94d64
 
e94d64
      return True;
e94d64
    }
e94d64
diff --git a/coregrind/m_translate.c b/coregrind/m_translate.c
e94d64
index 2f0ceac..55c845d 100644
e94d64
--- a/coregrind/m_translate.c
e94d64
+++ b/coregrind/m_translate.c
e94d64
@@ -1707,7 +1707,10 @@ Bool VG_(translate) ( ThreadId tid,
e94d64
 
e94d64
 #  if defined(VGP_arm64_linux)
e94d64
    vex_abiinfo.guest__use_fallback_LLSC
e94d64
-      = SimHintiS(SimHint_fallback_llsc, VG_(clo_sim_hints));
e94d64
+      = /* The user asked explicitly */
e94d64
+        SimHintiS(SimHint_fallback_llsc, VG_(clo_sim_hints))
e94d64
+        || /* we autodetected that it is necessary */
e94d64
+           vex_archinfo.arm64_requires_fallback_LLSC;
e94d64
 #  endif
e94d64
 
e94d64
    /* Set up closure args. */