diff options
author | Jussi Kivilinna <jussi.kivilinna@iki.fi> | 2014-11-02 17:45:35 +0200 |
---|---|---|
committer | Jussi Kivilinna <jussi.kivilinna@iki.fi> | 2014-11-02 17:45:35 +0200 |
commit | 95eef21583d8e998efc48f22898c1ae31b77cb48 (patch) | |
tree | 6046e3735454d48b86071af5d70edb386d8f8eb4 /src | |
parent | 0b520128551054d83fb0bb2db8873394f38de498 (diff) | |
download | libgcrypt-95eef21583d8e998efc48f22898c1ae31b77cb48.tar.gz |
Disable NEON for CPUs that are known to have broken NEON implementation
* src/hwf-arm.c (detect_arm_proc_cpuinfo): Add parsing for CPU version
information and check if CPU is known to have broken NEON
implementation.
(_gcry_hwf_detect_arm): Filter out broken HW features.
--
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
Diffstat (limited to 'src')
-rw-r--r-- | src/hwf-arm.c | 57 |
1 files changed, 54 insertions, 3 deletions
diff --git a/src/hwf-arm.c b/src/hwf-arm.c index dbbb607f..3dc050e7 100644 --- a/src/hwf-arm.c +++ b/src/hwf-arm.c @@ -98,17 +98,32 @@ detect_arm_at_hwcap(void) #define HAS_PROC_CPUINFO 1 static unsigned int -detect_arm_proc_cpuinfo(void) +detect_arm_proc_cpuinfo(unsigned int *broken_hwfs) { char buf[1024]; /* large enough */ char *str_features, *str_neon; + int cpu_implementer, cpu_arch, cpu_variant, cpu_part, cpu_revision; FILE *f; int readlen, i; static int cpuinfo_initialized = 0; static unsigned int stored_cpuinfo_features; + static unsigned int stored_broken_hwfs; + struct { + const char *name; + int *value; + } cpu_entries[5] = { + { "CPU implementer", &cpu_implementer }, + { "CPU architecture", &cpu_arch }, + { "CPU variant", &cpu_variant }, + { "CPU part", &cpu_part }, + { "CPU revision", &cpu_revision }, + }; if (cpuinfo_initialized) - return stored_cpuinfo_features; + { + *broken_hwfs |= stored_broken_hwfs; + return stored_cpuinfo_features; + } f = fopen("/proc/cpuinfo", "r"); if (!f) @@ -124,12 +139,32 @@ detect_arm_proc_cpuinfo(void) cpuinfo_initialized = 1; stored_cpuinfo_features = 0; + stored_broken_hwfs = 0; /* Find features line. */ str_features = strstr(buf, "Features"); if (!str_features) return stored_cpuinfo_features; + /* Find CPU version information. */ + for (i = 0; i < DIM(cpu_entries); i++) + { + char *str; + + *cpu_entries[i].value = -1; + + str = strstr(buf, cpu_entries[i].name); + if (!str) + continue; + + str = strstr(str, ": "); + if (!str) + continue; + + str += 2; + *cpu_entries[i].value = strtoul(str, NULL, 0); + } + /* Lines to strings. */ for (i = 0; i < sizeof(buf); i++) if (buf[i] == '\n') @@ -140,6 +175,19 @@ detect_arm_proc_cpuinfo(void) if (str_neon && (str_neon[5] == ' ' || str_neon[5] == '\0')) stored_cpuinfo_features |= HWF_ARM_NEON; + /* Check for CPUs with broken NEON implementation. See + * https://code.google.com/p/chromium/issues/detail?id=341598 + */ + if (cpu_implementer == 0x51 + && cpu_arch == 7 + && cpu_variant == 1 + && cpu_part == 0x4d + && cpu_revision == 0) + { + stored_broken_hwfs = HWF_ARM_NEON; + } + + *broken_hwfs |= stored_broken_hwfs; return stored_cpuinfo_features; } @@ -149,18 +197,21 @@ unsigned int _gcry_hwf_detect_arm (void) { unsigned int ret = 0; + unsigned int broken_hwfs = 0; #if defined (HAS_SYS_AT_HWCAP) ret |= detect_arm_at_hwcap (); #endif #if defined (HAS_PROC_CPUINFO) - ret |= detect_arm_proc_cpuinfo (); + ret |= detect_arm_proc_cpuinfo (&broken_hwfs); #endif #if defined(__ARM_NEON__) && defined(ENABLE_NEON_SUPPORT) ret |= HWF_ARM_NEON; #endif + ret &= ~broken_hwfs; + return ret; } |