summaryrefslogtreecommitdiff
path: root/src/hwf-arm.c
diff options
context:
space:
mode:
authorJussi Kivilinna <jussi.kivilinna@iki.fi>2014-11-02 17:45:35 +0200
committerJussi Kivilinna <jussi.kivilinna@iki.fi>2014-11-02 17:45:35 +0200
commit95eef21583d8e998efc48f22898c1ae31b77cb48 (patch)
tree6046e3735454d48b86071af5d70edb386d8f8eb4 /src/hwf-arm.c
parent0b520128551054d83fb0bb2db8873394f38de498 (diff)
downloadlibgcrypt-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/hwf-arm.c')
-rw-r--r--src/hwf-arm.c57
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;
}