From: Paul Floyd Date: Sat, 11 May 2024 16:10:03 +0000 (+0200) Subject: Bug 377966 - arm64 unhandled instruction dc zva X-Git-Tag: VALGRIND_3_24_0~147 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8b6c36ecf14530d7f50f65697c2a039e3d410092;p=thirdparty%2Fvalgrind.git Bug 377966 - arm64 unhandled instruction dc zva With contributions from Louis Brunner https://github.com/LouisBrunner/valgrind-macos --- diff --git a/NEWS b/NEWS index 514249e0e..f8be2521a 100644 --- 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 diff --git a/VEX/priv/guest_arm64_defs.h b/VEX/priv/guest_arm64_defs.h index c9d5e9df3..241dd36ba 100644 --- a/VEX/priv/guest_arm64_defs.h +++ b/VEX/priv/guest_arm64_defs.h @@ -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 ); diff --git a/VEX/priv/guest_arm64_helpers.c b/VEX/priv/guest_arm64_helpers.c index 8c8ebcb1a..938df2bd4 100644 --- a/VEX/priv/guest_arm64_helpers.c +++ b/VEX/priv/guest_arm64_helpers.c @@ -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) */ diff --git a/VEX/priv/guest_arm64_toIR.c b/VEX/priv/guest_arm64_toIR.c index 171912685..d6053e6e3 100644 --- a/VEX/priv/guest_arm64_toIR.c +++ b/VEX/priv/guest_arm64_toIR.c @@ -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 diff --git a/VEX/priv/main_main.c b/VEX/priv/main_main.c index eda2fe6ee..4d0551c28 100644 --- a/VEX/priv/main_main.c +++ b/VEX/priv/main_main.c @@ -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; diff --git a/VEX/pub/libvex.h b/VEX/pub/libvex.h index 15e2d39de..544cf0348 100644 --- a/VEX/pub/libvex.h +++ b/VEX/pub/libvex.h @@ -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; diff --git a/coregrind/m_cache.c b/coregrind/m_cache.c index 428a4df43..24d8fd935 100644 --- a/coregrind/m_cache.c +++ b/coregrind/m_cache.c @@ -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