|
#include <stdint.h> |
|
|
|
#if CPUINFO_MOCK |
|
#include <cpuinfo-mock.h> |
|
#endif |
|
#include <arm/linux/api.h> |
|
#include <arm/linux/cp.h> |
|
#include <arm/midr.h> |
|
#include <cpuinfo/log.h> |
|
|
|
|
|
#if CPUINFO_MOCK |
|
uint32_t cpuinfo_arm_fpsid = 0; |
|
uint32_t cpuinfo_arm_mvfr0 = 0; |
|
uint32_t cpuinfo_arm_wcid = 0; |
|
|
|
void cpuinfo_set_fpsid(uint32_t fpsid) { |
|
cpuinfo_arm_fpsid = fpsid; |
|
} |
|
|
|
void cpuinfo_set_wcid(uint32_t wcid) { |
|
cpuinfo_arm_wcid = wcid; |
|
} |
|
#endif |
|
|
|
|
|
void cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo( |
|
uint32_t features, |
|
uint32_t features2, |
|
uint32_t midr, |
|
uint32_t architecture_version, |
|
uint32_t architecture_flags, |
|
const struct cpuinfo_arm_chipset chipset[restrict static 1], |
|
struct cpuinfo_arm_isa isa[restrict static 1]) |
|
{ |
|
if (architecture_version < 8) { |
|
const uint32_t armv8_features2_mask = CPUINFO_ARM_LINUX_FEATURE2_AES | CPUINFO_ARM_LINUX_FEATURE2_PMULL | |
|
CPUINFO_ARM_LINUX_FEATURE2_SHA1 | CPUINFO_ARM_LINUX_FEATURE2_SHA2 | CPUINFO_ARM_LINUX_FEATURE2_CRC32; |
|
if ((features2 & armv8_features2_mask) != 0 && architecture_version < 8) { |
|
architecture_version = 8; |
|
} |
|
} |
|
if (architecture_version >= 8) { |
|
|
|
|
|
|
|
|
|
isa->armv5e = true; |
|
isa->armv6 = true; |
|
isa->armv6k = true; |
|
isa->armv7 = true; |
|
isa->armv7mp = true; |
|
isa->armv8 = true; |
|
isa->thumb = true; |
|
isa->thumb2 = true; |
|
isa->idiv = true; |
|
isa->vfpv3 = true; |
|
isa->d32 = true; |
|
isa->fp16 = true; |
|
isa->fma = true; |
|
isa->neon = true; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (chipset->series == cpuinfo_arm_chipset_series_samsung_exynos && chipset->model == 9810) { |
|
|
|
cpuinfo_log_warning("FP16 arithmetics and RDM disabled: only little cores in Exynos 9810 support these extensions"); |
|
} else { |
|
switch (midr & (CPUINFO_ARM_MIDR_IMPLEMENTER_MASK | CPUINFO_ARM_MIDR_PART_MASK)) { |
|
case UINT32_C(0x4100D050): |
|
case UINT32_C(0x4100D060): |
|
case UINT32_C(0x4100D0A0): |
|
case UINT32_C(0x4100D0B0): |
|
case UINT32_C(0x4100D0D0): |
|
case UINT32_C(0x4100D0E0): |
|
case UINT32_C(0x4100D460): |
|
case UINT32_C(0x4100D470): |
|
case UINT32_C(0x4100D480): |
|
case UINT32_C(0x4800D400): |
|
case UINT32_C(0x51008020): |
|
case UINT32_C(0x51008030): |
|
case UINT32_C(0x51008040): |
|
case UINT32_C(0x51008050): |
|
case UINT32_C(0x53000030): |
|
case UINT32_C(0x53000040): |
|
isa->fp16arith = true; |
|
isa->rdm = true; |
|
break; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
switch (midr & (CPUINFO_ARM_MIDR_IMPLEMENTER_MASK | CPUINFO_ARM_MIDR_PART_MASK)) { |
|
case UINT32_C(0x4100D0B0): |
|
case UINT32_C(0x4100D0D0): |
|
case UINT32_C(0x4100D0E0): |
|
case UINT32_C(0x4800D400): |
|
case UINT32_C(0x4100D460): |
|
case UINT32_C(0x4100D470): |
|
case UINT32_C(0x4100D480): |
|
case UINT32_C(0x51008040): |
|
case UINT32_C(0x51008050): |
|
case UINT32_C(0x53000030): |
|
case UINT32_C(0x53000040): |
|
isa->dot = true; |
|
break; |
|
case UINT32_C(0x4100D050): |
|
isa->dot = !!(midr_get_variant(midr) >= 1); |
|
break; |
|
case UINT32_C(0x4100D0A0): |
|
isa->dot = !!(midr_get_variant(midr) >= 2); |
|
break; |
|
} |
|
} else { |
|
|
|
|
|
|
|
|
|
|
|
|
|
if (architecture_version == 7 && midr_is_arm11(midr)) { |
|
cpuinfo_log_warning("kernel-reported architecture ARMv7 ignored due to mismatch with processor microarchitecture (ARM11)"); |
|
architecture_version = 6; |
|
} |
|
|
|
if (architecture_version < 7) { |
|
const uint32_t armv7_features_mask = CPUINFO_ARM_LINUX_FEATURE_VFPV3 | CPUINFO_ARM_LINUX_FEATURE_VFPV3D16 | CPUINFO_ARM_LINUX_FEATURE_VFPD32 | |
|
CPUINFO_ARM_LINUX_FEATURE_VFPV4 | CPUINFO_ARM_LINUX_FEATURE_NEON | CPUINFO_ARM_LINUX_FEATURE_IDIVT | CPUINFO_ARM_LINUX_FEATURE_IDIVA; |
|
if (features & armv7_features_mask) { |
|
architecture_version = 7; |
|
} |
|
} |
|
if ((architecture_version >= 6) || (features & CPUINFO_ARM_LINUX_FEATURE_EDSP) || (architecture_flags & CPUINFO_ARM_LINUX_ARCH_E)) { |
|
isa->armv5e = true; |
|
} |
|
if (architecture_version >= 6) { |
|
isa->armv6 = true; |
|
} |
|
if (architecture_version >= 7) { |
|
isa->armv6k = true; |
|
isa->armv7 = true; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch (midr & (CPUINFO_ARM_MIDR_IMPLEMENTER_MASK | CPUINFO_ARM_MIDR_PART_MASK)) { |
|
case UINT32_C(0x4100C050): |
|
case UINT32_C(0x4100C090): |
|
case UINT32_C(0x510002D0): |
|
case UINT32_C(0x510004D0): |
|
case UINT32_C(0x510006F0): |
|
isa->armv7mp = true; |
|
break; |
|
default: |
|
|
|
isa->armv7mp = (features & CPUINFO_ARM_LINUX_FEATURE_IDIV) == CPUINFO_ARM_LINUX_FEATURE_IDIV; |
|
break; |
|
} |
|
} |
|
|
|
if (features & CPUINFO_ARM_LINUX_FEATURE_IWMMXT) { |
|
#if !defined(__ARM_ARCH_8A__) && !(defined(__ARM_ARCH) && (__ARM_ARCH >= 8)) |
|
const uint32_t wcid = read_wcid(); |
|
cpuinfo_log_debug("WCID = 0x%08"PRIx32, wcid); |
|
const uint32_t coprocessor_type = (wcid >> 8) & UINT32_C(0xFF); |
|
if (coprocessor_type >= 0x10) { |
|
isa->wmmx = true; |
|
if (coprocessor_type >= 0x20) { |
|
isa->wmmx2 = true; |
|
} |
|
} else { |
|
cpuinfo_log_warning("WMMX ISA disabled: OS reported iwmmxt feature, " |
|
"but WCID coprocessor type 0x%"PRIx32" indicates no WMMX support", |
|
coprocessor_type); |
|
} |
|
#else |
|
cpuinfo_log_warning("WMMX ISA disabled: OS reported iwmmxt feature, " |
|
"but there is no iWMMXt coprocessor"); |
|
#endif |
|
} |
|
|
|
if ((features & CPUINFO_ARM_LINUX_FEATURE_THUMB) || (architecture_flags & CPUINFO_ARM_LINUX_ARCH_T)) { |
|
isa->thumb = true; |
|
|
|
|
|
|
|
|
|
|
|
if (architecture_version >= 7 || midr_is_arm1156(midr)) { |
|
isa->thumb2 = true; |
|
} |
|
} |
|
if (features & CPUINFO_ARM_LINUX_FEATURE_THUMBEE) { |
|
isa->thumbee = true; |
|
} |
|
if ((features & CPUINFO_ARM_LINUX_FEATURE_JAVA) || (architecture_flags & CPUINFO_ARM_LINUX_ARCH_J)) { |
|
isa->jazelle = true; |
|
} |
|
|
|
|
|
if ((features & CPUINFO_ARM_LINUX_FEATURE_IDIV) == CPUINFO_ARM_LINUX_FEATURE_IDIV || midr_is_krait(midr)) { |
|
isa->idiv = true; |
|
} |
|
|
|
const uint32_t vfp_mask = \ |
|
CPUINFO_ARM_LINUX_FEATURE_VFP | CPUINFO_ARM_LINUX_FEATURE_VFPV3 | CPUINFO_ARM_LINUX_FEATURE_VFPV3D16 | \ |
|
CPUINFO_ARM_LINUX_FEATURE_VFPD32 | CPUINFO_ARM_LINUX_FEATURE_VFPV4 | CPUINFO_ARM_LINUX_FEATURE_NEON; |
|
if (features & vfp_mask) { |
|
const uint32_t vfpv3_mask = CPUINFO_ARM_LINUX_FEATURE_VFPV3 | CPUINFO_ARM_LINUX_FEATURE_VFPV3D16 | \ |
|
CPUINFO_ARM_LINUX_FEATURE_VFPD32 | CPUINFO_ARM_LINUX_FEATURE_VFPV4 | CPUINFO_ARM_LINUX_FEATURE_NEON; |
|
if ((architecture_version >= 7) || (features & vfpv3_mask)) { |
|
isa->vfpv3 = true; |
|
|
|
const uint32_t d32_mask = CPUINFO_ARM_LINUX_FEATURE_VFPD32 | CPUINFO_ARM_LINUX_FEATURE_NEON; |
|
if (features & d32_mask) { |
|
isa->d32 = true; |
|
} |
|
} else { |
|
#if defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_8A__) || defined(__ARM_ARCH) && (__ARM_ARCH >= 7) |
|
isa->vfpv3 = true; |
|
#else |
|
const uint32_t fpsid = read_fpsid(); |
|
cpuinfo_log_debug("FPSID = 0x%08"PRIx32, fpsid); |
|
const uint32_t subarchitecture = (fpsid >> 16) & UINT32_C(0x7F); |
|
if (subarchitecture >= 0x01) { |
|
isa->vfpv2 = true; |
|
} |
|
#endif |
|
} |
|
} |
|
if (features & CPUINFO_ARM_LINUX_FEATURE_NEON) { |
|
isa->neon = true; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
if ((features & CPUINFO_ARM_LINUX_FEATURE_VFPV4) || midr_is_cortex_a9(midr) || midr_is_scorpion(midr)) { |
|
isa->fp16 = true; |
|
} |
|
|
|
if (features & CPUINFO_ARM_LINUX_FEATURE_VFPV4) { |
|
isa->fma = true; |
|
} |
|
} |
|
|
|
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_AES) { |
|
isa->aes = true; |
|
} |
|
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_PMULL) { |
|
isa->pmull = true; |
|
} |
|
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SHA1) { |
|
isa->sha1 = true; |
|
} |
|
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SHA2) { |
|
isa->sha2 = true; |
|
} |
|
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_CRC32) { |
|
isa->crc32 = true; |
|
} |
|
} |
|
|