From 5f5e6d620f67063651a511afbf72439888fe3bf2 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Tue, 1 Feb 2022 08:25:05 -0800 Subject: [PATCH] Fix a getauxval comment and expand the Krait idiv workaround (#206) * Fix getauxval comment (API 18 not 20) getauxval is available in Android starting with API 18, not 20. The comment about __ANDROID_API__ appears to have been copied from the NDK's cpufeatures, which always uses dlopen/dlsym and doesn't assume it can directly call getauxval, even if __ANDROID_API__ is new enough. With this project, though, when __ANDROID_API__ is 18 or up, the CMakeLists.txt file would detect that getauxval is available and define HAVE_STRONG_GETAUXVAL. * Broaden Qualcomm Krait idiv workaround Some Qualcomm Krait CPUs have IDIV support but the kernel doesn't report it. Previously, this code looked for two CPUs: - 0x510006F2 (0x51/'Q', variant 0, part 0x06f, rev 2) - 0x510006F3 (0x51/'Q', variant 0, part 0x06f, rev 3) This check misses my 2013 Nexus 7 device, which has this CPU ID: - 0x511006f0 (0x51/'Q', variant 1, part 0x06f, rev 0) My Nexus 7 device doesn't report idiv through AT_HWCAP or through /proc/cpuinfo (AT_HWCAP is 0x1b0d7). Expand the check to anything with: - implementer 0x51 - architecture 7 - part 0x4d or 0x6f Part 0x4d appears to be a dual-core Krait (e.g. see https://crbug.com/341598#c43). This new matching behavior is a subset of what the upstream kernel does (patch[1] contributed by CodeAurora), and also closely matches the behavior of pytorch/cpuinfo. [1] https://github.com/torvalds/linux/commit/120ecfafabec382c4feb79ff159ef42a39b6d33b --- src/hwcaps.c | 8 +------- src/impl_arm_linux_or_android.c | 15 ++++++++------- test/cpuinfo_arm_test.cc | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/hwcaps.c b/src/hwcaps.c index 605f892..f44f6c3 100644 --- a/src/hwcaps.c +++ b/src/hwcaps.c @@ -68,13 +68,7 @@ static unsigned long GetElfHwcapFromGetauxval(uint32_t hwcap_type) { #elif defined(HAVE_DLFCN_H) // On Android we probe the system's C library for a 'getauxval' function and // call it if it exits, or return 0 for failure. This function is available -// since API level 20. -// -// This code does *NOT* check for '__ANDROID_API__ >= 20' to support the edge -// case where some NDK developers use headers for a platform that is newer than -// the one really targetted by their application. This is typically done to use -// newer native APIs only when running on more recent Android versions, and -// requires careful symbol management. +// since API level 18. // // Note that getauxval() can't really be re-implemented here, because its // implementation does not parse /proc/self/auxv. Instead it depends on values diff --git a/src/impl_arm_linux_or_android.c b/src/impl_arm_linux_or_android.c index d110a15..997ef93 100644 --- a/src/impl_arm_linux_or_android.c +++ b/src/impl_arm_linux_or_android.c @@ -152,13 +152,14 @@ static void FixErrors(ArmInfo* const info, // https://crbug.com/341598. info->features.neon = false; break; - case 0x510006F2: - case 0x510006F3: - // The Nexus 4 (Qualcomm Krait) kernel configuration forgets to report - // IDIV support. - info->features.idiva = true; - info->features.idivt = true; - break; + } + + // Some Qualcomm Krait kernels forget to report IDIV support. + // https://github.com/torvalds/linux/commit/120ecfafabec382c4feb79ff159ef42a39b6d33b + if (info->implementer == 0x51 && info->architecture == 7 && + (info->part == 0x4d || info->part == 0x6f)) { + info->features.idiva = true; + info->features.idivt = true; } // Propagate cpu features. diff --git a/test/cpuinfo_arm_test.cc b/test/cpuinfo_arm_test.cc index 85ee7fb..ad7f4e8 100644 --- a/test/cpuinfo_arm_test.cc +++ b/test/cpuinfo_arm_test.cc @@ -327,6 +327,24 @@ CPU revision : 3)"); EXPECT_EQ(GetArmCpuId(&info), 0x510006f3); } +// The 2013 Nexus 7 (Qualcomm Krait) kernel configuration forgets to report IDIV +// support. +TEST(CpuinfoArmTest, Nexus7_2013_0x511006f0) { + ResetHwcaps(); + auto& fs = GetEmptyFilesystem(); + fs.CreateFile("/proc/cpuinfo", + R"(CPU implementer : 0x51 +CPU architecture: 7 +CPU variant : 0x1 +CPU part : 0x06f +CPU revision : 0)"); + const auto info = GetArmInfo(); + EXPECT_TRUE(info.features.idiva); + EXPECT_TRUE(info.features.idivt); + + EXPECT_EQ(GetArmCpuId(&info), 0x511006f0); +} + // The emulator-specific Android 4.2 kernel fails to report support for the // 32-bit ARM IDIV instruction. Technically, this is a feature of the virtual // CPU implemented by the emulator.