in src/arm/linux/cpuinfo.c [100:309]
static void parse_features(
const char* features_start,
const char* features_end,
struct cpuinfo_arm_linux_processor processor[restrict static 1])
{
const char* feature_start = features_start;
const char* feature_end;
/* Mark the features as valid */
processor->flags |= CPUINFO_ARM_LINUX_VALID_FEATURES | CPUINFO_ARM_LINUX_VALID_PROCESSOR;
do {
feature_end = feature_start + 1;
for (; feature_end != features_end; feature_end++) {
if (*feature_end == ' ') {
break;
}
}
const size_t feature_length = (size_t) (feature_end - feature_start);
switch (feature_length) {
case 2:
if (memcmp(feature_start, "fp", feature_length) == 0) {
#if CPUINFO_ARCH_ARM64
processor->features |= CPUINFO_ARM_LINUX_FEATURE_FP;
#endif
#if CPUINFO_ARCH_ARM
} else if (memcmp(feature_start, "wp", feature_length) == 0) {
/*
* Some AArch64 kernels, including the one on Nexus 5X,
* erroneously report "swp" as "wp" to AArch32 programs
*/
processor->features |= CPUINFO_ARM_LINUX_FEATURE_SWP;
#endif
} else {
goto unexpected;
}
break;
case 3:
if (memcmp(feature_start, "aes", feature_length) == 0) {
#if CPUINFO_ARCH_ARM
processor->features2 |= CPUINFO_ARM_LINUX_FEATURE2_AES;
#elif CPUINFO_ARCH_ARM64
processor->features |= CPUINFO_ARM_LINUX_FEATURE_AES;
#endif
#if CPUINFO_ARCH_ARM
} else if (memcmp(feature_start, "swp", feature_length) == 0) {
processor->features |= CPUINFO_ARM_LINUX_FEATURE_SWP;
} else if (memcmp(feature_start, "fpa", feature_length) == 0) {
processor->features |= CPUINFO_ARM_LINUX_FEATURE_FPA;
} else if (memcmp(feature_start, "vfp", feature_length) == 0) {
processor->features |= CPUINFO_ARM_LINUX_FEATURE_VFP;
} else if (memcmp(feature_start, "tls", feature_length) == 0) {
processor->features |= CPUINFO_ARM_LINUX_FEATURE_TLS;
#endif /* CPUINFO_ARCH_ARM */
} else {
goto unexpected;
}
break;
case 4:
if (memcmp(feature_start, "sha1", feature_length) == 0) {
#if CPUINFO_ARCH_ARM
processor->features2 |= CPUINFO_ARM_LINUX_FEATURE2_SHA1;
#elif CPUINFO_ARCH_ARM64
processor->features |= CPUINFO_ARM_LINUX_FEATURE_SHA1;
#endif
} else if (memcmp(feature_start, "sha2", feature_length) == 0) {
#if CPUINFO_ARCH_ARM
processor->features2 |= CPUINFO_ARM_LINUX_FEATURE2_SHA2;
#elif CPUINFO_ARCH_ARM64
processor->features |= CPUINFO_ARM_LINUX_FEATURE_SHA2;
#endif
} else if (memcmp(feature_start, "fphp", feature_length) == 0) {
#if CPUINFO_ARCH_ARM64
processor->features |= CPUINFO_ARM_LINUX_FEATURE_FPHP;
#endif
} else if (memcmp(feature_start, "fcma", feature_length) == 0) {
#if CPUINFO_ARCH_ARM64
processor->features |= CPUINFO_ARM_LINUX_FEATURE_FCMA;
#endif
#if CPUINFO_ARCH_ARM
} else if (memcmp(feature_start, "half", feature_length) == 0) {
processor->features |= CPUINFO_ARM_LINUX_FEATURE_HALF;
} else if (memcmp(feature_start, "edsp", feature_length) == 0) {
processor->features |= CPUINFO_ARM_LINUX_FEATURE_EDSP;
} else if (memcmp(feature_start, "java", feature_length) == 0) {
processor->features |= CPUINFO_ARM_LINUX_FEATURE_JAVA;
} else if (memcmp(feature_start, "neon", feature_length) == 0) {
processor->features |= CPUINFO_ARM_LINUX_FEATURE_NEON;
} else if (memcmp(feature_start, "lpae", feature_length) == 0) {
processor->features |= CPUINFO_ARM_LINUX_FEATURE_LPAE;
} else if (memcmp(feature_start, "tlsi", feature_length) == 0) {
/*
* Some AArch64 kernels, including the one on Nexus 5X,
* erroneously report "tls" as "tlsi" to AArch32 programs
*/
processor->features |= CPUINFO_ARM_LINUX_FEATURE_TLS;
#endif /* CPUINFO_ARCH_ARM */
} else {
goto unexpected;
}
break;
case 5:
if (memcmp(feature_start, "pmull", feature_length) == 0) {
#if CPUINFO_ARCH_ARM
processor->features2 |= CPUINFO_ARM_LINUX_FEATURE2_PMULL;
#elif CPUINFO_ARCH_ARM64
processor->features |= CPUINFO_ARM_LINUX_FEATURE_PMULL;
#endif
} else if (memcmp(feature_start, "crc32", feature_length) == 0) {
#if CPUINFO_ARCH_ARM
processor->features2 |= CPUINFO_ARM_LINUX_FEATURE2_CRC32;
#elif CPUINFO_ARCH_ARM64
processor->features |= CPUINFO_ARM_LINUX_FEATURE_CRC32;
#endif
} else if (memcmp(feature_start, "asimd", feature_length) == 0) {
#if CPUINFO_ARCH_ARM64
processor->features |= CPUINFO_ARM_LINUX_FEATURE_ASIMD;
#endif
} else if (memcmp(feature_start, "cpuid", feature_length) == 0) {
#if CPUINFO_ARCH_ARM64
processor->features |= CPUINFO_ARM_LINUX_FEATURE_CPUID;
#endif
} else if (memcmp(feature_start, "jscvt", feature_length) == 0) {
#if CPUINFO_ARCH_ARM64
processor->features |= CPUINFO_ARM_LINUX_FEATURE_JSCVT;
#endif
} else if (memcmp(feature_start, "lrcpc", feature_length) == 0) {
#if CPUINFO_ARCH_ARM64
processor->features |= CPUINFO_ARM_LINUX_FEATURE_LRCPC;
#endif
#if CPUINFO_ARCH_ARM
} else if (memcmp(feature_start, "thumb", feature_length) == 0) {
processor->features |= CPUINFO_ARM_LINUX_FEATURE_THUMB;
} else if (memcmp(feature_start, "26bit", feature_length) == 0) {
processor->features |= CPUINFO_ARM_LINUX_FEATURE_26BIT;
} else if (memcmp(feature_start, "vfpv3", feature_length) == 0) {
processor->features |= CPUINFO_ARM_LINUX_FEATURE_VFPV3;
} else if (memcmp(feature_start, "vfpv4", feature_length) == 0) {
processor->features |= CPUINFO_ARM_LINUX_FEATURE_VFPV4;
} else if (memcmp(feature_start, "idiva", feature_length) == 0) {
processor->features |= CPUINFO_ARM_LINUX_FEATURE_IDIVA;
} else if (memcmp(feature_start, "idivt", feature_length) == 0) {
processor->features |= CPUINFO_ARM_LINUX_FEATURE_IDIVT;
#endif /* CPUINFO_ARCH_ARM */
} else {
goto unexpected;
}
break;
#if CPUINFO_ARCH_ARM
case 6:
if (memcmp(feature_start, "iwmmxt", feature_length) == 0) {
processor->features |= CPUINFO_ARM_LINUX_FEATURE_IWMMXT;
} else if (memcmp(feature_start, "crunch", feature_length) == 0) {
processor->features |= CPUINFO_ARM_LINUX_FEATURE_CRUNCH;
} else if (memcmp(feature_start, "vfpd32", feature_length) == 0) {
processor->features |= CPUINFO_ARM_LINUX_FEATURE_VFPD32;
} else {
goto unexpected;
}
break;
#endif /* CPUINFO_ARCH_ARM */
case 7:
if (memcmp(feature_start, "evtstrm", feature_length) == 0) {
processor->features |= CPUINFO_ARM_LINUX_FEATURE_EVTSTRM;
} else if (memcmp(feature_start, "atomics", feature_length) == 0) {
#if CPUINFO_ARCH_ARM64
processor->features |= CPUINFO_ARM_LINUX_FEATURE_ATOMICS;
#endif
} else if (memcmp(feature_start, "asimdhp", feature_length) == 0) {
#if CPUINFO_ARCH_ARM64
processor->features |= CPUINFO_ARM_LINUX_FEATURE_ASIMDHP;
#endif
#if CPUINFO_ARCH_ARM
} else if (memcmp(feature_start, "thumbee", feature_length) == 0) {
processor->features |= CPUINFO_ARM_LINUX_FEATURE_THUMBEE;
#endif /* CPUINFO_ARCH_ARM */
} else {
goto unexpected;
}
break;
case 8:
if (memcmp(feature_start, "asimdrdm", feature_length) == 0) {
#if CPUINFO_ARCH_ARM64
processor->features |= CPUINFO_ARM_LINUX_FEATURE_ASIMDRDM;
#endif
#if CPUINFO_ARCH_ARM
} else if (memcmp(feature_start, "fastmult", feature_length) == 0) {
processor->features |= CPUINFO_ARM_LINUX_FEATURE_FASTMULT;
} else if (memcmp(feature_start, "vfpv3d16", feature_length) == 0) {
processor->features |= CPUINFO_ARM_LINUX_FEATURE_VFPV3D16;
#endif /* CPUINFO_ARCH_ARM */
} else {
goto unexpected;
}
break;
default:
unexpected:
cpuinfo_log_warning("unexpected /proc/cpuinfo feature \"%.*s\" is ignored",
(int) feature_length, feature_start);
break;
}
feature_start = feature_end;
for (; feature_start != features_end; feature_start++) {
if (*feature_start != ' ') {
break;
}
}
} while (feature_start != feature_end);
}