diff --git a/CMakeLists.txt b/CMakeLists.txt index ac3c0a54..e8962e05 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,6 +73,8 @@ macro(add_cpu_features_headers_and_sources HDRS_LIST_NAME SRCS_LIST_NAME) list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_arm.h) elseif(PROCESSOR_IS_AARCH64) list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_aarch64.h) + list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/internal/cpuid_aarch64.h) + list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/internal/cputype_aarch64.h) elseif(PROCESSOR_IS_X86) list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_x86.h) list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/internal/cpuid_x86.h) diff --git a/include/cpu_features_macros.h b/include/cpu_features_macros.h index 8f5c38ca..384f31c5 100644 --- a/include/cpu_features_macros.h +++ b/include/cpu_features_macros.h @@ -39,7 +39,7 @@ #define CPU_FEATURES_ARCH_ARM #endif -#if defined(__aarch64__) +#if (defined(__aarch64__) || defined(__arm64__)) #define CPU_FEATURES_ARCH_AARCH64 #endif diff --git a/include/internal/bit_utils.h b/include/internal/bit_utils.h index 3467ff93..4b5f19ea 100644 --- a/include/internal/bit_utils.h +++ b/include/internal/bit_utils.h @@ -27,8 +27,8 @@ inline static bool IsBitSet(uint32_t reg, uint32_t bit) { return (reg >> bit) & 0x1; } -inline static uint32_t ExtractBitRange(uint32_t reg, uint32_t msb, - uint32_t lsb) { +inline static uint64_t ExtractBitRange(uint64_t reg, uint64_t msb, + uint64_t lsb) { const uint64_t bits = msb - lsb + 1ULL; const uint64_t mask = (1ULL << bits) - 1ULL; assert(msb >= lsb); diff --git a/include/internal/cpuid_aarch64.h b/include/internal/cpuid_aarch64.h new file mode 100644 index 00000000..9f46f98c --- /dev/null +++ b/include/internal/cpuid_aarch64.h @@ -0,0 +1,34 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CPU_FEATURES_CPUTYPE_AARCH64_H_ +#define CPU_FEATURES_CPUTYPE_AARCH64_H_ + +#include + +#include "cpu_features_macros.h" + +CPU_FEATURES_START_CPP_NAMESPACE + +uint64_t GetCpuid_MIDR_EL1(); +uint64_t GetCpuid_ID_AA64ISAR0_EL1(); +uint64_t GetCpuid_ID_AA64ISAR1_EL1(); +uint64_t GetCpuid_ID_AA64PFR0_EL1(); +uint64_t GetCpuid_ID_AA64ZFR0_EL1(); +uint64_t GetCpuid_ID_AA64MMFR2_EL1(); +uint64_t GetCpuid_ID_AA64PFR1_EL1(); + +CPU_FEATURES_END_CPP_NAMESPACE + +#endif // CPU_FEATURES_CPUTYPE_AARCH64_H_ diff --git a/include/internal/cputype_aarch64.h b/include/internal/cputype_aarch64.h new file mode 100644 index 00000000..31f4d93c --- /dev/null +++ b/include/internal/cputype_aarch64.h @@ -0,0 +1,211 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CPU_FEATURES_CPUTYPE_AARCH64_H_ +#define CPU_FEATURES_CPUTYPE_AARCH64_H_ + +// Arm Architecture Reference Manual Armv8, for A-profile architecture. D13.2.98 +// https://elixir.bootlin.com/linux/latest/source/arch/arm64/include/asm/cputype.h + +#define MIDR_REVISION_SHIFT 0 +#define MIDR_PARTNUM_SHIFT 4 +#define MIDR_ARCHITECTURE_SHIFT 16 +#define MIDR_IMPLEMENTOR_SHIFT 24 + +// MIDR: implementor, partnum +#define MIDR_CPU_MODEL_IP(imp, partnum) \ + (((imp) << MIDR_IMPLEMENTOR_SHIFT) | (0xF << MIDR_ARCHITECTURE_SHIFT) | \ + ((partnum) << MIDR_PARTNUM_SHIFT)) + +// MIDR: implementor, partnum, revision +#define MIDR_CPU_MODEL_IPR(imp, partnum, revision) \ + (((imp) << MIDR_IMPLEMENTOR_SHIFT) | (0xF << MIDR_ARCHITECTURE_SHIFT) | \ + ((partnum) << MIDR_PARTNUM_SHIFT) | ((revision) << MIDR_REVISION_SHIFT)) + +#define ARM_CPU_IMP_ARM 0x41 // ARM Limited. +#define ARM_CPU_IMP_BRCM 0x42 // Broadcom Corporation. +#define ARM_CPU_IMP_CAVIUM 0x43 // Cavium Inc. +#define CPU_VID_DEC 0x44 // Digital Equipment Corporation. +#define ARM_CPU_IMP_FUJITSU 0x46 // Fujitsu Ltd. +#define ARM_CPU_IMP_HISI 0x48 // HISI +#define ARM_CPU_IMP_INFINEON 0x49 // Infineon Technologies AG. +#define CPU_VID_MOTOROLA 0x4D // Motorola - Freescale Semiconductor Inc. +#define ARM_CPU_IMP_NVIDIA 0x4E // NVIDIA Corporation. +#define ARM_CPU_IMP_APM 0x50 // Applied Micro Circuits Corporation. +#define ARM_CPU_IMP_QCOM 0x51 // Qualcomm Inc. +#define ARM_CPU_IMP_MARVELL 0x56 // Marvell International Ltd. +#define ARM_CPU_IMP_APPLE 0x61 // Apple Inc. +#define ARM_CPU_IMP_INTEL 0x69 // Intel Corporation. +#define ARM_CPU_IMP_AMPERE 0xC0 // Ampere Computing. + +#define ARM_CPU_PART_AEM_V8 0xD0F +#define ARM_CPU_PART_FOUNDATION 0xD00 +#define ARM_CPU_PART_CORTEX_A57 0xD07 +#define ARM_CPU_PART_CORTEX_A72 0xD08 +#define ARM_CPU_PART_CORTEX_A53 0xD03 +#define ARM_CPU_PART_CORTEX_A73 0xD09 +#define ARM_CPU_PART_CORTEX_A75 0xD0A +#define ARM_CPU_PART_CORTEX_A35 0xD04 +#define ARM_CPU_PART_CORTEX_A55 0xD05 +#define ARM_CPU_PART_CORTEX_A76 0xD0B +#define ARM_CPU_PART_NEOVERSE_N1 0xD0C +#define ARM_CPU_PART_CORTEX_A77 0xD0D + +#define APM_CPU_PART_POTENZA 0x000 + +#define CAVIUM_CPU_PART_THUNDERX 0x0A1 +#define CAVIUM_CPU_PART_THUNDERX_81XX 0x0A2 +#define CAVIUM_CPU_PART_THUNDERX_83XX 0x0A3 +#define CAVIUM_CPU_PART_THUNDERX2 0x0AF + +#define BRCM_CPU_PART_BRAHMA_B53 0x100 +#define BRCM_CPU_PART_VULCAN 0x516 + +#define QCOM_CPU_PART_FALKOR_V1 0x800 +#define QCOM_CPU_PART_FALKOR 0xC00 +#define QCOM_CPU_PART_KRYO 0x200 +#define QCOM_CPU_PART_KRYO_2XX_GOLD 0x800 +#define QCOM_CPU_PART_KRYO_2XX_SILVER 0x801 +#define QCOM_CPU_PART_KRYO_3XX_SILVER 0x803 +#define QCOM_CPU_PART_KRYO_4XX_GOLD 0x804 +#define QCOM_CPU_PART_KRYO_4XX_SILVER 0x805 + +#define NVIDIA_CPU_PART_DENVER 0x003 +#define NVIDIA_CPU_PART_CARMEL 0x004 + +#define FUJITSU_CPU_PART_A64FX 0x001 + +#define HISI_CPU_PART_TSV110 0xD01 + +#define APPLE_CPU_PART_ICESTORM 0x020 +#define APPLE_CPU_PART_FIRESTORM 0x021 +#define APPLE_CPU_PART_M1_ICESTORM_TONGA 0x022 +#define APPLE_CPU_PART_M1_FIRESTORM_TONGA 0x023 + +#define MIDR_CORTEX_A53 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53) +#define MIDR_CORTEX_A53_R3 \ + MIDR_CPU_MODEL_IPR(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53, 3) + +#define MIDR_CORTEX_A57 \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57) +#define MIDR_CORTEX_A72 \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72) +#define MIDR_CORTEX_A73 \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A73) +#define MIDR_CORTEX_A75 \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A75) +#define MIDR_CORTEX_A35 \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A35) +#define MIDR_CORTEX_A55 \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A55) +#define MIDR_CORTEX_A76 \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A76) +#define MIDR_NEOVERSE_N1 \ + MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N1) +#define MIDR_CORTEX_A77 \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A77) + +#define MIDR_THUNDERX \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX) +#define MIDR_THUNDERX_81XX \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX) +#define MIDR_THUNDERX_83XX \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_83XX) +#define MIDR_CAVIUM_THUNDERX2 \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX2) + +#define MIDR_BRAHMA_B53 \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_BRCM, BRCM_CPU_PART_BRAHMA_B53) +#define MIDR_BRCM_VULCAN \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_BRCM, BRCM_CPU_PART_VULCAN) + +#define MIDR_QCOM_FALKOR_V1 \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_FALKOR_V1) +#define MIDR_QCOM_FALKOR \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_FALKOR) +#define MIDR_QCOM_KRYO MIDR_CPU_MODEL_IP(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO) +#define MIDR_QCOM_KRYO_2XX_GOLD \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_2XX_GOLD) +#define MIDR_QCOM_KRYO_2XX_SILVER \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_2XX_SILVER) +#define MIDR_QCOM_KRYO_3XX_SILVER \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_3XX_SILVER) +#define MIDR_QCOM_KRYO_4XX_GOLD \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_4XX_GOLD) +#define MIDR_QCOM_KRYO_4XX_SILVER \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_4XX_SILVER) + +#define MIDR_NVIDIA_DENVER \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_DENVER) +#define MIDR_NVIDIA_CARMEL \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_CARMEL) + +#define MIDR_FUJITSU_A64FX \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_FUJITSU, FUJITSU_CPU_PART_A64FX) + +#define MIDR_HISI_TSV110 \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_HISI, HISI_CPU_PART_TSV110) + +#define MIDR_APPLE_M1_ICESTORM \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM) +#define MIDR_APPLE_M1_FIRESTORM \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM) +#define MIDR_APPLE_M1_ICESTORM_TONGA \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM_TONGA) +#define MIDR_APPLE_M1_FIRESTORM_TONGA \ + MIDR_CPU_MODEL_IP(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM_TONGA) + +#define ID_AA64_SCHEME0_SHIFT 0 +#define ID_AA64_SCHEME1_SHIFT 4 +#define ID_AA64_SCHEME2_SHIFT 8 +#define ID_AA64_SCHEME3_SHIFT 12 +#define ID_AA64_SCHEME4_SHIFT 16 +#define ID_AA64_SCHEME5_SHIFT 20 +#define ID_AA64_SCHEME6_SHIFT 24 +#define ID_AA64_SCHEME7_SHIFT 28 +#define ID_AA64_SCHEME8_SHIFT 32 +#define ID_AA64_SCHEME9_SHIFT 36 +#define ID_AA64_SCHEME10_SHIFT 40 +#define ID_AA64_SCHEME11_SHIFT 44 +#define ID_AA64_SCHEME12_SHIFT 48 +#define ID_AA64_SCHEME13_SHIFT 52 +#define ID_AA64_SCHEME14_SHIFT 56 +#define ID_AA64_SCHEME15_SHIFT 60 + +#define ID_AA64_SCHEME_MODEL(r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, \ + r12, r13, r14, r15) \ + (((r15) << ID_AA64_SCHEME15_SHIFT) | ((r14) << ID_AA64_SCHEME14_SHIFT) | \ + ((r13) << ID_AA64_SCHEME13_SHIFT) | ((r12) << ID_AA64_SCHEME12_SHIFT) | \ + ((r11) << ID_AA64_SCHEME11_SHIFT) | ((r10) << ID_AA64_SCHEME10_SHIFT) | \ + ((r9) << ID_AA64_SCHEME9_SHIFT) | ((r8) << ID_AA64_SCHEME8_SHIFT) | \ + ((r7) << ID_AA64_SCHEME7_SHIFT) | ((r6) << ID_AA64_SCHEME6_SHIFT) | \ + ((r5) << ID_AA64_SCHEME5_SHIFT) | ((r4) << ID_AA64_SCHEME4_SHIFT) | \ + ((r3) << ID_AA64_SCHEME3_SHIFT) | ((r2) << ID_AA64_SCHEME2_SHIFT) | \ + ((r1) << ID_AA64_SCHEME1_SHIFT) | ((r0) << ID_AA64_SCHEME0_SHIFT)) + +/////////////////////////////////////////////////////////////////////////////// +// ID_AA64ISAR0_EL1 +/////////////////////////////////////////////////////////////////////////////// +#define ID_AA64ISAR0_EL1_ARM_CORTEX_A53_R3 \ + ID_AA64_SCHEME_MODEL(0UL, 2UL, 1UL, 1UL, 1UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, \ + 0UL, 0UL, 0UL, 0UL, 0UL) + +/////////////////////////////////////////////////////////////////////////////// +// ID_AA64PFR0_EL1 +/////////////////////////////////////////////////////////////////////////////// +#define ID_AA64PFR0_EL1_ARM_CORTEX_A53_R3 \ + ID_AA64_SCHEME_MODEL(0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, \ + 0UL, 0UL, 0UL, 0UL, 0UL) + +#endif // CPU_FEATURES_CPUTYPE_AARCH64_H_ diff --git a/src/define_cpuid_aarch64.inl b/src/define_cpuid_aarch64.inl new file mode 100644 index 00000000..55f8bada --- /dev/null +++ b/src/define_cpuid_aarch64.inl @@ -0,0 +1,69 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "stringize.inl" + +#define OP0_SHIFT 19 +#define OP1_SHIFT 16 +#define CRN_SHIFT 12 +#define CRM_SHIFT 8 +#define OP2_SHIFT 5 + +#define SYS_REG(op0, op1, crn, crm, op2) \ + (((op0) << OP0_SHIFT) | ((op1) << OP1_SHIFT) | ((crn) << CRN_SHIFT) | \ + ((crm) << CRM_SHIFT) | ((op2) << OP2_SHIFT)) + +#define SYS_MIDR_EL1 SYS_REG(3, 0, 0, 0, 0) + +#define SYS_ID_AA64PFR0_EL1 SYS_REG(3, 0, 0, 4, 0) +#define SYS_ID_AA64PFR1_EL1 SYS_REG(3, 0, 0, 4, 1) +#define SYS_ID_AA64ZFR0_EL1 SYS_REG(3, 0, 0, 4, 4) + +#define SYS_ID_AA64ISAR0_EL1 SYS_REG(3, 0, 0, 6, 0) +#define SYS_ID_AA64ISAR1_EL1 SYS_REG(3, 0, 0, 6, 1) + +#define SYS_ID_AA64MMFR2_EL1 SYS_REG(3, 0, 0, 7, 2) + +#if (defined(CPU_FEATURES_COMPILER_GCC) || defined(CPU_FEATURES_COMPILER_CLANG)) +#define EMIT_INST(x) ".inst " STRINGIZE((x)) "\n\t" + +#define DEFINE_MRS_MSR_S_REGNUM \ + " .irp " \ + "num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25, " \ + "26,27,28,29,30\n" \ + " .equ .L__reg_num_x\\num, \\num\n" \ + " .endr\n" \ + " .equ .L__reg_num_xzr, 31\n" + +#define DEFINE_MRS_S \ + DEFINE_MRS_MSR_S_REGNUM \ + " .macro mrs_s, rt, sreg\n" EMIT_INST( \ + 0xD5200000 | (\\sreg) | (.L__reg_num_\\rt)) " .endm\n" + +#define UNDEFINE_MRS_S " .purgem mrs_s\n" + +#define MRS_S(v, r) \ + DEFINE_MRS_S \ + " mrs_s " v ", " STRINGIZE(r) "\n" UNDEFINE_MRS_S + +// For registers without architectural names. +#define READ_SYS_REG_S(r) \ + ({ \ + uint64_t __val; \ + asm volatile(MRS_S("%0", r) : "=r"(__val)); \ + __val; \ + }) +#else +#error "Unsupported compiler, aarch64 cpuid requires either GCC or Clang." +#endif diff --git a/src/define_introspection.inl b/src/define_introspection.inl index c0eb916d..e2e2a92e 100644 --- a/src/define_introspection.inl +++ b/src/define_introspection.inl @@ -24,8 +24,7 @@ #include -#define STRINGIZE_(s) #s -#define STRINGIZE(s) STRINGIZE_(s) +#include "stringize.inl" #define FEAT_TYPE_NAME__(X) X##Features #define FEAT_TYPE_NAME_(X) FEAT_TYPE_NAME__(X) diff --git a/src/define_introspection_base_aarch64.inl b/src/define_introspection_base_aarch64.inl new file mode 100644 index 00000000..436eaa8a --- /dev/null +++ b/src/define_introspection_base_aarch64.inl @@ -0,0 +1,58 @@ +//////////////////////////////////////////////////////////////////////////////// +// Definitions for introspection. +//////////////////////////////////////////////////////////////////////////////// +#define INTROSPECTION_TABLE \ + LINE(AARCH64_FP, fp, , , ) \ + LINE(AARCH64_ASIMD, asimd, , , ) \ + LINE(AARCH64_EVTSTRM, evtstrm, , , ) \ + LINE(AARCH64_AES, aes, , , ) \ + LINE(AARCH64_PMULL, pmull, , , ) \ + LINE(AARCH64_SHA1, sha1, , , ) \ + LINE(AARCH64_SHA2, sha2, , , ) \ + LINE(AARCH64_CRC32, crc32, , , ) \ + LINE(AARCH64_ATOMICS, atomics, , , ) \ + LINE(AARCH64_FPHP, fphp, , , ) \ + LINE(AARCH64_ASIMDHP, asimdhp, , , ) \ + LINE(AARCH64_CPUID, cpuid, , , ) \ + LINE(AARCH64_ASIMDRDM, asimdrdm, , , ) \ + LINE(AARCH64_JSCVT, jscvt, , , ) \ + LINE(AARCH64_FCMA, fcma, , , ) \ + LINE(AARCH64_LRCPC, lrcpc, , , ) \ + LINE(AARCH64_DCPOP, dcpop, , , ) \ + LINE(AARCH64_SHA3, sha3, , , ) \ + LINE(AARCH64_SM3, sm3, , , ) \ + LINE(AARCH64_SM4, sm4, , , ) \ + LINE(AARCH64_ASIMDDP, asimddp, , , ) \ + LINE(AARCH64_SHA512, sha512, , , ) \ + LINE(AARCH64_SVE, sve, , , ) \ + LINE(AARCH64_ASIMDFHM, asimdfhm, , , ) \ + LINE(AARCH64_DIT, dit, , , ) \ + LINE(AARCH64_USCAT, uscat, , , ) \ + LINE(AARCH64_ILRCPC, ilrcpc, , , ) \ + LINE(AARCH64_FLAGM, flagm, , , ) \ + LINE(AARCH64_SSBS, ssbs, , , ) \ + LINE(AARCH64_SB, sb, , , ) \ + LINE(AARCH64_PACA, paca, , , ) \ + LINE(AARCH64_PACG, pacg, , , ) \ + LINE(AARCH64_DCPODP, dcpodp, , , ) \ + LINE(AARCH64_SVE2, sve2, , , ) \ + LINE(AARCH64_SVEAES, sveaes, , , ) \ + LINE(AARCH64_SVEPMULL, svepmull, , , ) \ + LINE(AARCH64_SVEBITPERM, svebitperm, , , ) \ + LINE(AARCH64_SVESHA3, svesha3, , , ) \ + LINE(AARCH64_SVESM4, svesm4, , , ) \ + LINE(AARCH64_FLAGM2, flagm2, , , ) \ + LINE(AARCH64_FRINT, frint, , , ) \ + LINE(AARCH64_SVEI8MM, svei8mm, , , ) \ + LINE(AARCH64_SVEF32MM, svef32mm, , , ) \ + LINE(AARCH64_SVEF64MM, svef64mm, , , ) \ + LINE(AARCH64_SVEBF16, svebf16, , , ) \ + LINE(AARCH64_I8MM, i8mm, , , ) \ + LINE(AARCH64_BF16, bf16, , , ) \ + LINE(AARCH64_DGH, dgh, , , ) \ + LINE(AARCH64_RNG, rng, , , ) \ + LINE(AARCH64_BTI, bti, , , ) \ + LINE(AARCH64_MTE, mte, , , ) +#define INTROSPECTION_PREFIX Aarch64 +#define INTROSPECTION_ENUM_PREFIX AARCH64 +#include "define_introspection.inl" diff --git a/src/impl_aarch64__base_implementation.inl b/src/impl_aarch64__base_implementation.inl new file mode 100644 index 00000000..f6e9f179 --- /dev/null +++ b/src/impl_aarch64__base_implementation.inl @@ -0,0 +1,205 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "cpuinfo_aarch64.h" +#include "define_cpuid_aarch64.inl" +#include "internal/bit_utils.h" +#include "internal/cpuid_aarch64.h" + +#ifndef CPU_FEATURES_ARCH_AARCH64 +#error "Cannot compile cpuinfo_aarch64 on a non aarch64 platform." +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Aarch64 info via mrs instruction +/////////////////////////////////////////////////////////////////////////////// + +#ifdef CPU_FEATURES_MOCK_CPUID_AARCH64 +// Implementation will be provided by test/cpuinfo_aarch64_test.cc. +#else +uint64_t GetCpuid_MIDR_EL1() { return READ_SYS_REG_S(SYS_MIDR_EL1); } + +uint64_t GetCpuid_ID_AA64PFR0_EL1() { + return READ_SYS_REG_S(SYS_ID_AA64PFR0_EL1); +} + +uint64_t GetCpuid_ID_AA64ISAR0_EL1() { + return READ_SYS_REG_S(SYS_ID_AA64ISAR0_EL1); +} + +uint64_t GetCpuid_ID_AA64ISAR1_EL1() { + return READ_SYS_REG_S(SYS_ID_AA64ISAR1_EL1); +} + +uint64_t GetCpuid_ID_AA64ZFR0_EL1() { + return READ_SYS_REG_S(SYS_ID_AA64ZFR0_EL1); +} + +uint64_t GetCpuid_ID_AA64MMFR2_EL1() { + return READ_SYS_REG_S(SYS_ID_AA64MMFR2_EL1); +} + +uint64_t GetCpuid_ID_AA64PFR1_EL1() { + return READ_SYS_REG_S(SYS_ID_AA64PFR1_EL1); +} +#endif + +#define ID_SCHEME(reg, msb, lsb) ExtractBitRange((reg), (msb), (lsb)) >= 1 + +// This function have to be implemented by the OS or +// can use base implementation DetectFeaturesBase. +static void DetectFeatures(Aarch64Info* info); + +static void DetectFeaturesBase(Aarch64Info* info) { + // ID_AA64PFR0_EL1 + const uint64_t pfr0 = GetCpuid_ID_AA64PFR0_EL1(); + + info->features.sve = ID_SCHEME(pfr0, 35, 32); + info->features.dit = ID_SCHEME(pfr0, 51, 48); + + const uint64_t fp = ExtractBitRange(pfr0, 19, 16); + + // fp_value = 0b0000: + // Floating-point is implemented, and includes support for: + // * Single-precision and double-precision floating-point types. + // * Conversions between single-precision and half-precision data types, + // and double-precision and half-precision data types. + if (fp == 0) info->features.fp = 1; + + // fp_value = 0b0001: + // As for 0b0000, and also includes support for half-precision + // floating-point arithmetic. + if (fp == 1) { + info->features.fp = 1; + info->features.fphp = 1; + } + + const uint64_t asimd = ExtractBitRange(pfr0, 23, 20); + + // Advanced SIMD is implemented, including support for the following SISD and + // SIMD operations: + // * Integer byte, halfword, word and doubleword element operations. + // * Single-precision and double-precision floating-point arithmetic. + // * Conversions between single-precision and half-precision data types, + // and double-precision and half-precision data types. + if (asimd == 0) info->features.asimd = 1; + + // asimd = 0b0001: + // As for 0b0000, and also includes support for half-precision + // floating-point arithmetic. + if (asimd == 1) { + info->features.asimd = 1; + info->features.asimdhp = 1; + } + + // ID_AA64PFR1_EL1 + const uint64_t pfr1 = GetCpuid_ID_AA64PFR1_EL1(); + info->features.bti = ID_SCHEME(pfr1, 3, 0); + + const uint64_t ssbs = ExtractBitRange(pfr1, 7, 4); + if (ssbs >= 2) info->features.ssbs = 1; + + info->features.bti = ID_SCHEME(pfr1, 11, 8); + + // ID_AA64ISAR0_EL1 + const uint64_t isa0 = GetCpuid_ID_AA64ISAR0_EL1(); + const uint64_t aes = ExtractBitRange(isa0, 7, 4); + if (aes >= 1) info->features.aes = 1; + if (aes >= 2) info->features.pmull = 1; + + info->features.sha1 = ID_SCHEME(isa0, 11, 8); + + const uint64_t sha2 = ExtractBitRange(isa0, 15, 12); + if (sha2 >= 1) info->features.sha2 = 1; + if (sha2 >= 2) info->features.sha512 = 1; + + info->features.crc32 = ID_SCHEME(isa0, 19, 16); + info->features.atomics = ID_SCHEME(isa0, 23, 20); + info->features.asimdrdm = ID_SCHEME(isa0, 31, 28); + info->features.sha3 = ID_SCHEME(isa0, 35, 32); + info->features.sm3 = ID_SCHEME(isa0, 39, 36); + info->features.sm4 = ID_SCHEME(isa0, 43, 40); + info->features.asimddp = ID_SCHEME(isa0, 47, 44); + info->features.asimdfhm = ID_SCHEME(isa0, 51, 48); + + const uint64_t ts = ExtractBitRange(isa0, 55, 52); + if (ts >= 1) info->features.flagm = 1; + if (ts >= 2) info->features.flagm2 = 1; + + info->features.rng = ID_SCHEME(isa0, 63, 60); + + // ID_AA64ISAR1_EL1 + const uint64_t isa1 = GetCpuid_ID_AA64ISAR1_EL1(); + const uint64_t dpb = ExtractBitRange(isa1, 3, 0); + if (dpb >= 1) info->features.dcpop = 1; + if (dpb >= 2) info->features.dcpodp = 1; + + const uint64_t apa = ExtractBitRange(isa1, 7, 4); + const uint64_t api = ExtractBitRange(isa1, 11, 8); + if (apa >= 1 || api >= 1) info->features.paca = 1; + + info->features.jscvt = ID_SCHEME(isa1, 15, 12); + info->features.fcma = ID_SCHEME(isa1, 19, 16); + + const uint64_t lrcpc = ExtractBitRange(isa1, 23, 20); + if (lrcpc >= 1) info->features.lrcpc = 1; + if (lrcpc >= 2) info->features.ilrcpc = 1; + + const uint64_t gpa = ExtractBitRange(isa1, 27, 24); + const uint64_t gpi = ExtractBitRange(isa1, 31, 28); + if (gpa >= 1 || gpi >= 1) info->features.pacg = 1; + + info->features.frint = ID_SCHEME(isa1, 35, 32); + info->features.sb = ID_SCHEME(isa1, 39, 36); + info->features.bf16 = ID_SCHEME(isa1, 47, 44); + info->features.dgh = ID_SCHEME(isa1, 51, 48); + info->features.i8mm = ID_SCHEME(isa1, 55, 52); + + // ID_AA64ZFR0_EL1 + if (info->features.sve) { + const uint64_t zfr0 = GetCpuid_ID_AA64ZFR0_EL1(); + info->features.sve2 = ID_SCHEME(zfr0, 0, 3); + info->features.svebitperm = ID_SCHEME(zfr0, 19, 16); + info->features.svebf16 = ID_SCHEME(zfr0, 23, 20); + info->features.svesha3 = ID_SCHEME(zfr0, 35, 32); + info->features.svesm4 = ID_SCHEME(zfr0, 43, 40); + info->features.svei8mm = ID_SCHEME(zfr0, 47, 44); + info->features.svef32mm = ID_SCHEME(zfr0, 55, 52); + info->features.svef64mm = ID_SCHEME(zfr0, 59, 56); + + const uint64_t sveaes = ExtractBitRange(zfr0, 7, 4); + if (sveaes >= 1) info->features.sveaes = 1; + if (sveaes >= 2) info->features.svepmull = 1; + } + + // ID_AA64MMFR2_EL1 + const uint64_t mmfr2 = GetCpuid_ID_AA64MMFR2_EL1(); + info->features.uscat = ID_SCHEME(mmfr2, 35, 32); +} + +static const Aarch64Info kEmptyAarch64Info; + +Aarch64Info GetAarch64Info(void) { + Aarch64Info info = kEmptyAarch64Info; + const uint64_t midr = GetCpuid_MIDR_EL1(); + if (midr) { + info.features.cpuid = 1; + info.implementer = ExtractBitRange(midr, 31, 24); + info.variant = ExtractBitRange(midr, 23, 20); + info.part = ExtractBitRange(midr, 15, 4); + info.revision = ExtractBitRange(midr, 3, 0); + DetectFeatures(&info); + } + return info; +} diff --git a/src/impl_aarch64_freebsd.c b/src/impl_aarch64_freebsd.c new file mode 100644 index 00000000..0507d8f0 --- /dev/null +++ b/src/impl_aarch64_freebsd.c @@ -0,0 +1,26 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "cpu_features_macros.h" + +#ifdef CPU_FEATURES_ARCH_AARCH64 +#ifdef CPU_FEATURES_OS_FREEBSD +#include "cpuinfo_aarch64.h" +#include "define_introspection_base_aarch64.inl" +#include "impl_aarch64__base_implementation.inl" + +static void DetectFeatures(Aarch64Info* info) { DetectFeaturesBase(info); } + +#endif // CPU_FEATURES_OS_FREEBSD +#endif // CPU_FEATURES_ARCH_AARCH64 diff --git a/src/impl_aarch64_linux_or_android.c b/src/impl_aarch64_linux_or_android.c index 745beb9c..dd6a0e90 100644 --- a/src/impl_aarch64_linux_or_android.c +++ b/src/impl_aarch64_linux_or_android.c @@ -16,7 +16,6 @@ #ifdef CPU_FEATURES_ARCH_AARCH64 #if defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID) - #include "cpuinfo_aarch64.h" //////////////////////////////////////////////////////////////////////////////// @@ -78,6 +77,7 @@ #define INTROSPECTION_PREFIX Aarch64 #define INTROSPECTION_ENUM_PREFIX AARCH64 #include "define_introspection_and_hwcaps.inl" +#include "impl_aarch64__base_implementation.inl" //////////////////////////////////////////////////////////////////////////////// // Implementation. @@ -85,10 +85,8 @@ #include -#include "internal/bit_utils.h" #include "internal/filesystem.h" #include "internal/stack_line_reader.h" -#include "internal/string_view.h" static bool HandleAarch64Line(const LineResult result, Aarch64Info* const info) { @@ -100,14 +98,6 @@ static bool HandleAarch64Line(const LineResult result, kSetters[i](&info->features, CpuFeatures_StringView_HasWord( value, kCpuInfoFlags[i], ' ')); } - } else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer"))) { - info->implementer = CpuFeatures_StringView_ParsePositiveNumber(value); - } else if (CpuFeatures_StringView_IsEquals(key, str("CPU variant"))) { - info->variant = CpuFeatures_StringView_ParsePositiveNumber(value); - } else if (CpuFeatures_StringView_IsEquals(key, str("CPU part"))) { - info->part = CpuFeatures_StringView_ParsePositiveNumber(value); - } else if (CpuFeatures_StringView_IsEquals(key, str("CPU revision"))) { - info->revision = CpuFeatures_StringView_ParsePositiveNumber(value); } } return !result.eof; @@ -127,23 +117,17 @@ static void FillProcCpuInfoData(Aarch64Info* const info) { } } -static const Aarch64Info kEmptyAarch64Info; - -Aarch64Info GetAarch64Info(void) { - // capabilities are fetched from both getauxval and /proc/cpuinfo so we can - // have some information if the executable is sandboxed (aka no access to - // /proc/cpuinfo). - Aarch64Info info = kEmptyAarch64Info; - - FillProcCpuInfoData(&info); +// capabilities are fetched from both getauxval and /proc/cpuinfo so we can +// have some information if the executable is sandboxed (aka no access to +// /proc/cpuinfo). +static void DetectFeatures(Aarch64Info* info) { + FillProcCpuInfoData(info); const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities(); for (size_t i = 0; i < AARCH64_LAST_; ++i) { if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) { - kSetters[i](&info.features, true); + kSetters[i](&info->features, true); } } - - return info; } #endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID) diff --git a/src/impl_aarch64_macos_or_iphone.c b/src/impl_aarch64_macos_or_iphone.c new file mode 100644 index 00000000..91e7aa43 --- /dev/null +++ b/src/impl_aarch64_macos_or_iphone.c @@ -0,0 +1,26 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "cpu_features_macros.h" + +#ifdef CPU_FEATURES_ARCH_AARCH64 +#if defined(CPU_FEATURES_OS_MACOS) || defined(CPU_FEATURES_OS_IPHONE) +#include "cpuinfo_aarch64.h" +#include "define_introspection_base_aarch64.inl" +#include "impl_aarch64__base_implementation.inl" + +static void DetectFeatures(Aarch64Info* info) { DetectFeaturesBase(info); } + +#endif // defined(CPU_FEATURES_OS_MACOS) || defined(CPU_FEATURES_OS_IPHONE) +#endif // CPU_FEATURES_ARCH_AARCH64 diff --git a/src/stringize.inl b/src/stringize.inl new file mode 100644 index 00000000..c13eea0b --- /dev/null +++ b/src/stringize.inl @@ -0,0 +1,16 @@ +// Copyright 2017 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#define STRINGIZE_(s) #s +#define STRINGIZE(s) STRINGIZE_(s) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8e8f72af..3e5ce264 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -71,7 +71,13 @@ endif() ##------------------------------------------------------------------------------ ## cpuinfo_aarch64_test if(PROCESSOR_IS_AARCH64) - add_executable(cpuinfo_aarch64_test cpuinfo_aarch64_test.cc ../src/impl_aarch64_linux_or_android.c) + add_executable(cpuinfo_aarch64_test + cpuinfo_aarch64_test.cc + ../src/impl_aarch64_linux_or_android.c + ../src/impl_aarch64_macos_or_iphone.c + ../src/impl_aarch64_freebsd.c + ) + target_compile_definitions(cpuinfo_aarch64_test PUBLIC CPU_FEATURES_MOCK_CPUID_AARCH64) target_link_libraries(cpuinfo_aarch64_test all_libraries) add_test(NAME cpuinfo_aarch64_test COMMAND cpuinfo_aarch64_test) endif() diff --git a/test/cpuinfo_aarch64_test.cc b/test/cpuinfo_aarch64_test.cc index 04b61438..f1cf94ee 100644 --- a/test/cpuinfo_aarch64_test.cc +++ b/test/cpuinfo_aarch64_test.cc @@ -14,19 +14,117 @@ #include "cpuinfo_aarch64.h" +#include + #include "filesystem_for_testing.h" #include "gtest/gtest.h" #include "hwcaps_for_testing.h" +#include "internal/cpuid_aarch64.h" namespace cpu_features { namespace { +class FakeCpuAarch64 { + public: + uint64_t GetCpuid_MIDR_EL1() const { return _midr_el1; } + + uint64_t GetCpuid_ID_AA64ISAR0_EL1() const { return _id_aa64isar0_el1; } + uint64_t GetCpuid_ID_AA64ISAR1_EL1() const { return _id_aa64isar1_el1; } + uint64_t GetCpuid_ID_AA64PFR0_EL1() const { return _id_aa64pfr0_el1; } + uint64_t GetCpuid_ID_AA64ZFR0_EL1() const { return _id_aa64zfr0_el1; } + uint64_t GetCpuid_ID_AA64PFR1_EL1() const { return _id_aa64pfr1_el1; } + uint64_t GetCpuid_ID_AA64MMFR2_EL1() const { return _id_aa64mmfr2_el1; } + + void SetCpuid_MIDR_EL1(uint64_t midr_el1) { _midr_el1 = midr_el1; } + + void SetCpuid_ID_AA64ISAR0_EL1(uint64_t id_aa64isar0_el1) { + _id_aa64isar0_el1 = id_aa64isar0_el1; + } + + void SetCpuid_ID_AA64ISAR1_EL1(uint64_t id_aa64isar1_el1) { + _id_aa64isar1_el1 = id_aa64isar1_el1; + } + + void SetCpuid_ID_AA64PFR0_EL1(uint64_t id_aa64pfr0_el1) { + _id_aa64pfr0_el1 = id_aa64pfr0_el1; + } + + void SetCpuid_ID_AA64ZFR0_EL1(uint64_t id_aa64zfr0_el1) { + _id_aa64pfr0_el1 = id_aa64zfr0_el1; + } + + void SetCpuid_ID_AA64PFR1_EL1(uint64_t id_aa64pfr1_el1) { + _id_aa64pfr1_el1 = id_aa64pfr1_el1; + } + + void SetCpuid_ID_AA64MMFR2_EL1(uint64_t id_aa64mmfr2_el1) { + _id_aa64mmfr2_el1 = id_aa64mmfr2_el1; + } + + private: + uint64_t _midr_el1; + uint64_t _id_aa64isar0_el1; + uint64_t _id_aa64isar1_el1; + uint64_t _id_aa64pfr0_el1; + uint64_t _id_aa64zfr0_el1; + uint64_t _id_aa64mmfr2_el1; + uint64_t _id_aa64pfr1_el1; +}; + +FakeCpuAarch64* g_fake_cpu_aarch64; + +FakeCpuAarch64& cpu() { + assert(g_fake_cpu_aarch64 != nullptr); + return *g_fake_cpu_aarch64; +} + +extern "C" uint64_t GetCpuid_MIDR_EL1() { return cpu().GetCpuid_MIDR_EL1(); } + +extern "C" uint64_t GetCpuid_ID_AA64ISAR0_EL1() { + return cpu().GetCpuid_ID_AA64ISAR0_EL1(); +} + +extern "C" uint64_t GetCpuid_ID_AA64ISAR1_EL1() { + return cpu().GetCpuid_ID_AA64ISAR1_EL1(); +} + +extern "C" uint64_t GetCpuid_ID_AA64PFR0_EL1() { + return cpu().GetCpuid_ID_AA64ISAR1_EL1(); +} + +extern "C" uint64_t GetCpuid_ID_AA64ZFR0_EL1() { + return cpu().GetCpuid_ID_AA64ISAR1_EL1(); +} + +extern "C" uint64_t GetCpuid_ID_AA64PFR1_EL1() { + return cpu().GetCpuid_ID_AA64PFR1_EL1(); +} + +extern "C" uint64_t GetCpuid_ID_AA64MMFR2_EL1() { + return cpu().GetCpuid_ID_AA64MMFR2_EL1(); +} + void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); } -TEST(CpuinfoAarch64Test, FromHardwareCap) { +class CpuInfoAarch64Test : public ::testing::Test { + protected: + void SetUp() override { + assert(g_fake_cpu_aarch64 == nullptr); + g_fake_cpu_aarch64 = new FakeCpuAarch64(); + } + + void TearDown() override { + delete g_fake_cpu_aarch64; + g_fake_cpu_aarch64 = nullptr; + } +}; + +#if defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID) +TEST_F(CpuInfoAarch64Test, FromHardwareCap_HWCAP) { ResetHwcaps(); SetHardwareCapabilities(AARCH64_HWCAP_FP | AARCH64_HWCAP_AES, 0); GetEmptyFilesystem(); // disabling /proc/cpuinfo + cpu().SetCpuid_MIDR_EL1(1); const auto info = GetAarch64Info(); EXPECT_TRUE(info.features.fp); EXPECT_FALSE(info.features.asimd); @@ -39,7 +137,7 @@ TEST(CpuinfoAarch64Test, FromHardwareCap) { EXPECT_FALSE(info.features.atomics); EXPECT_FALSE(info.features.fphp); EXPECT_FALSE(info.features.asimdhp); - EXPECT_FALSE(info.features.cpuid); + EXPECT_TRUE(info.features.cpuid); EXPECT_FALSE(info.features.asimdrdm); EXPECT_FALSE(info.features.jscvt); EXPECT_FALSE(info.features.fcma); @@ -62,11 +160,12 @@ TEST(CpuinfoAarch64Test, FromHardwareCap) { EXPECT_FALSE(info.features.pacg); } -TEST(CpuinfoAarch64Test, FromHardwareCap2) { +TEST_F(CpuInfoAarch64Test, FromHardwareCap2_HWCAP2) { ResetHwcaps(); SetHardwareCapabilities(AARCH64_HWCAP_FP, AARCH64_HWCAP2_SVE2 | AARCH64_HWCAP2_BTI); GetEmptyFilesystem(); // disabling /proc/cpuinfo + cpu().SetCpuid_MIDR_EL1(1); const auto info = GetAarch64Info(); EXPECT_TRUE(info.features.fp); @@ -91,7 +190,7 @@ TEST(CpuinfoAarch64Test, FromHardwareCap2) { EXPECT_FALSE(info.features.rng); } -TEST(CpuinfoAarch64Test, ARMCortexA53) { +TEST_F(CpuInfoAarch64Test, ARMCortexA53_PROC_CPUINFO) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); fs.CreateFile("/proc/cpuinfo", @@ -110,6 +209,7 @@ CPU architecture: AArch64 CPU variant : 0x0 CPU part : 0xd03 CPU revision : 3)"); + cpu().SetCpuid_MIDR_EL1(MIDR_CORTEX_A53_R3); const auto info = GetAarch64Info(); EXPECT_EQ(info.implementer, 0x41); EXPECT_EQ(info.variant, 0x0); @@ -169,6 +269,58 @@ CPU revision : 3)"); EXPECT_FALSE(info.features.bti); EXPECT_FALSE(info.features.mte); } +#else +TEST_F(CpuInfoAarch64Test, ARM_CORTEX_A72_MRS_MIDR_EL1) { + cpu().SetCpuid_MIDR_EL1(MIDR_CORTEX_A72); + const auto info = GetAarch64Info(); + EXPECT_EQ(info.implementer, 0x41); + EXPECT_EQ(info.variant, 0x0); + EXPECT_EQ(info.part, 0xD08); + EXPECT_EQ(info.revision, 0); +} + +TEST_F(CpuInfoAarch64Test, ARM_CORTEX_A53_R3_MRS_ID_AA64ISAR0_EL1) { + cpu().SetCpuid_MIDR_EL1(MIDR_CORTEX_A53_R3); + cpu().SetCpuid_ID_AA64ISAR0_EL1(ID_AA64ISAR0_EL1_ARM_CORTEX_A53_R3); + const auto info = GetAarch64Info(); + EXPECT_EQ(info.implementer, 0x41); + EXPECT_EQ(info.variant, 0x0); + EXPECT_EQ(info.part, 0xD03); + EXPECT_EQ(info.revision, 3); + + EXPECT_TRUE(info.features.cpuid); + EXPECT_TRUE(info.features.aes); + EXPECT_TRUE(info.features.pmull); + EXPECT_TRUE(info.features.sha1); + EXPECT_TRUE(info.features.sha2); + EXPECT_TRUE(info.features.crc32); + EXPECT_TRUE(info.features.cpuid); + EXPECT_FALSE(info.features.atomics); + EXPECT_FALSE(info.features.sha3); + EXPECT_FALSE(info.features.sm3); + EXPECT_FALSE(info.features.sm4); +} + +TEST_F(CpuInfoAarch64Test, ARM_CORTEX_A53_R3_MRS_ID_AA64PFR0_EL1) { + cpu().SetCpuid_MIDR_EL1(MIDR_CORTEX_A53_R3); + cpu().SetCpuid_ID_AA64PFR0_EL1(ID_AA64PFR0_EL1_ARM_CORTEX_A53_R3); + const auto info = GetAarch64Info(); + + EXPECT_EQ(info.implementer, 0x41); + EXPECT_EQ(info.variant, 0x0); + EXPECT_EQ(info.part, 0xD03); + EXPECT_EQ(info.revision, 3); + + EXPECT_TRUE(info.features.cpuid); + EXPECT_TRUE(info.features.asimd); + EXPECT_TRUE(info.features.fp); + EXPECT_FALSE(info.features.atomics); + EXPECT_FALSE(info.features.sve); + EXPECT_FALSE(info.features.dit); + EXPECT_FALSE(info.features.fphp); + EXPECT_FALSE(info.features.asimdhp); +} +#endif } // namespace } // namespace cpu_features