]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Bug 377966 - arm64 unhandled instruction dc zva
authorPaul Floyd <pjfloyd@wanadoo.fr>
Sat, 11 May 2024 16:10:03 +0000 (18:10 +0200)
committerPaul Floyd <pjfloyd@wanadoo.fr>
Sat, 11 May 2024 16:10:03 +0000 (18:10 +0200)
With contributions from
Louis Brunner https://github.com/LouisBrunner/valgrind-macos

NEWS
VEX/priv/guest_arm64_defs.h
VEX/priv/guest_arm64_helpers.c
VEX/priv/guest_arm64_toIR.c
VEX/priv/main_main.c
VEX/pub/libvex.h
coregrind/m_cache.c

diff --git a/NEWS b/NEWS
index 514249e0e547507fcb417416d8ad1406491d3248..f8be2521a87db6e794590a511cf6f070edbf45ca 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -23,9 +23,11 @@ bugzilla (https://bugs.kde.org/enter_bug.cgi?product=valgrind) rather
 than mailing the developers (or mailing lists) directly -- bugs that
 are not entered into bugzilla tend to get forgotten about or ignored.
 
-392146  aarch64: unhandled instruction 0xD5380001 (MRS rT, midr_el1)
+377966  arm64 unhandled instruction dc zva392146  aarch64: unhandled
+        instruction 0xD5380001 (MRS rT, midr_el1)
 412377  SIGILL on cache flushes on arm64
-486180  [Valgrind][MIPS] 'VexGuestArchState' has no member named 'guest_IP_AT_SYSCALL'
+486180  [Valgrind][MIPS] 'VexGuestArchState' has no member named
+        'guest_IP_AT_SYSCALL'
 486293  memccpy false positives
 486569  linux inotify_init syscall wrapper missing POST entry in syscall_table
 
index c9d5e9df3f02bcda1ef55c20b60fe9e830570319..241dd36bab390c80b2535811d692c4bfc964701e 100644 (file)
@@ -116,6 +116,7 @@ extern ULong arm64g_calc_crc32cw ( ULong acc, ULong bits );
 extern ULong arm64g_calc_crc32cx ( ULong acc, ULong bits );
 
 /* --- DIRTY HELPERS --- */
+extern ULong arm64g_dirtyhelper_MRS_DCZID_EL0 ( void );
 
 extern ULong arm64g_dirtyhelper_MRS_CNTVCT_EL0 ( void );
 
index 8c8ebcb1ad699c4afd5af71884eadc52a3a6c26d..938df2bd484e0a63ce6bee9e9ed5f6329a86350a 100644 (file)
@@ -776,6 +776,19 @@ ULong arm64g_calc_crc32cx ( ULong acc, ULong bits )
    return crc;
 }
 
+/* CALLED FROM GENERATED CODE */
+/* DIRTY HELPER (non-referentially-transparent) */
+/* Horrible hack.  On non-arm64 platforms, return 0. */
+ULong arm64g_dirtyhelper_MRS_DCZID_EL0 ( void )
+{
+#  if defined(__aarch64__) && !defined(__arm__)
+   ULong w = 0x5555555555555555ULL; /* overwritten */
+   __asm__ __volatile__("mrs %0, dczid_el0" : "=r"(w));
+   return w;
+#  else
+   return 0ULL;
+#  endif
+}
 
 /* CALLED FROM GENERATED CODE */
 /* DIRTY HELPER (non-referentially-transparent) */
index 17191268567a6c530a5a7deb81d53076e199dddc..d6053e6e355fad33559945bf82881405f2355731 100644 (file)
@@ -7877,14 +7877,25 @@ Bool dis_ARM64_branch_etc(/*MB_OUT*/DisResult* dres, UInt insn,
       return True;
    }
    /* ---- Cases for DCZID_EL0 ----
-      Don't support arbitrary reads and writes to this register.  Just
-      return the value 16, which indicates that the DC ZVA instruction
-      is not permitted, so we don't have to emulate it.
+      This is the data cache zero ID register. It controls whether
+      DC ZVA is supported and if so the block size used. Support reads of it
+      only by passing through to the host.
       D5 3B 00 111 Rt  MRS rT, dczid_el0
    */
    if ((INSN(31,0) & 0xFFFFFFE0) == 0xD53B00E0) {
       UInt tt = INSN(4,0);
-      putIReg64orZR(tt, mkU64(1<<4));
+      IRTemp   val  = newTemp(Ity_I64);
+      IRExpr** args = mkIRExprVec_0();
+      IRDirty* d    = unsafeIRDirty_1_N (
+                         val,
+                         0/*regparms*/,
+                         "arm64g_dirtyhelper_MRS_DCZID_EL0",
+                         &arm64g_dirtyhelper_MRS_DCZID_EL0,
+                         args
+                      );
+      /* execute the dirty call, dumping the result in val. */
+      stmt( IRStmt_Dirty(d) );
+      putIReg64orZR(tt, mkexpr(val));
       DIP("mrs %s, dczid_el0 (FAKED)\n", nameIReg64orZR(tt));
       return True;
    }
@@ -7986,6 +7997,25 @@ Bool dis_ARM64_branch_etc(/*MB_OUT*/DisResult* dres, UInt insn,
       return True;
    }
 
+   /* ------------------ DC_ZVA ------------------ */
+   /* D5 0B 74 001 Rt  dc zva, rT
+   */
+   if ((INSN(31,0) & 0xFFFFFFE0) == 0xD50B7420) {
+      /* Round the requested address, in rT, down to the start of the
+         containing block. */
+      UInt   tt      = INSN(4,0);
+      ULong  lineszB = 1ULL << archinfo->arm64_cache_block_size;
+      IRTemp addr    = newTemp(Ity_I64);
+      assign( addr, binop( Iop_And64,
+                           getIReg64orZR(tt),
+                           mkU64(~(lineszB - 1))) );
+      for (ULong o = 0; o < lineszB; o += 8) {
+          storeLE(binop(Iop_Add64,mkexpr(addr),mkU64(o)), mkU64(0));
+      }
+      DIP("dc zva, %s\n", nameIReg64orZR(tt));
+      return True;
+   }
+
    /* ------------------ DC_CVAU ------------------ */
    /* D5 0B 7A 001 Rt  dc cvac, rT
       D5 0B 7B 001 Rt  dc cvau, rT
index eda2fe6eeecdb0c65074bef75d003b7b4563d0ca..4d0551c281775baa7eca47c6cdc8ed7092c8b89b 100644 (file)
@@ -1549,6 +1549,7 @@ void LibVEX_default_VexArchInfo ( /*OUT*/VexArchInfo* vai )
    vai->ppc_dcbzl_szB           = 0;
    vai->arm64_dMinLine_lg2_szB  = 0;
    vai->arm64_iMinLine_lg2_szB  = 0;
+   vai->arm64_cache_block_size  = 0;
    vai->arm64_requires_fallback_LLSC = False;
    vai->hwcache_info.num_levels = 0;
    vai->hwcache_info.num_caches = 0;
index 15e2d39deb108971222fd0e4235eb848b9fba16d..544cf034890c922dbd3000f994a666aac8f8df77 100644 (file)
@@ -375,6 +375,7 @@ typedef
          line size of 64 bytes would be encoded here as 6. */
       UInt arm64_dMinLine_lg2_szB;
       UInt arm64_iMinLine_lg2_szB;
+      UChar arm64_cache_block_size;
       /* ARM64: does the host require us to use the fallback LLSC
          implementation? */
       Bool arm64_requires_fallback_LLSC;
index 428a4df43fb6731a2f8e8d7f926e682911f477f6..24d8fd9356478c8383487c0862ad8992d9d09e74 100644 (file)
@@ -543,6 +543,11 @@ get_cache_info(VexArchInfo *vai)
 static Bool
 get_cache_info(VexArchInfo *vai)
 {
+   unsigned long val;
+   asm volatile("mrs %0, dczid_el0" : "=r" (val));
+   // The ARM manual says that 4 bits are used but 9 is the maximum
+   vg_assert(val <= 9);
+   vai->arm64_cache_block_size = val;
    vai->hwcache_info.icaches_maintain_coherence = False;
 
    return False;   // not yet