From c5885699f0ec862fa43012ce92361c4b15687bc0 Mon Sep 17 00:00:00 2001 From: The Tumultuous Unicorn Of Darkness Date: Fri, 28 Jun 2024 20:41:00 +0200 Subject: [PATCH] Add initial support for ARM CPUs Close #200 --- .github/workflows/release.yml | 38 +- .github/workflows/unix.yml | 12 +- .github/workflows/windows.yml | 8 +- CMakeLists.txt | 15 +- configure.ac | 16 + cpuid_tool/cpuid_tool.c | 142 ++-- libcpuid/CMakeLists.txt | 1 + libcpuid/Makefile.am | 2 + libcpuid/Makefile.x64 | 5 +- libcpuid/Makefile.x86 | 5 +- libcpuid/asm-bits.c | 9 +- libcpuid/asm-bits.h | 33 +- libcpuid/check-consistency.py | 24 +- libcpuid/cpuid_main.c | 717 ++++++++++++++--- libcpuid/exports.def | 1 + libcpuid/libcpuid.dsp | 8 + libcpuid/libcpuid.h | 465 ++++++++++- libcpuid/libcpuid.sym | 1 + libcpuid/libcpuid_constants.h | 8 +- libcpuid/libcpuid_internal.h | 2 +- libcpuid/libcpuid_util.c | 24 +- libcpuid/libcpuid_util.h | 1 + libcpuid/libcpuid_vc10.vcxproj | 2 + libcpuid/libcpuid_vc10.vcxproj.filters | 6 + libcpuid/libcpuid_vc71.vcproj | 6 + libcpuid/rdmsr.c | 10 +- libcpuid/rdtsc.c | 12 +- libcpuid/recog_amd.c | 8 +- libcpuid/recog_arm.c | 1011 ++++++++++++++++++++++++ libcpuid/recog_arm.h | 33 + libcpuid/recog_intel.c | 36 +- tests/arm/armv8a/cortex-a53.test | 87 ++ tests/arm/armv8a/cortex-a57-qemu.test | 87 ++ tests/arm/armv9a/neoverse-n2-qemu.test | 87 ++ tests/create_test.py | 7 +- tests/run_tests.py | 12 +- utils/parse_arm_arm_pdf.sh | 47 ++ 37 files changed, 2709 insertions(+), 279 deletions(-) create mode 100644 libcpuid/recog_arm.c create mode 100644 libcpuid/recog_arm.h create mode 100644 tests/arm/armv8a/cortex-a53.test create mode 100644 tests/arm/armv8a/cortex-a57-qemu.test create mode 100644 tests/arm/armv9a/neoverse-n2-qemu.test create mode 100755 utils/parse_arm_arm_pdf.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2d007a2..3363b8b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,36 +23,45 @@ jobs: ./configure make dist - - name: Download macOS artifacts + - name: Download macOS x86_64 artifacts uses: dawidd6/action-download-artifact@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} workflow: unix.yml commit: ${{ github.sha }} - name: macos - path: macos + name: macos-x86_64 + path: macos-x86_64 - - name: Download Windows (32-bit) artifacts + - name: Download macOS AArch64 artifacts + uses: dawidd6/action-download-artifact@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + workflow: unix.yml + commit: ${{ github.sha }} + name: macos-aarch64 + path: macos-aarch64 + + - name: Download Windows ix86 artifacts uses: dawidd6/action-download-artifact@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} workflow: windows.yml commit: ${{ github.sha }} - name: win32 - path: win32 + name: windows-ix86 + path: windows-ix86 - - name: Download Windows (64-bit) artifacts + - name: Download Windows x86_64 artifacts uses: dawidd6/action-download-artifact@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} workflow: windows.yml commit: ${{ github.sha }} - name: win64 - path: win64 + name: window-x86_64 + path: window-x86_64 - name: Compress artifacts run: | - for dir in macos win32 win64; do + for dir in macos-* windows-*; do zip -r "libcpuid-$VERSION-$dir.zip" "$dir" done env: @@ -70,7 +79,8 @@ jobs: As a convenience, the following binaries are provided: - A source tarball; - - Build for 64-bit macOS (built under [macOS 14.X](https://github.com/actions/runner-images/blob/main/images/macos/macos-14-Readme.md)); - - Build for 32-bit Windows, using MSVC XX.XX, in Debug, Release and Release DLL configurations (built under [Windows Server 2022](https://github.com/actions/runner-images/blob/main/images/windows/Windows2022-Readme.md)); - - Build for 64-bit Windows, using MSVC XX.XX, in Debug, Release and Release DLL configurations (built under [Windows Server 2022](https://github.com/actions/runner-images/blob/main/images/windows/Windows2022-Readme.md)). - artifacts: "libcpuid-${{ env.VERSION }}.tar.gz,libcpuid-${{ env.VERSION }}-macos.zip,libcpuid-${{ env.VERSION }}-win32.zip,libcpuid-${{ env.VERSION }}-win64.zip" + - Build for x86_64 macOS (built under [macOS 13.X](https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md)); + - Build for AArch64 macOS (built under [macOS 14.X](https://github.com/actions/runner-images/blob/main/images/macos/macos-14-Readme.md)); + - Build for ix86 Windows, using MSVC XX.XX, in Debug, Release and Release DLL configurations (built under [Windows Server 2022](https://github.com/actions/runner-images/blob/main/images/windows/Windows2022-Readme.md)); + - Build for x86_64 Windows, using MSVC XX.XX, in Debug, Release and Release DLL configurations (built under [Windows Server 2022](https://github.com/actions/runner-images/blob/main/images/windows/Windows2022-Readme.md)). + artifacts: "libcpuid-${{ env.VERSION }}.tar.gz,libcpuid-${{ env.VERSION }}-macos-x86_64.zip,libcpuid-${{ env.VERSION }}-macos-aarch64.zip,libcpuid-${{ env.VERSION }}-windows-ix86.zip,libcpuid-${{ env.VERSION }}-window-x86_64.zip" diff --git a/.github/workflows/unix.yml b/.github/workflows/unix.yml index 4e97a9f..e21d1b5 100644 --- a/.github/workflows/unix.yml +++ b/.github/workflows/unix.yml @@ -15,8 +15,9 @@ jobs: strategy: matrix: os: - - { label: macos-latest, name: macos } - - { label: ubuntu-latest, name: linux } + - { label: macos-latest, name: macos-aarch64 } + - { label: macos-13, name: macos-x86_64 } + - { label: ubuntu-latest, name: linux-x86_64 } env: OS_NAME: ${{ matrix.os.name }} @@ -29,6 +30,13 @@ jobs: - name: Build run: cmake --build build + # - name: Run cpuid_tool + # run: | + # echo "RAW dump" + # ./build/cpuid_tool/cpuid_tool --save=- + # echo "Report" + # ./build/cpuid_tool/cpuid_tool --all + - name: Run tests run: | make -C build consistency diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index d42375e..1cd1277 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -16,8 +16,8 @@ jobs: matrix: config: [Debug, Release, ReleaseDLL] platform: - - { bitness: x32, ms: Win32, name: win32 } - - { bitness: x64, ms: x64, name: win64 } + - { bitness: x32, ms: Win32, name: windows-ix86 } + - { bitness: x64, ms: x64, name: window-x86_64 } env: CONFIG: ${{ matrix.config }} BITNESS: ${{ matrix.platform.bitness }} @@ -73,8 +73,8 @@ jobs: strategy: matrix: platform: - - win32 - - win64 + - windows-ix86 + - window-x86_64 steps: - name: Merge artifacts for ${{ matrix.platform }} diff --git a/CMakeLists.txt b/CMakeLists.txt index b0bfba5..261025d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,19 @@ if(HAVE_POPCOUNT64) add_definitions(-DHAVE_POPCOUNT64) endif(HAVE_POPCOUNT64) +# check if auxiliary vector is available +if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + check_symbol_exists(getauxval "sys/auxv.h" HAVE_GETAUXVAL) + if(HAVE_GETAUXVAL) + add_definitions(-DHAVE_GETAUXVAL) + endif(HAVE_GETAUXVAL) +elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") + check_symbol_exists(elf_aux_info "sys/auxv.h" HAVE_ELF_AUX_INFO) + if(HAVE_ELF_AUX_INFO) + add_definitions(-DHAVE_ELF_AUX_INFO) + endif(HAVE_ELF_AUX_INFO) +endif() + # Global variables list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") @@ -42,7 +55,7 @@ if(UNIX) set(exec_prefix "\${prefix}") set(libdir "\${exec_prefix}/lib") set(includedir "\${prefix}/include") - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wall -Wuninitialized -Wstrict-prototypes -Wformat -Wformat-security -Wunused-parameter") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wall -Wuninitialized -Wstrict-prototypes -Wformat -Wformat-security -Wunused-parameter -Wno-deprecated-declarations") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/libcpuid.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/libcpuid.pc" ESCAPE_QUOTES @ONLY) install(FILES "${PROJECT_BINARY_DIR}/libcpuid.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") diff --git a/configure.ac b/configure.ac index 8ff08ff..95bb964 100644 --- a/configure.ac +++ b/configure.ac @@ -67,6 +67,8 @@ AC_CANONICAL_HOST build_windows=no build_netbsd=no build_dragonflybsd=no +build_freebsd=no +build_linux=no case "${host_os}" in cygwin*|mingw*) @@ -78,6 +80,12 @@ case "${host_os}" in dragonfly*) build_dragonflybsd=yes ;; + freebsd*) + build_freebsd=yes + ;; + linux*) + build_linux=yes + ;; esac if test "$build_windows" = "no"; then @@ -88,6 +96,14 @@ if test "$build_netbsd" = "yes" || test "$build_dragonflybsd" = "yes"; then AM_LDFLAGS="$AM_LDFLAGS -pthread" fi +if test "$build_linux" = "yes"; then + AC_CHECK_FUNCS([getauxval]) +fi + +if test "$build_freebsd" = "yes"; then + AC_CHECK_FUNCS([elf_aux_info]) +fi + AM_CONDITIONAL([WINDOWS], [test "$build_windows" = "yes"]) AC_SUBST(AM_CPPFLAGS) diff --git a/cpuid_tool/cpuid_tool.c b/cpuid_tool/cpuid_tool.c index bccfb70..8079a73 100644 --- a/cpuid_tool/cpuid_tool.c +++ b/cpuid_tool/cpuid_tool.c @@ -59,6 +59,7 @@ char out_file[256] = ""; typedef enum { NEED_CPUID_PRESENT, NEED_ARCHITECTURE, + NEED_FEATURE_LEVEL, NEED_PURPOSE, NEED_VENDOR_STR, NEED_VENDOR_ID, @@ -68,6 +69,10 @@ typedef enum { NEED_STEPPING, NEED_EXT_FAMILY, NEED_EXT_MODEL, + NEED_IMPLEMENTER, + NEED_VARIANT, + NEED_PART_NUM, + NEED_REVISION, NEED_NUM_CORES, NEED_NUM_LOGICAL, NEED_TOTAL_CPUS, @@ -127,6 +132,7 @@ const struct { output_data_switch sw; const char* synopsis; int ident_required; matchtable[] = { { NEED_CPUID_PRESENT, "--cpuid" , 0}, { NEED_ARCHITECTURE , "--architecture" , 1}, + { NEED_FEATURE_LEVEL, "--feature-level", 1}, { NEED_PURPOSE , "--purpose" , 1}, { NEED_VENDOR_STR , "--vendorstr" , 1}, { NEED_VENDOR_ID , "--vendorid" , 1}, @@ -136,6 +142,10 @@ matchtable[] = { { NEED_STEPPING , "--stepping" , 1}, { NEED_EXT_FAMILY , "--extfamily" , 1}, { NEED_EXT_MODEL , "--extmodel" , 1}, + { NEED_IMPLEMENTER , "--implementer" , 1}, + { NEED_VARIANT , "--variant" , 1}, + { NEED_PART_NUM , "--part-num" , 1}, + { NEED_REVISION , "--revision" , 1}, { NEED_NUM_CORES , "--cores" , 1}, { NEED_NUM_LOGICAL , "--logical" , 1}, { NEED_TOTAL_CPUS , "--total-cpus" , 1}, @@ -371,6 +381,9 @@ static void print_info(output_data_switch query, struct cpu_id_t* data) case NEED_ARCHITECTURE: fprintf(fout, "%s\n", cpu_architecture_str(data->architecture)); break; + case NEED_FEATURE_LEVEL: + fprintf(fout, "%s\n", cpu_feature_level_str(data->feature_level)); + break; case NEED_PURPOSE: fprintf(fout, "%s\n", cpu_purpose_str(data->purpose)); break; @@ -384,19 +397,31 @@ static void print_info(output_data_switch query, struct cpu_id_t* data) fprintf(fout, "%s\n", data->brand_str); break; case NEED_FAMILY: - fprintf(fout, "%d\n", data->family); + fprintf(fout, "%d\n", data->x86.family); break; case NEED_MODEL: - fprintf(fout, "%d\n", data->model); + fprintf(fout, "%d\n", data->x86.model); break; case NEED_STEPPING: - fprintf(fout, "%d\n", data->stepping); + fprintf(fout, "%d\n", data->x86.stepping); break; case NEED_EXT_FAMILY: - fprintf(fout, "%d\n", data->ext_family); + fprintf(fout, "%d\n", data->x86.ext_family); break; case NEED_EXT_MODEL: - fprintf(fout, "%d\n", data->ext_model); + fprintf(fout, "%d\n", data->x86.ext_model); + break; + case NEED_IMPLEMENTER: + fprintf(fout, "%d\n", data->arm.implementer); + break; + case NEED_VARIANT: + fprintf(fout, "%d\n", data->arm.variant); + break; + case NEED_PART_NUM: + fprintf(fout, "%d\n", data->arm.part_num); + break; + case NEED_REVISION: + fprintf(fout, "%d\n", data->arm.revision); break; case NEED_NUM_CORES: fprintf(fout, "%d\n", data->num_cores); @@ -532,7 +557,7 @@ static void print_info(output_data_switch query, struct cpu_id_t* data) } case NEED_SSE_UNIT_SIZE: { - fprintf(fout, "%d (%s)\n", data->sse_size, + fprintf(fout, "%d (%s)\n", data->x86.sse_size, data->detection_hints[CPU_HINT_SSE_SIZE_AUTH] ? "authoritative" : "non-authoritative"); break; } @@ -548,7 +573,7 @@ static void print_cpulist(void) struct cpu_list_t list; const struct { const char *name; cpu_vendor_t vendor; } cpu_vendors[] = { { "Intel", VENDOR_INTEL }, - { "AMD", VENDOR_AMD }, + { "AMD/Hygon", VENDOR_AMD }, { "Cyrix", VENDOR_CYRIX }, { "NexGen", VENDOR_NEXGEN }, { "Transmeta", VENDOR_TRANSMETA }, @@ -557,6 +582,24 @@ static void print_cpulist(void) { "Rise", VENDOR_RISE }, { "SiS", VENDOR_SIS }, { "NSC", VENDOR_NSC }, + { "ARM", VENDOR_ARM }, + { "Broadcom", VENDOR_BROADCOM }, + { "Cavium", VENDOR_CAVIUM }, + { "DEC", VENDOR_DEC }, + { "FUJITSU", VENDOR_FUJITSU }, + { "HiSilicon", VENDOR_HISILICON }, + { "Infineon", VENDOR_INFINEON }, + { "Motorola/Freescale", VENDOR_FREESCALE }, + { "NVIDIA" , VENDOR_NVIDIA }, + { "APM", VENDOR_APM }, + { "Qualcomm", VENDOR_QUALCOMM }, + { "Samsung", VENDOR_SAMSUNG }, + { "Marvell" , VENDOR_MARVELL }, + { "Apple", VENDOR_APPLE }, + { "Faraday", VENDOR_FARADAY }, + { "Microsoft" , VENDOR_MICROSOFT }, + { "Phytium", VENDOR_PHYTIUM }, + { "Ampere" , VENDOR_AMPERE }, }; for (i = 0; i < sizeof(cpu_vendors)/sizeof(cpu_vendors[0]); i++) { fprintf(fout, "-----%s-----\n", cpu_vendors[i].name); @@ -570,17 +613,17 @@ static void print_cpulist(void) static void print_sgx_data(const struct cpu_raw_data_t* raw, const struct cpu_id_t* data) { int i; - fprintf(fout, "SGX: %d (%s)\n", data->sgx.present, data->sgx.present ? "present" : "absent"); - if (data->sgx.present) { - fprintf(fout, "SGX max enclave size (32-bit): 2^%d\n", data->sgx.max_enclave_32bit); - fprintf(fout, "SGX max enclave size (64-bit): 2^%d\n", data->sgx.max_enclave_64bit); - fprintf(fout, "SGX1 extensions : %d (%s)\n", data->sgx.flags[INTEL_SGX1], data->sgx.flags[INTEL_SGX1] ? "present" : "absent"); - fprintf(fout, "SGX2 extensions : %d (%s)\n", data->sgx.flags[INTEL_SGX2], data->sgx.flags[INTEL_SGX2] ? "present" : "absent"); - fprintf(fout, "SGX MISCSELECT : %08x\n", data->sgx.misc_select); - fprintf(fout, "SGX SECS.ATTRIBUTES mask : %016llx\n", (unsigned long long) data->sgx.secs_attributes); - fprintf(fout, "SGX SECS.XSAVE feature mask : %016llx\n", (unsigned long long) data->sgx.secs_xfrm); - fprintf(fout, "SGX EPC sections count : %d\n", data->sgx.num_epc_sections); - for (i = 0; i < data->sgx.num_epc_sections; i++) { + fprintf(fout, "SGX: %d (%s)\n", data->x86.sgx.present, data->x86.sgx.present ? "present" : "absent"); + if (data->x86.sgx.present) { + fprintf(fout, "SGX max enclave size (32-bit): 2^%d\n", data->x86.sgx.max_enclave_32bit); + fprintf(fout, "SGX max enclave size (64-bit): 2^%d\n", data->x86.sgx.max_enclave_64bit); + fprintf(fout, "SGX1 extensions : %d (%s)\n", data->x86.sgx.flags[INTEL_SGX1], data->x86.sgx.flags[INTEL_SGX1] ? "present" : "absent"); + fprintf(fout, "SGX2 extensions : %d (%s)\n", data->x86.sgx.flags[INTEL_SGX2], data->x86.sgx.flags[INTEL_SGX2] ? "present" : "absent"); + fprintf(fout, "SGX MISCSELECT : %08x\n", data->x86.sgx.misc_select); + fprintf(fout, "SGX SECS.ATTRIBUTES mask : %016llx\n", (unsigned long long) data->x86.sgx.secs_attributes); + fprintf(fout, "SGX SECS.XSAVE feature mask : %016llx\n", (unsigned long long) data->x86.sgx.secs_xfrm); + fprintf(fout, "SGX EPC sections count : %d\n", data->x86.sgx.num_epc_sections); + for (i = 0; i < data->x86.sgx.num_epc_sections; i++) { struct cpu_epc_t epc = cpuid_get_epc(i, raw); fprintf(fout, " SGX EPC section #%-8d: start = %llx, size = %llu\n", i, (unsigned long long) epc.start_addr, (unsigned long long) epc.length); @@ -728,40 +771,51 @@ int main(int argc, char** argv) for (cpu_type_index = 0; cpu_type_index < data.num_cpu_types; cpu_type_index++) { fprintf(fout, "CPU Info for type #%d:\n------------------\n", cpu_type_index); fprintf(fout, " arch : %s\n", cpu_architecture_str(data.cpu_types[cpu_type_index].architecture)); + fprintf(fout, " feat_level : %s\n", cpu_feature_level_str(data.cpu_types[cpu_type_index].feature_level)); fprintf(fout, " purpose : %s\n", cpu_purpose_str(data.cpu_types[cpu_type_index].purpose)); fprintf(fout, " vendor_str : `%s'\n", data.cpu_types[cpu_type_index].vendor_str); fprintf(fout, " vendor id : %d\n", (int) data.cpu_types[cpu_type_index].vendor); fprintf(fout, " brand_str : `%s'\n", data.cpu_types[cpu_type_index].brand_str); - fprintf(fout, " family : %d (%02Xh)\n", data.cpu_types[cpu_type_index].family, data.cpu_types[cpu_type_index].family); - fprintf(fout, " model : %d (%02Xh)\n", data.cpu_types[cpu_type_index].model, data.cpu_types[cpu_type_index].model); - fprintf(fout, " stepping : %d (%02Xh)\n", data.cpu_types[cpu_type_index].stepping, data.cpu_types[cpu_type_index].stepping); - fprintf(fout, " ext_family : %d (%02Xh)\n", data.cpu_types[cpu_type_index].ext_family, data.cpu_types[cpu_type_index].ext_family); - fprintf(fout, " ext_model : %d (%02Xh)\n", data.cpu_types[cpu_type_index].ext_model, data.cpu_types[cpu_type_index].ext_model); + if (data.cpu_types[cpu_type_index].architecture == ARCHITECTURE_X86) { + fprintf(fout, " family : %d (%02Xh)\n", data.cpu_types[cpu_type_index].x86.family, data.cpu_types[cpu_type_index].x86.family); + fprintf(fout, " model : %d (%02Xh)\n", data.cpu_types[cpu_type_index].x86.model, data.cpu_types[cpu_type_index].x86.model); + fprintf(fout, " stepping : %d (%02Xh)\n", data.cpu_types[cpu_type_index].x86.stepping, data.cpu_types[cpu_type_index].x86.stepping); + fprintf(fout, " ext_family : %d (%02Xh)\n", data.cpu_types[cpu_type_index].x86.ext_family, data.cpu_types[cpu_type_index].x86.ext_family); + fprintf(fout, " ext_model : %d (%02Xh)\n", data.cpu_types[cpu_type_index].x86.ext_model, data.cpu_types[cpu_type_index].x86.ext_model); + } + else if (data.cpu_types[cpu_type_index].architecture == ARCHITECTURE_ARM) { + fprintf(fout, " implementer: %d (%02Xh)\n", data.cpu_types[cpu_type_index].arm.implementer, data.cpu_types[cpu_type_index].arm.implementer); + fprintf(fout, " variant : %d (%02Xh)\n", data.cpu_types[cpu_type_index].arm.variant, data.cpu_types[cpu_type_index].arm.variant); + fprintf(fout, " part_num : %d (%02Xh)\n", data.cpu_types[cpu_type_index].arm.part_num, data.cpu_types[cpu_type_index].arm.part_num); + fprintf(fout, " revision : %d (%02Xh)\n", data.cpu_types[cpu_type_index].arm.revision, data.cpu_types[cpu_type_index].arm.revision); + } fprintf(fout, " num_cores : %d\n", data.cpu_types[cpu_type_index].num_cores); fprintf(fout, " num_logical: %d\n", data.cpu_types[cpu_type_index].num_logical_cpus); fprintf(fout, " tot_logical: %d\n", data.cpu_types[cpu_type_index].total_logical_cpus); fprintf(fout, " affi_mask : 0x%s\n", affinity_mask_str(&data.cpu_types[cpu_type_index].affinity_mask)); - fprintf(fout, " L1 D cache : %d KB\n", data.cpu_types[cpu_type_index].l1_data_cache); - fprintf(fout, " L1 I cache : %d KB\n", data.cpu_types[cpu_type_index].l1_instruction_cache); - fprintf(fout, " L2 cache : %d KB\n", data.cpu_types[cpu_type_index].l2_cache); - fprintf(fout, " L3 cache : %d KB\n", data.cpu_types[cpu_type_index].l3_cache); - fprintf(fout, " L4 cache : %d KB\n", data.cpu_types[cpu_type_index].l4_cache); - fprintf(fout, " L1D assoc. : %d-way\n", data.cpu_types[cpu_type_index].l1_data_assoc); - fprintf(fout, " L1I assoc. : %d-way\n", data.cpu_types[cpu_type_index].l1_instruction_assoc); - fprintf(fout, " L2 assoc. : %d-way\n", data.cpu_types[cpu_type_index].l2_assoc); - fprintf(fout, " L3 assoc. : %d-way\n", data.cpu_types[cpu_type_index].l3_assoc); - fprintf(fout, " L4 assoc. : %d-way\n", data.cpu_types[cpu_type_index].l4_assoc); - fprintf(fout, " L1D line sz: %d bytes\n", data.cpu_types[cpu_type_index].l1_data_cacheline); - fprintf(fout, " L1I line sz: %d bytes\n", data.cpu_types[cpu_type_index].l1_instruction_cacheline); - fprintf(fout, " L2 line sz : %d bytes\n", data.cpu_types[cpu_type_index].l2_cacheline); - fprintf(fout, " L3 line sz : %d bytes\n", data.cpu_types[cpu_type_index].l3_cacheline); - fprintf(fout, " L4 line sz : %d bytes\n", data.cpu_types[cpu_type_index].l4_cacheline); - fprintf(fout, " L1D inst. : %d\n", data.cpu_types[cpu_type_index].l1_data_instances); - fprintf(fout, " L1I inst. : %d\n", data.cpu_types[cpu_type_index].l1_instruction_instances); - fprintf(fout, " L2 inst. : %d\n", data.cpu_types[cpu_type_index].l2_instances); - fprintf(fout, " L3 inst. : %d\n", data.cpu_types[cpu_type_index].l3_instances); - fprintf(fout, " L4 inst. : %d\n", data.cpu_types[cpu_type_index].l4_instances); - fprintf(fout, " SSE units : %d bits (%s)\n", data.cpu_types[cpu_type_index].sse_size, data.cpu_types[cpu_type_index].detection_hints[CPU_HINT_SSE_SIZE_AUTH] ? "authoritative" : "non-authoritative"); + if (data.cpu_types[cpu_type_index].architecture == ARCHITECTURE_X86) { + fprintf(fout, " L1 D cache : %d KB\n", data.cpu_types[cpu_type_index].l1_data_cache); + fprintf(fout, " L1 I cache : %d KB\n", data.cpu_types[cpu_type_index].l1_instruction_cache); + fprintf(fout, " L2 cache : %d KB\n", data.cpu_types[cpu_type_index].l2_cache); + fprintf(fout, " L3 cache : %d KB\n", data.cpu_types[cpu_type_index].l3_cache); + fprintf(fout, " L4 cache : %d KB\n", data.cpu_types[cpu_type_index].l4_cache); + fprintf(fout, " L1D assoc. : %d-way\n", data.cpu_types[cpu_type_index].l1_data_assoc); + fprintf(fout, " L1I assoc. : %d-way\n", data.cpu_types[cpu_type_index].l1_instruction_assoc); + fprintf(fout, " L2 assoc. : %d-way\n", data.cpu_types[cpu_type_index].l2_assoc); + fprintf(fout, " L3 assoc. : %d-way\n", data.cpu_types[cpu_type_index].l3_assoc); + fprintf(fout, " L4 assoc. : %d-way\n", data.cpu_types[cpu_type_index].l4_assoc); + fprintf(fout, " L1D line sz: %d bytes\n", data.cpu_types[cpu_type_index].l1_data_cacheline); + fprintf(fout, " L1I line sz: %d bytes\n", data.cpu_types[cpu_type_index].l1_instruction_cacheline); + fprintf(fout, " L2 line sz : %d bytes\n", data.cpu_types[cpu_type_index].l2_cacheline); + fprintf(fout, " L3 line sz : %d bytes\n", data.cpu_types[cpu_type_index].l3_cacheline); + fprintf(fout, " L4 line sz : %d bytes\n", data.cpu_types[cpu_type_index].l4_cacheline); + fprintf(fout, " L1D inst. : %d\n", data.cpu_types[cpu_type_index].l1_data_instances); + fprintf(fout, " L1I inst. : %d\n", data.cpu_types[cpu_type_index].l1_instruction_instances); + fprintf(fout, " L2 inst. : %d\n", data.cpu_types[cpu_type_index].l2_instances); + fprintf(fout, " L3 inst. : %d\n", data.cpu_types[cpu_type_index].l3_instances); + fprintf(fout, " L4 inst. : %d\n", data.cpu_types[cpu_type_index].l4_instances); + fprintf(fout, " SSE units : %d bits (%s)\n", data.cpu_types[cpu_type_index].x86.sse_size, data.cpu_types[cpu_type_index].detection_hints[CPU_HINT_SSE_SIZE_AUTH] ? "authoritative" : "non-authoritative"); + } fprintf(fout, " code name : `%s'\n", data.cpu_types[cpu_type_index].cpu_codename); fprintf(fout, " features :"); /* diff --git a/libcpuid/CMakeLists.txt b/libcpuid/CMakeLists.txt index dcad1bf..67efebe 100644 --- a/libcpuid/CMakeLists.txt +++ b/libcpuid/CMakeLists.txt @@ -1,6 +1,7 @@ set(cpuid_sources cpuid_main.c recog_amd.c + recog_arm.c recog_centaur.c recog_intel.c rdtsc.c diff --git a/libcpuid/Makefile.am b/libcpuid/Makefile.am index d948157..3a9a0d1 100644 --- a/libcpuid/Makefile.am +++ b/libcpuid/Makefile.am @@ -9,6 +9,7 @@ libcpuid_la_LDFLAGS = \ libcpuid_la_SOURCES = \ cpuid_main.c \ recog_amd.c \ + recog_arm.c \ recog_centaur.c \ recog_intel.c \ rdtsc.c \ @@ -37,6 +38,7 @@ noinst_HEADERS = \ libcpuid_internal.h \ libcpuid_util.h \ recog_amd.h \ + recog_arm.h \ recog_centaur.h \ recog_intel.h \ rdtsc.h diff --git a/libcpuid/Makefile.x64 b/libcpuid/Makefile.x64 index 849c099..2ce5eb7 100644 --- a/libcpuid/Makefile.x64 +++ b/libcpuid/Makefile.x64 @@ -6,7 +6,7 @@ ASM = ml64 /nologo CC = cl.exe /nologo /TC OPTFLAGS = /MT DEFINES = /D "VERSION=\"0.6.5\"" -OBJECTS = masm-x64.obj asm-bits.obj cpuid_main.obj libcpuid_util.obj recog_amd.obj recog_centaur.obj recog_intel.obj rdtsc.obj +OBJECTS = masm-x64.obj asm-bits.obj cpuid_main.obj libcpuid_util.obj recog_amd.obj recog_arm.obj recog_centaur.obj recog_intel.obj rdtsc.obj libcpuid.lib: $(OBJECTS) lib /nologo /MACHINE:AMD64 /out:libcpuid.lib $(OBJECTS) bufferoverflowU.lib @@ -26,6 +26,9 @@ libcpuid_util.obj: libcpuid_util.c recog_amd.obj: recog_amd.c $(CC) $(OPTFLAGS) $(DEFINES) /c recog_amd.c +recog_arm.obj: recog_arm.c + $(CC) $(OPTFLAGS) $(DEFINES) /c recog_arm.c + recog_centaur.obj: recog_centaur.c $(CC) $(OPTFLAGS) $(DEFINES) /c recog_centaur.c diff --git a/libcpuid/Makefile.x86 b/libcpuid/Makefile.x86 index a15dc8d..63eb980 100644 --- a/libcpuid/Makefile.x86 +++ b/libcpuid/Makefile.x86 @@ -13,7 +13,7 @@ all: libcpuid.lib CC = cl.exe /nologo /TC OPTFLAGS = /MT DEFINES = /D "VERSION=\"0.6.5\"" -OBJECTS = asm-bits.obj cpuid_main.obj libcpuid_util.obj recog_amd.obj recog_centaur.obj recog_intel.obj rdtsc.obj +OBJECTS = asm-bits.obj cpuid_main.obj libcpuid_util.obj recog_amd.obj recog_arm.obj recog_centaur.obj recog_intel.obj rdtsc.obj libcpuid.lib: $(OBJECTS) lib /nologo /out:libcpuid.lib $(OBJECTS) @@ -30,6 +30,9 @@ libcpuid_util.obj: libcpuid_util.c recog_amd.obj: recog_amd.c $(CC) $(OPTFLAGS) $(DEFINES) /c recog_amd.c +recog_arm.obj: recog_arm.c + $(CC) $(OPTFLAGS) $(DEFINES) /c recog_arm.c + recog_centaur.obj: recog_centaur.c $(CC) $(OPTFLAGS) $(DEFINES) /c recog_centaur.c diff --git a/libcpuid/asm-bits.c b/libcpuid/asm-bits.c index db1f2fb..fb9be74 100644 --- a/libcpuid/asm-bits.c +++ b/libcpuid/asm-bits.c @@ -25,6 +25,7 @@ */ #include "libcpuid.h" +#include "libcpuid_util.h" #include "asm-bits.h" int cpuid_exists_by_eflags(void) @@ -135,6 +136,8 @@ void exec_cpuid(uint32_t *regs) :"m"(regs) :"memory", "eax", "edi" ); +# else + UNUSED(regs); # endif /* COMPILER_GCC */ #else # ifdef COMPILER_MICROSOFT @@ -167,7 +170,7 @@ void exec_cpuid(uint32_t *regs) # endif /* COMPILER_MICROSOFT */ #endif } -#endif /* INLINE_ASSEMBLY_SUPPORTED */ +#endif /* INLINE_ASM_SUPPORTED */ #ifdef INLINE_ASM_SUPPORTED void cpu_rdtsc(uint64_t* result) @@ -516,6 +519,8 @@ void busy_sse_loop(int cycles) " jnz 1b\n" ::"a"(cycles) ); +#else + UNUSED(cycles); #endif #else # ifdef COMPILER_MICROSOFT @@ -829,4 +834,4 @@ bsLoop: # endif /* COMPILER_MICROSOFT */ #endif /* COMPILER_GCC */ } -#endif /* INLINE_ASSEMBLY_SUPPORTED */ \ No newline at end of file +#endif /* INLINE_ASM_SUPPORTED */ diff --git a/libcpuid/asm-bits.h b/libcpuid/asm-bits.h index f9ab24e..04b659d 100644 --- a/libcpuid/asm-bits.h +++ b/libcpuid/asm-bits.h @@ -51,13 +51,32 @@ #if !defined(PLATFORM_X86) # define PLATFORM_X86 #endif -#elif defined(__ARMEL__) +#elif defined(__arm__) #if !defined(PLATFORM_ARM) # define PLATFORM_ARM #endif #elif defined(__aarch64__) -#if !defined(PLATFORM_ARM) +#if !defined(PLATFORM_AARCH64) # define PLATFORM_AARCH64 +/* + * Older assemblers don't recognize newer system register names, + * but we can still access them by the Sn_n_Cn_Cn_n syntax. + */ +# define SYS_ID_AA64PFR0_EL1 "S3_0_C0_C4_0" +# define SYS_ID_AA64PFR1_EL1 "S3_0_C0_C4_1" +# define SYS_ID_AA64PFR2_EL1 "S3_0_C0_C4_2" +# define SYS_ID_AA64ZFR0_EL1 "S3_0_C0_C4_4" +# define SYS_ID_AA64SMFR0_EL1 "S3_0_C0_C4_5" +# define SYS_ID_AA64DFR0_EL1 "S3_0_C0_C5_0" +# define SYS_ID_AA64DFR1_EL1 "S3_0_C0_C5_1" +# define SYS_ID_AA64ISAR0_EL1 "S3_0_C0_C6_0" +# define SYS_ID_AA64ISAR1_EL1 "S3_0_C0_C6_1" +# define SYS_ID_AA64ISAR2_EL1 "S3_0_C0_C6_2" +# define SYS_ID_AA64MMFR0_EL1 "S3_0_C0_C7_0" +# define SYS_ID_AA64MMFR1_EL1 "S3_0_C0_C7_1" +# define SYS_ID_AA64MMFR2_EL1 "S3_0_C0_C7_2" +# define SYS_ID_AA64MMFR3_EL1 "S3_0_C0_C7_3" +# define SYS_ID_AA64MMFR4_EL1 "S3_0_C0_C7_4" #endif #endif @@ -67,6 +86,16 @@ # define INLINE_ASM_SUPPORTED #endif +#ifdef INLINE_ASM_SUPPORTED +# if defined(COMPILER_GCC) || defined(COMPILER_CLANG) +# define cpu_exec_mrs(reg_name, reg_value) __asm __volatile("mrs %0, " reg_name : "=r" (reg_value)) +# elif defined(COMPILER_MICROSOFT) +# define cpu_exec_mrs(reg_name, reg_value) __asm { mrs reg_value, reg_name } +# else +# error "Unsupported compiler" +# endif /* COMPILER */ +#endif /* INLINE_ASM_SUPPORTED */ + int cpuid_exists_by_eflags(void); void exec_cpuid(uint32_t *regs); void busy_sse_loop(int cycles); diff --git a/libcpuid/check-consistency.py b/libcpuid/check-consistency.py index a863ee2..ad937f9 100755 --- a/libcpuid/check-consistency.py +++ b/libcpuid/check-consistency.py @@ -108,18 +108,30 @@ firstError = True files_code = {} -rexp = re.compile('\t+{ *[0-9]+, (CPU_FEATURE_[^ }]+).*') +rexp1 = re.compile(r'.*flags\[(CPU_FEATURE_[^\]]+)\]\s*=\s*1.*') # e.g. "data->flags[CPU_FEATURE_MPAM] = 1;" +rexp2 = re.compile(r'.*(CPU_FEATURE_[^ ,]+)\s*,\s*FEATURE_LEVEL_ARM_.*') # e.g. "{ 35, 32, 0b0101, CPU_FEATURE_SPEV1P4, FEATURE_LEVEL_ARM_V8_8_A, -1 }," +rexp3 = re.compile(r'.*(CPU_FEATURE_[^ }]+).*') # e.g. "{ 28, CPU_FEATURE_HT }," for fn in glob.glob("%s/*.c" % sys.argv[1]): f = open(fn, "rt") files_code[fn] = [] for s in f.readlines(): - if rexp.match(s): - entry = rexp.findall(s)[0] + if rexp1.match(s): + entry = rexp1.findall(s)[0] files_code[fn].append(entry) + elif rexp2.match(s): + entry = rexp2.findall(s)[0] + files_code[fn].append(entry) + elif rexp3.match(s): + entry = rexp3.findall(s)[0] + files_code[fn].append(entry) + f.close() -features_whitelist = ["CPU_FEATURE_SSE5"] +features_whitelist = [ + "CPU_FEATURE_SSE5", # deprecated, never defined + "CPU_FEATURE_AES", # defined twice (x86 + ARM) +] for feature in allf: matching_files = [] for fn in files_code: @@ -131,7 +143,7 @@ for feature in allf: firstError = False err += 1 print("..No detection code for %s" % feature) - if len(matching_files) > 1: + if len(matching_files) > 1 and feature not in features_whitelist: if firstError: print("FAILED:") firstError = False @@ -143,7 +155,7 @@ if firstError: print("") print("Checking processor definitions:") -cache_exp = re.compile(".*([\(/ ][0-9]+K).*") +cache_exp = re.compile(r".*([\(/ ][0-9]+K).*") # Check whether CPU codenames for consistency: # - Codenames should not exceed 31 characters # - Check for common typos diff --git a/libcpuid/cpuid_main.c b/libcpuid/cpuid_main.c index 111f43f..2155fb0 100644 --- a/libcpuid/cpuid_main.c +++ b/libcpuid/cpuid_main.c @@ -26,17 +26,24 @@ #include "libcpuid.h" #include "libcpuid_internal.h" #include "recog_amd.h" +#include "recog_arm.h" #include "recog_centaur.h" #include "recog_intel.h" #include "asm-bits.h" #include "libcpuid_util.h" #ifdef HAVE_CONFIG_H -#include "config.h" -#endif +# include "config.h" +#endif /* HAVE_CONFIG_H */ #include #include #include #include +#ifdef HAVE_GETAUXVAL +# include +#endif /* HAVE_GETAUXVAL */ +#ifdef HAVE_ELF_AUX_INFO +# include +#endif /* HAVE_ELF_AUX_INFO */ /* Implementation: */ @@ -69,11 +76,14 @@ static void raw_data_t_constructor(struct cpu_raw_data_t* raw) static void cpu_id_t_constructor(struct cpu_id_t* id) { memset(id, 0, sizeof(struct cpu_id_t)); + id->architecture = ARCHITECTURE_UNKNOWN; + id->feature_level = FEATURE_LEVEL_UNKNOWN; + id->vendor = VENDOR_UNKNOWN; id->l1_data_cache = id->l1_instruction_cache = id->l2_cache = id->l3_cache = id->l4_cache = -1; id->l1_assoc = id->l1_data_assoc = id->l1_instruction_assoc = id->l2_assoc = id->l3_assoc = id->l4_assoc = -1; id->l1_cacheline = id->l1_data_cacheline = id->l1_instruction_cacheline = id->l2_cacheline = id->l3_cacheline = id->l4_cacheline = -1; id->l1_data_instances = id->l1_instruction_instances = id->l2_instances = id->l3_instances = id->l4_instances = -1; - id->sse_size = -1; + id->x86.sse_size = -1; init_affinity_mask(&id->affinity_mask); id->purpose = PURPOSE_GENERAL; } @@ -96,14 +106,14 @@ static void system_id_t_constructor(struct system_id_t* system) system->l4_total_instances = -1; } -static void apic_info_t_constructor(struct internal_apic_info_t* apic_info, logical_cpu_t logical_cpu) +static void topology_t_constructor(struct internal_topology_t* topology, logical_cpu_t logical_cpu) { - memset(apic_info, 0, sizeof(struct internal_apic_info_t)); - apic_info->apic_id = -1; - apic_info->package_id = -1; - apic_info->core_id = -1; - apic_info->smt_id = -1; - apic_info->logical_cpu = logical_cpu; + memset(topology, 0, sizeof(struct internal_topology_t)); + topology->apic_id = -1; + topology->package_id = -1; + topology->core_id = -1; + topology->smt_id = -1; + topology->logical_cpu = logical_cpu; } static void core_instances_t_constructor(struct internal_core_instances_t* data) @@ -125,11 +135,11 @@ static void type_info_array_t_constructor(struct internal_type_info_array_t* dat } static int16_t cpuid_find_index_system_id(struct system_id_t* system, cpu_purpose_t purpose, - struct internal_type_info_array_t* type_info, int32_t package_id, bool is_apic_supported) + struct internal_type_info_array_t* type_info, int32_t package_id, bool is_topology_supported) { int16_t i = 0; - if (is_apic_supported) { + if (is_topology_supported) { for (i = 0; i < system->num_cpu_types; i++) if ((system->cpu_types[i].purpose == purpose) && (type_info->data[i].package_id == package_id)) return i; @@ -209,6 +219,16 @@ static void cpuid_free_type_info(struct internal_type_info_array_t* type_info) type_info->num = 0; } +static cpu_architecture_t cpuid_architecture_identify(struct cpu_raw_data_t* raw) +{ + if (raw->basic_cpuid[0][EAX] != 0x0 || raw->basic_cpuid[0][EBX] != 0x0 || raw->basic_cpuid[0][ECX] != 0x0 || raw->basic_cpuid[0][EDX] != 0x0) + return ARCHITECTURE_X86; + else if (raw->arm_midr != 0x0) + return ARCHITECTURE_ARM; + + return ARCHITECTURE_UNKNOWN; +} + /* get_total_cpus() system specific code: uses OS routines to determine total number of CPUs */ #ifdef __APPLE__ #include @@ -583,6 +603,7 @@ static int cpuid_serialize_raw_data_internal(struct cpu_raw_data_t* single_raw, const bool use_raw_array = (raw_array != NULL) && raw_array->num_raw > 0; logical_cpu_t logical_cpu = 0; struct cpu_raw_data_t* raw_ptr = use_raw_array ? &raw_array->raw[0] : single_raw; + const cpu_architecture_t architecture = cpuid_architecture_identify(raw_ptr); FILE *f; /* Open file descriptor */ @@ -599,34 +620,58 @@ static int cpuid_serialize_raw_data_internal(struct cpu_raw_data_t* single_raw, fprintf(f, "\n_________________ Logical CPU #%i _________________\n", logical_cpu); raw_ptr = &raw_array->raw[logical_cpu]; } - for (i = 0; i < MAX_CPUID_LEVEL; i++) - fprintf(f, "basic_cpuid[%d]=%08x %08x %08x %08x\n", i, - raw_ptr->basic_cpuid[i][EAX], raw_ptr->basic_cpuid[i][EBX], - raw_ptr->basic_cpuid[i][ECX], raw_ptr->basic_cpuid[i][EDX]); - for (i = 0; i < MAX_EXT_CPUID_LEVEL; i++) - fprintf(f, "ext_cpuid[%d]=%08x %08x %08x %08x\n", i, - raw_ptr->ext_cpuid[i][EAX], raw_ptr->ext_cpuid[i][EBX], - raw_ptr->ext_cpuid[i][ECX], raw_ptr->ext_cpuid[i][EDX]); - for (i = 0; i < MAX_INTELFN4_LEVEL; i++) - fprintf(f, "intel_fn4[%d]=%08x %08x %08x %08x\n", i, - raw_ptr->intel_fn4[i][EAX], raw_ptr->intel_fn4[i][EBX], - raw_ptr->intel_fn4[i][ECX], raw_ptr->intel_fn4[i][EDX]); - for (i = 0; i < MAX_INTELFN11_LEVEL; i++) - fprintf(f, "intel_fn11[%d]=%08x %08x %08x %08x\n", i, - raw_ptr->intel_fn11[i][EAX], raw_ptr->intel_fn11[i][EBX], - raw_ptr->intel_fn11[i][ECX], raw_ptr->intel_fn11[i][EDX]); - for (i = 0; i < MAX_INTELFN12H_LEVEL; i++) - fprintf(f, "intel_fn12h[%d]=%08x %08x %08x %08x\n", i, - raw_ptr->intel_fn12h[i][EAX], raw_ptr->intel_fn12h[i][EBX], - raw_ptr->intel_fn12h[i][ECX], raw_ptr->intel_fn12h[i][EDX]); - for (i = 0; i < MAX_INTELFN14H_LEVEL; i++) - fprintf(f, "intel_fn14h[%d]=%08x %08x %08x %08x\n", i, - raw_ptr->intel_fn14h[i][EAX], raw_ptr->intel_fn14h[i][EBX], - raw_ptr->intel_fn14h[i][ECX], raw_ptr->intel_fn14h[i][EDX]); - for (i = 0; i < MAX_AMDFN8000001DH_LEVEL; i++) - fprintf(f, "amd_fn8000001dh[%d]=%08x %08x %08x %08x\n", i, - raw_ptr->amd_fn8000001dh[i][EAX], raw_ptr->amd_fn8000001dh[i][EBX], - raw_ptr->amd_fn8000001dh[i][ECX], raw_ptr->amd_fn8000001dh[i][EDX]); + switch (architecture) { + case ARCHITECTURE_X86: + for (i = 0; i < MAX_CPUID_LEVEL; i++) + fprintf(f, "basic_cpuid[%d]=%08x %08x %08x %08x\n", i, + raw_ptr->basic_cpuid[i][EAX], raw_ptr->basic_cpuid[i][EBX], + raw_ptr->basic_cpuid[i][ECX], raw_ptr->basic_cpuid[i][EDX]); + for (i = 0; i < MAX_EXT_CPUID_LEVEL; i++) + fprintf(f, "ext_cpuid[%d]=%08x %08x %08x %08x\n", i, + raw_ptr->ext_cpuid[i][EAX], raw_ptr->ext_cpuid[i][EBX], + raw_ptr->ext_cpuid[i][ECX], raw_ptr->ext_cpuid[i][EDX]); + for (i = 0; i < MAX_INTELFN4_LEVEL; i++) + fprintf(f, "intel_fn4[%d]=%08x %08x %08x %08x\n", i, + raw_ptr->intel_fn4[i][EAX], raw_ptr->intel_fn4[i][EBX], + raw_ptr->intel_fn4[i][ECX], raw_ptr->intel_fn4[i][EDX]); + for (i = 0; i < MAX_INTELFN11_LEVEL; i++) + fprintf(f, "intel_fn11[%d]=%08x %08x %08x %08x\n", i, + raw_ptr->intel_fn11[i][EAX], raw_ptr->intel_fn11[i][EBX], + raw_ptr->intel_fn11[i][ECX], raw_ptr->intel_fn11[i][EDX]); + for (i = 0; i < MAX_INTELFN12H_LEVEL; i++) + fprintf(f, "intel_fn12h[%d]=%08x %08x %08x %08x\n", i, + raw_ptr->intel_fn12h[i][EAX], raw_ptr->intel_fn12h[i][EBX], + raw_ptr->intel_fn12h[i][ECX], raw_ptr->intel_fn12h[i][EDX]); + for (i = 0; i < MAX_INTELFN14H_LEVEL; i++) + fprintf(f, "intel_fn14h[%d]=%08x %08x %08x %08x\n", i, + raw_ptr->intel_fn14h[i][EAX], raw_ptr->intel_fn14h[i][EBX], + raw_ptr->intel_fn14h[i][ECX], raw_ptr->intel_fn14h[i][EDX]); + for (i = 0; i < MAX_AMDFN8000001DH_LEVEL; i++) + fprintf(f, "amd_fn8000001dh[%d]=%08x %08x %08x %08x\n", i, + raw_ptr->amd_fn8000001dh[i][EAX], raw_ptr->amd_fn8000001dh[i][EBX], + raw_ptr->amd_fn8000001dh[i][ECX], raw_ptr->amd_fn8000001dh[i][EDX]); + break; + case ARCHITECTURE_ARM: + fprintf(f, "arm_midr=%016lx\n", raw_ptr->arm_midr); + fprintf(f, "arm_mpidr=%016lx\n", raw_ptr->arm_mpidr); + fprintf(f, "arm_revidr=%016lx\n", raw_ptr->arm_revidr); + for (i = 0; i < MAX_ARM_ID_AA64DFR_REGS; i++) + fprintf(f, "arm_id_aa64dfr%d=%016lx\n", i, raw_ptr->arm_id_aa64dfr[i]); + for (i = 0; i < MAX_ARM_ID_AA64ISAR_REGS; i++) + fprintf(f, "arm_id_aa64isar%d=%016lx\n", i, raw_ptr->arm_id_aa64isar[i]); + for (i = 0; i < MAX_ARM_ID_AA64MMFR_REGS; i++) + fprintf(f, "arm_id_aa64mmfr%d=%016lx\n", i, raw_ptr->arm_id_aa64mmfr[i]); + for (i = 0; i < MAX_ARM_ID_AA64PFR_REGS; i++) + fprintf(f, "arm_id_aa64pfr%d=%016lx\n", i, raw_ptr->arm_id_aa64pfr[i]); + for (i = 0; i < MAX_ARM_ID_AA64SMFR_REGS; i++) + fprintf(f, "arm_id_aa64smfr%d=%016lx\n", i, raw_ptr->arm_id_aa64smfr[i]); + for (i = 0; i < MAX_ARM_ID_AA64ZFR_REGS; i++) + fprintf(f, "arm_id_aa64zfr%d=%016lx\n", i, raw_ptr->arm_id_aa64zfr[i]); + break; + default: + break; + } + logical_cpu++; end_loop = ((use_raw_array && (logical_cpu >= raw_array->num_raw)) || !use_raw_array); } @@ -637,7 +682,8 @@ static int cpuid_serialize_raw_data_internal(struct cpu_raw_data_t* single_raw, return cpuid_set_error(ERR_OK); } -#define RAW_ASSIGN_LINE(__line) __line[EAX] = eax ; __line[EBX] = ebx ; __line[ECX] = ecx ; __line[EDX] = edx +#define RAW_ASSIGN_LINE_X86(__line) __line[EAX] = eax ; __line[EBX] = ebx ; __line[ECX] = ecx ; __line[EDX] = edx +#define RAW_ASSIGN_LINE_ARM(__line) __line = arm_reg static int cpuid_deserialize_raw_data_internal(struct cpu_raw_data_t* single_raw, struct cpu_raw_data_array_t* raw_array, const char* filename) { int i; @@ -650,6 +696,7 @@ static int cpuid_deserialize_raw_data_internal(struct cpu_raw_data_t* single_raw const bool use_raw_array = (raw_array != NULL); logical_cpu_t logical_cpu = 0; uint32_t addr, eax, ebx, ecx, edx; + uint64_t arm_reg; char version[8] = ""; char line[100]; struct cpu_raw_data_t* raw_ptr = single_raw; @@ -711,25 +758,52 @@ static int cpuid_deserialize_raw_data_internal(struct cpu_raw_data_t* single_raw raw_array->with_affinity = true; } else if ((sscanf(line, "basic_cpuid[%d]=%x %x %x %x", &i, &eax, &ebx, &ecx, &edx) >= 5) && (i >= 0) && (i < MAX_CPUID_LEVEL)) { - RAW_ASSIGN_LINE(raw_ptr->basic_cpuid[i]); + RAW_ASSIGN_LINE_X86(raw_ptr->basic_cpuid[i]); } else if ((sscanf(line, "ext_cpuid[%d]=%x %x %x %x", &i, &eax, &ebx, &ecx, &edx) >= 5) && (i >= 0) && (i < MAX_EXT_CPUID_LEVEL)) { - RAW_ASSIGN_LINE(raw_ptr->ext_cpuid[i]); + RAW_ASSIGN_LINE_X86(raw_ptr->ext_cpuid[i]); } else if ((sscanf(line, "intel_fn4[%d]=%x %x %x %x", &i, &eax, &ebx, &ecx, &edx) >= 5) && (i >= 0) && (i < MAX_INTELFN4_LEVEL)) { - RAW_ASSIGN_LINE(raw_ptr->intel_fn4[i]); + RAW_ASSIGN_LINE_X86(raw_ptr->intel_fn4[i]); } else if ((sscanf(line, "intel_fn11[%d]=%x %x %x %x", &i, &eax, &ebx, &ecx, &edx) >= 5) && (i >= 0) && (i < MAX_INTELFN11_LEVEL)) { - RAW_ASSIGN_LINE(raw_ptr->intel_fn11[i]); + RAW_ASSIGN_LINE_X86(raw_ptr->intel_fn11[i]); } else if ((sscanf(line, "intel_fn12h[%d]=%x %x %x %x", &i, &eax, &ebx, &ecx, &edx) >= 5) && (i >= 0) && (i < MAX_INTELFN12H_LEVEL)) { - RAW_ASSIGN_LINE(raw_ptr->intel_fn12h[i]); + RAW_ASSIGN_LINE_X86(raw_ptr->intel_fn12h[i]); } else if ((sscanf(line, "intel_fn14h[%d]=%x %x %x %x", &i, &eax, &ebx, &ecx, &edx) >= 5) && (i >= 0) && (i < MAX_INTELFN14H_LEVEL)) { - RAW_ASSIGN_LINE(raw_ptr->intel_fn14h[i]); + RAW_ASSIGN_LINE_X86(raw_ptr->intel_fn14h[i]); } else if ((sscanf(line, "amd_fn8000001dh[%d]=%x %x %x %x", &i, &eax, &ebx, &ecx, &edx) >= 5) && (i >= 0) && (i < MAX_AMDFN8000001DH_LEVEL)) { - RAW_ASSIGN_LINE(raw_ptr->amd_fn8000001dh[i]); + RAW_ASSIGN_LINE_X86(raw_ptr->amd_fn8000001dh[i]); + } + else if ((sscanf(line, "arm_midr=%lx", &arm_reg) >= 1)) { + RAW_ASSIGN_LINE_ARM(raw_ptr->arm_midr); + } + else if ((sscanf(line, "arm_mpidr=%lx", &arm_reg) >= 1)) { + RAW_ASSIGN_LINE_ARM(raw_ptr->arm_mpidr); + } + else if ((sscanf(line, "arm_revidr=%lx", &arm_reg) >= 1)) { + RAW_ASSIGN_LINE_ARM(raw_ptr->arm_revidr); + } + else if ((sscanf(line, "arm_id_aa64dfr%d=%lx", &i, &arm_reg) >= 2)) { + RAW_ASSIGN_LINE_ARM(raw_ptr->arm_id_aa64dfr[i]); + } + else if ((sscanf(line, "arm_id_aa64isar%d=%lx", &i, &arm_reg) >= 2)) { + RAW_ASSIGN_LINE_ARM(raw_ptr->arm_id_aa64isar[i]); + } + else if ((sscanf(line, "arm_id_aa64mmfr%d=%lx", &i, &arm_reg) >= 2)) { + RAW_ASSIGN_LINE_ARM(raw_ptr->arm_id_aa64mmfr[i]); + } + else if ((sscanf(line, "arm_id_aa64pfr%d=%lx", &i, &arm_reg) >= 2)) { + RAW_ASSIGN_LINE_ARM(raw_ptr->arm_id_aa64pfr[i]); + } + else if ((sscanf(line, "arm_id_aa64smfr%d=%lx", &i, &arm_reg) >= 2)) { + RAW_ASSIGN_LINE_ARM(raw_ptr->arm_id_aa64smfr[i]); + } + else if ((sscanf(line, "arm_id_aa64zfr%d=%lx", &i, &arm_reg) >= 2)) { + RAW_ASSIGN_LINE_ARM(raw_ptr->arm_id_aa64zfr[i]); } else if (line[0] != '\0') { warnf("Warning: file '%s', line %d: '%s' not understood!\n", filename, cur_line, line); @@ -751,21 +825,21 @@ static int cpuid_deserialize_raw_data_internal(struct cpu_raw_data_t* single_raw if ((assigned >= 5) && (subleaf == 0)) { if (addr < MAX_CPUID_LEVEL) { i = (int) addr; - RAW_ASSIGN_LINE(raw_ptr->basic_cpuid[i]); + RAW_ASSIGN_LINE_X86(raw_ptr->basic_cpuid[i]); } else if ((addr >= ADDRESS_EXT_CPUID_START) && (addr < ADDRESS_EXT_CPUID_END)) { i = (int) addr - ADDRESS_EXT_CPUID_START; - RAW_ASSIGN_LINE(raw_ptr->ext_cpuid[i]); + RAW_ASSIGN_LINE_X86(raw_ptr->ext_cpuid[i]); } } if (assigned >= 6) { i = subleaf; switch (addr) { - case 0x00000004: RAW_ASSIGN_LINE(raw_ptr->intel_fn4[i]); break; - case 0x0000000B: RAW_ASSIGN_LINE(raw_ptr->intel_fn11[i]); break; - case 0x00000012: RAW_ASSIGN_LINE(raw_ptr->intel_fn12h[i]); break; - case 0x00000014: RAW_ASSIGN_LINE(raw_ptr->intel_fn14h[i]); break; - case 0x8000001D: RAW_ASSIGN_LINE(raw_ptr->amd_fn8000001dh[i]); break; + case 0x00000004: RAW_ASSIGN_LINE_X86(raw_ptr->intel_fn4[i]); break; + case 0x0000000B: RAW_ASSIGN_LINE_X86(raw_ptr->intel_fn11[i]); break; + case 0x00000012: RAW_ASSIGN_LINE_X86(raw_ptr->intel_fn12h[i]); break; + case 0x00000014: RAW_ASSIGN_LINE_X86(raw_ptr->intel_fn14h[i]); break; + case 0x8000001D: RAW_ASSIGN_LINE_X86(raw_ptr->amd_fn8000001dh[i]); break; default: break; } } @@ -777,7 +851,8 @@ static int cpuid_deserialize_raw_data_internal(struct cpu_raw_data_t* single_raw fclose(f); return cpuid_set_error(ERR_OK); } -#undef RAW_ASSIGN_LINE +#undef RAW_ASSIGN_LINE_X86 +#undef RAW_ASSIGN_LINE_ARM static void load_features_common(struct cpu_raw_data_t* raw, struct cpu_id_t* data) { @@ -863,10 +938,10 @@ static void load_features_common(struct cpu_raw_data_t* raw, struct cpu_id_t* da /* apply guesswork to check if the SSE unit width is 128 bit */ switch (data->vendor) { case VENDOR_AMD: - data->sse_size = (data->ext_family >= 16 && data->ext_family != 17) ? 128 : 64; + data->x86.sse_size = (data->x86.ext_family >= 16 && data->x86.ext_family != 17) ? 128 : 64; break; case VENDOR_INTEL: - data->sse_size = (data->family == 6 && data->ext_model >= 15) ? 128 : 64; + data->x86.sse_size = (data->x86.family == 6 && data->x86.ext_model >= 15) ? 128 : 64; break; default: break; @@ -918,19 +993,19 @@ static int cpuid_basic_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* dat if (data->vendor == VENDOR_UNKNOWN) return cpuid_set_error(ERR_CPU_UNKN); - data->architecture = ARCHITECTURE_X86; + basic = raw->basic_cpuid[0][EAX]; if (basic >= 1) { - data->family = (raw->basic_cpuid[1][EAX] >> 8) & 0xf; - data->model = (raw->basic_cpuid[1][EAX] >> 4) & 0xf; - data->stepping = raw->basic_cpuid[1][EAX] & 0xf; + data->x86.family = (raw->basic_cpuid[1][EAX] >> 8) & 0xf; + data->x86.model = (raw->basic_cpuid[1][EAX] >> 4) & 0xf; + data->x86.stepping = raw->basic_cpuid[1][EAX] & 0xf; xmodel = (raw->basic_cpuid[1][EAX] >> 16) & 0xf; xfamily = (raw->basic_cpuid[1][EAX] >> 20) & 0xff; - if (data->vendor == VENDOR_AMD && data->family < 0xf) - data->ext_family = data->family; + if (data->vendor == VENDOR_AMD && data->x86.family < 0xf) + data->x86.ext_family = data->x86.family; else - data->ext_family = data->family + xfamily; - data->ext_model = data->model + (xmodel << 4); + data->x86.ext_family = data->x86.family + xfamily; + data->x86.ext_model = data->x86.model + (xmodel << 4); } ext = raw->ext_cpuid[0][EAX] - 0x80000000; @@ -984,20 +1059,17 @@ static void make_list_from_string(const char* csv, struct cpu_list_t* list) } } -static bool cpu_ident_apic_id(logical_cpu_t logical_cpu, struct cpu_raw_data_t* raw, struct internal_apic_info_t* apic_info) +static bool cpu_ident_id_x86(struct cpu_raw_data_t* raw, struct internal_topology_t* topology) { bool is_apic_id_supported = false; uint8_t subleaf; uint8_t level_type = 0; uint8_t mask_core_shift = 0; uint32_t mask_smt_shift, core_plus_mask_width, package_mask, core_mask, smt_mask = 0; - cpu_vendor_t vendor = VENDOR_UNKNOWN; char vendor_str[VENDOR_STR_MAX]; - apic_info_t_constructor(apic_info, logical_cpu); - /* Only AMD and Intel x86 CPUs support Extended Processor Topology Eumeration */ - vendor = cpuid_vendor_identify(raw->basic_cpuid[0], vendor_str); + const cpu_vendor_t vendor = cpuid_vendor_identify(raw->basic_cpuid[0], vendor_str); switch (vendor) { case VENDOR_INTEL: case VENDOR_AMD: @@ -1029,18 +1101,18 @@ static bool cpu_ident_apic_id(logical_cpu_t logical_cpu, struct cpu_raw_data_t* /* Find mask and ID for SMT and cores */ for (subleaf = 0; (raw->intel_fn11[subleaf][EAX] != 0x0) && (raw->intel_fn11[subleaf][EBX] != 0x0) && (subleaf < MAX_INTELFN11_LEVEL); subleaf++) { - level_type = EXTRACTS_BITS(raw->intel_fn11[subleaf][ECX], 15, 8); - apic_info->apic_id = raw->intel_fn11[subleaf][EDX]; + level_type = EXTRACTS_BITS(raw->intel_fn11[subleaf][ECX], 15, 8); + topology->apic_id = raw->intel_fn11[subleaf][EDX]; switch (level_type) { case 0x01: mask_smt_shift = EXTRACTS_BITS(raw->intel_fn11[subleaf][EAX], 4, 0); smt_mask = ~( (-1) << mask_smt_shift); - apic_info->smt_id = apic_info->apic_id & smt_mask; + topology->smt_id = topology->apic_id & smt_mask; break; case 0x02: core_plus_mask_width = ~( (-1) << mask_core_shift); core_mask = core_plus_mask_width ^ smt_mask; - apic_info->core_id = apic_info->apic_id & core_mask; + topology->core_id = topology->apic_id & core_mask; break; default: break; @@ -1049,11 +1121,51 @@ static bool cpu_ident_apic_id(logical_cpu_t logical_cpu, struct cpu_raw_data_t* /* Find mask and ID for packages */ package_mask = (-1) << mask_core_shift; - apic_info->package_id = apic_info->apic_id & package_mask; + topology->package_id = topology->apic_id & package_mask; return (level_type > 0); } +static bool cpu_ident_id_arm(struct cpu_raw_data_t* raw, struct internal_topology_t* topology) +{ + /* Documentation: Multiprocessor Affinity Register + https://developer.arm.com/documentation/ddi0601/2020-12/AArch64-Registers/MPIDR-EL1--Multiprocessor-Affinity-Register + */ + const bool aff0_is_threads = EXTRACTS_BIT(raw->arm_mpidr, 24); + if (aff0_is_threads) { + /* Aff0: the level identifies individual threads within a multithreaded core + On single-threaded CPUs this field has the value 0x00 */ + topology->smt_id = EXTRACTS_BITS(raw->arm_mpidr, 7, 0); // Aff0 + topology->core_id = EXTRACTS_BITS(raw->arm_mpidr, 15, 8); // Aff1 + topology->package_id = EXTRACTS_BITS(raw->arm_mpidr, 23, 16); // Aff2 + } + else { + topology->core_id = EXTRACTS_BITS(raw->arm_mpidr, 7, 0); // Aff0 + topology->package_id = EXTRACTS_BITS(raw->arm_mpidr, 15, 8); // Aff1 + } + + /* Always implemented since ARMv7 + https://developer.arm.com/documentation/ddi0406/c/System-Level-Architecture/System-Control-Registers-in-a-PMSA-implementation/PMSA-System-control-registers-descriptions--in-register-order/MPIDR--Multiprocessor-Affinity-Register--PMSA?lang=en + */ + return true; +} + +static bool cpu_ident_id(logical_cpu_t logical_cpu, struct cpu_raw_data_t* raw, struct internal_topology_t* topology) +{ + topology_t_constructor(topology, logical_cpu); + + const cpu_architecture_t architecture = cpuid_architecture_identify(raw); + switch (architecture) { + case ARCHITECTURE_X86: + return cpu_ident_id_x86(raw, topology); + case ARCHITECTURE_ARM: + return cpu_ident_id_arm(raw, topology); + default: + break; + } + + return false; +} /* Interface: */ @@ -1064,7 +1176,21 @@ int cpuid_get_total_cpus(void) int cpuid_present(void) { +#if defined(PLATFORM_X86) || defined(PLATFORM_X64) return cpuid_exists_by_eflags(); +#elif defined(PLATFORM_AARCH64) +# if defined(HAVE_GETAUXVAL) /* Linux */ + return (getauxval(AT_HWCAP) & HWCAP_CPUID); +# elif defined(HAVE_ELF_AUX_INFO) /* FreeBSD */ + unsigned long hwcap = 0; + if (elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap)) == 0) + return ((hwcap & HWCAP_CPUID) != 0); +# endif /* HAVE_GETAUXVAL */ + /* On AArch64, return 0 by default */ + return 0; +#else + return 0; +#endif } void cpu_exec_cpuid(uint32_t eax, uint32_t* regs) @@ -1081,9 +1207,10 @@ void cpu_exec_cpuid_ext(uint32_t* regs) int cpuid_get_raw_data(struct cpu_raw_data_t* data) { - unsigned i; if (!cpuid_present()) return cpuid_set_error(ERR_NO_CPUID); +#if defined(PLATFORM_X86) || defined(PLATFORM_X64) + unsigned i; for (i = 0; i < 32; i++) cpu_exec_cpuid(i, data->basic_cpuid[i]); for (i = 0; i < 32; i++) @@ -1118,6 +1245,34 @@ int cpuid_get_raw_data(struct cpu_raw_data_t* data) data->amd_fn8000001dh[i][ECX] = i; cpu_exec_cpuid_ext(data->amd_fn8000001dh[i]); } +#elif defined(PLATFORM_ARM) + /* We cannot support ARM CPUs running in 32-bit mode, because the Main ID Register is accessible only in privileged modes + Some related links: + - https://github.com/anrieff/libcpuid/issues/96 + - https://developer.arm.com/documentation/ddi0406/b/System-Level-Architecture/Protected-Memory-System-Architecture--PMSA-/CP15-registers-for-a-PMSA-implementation/c0--Main-ID-Register--MIDR- + */ +# warning The 32-bit ARM platform is not supported (Main ID Register is accessible only in privileged modes) + UNUSED(data); +#elif defined(PLATFORM_AARCH64) + cpu_exec_mrs("MIDR_EL1", data->arm_midr); + cpu_exec_mrs("MPIDR_EL1", data->arm_mpidr); + cpu_exec_mrs("REVIDR_EL1", data->arm_revidr); + cpu_exec_mrs(SYS_ID_AA64DFR0_EL1, data->arm_id_aa64dfr[0]); + cpu_exec_mrs(SYS_ID_AA64DFR1_EL1, data->arm_id_aa64dfr[1]); + cpu_exec_mrs(SYS_ID_AA64ISAR0_EL1, data->arm_id_aa64isar[0]); + cpu_exec_mrs(SYS_ID_AA64ISAR1_EL1, data->arm_id_aa64isar[1]); + cpu_exec_mrs(SYS_ID_AA64ISAR2_EL1, data->arm_id_aa64isar[2]); + cpu_exec_mrs(SYS_ID_AA64MMFR0_EL1, data->arm_id_aa64mmfr[0]); + cpu_exec_mrs(SYS_ID_AA64MMFR1_EL1, data->arm_id_aa64mmfr[1]); + cpu_exec_mrs(SYS_ID_AA64MMFR2_EL1, data->arm_id_aa64mmfr[2]); + cpu_exec_mrs(SYS_ID_AA64MMFR3_EL1, data->arm_id_aa64mmfr[3]); + cpu_exec_mrs(SYS_ID_AA64MMFR4_EL1, data->arm_id_aa64mmfr[4]); + cpu_exec_mrs(SYS_ID_AA64PFR0_EL1, data->arm_id_aa64pfr[0]); + cpu_exec_mrs(SYS_ID_AA64PFR1_EL1, data->arm_id_aa64pfr[1]); + cpu_exec_mrs(SYS_ID_AA64PFR2_EL1, data->arm_id_aa64pfr[2]); + cpu_exec_mrs(SYS_ID_AA64SMFR0_EL1, data->arm_id_aa64smfr[0]); + cpu_exec_mrs(SYS_ID_AA64ZFR0_EL1, data->arm_id_aa64zfr[0]); +#endif return cpuid_set_error(ERR_OK); } @@ -1182,26 +1337,46 @@ int cpu_ident_internal(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct } cpu_id_t_constructor(data); memset(internal->cache_mask, 0, sizeof(internal->cache_mask)); - if ((r = cpuid_basic_identify(raw, data)) < 0) - return cpuid_set_error(r); - switch (data->vendor) { - case VENDOR_INTEL: - r = cpuid_identify_intel(raw, data, internal); + data->architecture = cpuid_architecture_identify(raw); + + switch (data->architecture) { + case ARCHITECTURE_X86: + if ((r = cpuid_basic_identify(raw, data)) < 0) + return cpuid_set_error(r); + switch (data->vendor) { + case VENDOR_INTEL: + r = cpuid_identify_intel(raw, data, internal); + break; + case VENDOR_AMD: + case VENDOR_HYGON: + r = cpuid_identify_amd(raw, data, internal); + break; + case VENDOR_CENTAUR: + r = cpuid_identify_centaur(raw, data, internal); + break; + default: + break; + } break; - case VENDOR_AMD: - case VENDOR_HYGON: - r = cpuid_identify_amd(raw, data, internal); - break; - case VENDOR_CENTAUR: - r = cpuid_identify_centaur(raw, data, internal); + case ARCHITECTURE_ARM: + r = cpuid_identify_arm(raw, data); break; default: - break; + return cpuid_set_error(ERR_CPU_UNKN); } /* Backward compatibility */ /* - Deprecated since v0.5.0 */ data->l1_assoc = data->l1_data_assoc; data->l1_cacheline = data->l1_data_cacheline; + /* - Deprecated since v0.7.0 */ + data->family = data->x86.family; + data->model = data->x86.model; + data->stepping = data->x86.stepping; + data->ext_family = data->x86.ext_family; + data->ext_model = data->x86.ext_model; + data->sse_size = data->x86.sse_size; + data->sgx = data->x86.sgx; + return cpuid_set_error(r); } @@ -1211,23 +1386,28 @@ static cpu_purpose_t cpu_ident_purpose(struct cpu_raw_data_t* raw) cpu_purpose_t purpose = PURPOSE_GENERAL; char vendor_str[VENDOR_STR_MAX]; - vendor = cpuid_vendor_identify(raw->basic_cpuid[0], vendor_str); - if (vendor == VENDOR_UNKNOWN) { - cpuid_set_error(ERR_CPU_UNKN); - return purpose; - } - - switch (vendor) { - case VENDOR_AMD: - purpose = cpuid_identify_purpose_amd(raw); + const cpu_architecture_t architecture = cpuid_architecture_identify(raw); + switch (architecture) { + case ARCHITECTURE_X86: + vendor = cpuid_vendor_identify(raw->basic_cpuid[0], vendor_str); + switch (vendor) { + case VENDOR_AMD: + purpose = cpuid_identify_purpose_amd(raw); + break; + case VENDOR_INTEL: + purpose = cpuid_identify_purpose_intel(raw); + break; + default: + break; + } break; - case VENDOR_INTEL: - purpose = cpuid_identify_purpose_intel(raw); + case ARCHITECTURE_ARM: + purpose = cpuid_identify_purpose_arm(raw); break; default: - purpose = PURPOSE_GENERAL; break; } + debugf(3, "Identified a '%s' CPU core type\n", cpu_purpose_str(purpose)); return purpose; @@ -1242,25 +1422,25 @@ int cpu_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* data) } static void update_core_instances(struct internal_core_instances_t* cores, - struct internal_apic_info_t* apic_info) + struct internal_topology_t* topology) { uint32_t core_id_index = 0; - core_id_index = apic_info->core_id % CORES_HTABLE_SIZE; - if ((cores->htable[core_id_index].core_id == 0) || (cores->htable[core_id_index].core_id == apic_info->core_id)) { + core_id_index = topology->core_id % CORES_HTABLE_SIZE; + if ((cores->htable[core_id_index].core_id == 0) || (cores->htable[core_id_index].core_id == topology->core_id)) { if (cores->htable[core_id_index].num_logical_cpu == 0) cores->instances++; - cores->htable[core_id_index].core_id = apic_info->core_id; + cores->htable[core_id_index].core_id = topology->core_id; cores->htable[core_id_index].num_logical_cpu++; } else { warnf("update_core_instances: collision at index %u (core ID is %i, not %i)\n", - core_id_index, cores->htable[core_id_index].core_id, apic_info->core_id); + core_id_index, cores->htable[core_id_index].core_id, topology->core_id); } } static void update_cache_instances(struct internal_cache_instances_t* caches, - struct internal_apic_info_t* apic_info, + struct internal_topology_t* topology, struct internal_id_info_t* id_info, bool debugf_is_needed) { @@ -1269,27 +1449,27 @@ static void update_cache_instances(struct internal_cache_instances_t* caches, for (level = 0; level < NUM_CACHE_TYPES; level++) { if (id_info->cache_mask[level] == 0x00000000) { - apic_info->cache_id[level] = -1; + topology->cache_id[level] = -1; continue; } - apic_info->cache_id[level] = apic_info->apic_id & id_info->cache_mask[level]; - cache_id_index = apic_info->cache_id[level] % CACHES_HTABLE_SIZE; - if ((caches->htable[level][cache_id_index].cache_id == 0) || (caches->htable[level][cache_id_index].cache_id == apic_info->cache_id[level])) { + topology->cache_id[level] = topology->apic_id & id_info->cache_mask[level]; + cache_id_index = topology->cache_id[level] % CACHES_HTABLE_SIZE; + if ((caches->htable[level][cache_id_index].cache_id == 0) || (caches->htable[level][cache_id_index].cache_id == topology->cache_id[level])) { if (caches->htable[level][cache_id_index].num_logical_cpu == 0) caches->instances[level]++; - caches->htable[level][cache_id_index].cache_id = apic_info->cache_id[level]; + caches->htable[level][cache_id_index].cache_id = topology->cache_id[level]; caches->htable[level][cache_id_index].num_logical_cpu++; } else { warnf("update_cache_instances: collision at index %u (cache ID is %i, not %i)\n", - cache_id_index, caches->htable[level][cache_id_index].cache_id, apic_info->cache_id[level]); + cache_id_index, caches->htable[level][cache_id_index].cache_id, topology->cache_id[level]); } } if (debugf_is_needed) debugf(3, "Logical CPU %4u: APIC ID %4i, package ID %4i, core ID %4i, thread %i, L1I$ ID %4i, L1D$ ID %4i, L2$ ID %4i, L3$ ID %4i, L4$ ID %4i\n", - apic_info->logical_cpu, apic_info->apic_id, apic_info->package_id, apic_info->core_id, apic_info->smt_id, - apic_info->cache_id[L1I], apic_info->cache_id[L1D], apic_info->cache_id[L2], apic_info->cache_id[L3], apic_info->cache_id[L4]); + topology->logical_cpu, topology->apic_id, topology->package_id, topology->core_id, topology->smt_id, + topology->cache_id[L1I], topology->cache_id[L1D], topology->cache_id[L2], topology->cache_id[L3], topology->cache_id[L4]); } int cpu_identify_all(struct cpu_raw_data_array_t* raw_array, struct system_id_t* system) @@ -1298,14 +1478,14 @@ int cpu_identify_all(struct cpu_raw_data_array_t* raw_array, struct system_id_t* int ret_error = cpuid_set_error(ERR_OK); double smt_divisor; bool is_smt_supported; - bool is_apic_supported = true; + bool is_topology_supported = true; int16_t cpu_type_index = -1; int32_t cur_package_id = 0; logical_cpu_t logical_cpu = 0; cpu_purpose_t purpose; cpu_affinity_mask_t affinity_mask; struct cpu_raw_data_array_t my_raw_array; - struct internal_apic_info_t apic_info; + struct internal_topology_t topology; struct internal_type_info_array_t type_info; struct internal_cache_instances_t caches_all; @@ -1331,24 +1511,24 @@ int cpu_identify_all(struct cpu_raw_data_array_t* raw_array, struct system_id_t* APIC ID are unique for each logical CPU cores. */ purpose = cpu_ident_purpose(&raw_array->raw[logical_cpu]); - if (raw_array->with_affinity && is_apic_supported) { - is_apic_supported = cpu_ident_apic_id(logical_cpu, &raw_array->raw[logical_cpu], &apic_info); - if (is_apic_supported) - cur_package_id = apic_info.package_id; + if (raw_array->with_affinity && is_topology_supported) { + is_topology_supported = cpu_ident_id(logical_cpu, &raw_array->raw[logical_cpu], &topology); + if (is_topology_supported) + cur_package_id = topology.package_id; } /* Put data to system->cpu_types on the first iteration or when purpose is new. For motherboards with multiple CPUs, we grow the array when package ID is different. */ - cpu_type_index = cpuid_find_index_system_id(system, purpose, &type_info, cur_package_id, is_apic_supported); + cpu_type_index = cpuid_find_index_system_id(system, purpose, &type_info, cur_package_id, is_topology_supported); if (cpu_type_index < 0) { - cpu_type_index = system->num_cpu_types; + cpu_type_index = system->num_cpu_types; cpuid_grow_system_id(system, system->num_cpu_types + 1); cpuid_grow_type_info(&type_info, type_info.num + 1); cur_error = cpu_ident_internal(&raw_array->raw[logical_cpu], &system->cpu_types[cpu_type_index], &type_info.data[cpu_type_index].id_info); type_info.data[cpu_type_index].purpose = purpose; if (ret_error == ERR_OK) ret_error = cur_error; - if (is_apic_supported) + if (is_topology_supported) type_info.data[cpu_type_index].package_id = cur_package_id; if (raw_array->with_affinity) system->cpu_types[cpu_type_index].num_logical_cpus = 0; @@ -1358,10 +1538,10 @@ int cpu_identify_all(struct cpu_raw_data_array_t* raw_array, struct system_id_t* if (raw_array->with_affinity) { set_affinity_mask_bit(logical_cpu, &system->cpu_types[cpu_type_index].affinity_mask); system->cpu_types[cpu_type_index].num_logical_cpus++; - if (is_apic_supported) { - update_core_instances(&type_info.data[cpu_type_index].core_instances, &apic_info); - update_cache_instances(&type_info.data[cpu_type_index].cache_instances, &apic_info, &type_info.data[cpu_type_index].id_info, true); - update_cache_instances(&caches_all, &apic_info, &type_info.data[cpu_type_index].id_info, false); + if (is_topology_supported) { + update_core_instances(&type_info.data[cpu_type_index].core_instances, &topology); + update_cache_instances(&type_info.data[cpu_type_index].cache_instances, &topology, &type_info.data[cpu_type_index].id_info, true); + update_cache_instances(&caches_all, &topology, &type_info.data[cpu_type_index].id_info, false); } } } @@ -1370,7 +1550,7 @@ int cpu_identify_all(struct cpu_raw_data_array_t* raw_array, struct system_id_t* for (cpu_type_index = 0; cpu_type_index < system->num_cpu_types; cpu_type_index++) { /* Overwrite core and cache counters when information is available per core */ if (raw_array->with_affinity) { - if (is_apic_supported) { + if (is_topology_supported) { system->cpu_types[cpu_type_index].num_cores = type_info.data[cpu_type_index].core_instances.instances; system->cpu_types[cpu_type_index].l1_instruction_instances = type_info.data[cpu_type_index].cache_instances.instances[L1I]; system->cpu_types[cpu_type_index].l1_data_instances = type_info.data[cpu_type_index].cache_instances.instances[L1D]; @@ -1392,7 +1572,7 @@ int cpu_identify_all(struct cpu_raw_data_array_t* raw_array, struct system_id_t* cpuid_free_type_info(&type_info); /* Update the grand total of cache instances */ - if (is_apic_supported) { + if (is_topology_supported) { system->l1_instruction_total_instances = caches_all.instances[L1I]; system->l1_data_total_instances = caches_all.instances[L1D]; system->l2_total_instances = caches_all.instances[L2]; @@ -1444,6 +1624,55 @@ const char* cpu_architecture_str(cpu_architecture_t architecture) return ""; } +const char* cpu_feature_level_str(cpu_feature_level_t level) +{ + const struct { cpu_feature_level_t level; const char* name; } + matchtable[] = { + { FEATURE_LEVEL_UNKNOWN, "unknown" }, + { FEATURE_LEVEL_ARM_V1, "ARMv1" }, + { FEATURE_LEVEL_ARM_V2, "ARMv2" }, + { FEATURE_LEVEL_ARM_V3, "ARMv3" }, + { FEATURE_LEVEL_ARM_V4, "ARMv4" }, + { FEATURE_LEVEL_ARM_V4T, "ARMv4T" }, + { FEATURE_LEVEL_ARM_V5, "ARMv5" }, + { FEATURE_LEVEL_ARM_V5T, "ARMv5T" }, + { FEATURE_LEVEL_ARM_V5TE, "ARMv5TE" }, + { FEATURE_LEVEL_ARM_V5TEJ, "ARMv5TEJ" }, + { FEATURE_LEVEL_ARM_V6, "ARMv6" }, + { FEATURE_LEVEL_ARM_V6_M, "ARMv6-M" }, + { FEATURE_LEVEL_ARM_V7_A, "ARMv7-A" }, + { FEATURE_LEVEL_ARM_V7_M, "ARMv7-M" }, + { FEATURE_LEVEL_ARM_V7_R, "ARMv7-R" }, + { FEATURE_LEVEL_ARM_V7E_M, "ARMv7E-M" }, + { FEATURE_LEVEL_ARM_V8_0_A, "ARMv8.0-A" }, + { FEATURE_LEVEL_ARM_V8_0_M, "ARMv8.0-M" }, + { FEATURE_LEVEL_ARM_V8_0_R, "ARMv8.0-R" }, + { FEATURE_LEVEL_ARM_V8_1_A, "ARMv8.1-A" }, + { FEATURE_LEVEL_ARM_V8_1_M, "ARMv8.1-M" }, + { FEATURE_LEVEL_ARM_V8_2_A, "ARMv8.2-A" }, + { FEATURE_LEVEL_ARM_V8_3_A, "ARMv8.3-A" }, + { FEATURE_LEVEL_ARM_V8_4_A, "ARMv8.4-A" }, + { FEATURE_LEVEL_ARM_V8_5_A, "ARMv8.5-A" }, + { FEATURE_LEVEL_ARM_V8_6_A, "ARMv8.6-A" }, + { FEATURE_LEVEL_ARM_V8_7_A, "ARMv8.7-A" }, + { FEATURE_LEVEL_ARM_V8_8_A, "ARMv8.8-A" }, + { FEATURE_LEVEL_ARM_V8_9_A, "ARMv8.9-A" }, + { FEATURE_LEVEL_ARM_V9_0_A, "ARMv9.0-A" }, + { FEATURE_LEVEL_ARM_V9_1_A, "ARMv9.1-A" }, + { FEATURE_LEVEL_ARM_V9_2_A, "ARMv9.2-A" }, + { FEATURE_LEVEL_ARM_V9_3_A, "ARMv9.3-A" }, + { FEATURE_LEVEL_ARM_V9_4_A, "ARMv9.4-A" }, + }; + unsigned i, n = COUNT_OF(matchtable); + if (n != (NUM_CPU_FEATURE_LEVELS - FEATURE_LEVEL_ARM_V1) + 1) { + warnf("Warning: incomplete library, feature level matchtable size differs from the actual number of levels.\n"); + } + for (i = 0; i < n; i++) + if (matchtable[i].level == level) + return matchtable[i].name; + return ""; +} + const char* cpu_purpose_str(cpu_purpose_t purpose) { const struct { cpu_purpose_t purpose; const char* name; } @@ -1452,6 +1681,7 @@ const char* cpu_purpose_str(cpu_purpose_t purpose) { PURPOSE_PERFORMANCE, "performance" }, { PURPOSE_EFFICIENCY, "efficiency" }, { PURPOSE_LP_EFFICIENCY, "low-power efficiency" }, + { PURPOSE_U_PERFORMANCE, "ultimate performance" }, }; unsigned i, n = COUNT_OF(matchtable); if (n != NUM_CPU_PURPOSES) { @@ -1609,6 +1839,210 @@ const char* cpu_feature_str(cpu_feature_t feature) { CPU_FEATURE_AVX512VBMI, "avx512vbmi" }, { CPU_FEATURE_AVX512VBMI2, "avx512vbmi2" }, { CPU_FEATURE_HYPERVISOR, "hypervisor" }, + { CPU_FEATURE_ASID16, "asid16" }, + { CPU_FEATURE_ADVSIMD, "advsimd" }, + { CPU_FEATURE_CRC32, "crc32" }, + { CPU_FEATURE_CSV2_1P1, "csv2_1p1" }, + { CPU_FEATURE_CSV2_1P2, "csv2_1p2" }, + { CPU_FEATURE_CSV2_2, "csv2_2" }, + { CPU_FEATURE_CSV2_3, "csv2_3" }, + { CPU_FEATURE_DOUBLELOCK, "doublelock" }, + { CPU_FEATURE_ETS2, "ets2" }, + { CPU_FEATURE_FP, "fp" }, + { CPU_FEATURE_MIXEDEND, "mixedend" }, + { CPU_FEATURE_MIXEDENDEL0, "mixedendel0" }, + { CPU_FEATURE_PMULL, "pmull" }, + { CPU_FEATURE_PMUV3, "pmuv3" }, + { CPU_FEATURE_SHA1, "sha1" }, + { CPU_FEATURE_SHA256, "sha256" }, + { CPU_FEATURE_HAFDBS, "hafdbs" }, + { CPU_FEATURE_HPDS, "hpds" }, + { CPU_FEATURE_LOR, "lor" }, + { CPU_FEATURE_LSE, "lse" }, + { CPU_FEATURE_PAN, "pan" }, + { CPU_FEATURE_PMUV3P1, "pmuv3p1" }, + { CPU_FEATURE_RDM, "rdm" }, + { CPU_FEATURE_VHE, "vhe" }, + { CPU_FEATURE_VMID16, "vmid16" }, + //{ CPU_FEATURE_AA32HPD, "aa32hpd" }, + //{ CPU_FEATURE_AA32I8MM, "aa32i8mm" }, + { CPU_FEATURE_DPB, "dpb" }, + { CPU_FEATURE_DEBUGV8P2, "debugv8p2" }, + { CPU_FEATURE_F32MM, "f32mm" }, + { CPU_FEATURE_F64MM, "f64mm" }, + { CPU_FEATURE_FP16, "fp16" }, + { CPU_FEATURE_HPDS2, "hpds2" }, + { CPU_FEATURE_I8MM, "i8mm" }, + { CPU_FEATURE_IESB, "iesb" }, + { CPU_FEATURE_LPA, "lpa" }, + { CPU_FEATURE_LSMAOC, "lsmaoc" }, + { CPU_FEATURE_LVA, "lva" }, + { CPU_FEATURE_PAN2, "pan2" }, + { CPU_FEATURE_RAS, "ras" }, + { CPU_FEATURE_SHA3, "sha3" }, + { CPU_FEATURE_SHA512, "sha512" }, + { CPU_FEATURE_SM3, "sm3" }, + { CPU_FEATURE_SM4, "sm4" }, + { CPU_FEATURE_SPE, "spe" }, + { CPU_FEATURE_SVE, "sve" }, + { CPU_FEATURE_TTCNP, "ttcnp" }, + { CPU_FEATURE_UAO, "uao" }, + { CPU_FEATURE_XNX, "xnx" }, + { CPU_FEATURE_CCIDX, "ccidx" }, + { CPU_FEATURE_CONSTPACFIELD, "constpacfield" }, + { CPU_FEATURE_EPAC, "epac" }, + { CPU_FEATURE_FCMA, "fcma" }, + { CPU_FEATURE_FPAC, "fpac" }, + { CPU_FEATURE_FPACCOMBINE, "fpaccombine" }, + { CPU_FEATURE_JSCVT, "jscvt" }, + { CPU_FEATURE_LRCPC, "lrcpc" }, + { CPU_FEATURE_PACIMP, "pacimp" }, + { CPU_FEATURE_PACQARMA3, "pacqarma3" }, + { CPU_FEATURE_PACQARMA5, "pacqarma5" }, + { CPU_FEATURE_PAUTH, "pauth" }, + { CPU_FEATURE_SPEV1P1, "spev1p1" }, + { CPU_FEATURE_AMUV1, "amuv1" }, + { CPU_FEATURE_BBM, "bbm" }, + { CPU_FEATURE_DIT, "dit" }, + { CPU_FEATURE_DEBUGV8P4, "debugv8p4" }, + { CPU_FEATURE_DOTPROD, "dotprod" }, + { CPU_FEATURE_DOUBLEFAULT, "doublefault" }, + { CPU_FEATURE_FHM, "fhm" }, + { CPU_FEATURE_FLAGM, "flagm" }, + { CPU_FEATURE_IDST, "idst" }, + { CPU_FEATURE_LRCPC2, "lrcpc2" }, + { CPU_FEATURE_LSE2, "lse2" }, + { CPU_FEATURE_MPAM, "mpam" }, + { CPU_FEATURE_PMUV3P4, "pmuv3p4" }, + { CPU_FEATURE_RASV1P1, "rasv1p1" }, + { CPU_FEATURE_S2FWB, "s2fwb" }, + { CPU_FEATURE_SEL2, "sel2" }, + { CPU_FEATURE_TLBIOS, "tlbios" }, + { CPU_FEATURE_TLBIRANGE, "tlbirange" }, + { CPU_FEATURE_TRF, "trf" }, + { CPU_FEATURE_TTL, "ttl" }, + { CPU_FEATURE_TTST, "ttst" }, + { CPU_FEATURE_BTI, "bti" }, + { CPU_FEATURE_CSV2, "csv2" }, + { CPU_FEATURE_CSV3, "csv3" }, + { CPU_FEATURE_DPB2, "dpb2" }, + { CPU_FEATURE_E0PD, "e0pd" }, + { CPU_FEATURE_EVT, "evt" }, + { CPU_FEATURE_EXS, "exs" }, + { CPU_FEATURE_FRINTTS, "frintts" }, + { CPU_FEATURE_FLAGM2, "flagm2" }, + { CPU_FEATURE_MTE, "mte" }, + { CPU_FEATURE_MTE2, "mte2" }, + { CPU_FEATURE_PMUV3P5, "pmuv3p5" }, + { CPU_FEATURE_RNG, "rng" }, + { CPU_FEATURE_RNG_TRAP, "rng_trap" }, + { CPU_FEATURE_SB, "sb" }, + { CPU_FEATURE_SPECRES, "specres" }, + { CPU_FEATURE_SSBS, "ssbs" }, + { CPU_FEATURE_SSBS2, "ssbs2" }, + { CPU_FEATURE_AMUV1P1, "amuv1p1" }, + { CPU_FEATURE_BF16, "bf16" }, + { CPU_FEATURE_DGH, "dgh" }, + { CPU_FEATURE_ECV, "ecv" }, + { CPU_FEATURE_FGT, "fgt" }, + { CPU_FEATURE_MPAMV0P1, "mpamv0p1" }, + { CPU_FEATURE_MPAMV1P1, "mpamv1p1" }, + { CPU_FEATURE_MTPMU, "mtpmu" }, + { CPU_FEATURE_PAUTH2, "pauth2" }, + { CPU_FEATURE_TWED, "twed" }, + { CPU_FEATURE_AFP, "afp" }, + { CPU_FEATURE_EBF16, "ebf16" }, + { CPU_FEATURE_HCX, "hcx" }, + { CPU_FEATURE_LPA2, "lpa2" }, + { CPU_FEATURE_LS64, "ls64" }, + { CPU_FEATURE_LS64_ACCDATA, "ls64_accdata" }, + { CPU_FEATURE_LS64_V, "ls64_v" }, + { CPU_FEATURE_MTE3, "mte3" }, + { CPU_FEATURE_MTE_ASYM_FAULT, "mte_asym_fault" }, + { CPU_FEATURE_PAN3, "pan3" }, + { CPU_FEATURE_PMUV3P7, "pmuv3p7" }, + { CPU_FEATURE_RPRES, "rpres" }, + { CPU_FEATURE_SPEV1P2, "spev1p2" }, + { CPU_FEATURE_WFXT, "wfxt" }, + { CPU_FEATURE_XS, "xs" }, + { CPU_FEATURE_CMOW, "cmow" }, + { CPU_FEATURE_DEBUGV8P8, "debugv8p8" }, + { CPU_FEATURE_HBC, "hbc" }, + { CPU_FEATURE_MOPS, "mops" }, + { CPU_FEATURE_NMI, "nmi" }, + { CPU_FEATURE_PMUV3P8, "pmuv3p8" }, + { CPU_FEATURE_SCTLR2, "sctlr2" }, + { CPU_FEATURE_SPEV1P3, "spev1p3" }, + { CPU_FEATURE_TCR2, "tcr2" }, + { CPU_FEATURE_TIDCP1, "tidcp1" }, + { CPU_FEATURE_ADERR, "aderr" }, + { CPU_FEATURE_AIE, "aie" }, + { CPU_FEATURE_ANERR, "anerr" }, + { CPU_FEATURE_ATS1A, "ats1a" }, + { CPU_FEATURE_CLRBHB, "clrbhb" }, + { CPU_FEATURE_CSSC, "cssc" }, + { CPU_FEATURE_DEBUGV8P9, "debugv8p9" }, + { CPU_FEATURE_DOUBLEFAULT2, "doublefault2" }, + { CPU_FEATURE_ECBHB, "ecbhb" }, + { CPU_FEATURE_FGT2, "fgt2" }, + { CPU_FEATURE_HAFT, "haft" }, + { CPU_FEATURE_LRCPC3, "lrcpc3" }, + { CPU_FEATURE_MTE4, "mte4" }, + { CPU_FEATURE_MTE_ASYNC, "mte_async" }, + { CPU_FEATURE_MTE_CANONICAL_TAGS, "mte_canonical_tags" }, + { CPU_FEATURE_MTE_NO_ADDRESS_TAGS, "mte_no_address_tags" }, + { CPU_FEATURE_MTE_PERM, "mte_perm" }, + { CPU_FEATURE_MTE_STORE_ONLY, "mte_store_only" }, + { CPU_FEATURE_MTE_TAGGED_FAR, "mte_tagged_far" }, + { CPU_FEATURE_PFAR, "pfar" }, + { CPU_FEATURE_PMUV3_ICNTR, "pmuv3_icntr" }, + { CPU_FEATURE_PMUV3_SS, "pmuv3_ss" }, + { CPU_FEATURE_PMUV3P9, "pmuv3p9" }, + { CPU_FEATURE_PRFMSLC, "prfmslc" }, + { CPU_FEATURE_RASV2, "rasv2" }, + { CPU_FEATURE_RPRFM, "rprfm" }, + { CPU_FEATURE_S1PIE, "s1pie" }, + { CPU_FEATURE_S1POE, "s1poe" }, + { CPU_FEATURE_S2PIE, "s2pie" }, + { CPU_FEATURE_S2POE, "s2poe" }, + { CPU_FEATURE_SPECRES2, "specres2" }, + { CPU_FEATURE_SPE_DPFZS, "spe_dpfzs" }, + { CPU_FEATURE_SPEV1P4, "spev1p4" }, + { CPU_FEATURE_SPMU, "spmu" }, + { CPU_FEATURE_THE, "the" }, + { CPU_FEATURE_SVE2, "sve2" }, + { CPU_FEATURE_SVE_AES, "sve_aes" }, + { CPU_FEATURE_SVE_BITPERM, "sve_bitperm" }, + { CPU_FEATURE_SVE_PMULL128, "sve_pmull128" }, + { CPU_FEATURE_SVE_SHA3, "sve_sha3" }, + { CPU_FEATURE_SVE_SM4, "sve_sm4" }, + { CPU_FEATURE_TME, "tme" }, + { CPU_FEATURE_TRBE, "trbe" }, + { CPU_FEATURE_BRBE, "brbe" }, + { CPU_FEATURE_RME, "rme" }, + { CPU_FEATURE_SME, "sme" }, + { CPU_FEATURE_SME_F64F64, "sme_f64f64" }, + { CPU_FEATURE_SME_FA64, "sme_fa64" }, + { CPU_FEATURE_SME_I16I64, "sme_i16i64" }, + { CPU_FEATURE_BRBEV1P1, "brbev1p1" }, + { CPU_FEATURE_MEC, "mec" }, + { CPU_FEATURE_SME2, "sme2" }, + { CPU_FEATURE_ABLE, "able" }, + { CPU_FEATURE_BWE, "bwe" }, + { CPU_FEATURE_D128, "d128" }, + { CPU_FEATURE_EBEP, "ebep" }, + { CPU_FEATURE_GCS, "gcs" }, + { CPU_FEATURE_ITE, "ite" }, + { CPU_FEATURE_LSE128, "lse128" }, + { CPU_FEATURE_LVA3, "lva3" }, + { CPU_FEATURE_SEBEP, "sebep" }, + { CPU_FEATURE_SME2P1, "sme2p1" }, + { CPU_FEATURE_SME_F16F16, "sme_f16f16" }, + { CPU_FEATURE_SVE2P1, "sve2p1" }, + { CPU_FEATURE_SVE_B16B16, "sve_b16b16" }, + { CPU_FEATURE_SYSINSTR128, "sysinstr128" }, + { CPU_FEATURE_SYSREG128, "sysreg128" }, + { CPU_FEATURE_TRBE_EXT, "trbe_ext" }, }; unsigned i, n = COUNT_OF(matchtable); if (n != NUM_CPU_FEATURES) { @@ -1690,6 +2124,7 @@ void cpuid_get_cpu_list(cpu_vendor_t vendor, struct cpu_list_t* list) switch (vendor) { case VENDOR_INTEL: cpuid_get_list_intel(list); + cpuid_get_list_arm(vendor, list); break; case VENDOR_AMD: case VENDOR_HYGON: @@ -1719,6 +2154,26 @@ void cpuid_get_cpu_list(cpu_vendor_t vendor, struct cpu_list_t* list) case VENDOR_NSC: make_list_from_string("Geode GXm,Geode GXLV,Geode GX1,Geode GX2", list); break; + case VENDOR_ARM: + case VENDOR_BROADCOM: + case VENDOR_CAVIUM: + case VENDOR_DEC: + case VENDOR_FUJITSU: + case VENDOR_HISILICON: + case VENDOR_INFINEON: + case VENDOR_FREESCALE: + case VENDOR_NVIDIA: + case VENDOR_APM: + case VENDOR_QUALCOMM: + case VENDOR_SAMSUNG: + case VENDOR_MARVELL: + case VENDOR_APPLE: + case VENDOR_FARADAY: + case VENDOR_MICROSOFT: + case VENDOR_PHYTIUM: + case VENDOR_AMPERE: + cpuid_get_list_arm(vendor, list); + break; default: warnf("Unknown vendor passed to cpuid_get_cpu_list()\n"); cpuid_set_error(ERR_INVRANGE); @@ -1794,6 +2249,8 @@ void cpuid_free_cpu_list(struct cpu_list_t* list) for (i = 0; i < list->num_entries; i++) free(list->names[i]); free(list->names); + list->names = NULL; + list->num_entries = 0; } void cpuid_free_raw_data_array(struct cpu_raw_data_array_t* raw_array) diff --git a/libcpuid/exports.def b/libcpuid/exports.def index 711f767..e546918 100644 --- a/libcpuid/exports.def +++ b/libcpuid/exports.def @@ -46,3 +46,4 @@ cpuid_free_system_id @42 affinity_mask_str_r @43 cpuid_get_hypervisor @44 cpu_clock_by_tsc @45 +cpu_feature_level_str @46 diff --git a/libcpuid/libcpuid.dsp b/libcpuid/libcpuid.dsp index 4dc4cb5..3f1fedc 100644 --- a/libcpuid/libcpuid.dsp +++ b/libcpuid/libcpuid.dsp @@ -113,6 +113,10 @@ SOURCE=.\recog_amd.c # End Source File # Begin Source File +SOURCE=.\recog_arm.c +# End Source File +# Begin Source File + SOURCE=.\recog_intel.c # End Source File # Begin Source File @@ -153,6 +157,10 @@ SOURCE=.\recog_amd.h # End Source File # Begin Source File +SOURCE=.\recog_arm.h +# End Source File +# Begin Source File + SOURCE=.\recog_centaur.h # End Source File # Begin Source File diff --git a/libcpuid/libcpuid.h b/libcpuid/libcpuid.h index a8a6cad..78672fc 100644 --- a/libcpuid/libcpuid.h +++ b/libcpuid/libcpuid.h @@ -116,6 +116,21 @@ /* Some limits and other constants */ #include "libcpuid_constants.h" +#ifndef LIBCPUID_DEPRECATED +# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */ +# define LIBCPUID_DEPRECATED(message) [[deprecated(message)]] +# elif (defined(GNUC) && (GNUC > 4 || (GNUC == 4 && GNUC_MINOR >= 5))) || defined(__clang__) +# define LIBCPUID_DEPRECATED(message) __attribute__((deprecated(message))) +# elif defined(__GNUC__) && (__GNUC__ >= 3) +# define LIBCPUID_DEPRECATED(message) __attribute__((deprecated)) +# elif defined(_MSC_VER) +# define LIBCPUID_DEPRECATED(message) __declspec(deprecated(message)) +# else +# pragma message("WARNING: You need to implement LIBCPUID_DEPRECATED for this compiler") +# define LIBCPUID_DEPRECATED(message) +# endif +#endif /* LIBCPUID_DEPRECATED */ + #ifdef __cplusplus extern "C" { #endif @@ -135,6 +150,24 @@ typedef enum { VENDOR_SIS, /*!< x86 CPU by SiS */ VENDOR_NSC, /*!< x86 CPU by National Semiconductor */ VENDOR_HYGON, /*!< Hygon CPU */ + VENDOR_ARM, /*!< ARM CPU */ + VENDOR_BROADCOM, /*!< Broadcom Corporation CPU */ + VENDOR_CAVIUM, /*!< Cavium Inc. CPU */ + VENDOR_DEC, /*!< Digital Equipment Corporation CPU */ + VENDOR_FUJITSU, /*!< Fujitsu Ltd. CPU */ + VENDOR_HISILICON, /*!< HiSilicon Technology Co., Ltd. CPU */ + VENDOR_INFINEON, /*!< Infineon Technologies AG CPU */ + VENDOR_FREESCALE, /*!< Motorola or Freescale Semiconductor Inc. CPU */ + VENDOR_NVIDIA, /*!< NVIDIA Corporation CPU */ + VENDOR_APM, /*!< Applied Micro Circuits Corporation CPU */ + VENDOR_QUALCOMM, /*!< Qualcomm Inc. CPU */ + VENDOR_SAMSUNG, /*!< Samsung Group CPU */ + VENDOR_MARVELL, /*!< Marvell International Ltd. CPU */ + VENDOR_APPLE, /*!< Apple Inc. CPU */ + VENDOR_FARADAY, /*!< Faraday Technology CPU */ + VENDOR_MICROSOFT, /*!< Microsoft Corporation CPU */ + VENDOR_PHYTIUM, /*!< Phytium Technology Co., Ltd CPU */ + VENDOR_AMPERE, /*!< Ampere Computing CPU */ NUM_CPU_VENDORS, /*!< Valid CPU vendor ids: 0..NUM_CPU_VENDORS - 1 */ VENDOR_UNKNOWN = -1, @@ -153,6 +186,50 @@ typedef enum { } cpu_architecture_t; #define NUM_CPU_ARCHITECTURES NUM_CPU_ARCHITECTURES +/** + * @brief CPU architecture + */ +typedef enum { + /* TODO: add x86 levels */ + FEATURE_LEVEL_ARM_V1 = 100, /*!< ARMv1 */ + FEATURE_LEVEL_ARM_V2, /*!< ARMv2 */ + FEATURE_LEVEL_ARM_V3, /*!< ARMv3 */ + FEATURE_LEVEL_ARM_V4, /*!< ARMv4 */ + FEATURE_LEVEL_ARM_V4T, /*!< ARMv4T */ + FEATURE_LEVEL_ARM_V5, /*!< ARMv5 (obsolete) */ + FEATURE_LEVEL_ARM_V5T, /*!< ARMv5T */ + FEATURE_LEVEL_ARM_V5TE, /*!< ARMv5TE */ + FEATURE_LEVEL_ARM_V5TEJ, /*!< ARMv5TEJ */ + FEATURE_LEVEL_ARM_V6, /*!< ARMv6 */ + FEATURE_LEVEL_ARM_V6_M, /*!< ARMv6-M */ + FEATURE_LEVEL_ARM_V7_A, /*!< ARMv7-A */ + FEATURE_LEVEL_ARM_V7_M, /*!< ARMv7-M */ + FEATURE_LEVEL_ARM_V7_R, /*!< ARMv7-R */ + FEATURE_LEVEL_ARM_V7E_M, /*!< ARMv7E-M */ + FEATURE_LEVEL_ARM_V8_0_A, /*!< ARMv8.0-A */ + FEATURE_LEVEL_ARM_V8_0_M, /*!< ARMv8.0-M */ + FEATURE_LEVEL_ARM_V8_0_R, /*!< ARMv8.0-R */ + FEATURE_LEVEL_ARM_V8_1_A, /*!< ARMv8.1-A */ + FEATURE_LEVEL_ARM_V8_1_M, /*!< ARMv8.1-M */ + FEATURE_LEVEL_ARM_V8_2_A, /*!< ARMv8.2-A */ + FEATURE_LEVEL_ARM_V8_3_A, /*!< ARMv8.3-A */ + FEATURE_LEVEL_ARM_V8_4_A, /*!< ARMv8.4-A */ + FEATURE_LEVEL_ARM_V8_5_A, /*!< ARMv8.5-A */ + FEATURE_LEVEL_ARM_V8_6_A, /*!< ARMv8.6-A */ + FEATURE_LEVEL_ARM_V8_7_A, /*!< ARMv8.7-A */ + FEATURE_LEVEL_ARM_V8_8_A, /*!< ARMv8.8-A */ + FEATURE_LEVEL_ARM_V8_9_A, /*!< ARMv8.9-A */ + FEATURE_LEVEL_ARM_V9_0_A, /*!< ARMv9.0-A */ + FEATURE_LEVEL_ARM_V9_1_A, /*!< ARMv9.1-A */ + FEATURE_LEVEL_ARM_V9_2_A, /*!< ARMv9.2-A */ + FEATURE_LEVEL_ARM_V9_3_A, /*!< ARMv9.3-A */ + FEATURE_LEVEL_ARM_V9_4_A, /*!< ARMv9.4-A */ + + NUM_CPU_FEATURE_LEVELS, /*!< Valid feature level ids: 0..NUM_CPU_FEATURE_LEVELS - 1 */ + FEATURE_LEVEL_UNKNOWN = -1, +} cpu_feature_level_t; +#define NUM_CPU_FEATURE_LEVELS NUM_CPU_FEATURE_LEVELS + /** * @brief CPU purpose */ @@ -161,6 +238,7 @@ typedef enum { PURPOSE_PERFORMANCE, /*!< performance CPU */ PURPOSE_EFFICIENCY, /*!< efficiency CPU */ PURPOSE_LP_EFFICIENCY, /*!< low-power efficiency CPU */ + PURPOSE_U_PERFORMANCE, /*!< ultimate performance CPU */ NUM_CPU_PURPOSES, /*!< Valid CPU purpose ids: 0..NUM_CPU_PURPOSES - 1 */ } cpu_purpose_t; @@ -224,6 +302,42 @@ struct cpu_raw_data_t { * this stores the result of CPUID with eax = 8000001Dh and * ecx = 0, 1, 2... */ uint32_t amd_fn8000001dh[MAX_AMDFN8000001DH_LEVEL][NUM_REGS]; + + /** when then CPU is ARM-based and supports MIDR + * (Main ID Register) */ + uint64_t arm_midr; + + /** when then CPU is ARM-based and supports MPIDR + * (Multiprocessor Affinity Register) */ + uint64_t arm_mpidr; + + /** when then CPU is ARM-based and supports REVIDR + * (Revision ID Register) */ + uint64_t arm_revidr; + + /** when then CPU is ARM-based and supports ID_AA64DFR* + * (AArch64 Debug Feature Register) */ + uint64_t arm_id_aa64dfr[MAX_ARM_ID_AA64DFR_REGS]; + + /** when then CPU is ARM-based and supports D_AA64ISAR* + * (AArch64 Instruction Set Attribute Register) */ + uint64_t arm_id_aa64isar[MAX_ARM_ID_AA64ISAR_REGS]; + + /** when then CPU is ARM-based and supports ID_AA64MMFR* + * (AArch64 Memory Model Feature Register) */ + uint64_t arm_id_aa64mmfr[MAX_ARM_ID_AA64MMFR_REGS]; + + /** when then CPU is ARM-based and supports ID_AA64PFR* + * (AArch64 Processor Feature Register) */ + uint64_t arm_id_aa64pfr[MAX_ARM_ID_AA64PFR_REGS]; + + /** when then CPU is ARM-based and supports ID_AA64SMFR* + * (AArch64 SME Feature ID Register ) */ + uint64_t arm_id_aa64smfr[MAX_ARM_ID_AA64SMFR_REGS]; + + /** when then CPU is ARM-based and supports ID_AA64ZFR* + * (SVE Feature ID register) */ + uint64_t arm_id_aa64zfr[MAX_ARM_ID_AA64ZFR_REGS]; }; /** @@ -314,28 +428,11 @@ struct cpu_sgx_t { }; /** - * @brief This contains the recognized CPU features/info + * @brief Contains x86 specific info. + * + * @note This is part of \ref cpu_id_t. */ -struct cpu_id_t { - /** contains the CPU architecture ID (e.g. ARCHITECTURE_X86) */ - cpu_architecture_t architecture; - - /** contains the CPU vendor string, e.g. "GenuineIntel" */ - char vendor_str[VENDOR_STR_MAX]; - - /** contains the brand string, e.g. "Intel(R) Xeon(TM) CPU 2.40GHz" */ - char brand_str[BRAND_STR_MAX]; - - /** contains the recognized CPU vendor */ - cpu_vendor_t vendor; - - /** - * contain CPU flags. Used to test for features. See - * the \ref cpu_feature_t "CPU_FEATURE_*" macros below. - * @see Features - */ - uint8_t flags[CPU_FLAGS_MAX]; - +struct x86_id_t { /** CPU family (BaseFamily[3:0]) */ int32_t family; @@ -354,6 +451,107 @@ struct cpu_id_t { */ int32_t ext_model; + /** SSE execution unit size (64 or 128; -1 if N/A) */ + int32_t sse_size; + + /** contains information about SGX features if the processor, if present */ + struct cpu_sgx_t sgx; +}; + +/** + * @brief Contains ARM specific info. + * + * @note This is part of \ref cpu_id_t. + */ +struct arm_id_t { + /** CPU implementer code */ + uint8_t implementer; + + /** CPU variant number */ + uint8_t variant; + + /** CPU primary part number */ + uint16_t part_num; + + /** CPU revision number */ + uint8_t revision; +}; + +/** + * @brief This contains the recognized CPU features/info + */ +struct cpu_id_t { + /** contains the CPU architecture ID (e.g. ARCHITECTURE_X86) */ + cpu_architecture_t architecture; + + /** + * contains the CPU feature level, + * also know as microarchitecture levels (x86) + * and architecture version (ARM) + */ + cpu_feature_level_t feature_level; + + /** contains the CPU vendor string, e.g. "GenuineIntel" */ + char vendor_str[VENDOR_STR_MAX]; + + /** contains the brand string, e.g. "Intel(R) Xeon(TM) CPU 2.40GHz" */ + char brand_str[BRAND_STR_MAX]; + + /** contains the recognized CPU vendor */ + cpu_vendor_t vendor; + + /** + * contain CPU flags. Used to test for features. See + * the \ref cpu_feature_t "CPU_FEATURE_*" macros below. + * @see Features + */ + uint8_t flags[CPU_FLAGS_MAX]; + + /** + * CPU family (BaseFamily[3:0]) + * @deprecated replaced by \ref x86_id_t::family (prefix member with `x86.`, e.g. `id.x86.family`) + */ + LIBCPUID_DEPRECATED("replace with '.x86.family' in your code to fix the warning") + int32_t family; + + /** + * CPU model (BaseModel[3:0]) + * @deprecated replaced by \ref x86_id_t::model (prefix member with `x86.`, e.g. `id.x86.model`) + */ + LIBCPUID_DEPRECATED("replace with '.x86.model' in your code to fix the warning") + int32_t model; + + /** + * CPU stepping + * @deprecated replaced by \ref x86_id_t::stepping (prefix member with `x86.`, e.g. `id.x86.stepping`) + */ + LIBCPUID_DEPRECATED("replace with '.x86.stepping' in your code to fix the warning") + int32_t stepping; + + /** + * CPU display ("true") family (computed as BaseFamily[3:0]+ExtendedFamily[7:0]) + * @deprecated replaced by \ref x86_id_t::ext_family (prefix member with `x86.`, e.g. `id.x86.ext_family`) + */ + LIBCPUID_DEPRECATED("replace with '.x86.ext_family' in your code to fix the warning") + int32_t ext_family; + + /** + * CPU display ("true") model (computed as (ExtendedModel[3:0]<<4) + BaseModel[3:0]) + * For detailed discussion about what BaseModel / ExtendedModel / Model are, see Github issue #150. + * @deprecated replaced by \ref x86_id_t::ext_model (prefix member with `x86.`, e.g. `id.x86.ext_model`) + */ + LIBCPUID_DEPRECATED("replace with '.x86.ext_model' in your code to fix the warning") + int32_t ext_model; + + /** + * contains architecture specific info. + * Use \ref cpu_id_t::architecture to know which member is valid. + */ + union { + struct x86_id_t x86; + struct arm_id_t arm; + }; + /** Number of CPU cores on the current processor */ int32_t num_cores; @@ -409,6 +607,7 @@ struct cpu_id_t { /** Cache associativity for the L1 data cache. -1 if undetermined * @deprecated replaced by \ref cpu_id_t::l1_data_assoc */ + LIBCPUID_DEPRECATED("replace with 'l1_data_assoc' in your code to fix the warning") int32_t l1_assoc; /** Cache associativity for the L1 data cache. -1 if undetermined */ @@ -429,6 +628,7 @@ struct cpu_id_t { /** Cache-line size for L1 data cache. -1 if undetermined * @deprecated replaced by \ref cpu_id_t::l1_data_cacheline */ + LIBCPUID_DEPRECATED("replace with 'l1_data_cacheline' in your code to fix the warning") int32_t l1_cacheline; /** Cache-line size for L1 data cache. -1 if undetermined */ @@ -477,7 +677,11 @@ struct cpu_id_t { */ char cpu_codename[CODENAME_STR_MAX]; - /** SSE execution unit size (64 or 128; -1 if N/A) */ + /** + * SSE execution unit size (64 or 128; -1 if N/A) + * @deprecated replaced by \ref x86_id_t::sse_size (prefix member with `x86.`, e.g. `id.x86.sse_size`) + */ + LIBCPUID_DEPRECATED("replace with '.x86.sse_size' in your code to fix the warning") int32_t sse_size; /** @@ -487,7 +691,11 @@ struct cpu_id_t { */ uint8_t detection_hints[CPU_HINTS_MAX]; - /** contains information about SGX features if the processor, if present */ + /** + * contains information about SGX features if the processor, if present + * @deprecated replaced by \ref x86_id_t::sgx (prefix member with `x86.`, e.g. `id.x86.sgx`) + */ + LIBCPUID_DEPRECATED("replace with '.x86.sgx' in your code to fix the warning") struct cpu_sgx_t sgx; /** bitmask of the affinity ids this processor type is occupying */ @@ -658,6 +866,210 @@ typedef enum { CPU_FEATURE_AVX512VBMI, /*!< AVX-512 Vector Bit ManipulationInstructions (version 1) */ CPU_FEATURE_AVX512VBMI2, /*!< AVX-512 Vector Bit ManipulationInstructions (version 2) */ CPU_FEATURE_HYPERVISOR, /*!< Hypervisor present (always zero on physical CPUs) */ + CPU_FEATURE_ASID16, /*!< ARM: 16 bit ASID */ + CPU_FEATURE_ADVSIMD, /*!< ARM: Advanced SIMD Extension */ + CPU_FEATURE_CRC32, /*!< ARM: CRC32 instructions */ + CPU_FEATURE_CSV2_1P1, /*!< ARM: Cache Speculation Variant 2 */ + CPU_FEATURE_CSV2_1P2, /*!< ARM: Cache Speculation Variant 2 version 1.2 */ + CPU_FEATURE_CSV2_2, /*!< ARM: Cache Speculation Variant 2 version 2 */ + CPU_FEATURE_CSV2_3, /*!< ARM: Cache Speculation Variant 2 version 3 */ + CPU_FEATURE_DOUBLELOCK, /*!< ARM: Double Lock */ + CPU_FEATURE_ETS2, /*!< ARM: Enhanced Translation Synchronization */ + CPU_FEATURE_FP, /*!< ARM: Floating Point extensions */ + CPU_FEATURE_MIXEDEND, /*!< ARM: Mixed-endian support */ + CPU_FEATURE_MIXEDENDEL0, /*!< ARM: Mixed-endian support at EL0 */ + CPU_FEATURE_PMULL, /*!< ARM: Advanced SIMD PMULL instructions */ + CPU_FEATURE_PMUV3, /*!< ARM: PMU extension version 3 */ + CPU_FEATURE_SHA1, /*!< ARM: Advanced SIMD SHA1 instructions */ + CPU_FEATURE_SHA256, /*!< ARM: Advanced SIMD SHA256 instructions */ + CPU_FEATURE_HAFDBS, /*!< ARM: Hardware management of the Access flag and dirty state */ + CPU_FEATURE_HPDS, /*!< ARM: Hierarchical permission disables in translations tables */ + CPU_FEATURE_LOR, /*!< ARM: Limited ordering regions */ + CPU_FEATURE_LSE, /*!< ARM: Large System Extensions */ + CPU_FEATURE_PAN, /*!< ARM: Privileged access never */ + CPU_FEATURE_PMUV3P1, /*!< ARM: Armv8.1 PMU extensions */ + CPU_FEATURE_RDM, /*!< ARM: Advanced SIMD rounding double multiply accumulate instructions */ + CPU_FEATURE_VHE, /*!< ARM: Virtualization Host Extensions */ + CPU_FEATURE_VMID16, /*!< ARM: 16-bit VMID */ + //CPU_FEATURE_AA32HPD, /*!< ARM: AArch32 Hierarchical permission disables */ + //CPU_FEATURE_AA32I8MM, /*!< ARM: AArch32 Int8 matrix multiplication instructions */ + CPU_FEATURE_DPB, /*!< ARM: DC CVAP instruction */ + CPU_FEATURE_DEBUGV8P2, /*!< ARM: Debug v8.2 */ + CPU_FEATURE_F32MM, /*!< ARM: Single-precision Matrix Multiplication */ + CPU_FEATURE_F64MM, /*!< ARM: Double-precision Matrix Multiplication */ + CPU_FEATURE_FP16, /*!< ARM: Half-precision floating-point data processing */ + CPU_FEATURE_HPDS2, /*!< ARM: Hierarchical permission disables */ + CPU_FEATURE_I8MM, /*!< ARM: AArch64 Int8 matrix multiplication instructions */ + CPU_FEATURE_IESB, /*!< ARM: Implicit Error Synchronization event */ + CPU_FEATURE_LPA, /*!< ARM: Large PA and IPA support */ + CPU_FEATURE_LSMAOC, /*!< ARM: AArch32 Load/Store Multiple instruction atomicity and ordering controls */ + CPU_FEATURE_LVA, /*!< ARM: Large VA support */ + CPU_FEATURE_PAN2, /*!< ARM: AT S1E1R and AT S1E1W instruction variants affected by PSTATE.PAN */ + CPU_FEATURE_RAS, /*!< ARM: Reliability, Availability and Serviceability (RAS) Extension */ + CPU_FEATURE_SHA3, /*!< ARM: Advanced SIMD SHA3 instructions (ARMv8.2 architecture extension) */ + CPU_FEATURE_SHA512, /*!< ARM: Advanced SIMD SHA512 instructions (ARMv8.1 architecture extension) */ + CPU_FEATURE_SM3, /*!< ARM: Advanced SIMD SM3 instructions */ + CPU_FEATURE_SM4, /*!< ARM: Advanced SIMD SM4 instructions */ + CPU_FEATURE_SPE, /*!< ARM: Statistical Profiling Extension */ + CPU_FEATURE_SVE, /*!< ARM: Scalable Vector Extension */ + CPU_FEATURE_TTCNP, /*!< ARM: Translation table Common not private translations */ + CPU_FEATURE_UAO, /*!< ARM: Unprivileged Access Override control */ + CPU_FEATURE_XNX, /*!< ARM: Translation table stage 2 Unprivileged Execute-never */ + CPU_FEATURE_CCIDX, /*!< ARM: Extended cache index */ + CPU_FEATURE_CONSTPACFIELD, /*!< ARM: PAC algorithm enhancement */ + CPU_FEATURE_EPAC, /*!< ARM: Enhanced pointer authentication */ + CPU_FEATURE_FCMA, /*!< ARM: Floating-point complex number instructions */ + CPU_FEATURE_FPAC, /*!< ARM: Faulting on AUT* instructions */ + CPU_FEATURE_FPACCOMBINE, /*!< ARM: Faulting on combined pointer authentication instructions */ + CPU_FEATURE_JSCVT, /*!< ARM: JavaScript conversion instructions */ + CPU_FEATURE_LRCPC, /*!< ARM: Load-Acquire RCpc instructions */ + CPU_FEATURE_PACIMP, /*!< ARM: Pointer authentication - IMPLEMENTATION DEFINED algorithm */ + CPU_FEATURE_PACQARMA3, /*!< ARM: Pointer authentication - QARMA3 algorithm */ + CPU_FEATURE_PACQARMA5, /*!< ARM: Pointer authentication - QARMA5 algorithm */ + CPU_FEATURE_PAUTH, /*!< ARM: Pointer authentication */ + CPU_FEATURE_SPEV1P1, /*!< ARM: Statistical Profiling Extension version 1 */ + CPU_FEATURE_AMUV1, /*!< ARM: Activity Monitors Extension version 1 */ + CPU_FEATURE_BBM, /*!< ARM: Translation table break-before-make levels */ + CPU_FEATURE_DIT, /*!< ARM: Data Independent Timing instructions */ + CPU_FEATURE_DEBUGV8P4, /*!< ARM: Debug v8.4 */ + CPU_FEATURE_DOTPROD, /*!< ARM: Advanced SIMD dot product instructions */ + CPU_FEATURE_DOUBLEFAULT, /*!< ARM: Double Fault Extension */ + CPU_FEATURE_FHM, /*!< ARM: Floating-point half-precision to single-precision multiply-add instructions */ + CPU_FEATURE_FLAGM, /*!< ARM: Condition flag manipulation instructions */ + CPU_FEATURE_IDST, /*!< ARM: ID space trap handling */ + CPU_FEATURE_LRCPC2, /*!< ARM: Load-Acquire RCpc instructions version 2 */ + CPU_FEATURE_LSE2, /*!< ARM: Large System Extensions version 2 */ + CPU_FEATURE_MPAM, /*!< ARM: Memory Partitioning and Monitoring Extension */ + CPU_FEATURE_PMUV3P4, /*!< ARM: Arm8.4 PMU extensions */ + CPU_FEATURE_RASV1P1, /*!< ARM: RAS extension v1.1 */ + CPU_FEATURE_S2FWB, /*!< ARM: Stage 2 forced Write-Back */ + CPU_FEATURE_SEL2, /*!< ARM: Secure EL2 */ + CPU_FEATURE_TLBIOS, /*!< ARM: TLB invalidate instructions in Outer Shareable domain */ + CPU_FEATURE_TLBIRANGE, /*!< ARM: TLB invalidate range instructions */ + CPU_FEATURE_TRF, /*!< ARM: Self-hosted Trace extensions */ + CPU_FEATURE_TTL, /*!< ARM: Translation Table Level */ + CPU_FEATURE_TTST, /*!< ARM: Small translation tables */ + CPU_FEATURE_BTI, /*!< ARM: Branch Target Identification */ + CPU_FEATURE_CSV2, /*!< ARM: Cache Speculation Variant 2 */ + CPU_FEATURE_CSV3, /*!< ARM: Cache Speculation Variant 3 */ + CPU_FEATURE_DPB2, /*!< ARM: DC CVADP instruction */ + CPU_FEATURE_E0PD, /*!< ARM: Preventing EL0 access to halves of address maps */ + CPU_FEATURE_EVT, /*!< ARM: Enhanced Virtualization Traps */ + CPU_FEATURE_EXS, /*!< ARM: Context synchronization and exception handling */ + CPU_FEATURE_FRINTTS, /*!< ARM: Floating-point to integer instructions */ + CPU_FEATURE_FLAGM2, /*!< ARM: Enhancements to flag manipulation instructions */ + CPU_FEATURE_MTE, /*!< ARM: Memory Tagging Extension */ + CPU_FEATURE_MTE2, /*!< ARM: Memory Tagging Extension */ + CPU_FEATURE_PMUV3P5, /*!< ARM: Arm8.5 PMU extensions */ + CPU_FEATURE_RNG, /*!< ARM: Random number generator */ + CPU_FEATURE_RNG_TRAP, /*!< ARM: Trapping support for RNDR/RNDRRS */ + CPU_FEATURE_SB, /*!< ARM: Speculation Barrier */ + CPU_FEATURE_SPECRES, /*!< ARM: Speculation restriction instructions */ + CPU_FEATURE_SSBS, /*!< ARM: Speculative Store Bypass Safe */ + CPU_FEATURE_SSBS2, /*!< ARM: MRS and MSR instructions for SSBS version 2 */ + CPU_FEATURE_AMUV1P1, /*!< ARM: Activity Monitors Extension version 1.1 */ + CPU_FEATURE_BF16, /*!< ARM: AArch64 BFloat16 instructions */ + CPU_FEATURE_DGH, /*!< ARM: Data Gathering Hint */ + CPU_FEATURE_ECV, /*!< ARM: Enhanced Counter Virtualization */ + CPU_FEATURE_FGT, /*!< ARM: Fine Grain Traps */ + CPU_FEATURE_MPAMV0P1, /*!< ARM: Memory Partitioning and Monitoring version 0.1 */ + CPU_FEATURE_MPAMV1P1, /*!< ARM: Memory Partitioning and Monitoring version 1.1 */ + CPU_FEATURE_MTPMU, /*!< ARM: Multi-threaded PMU extensions */ + CPU_FEATURE_PAUTH2, /*!< ARM: Enhancements to pointer authentication */ + CPU_FEATURE_TWED, /*!< ARM: Delayed Trapping of WFE */ + CPU_FEATURE_AFP, /*!< ARM: Alternate floating-point behavior */ + CPU_FEATURE_EBF16, /*!< ARM: AArch64 Extended BFloat16 instructions */ + CPU_FEATURE_HCX, /*!< ARM: Support for the HCRX_EL2 register */ + CPU_FEATURE_LPA2, /*!< ARM: Larger physical address for 4KB and 16KB translation granules */ + CPU_FEATURE_LS64, /*!< ARM: Support for 64-byte loads and stores without status */ + CPU_FEATURE_LS64_ACCDATA, /*!< ARM: Support for 64-byte EL0 stores with status */ + CPU_FEATURE_LS64_V, /*!< ARM: Support for 64-byte stores with status */ + CPU_FEATURE_MTE3, /*!< ARM: MTE Asymmetric Fault Handling */ + CPU_FEATURE_MTE_ASYM_FAULT, /*!< ARM: Memory tagging asymmetric faults */ + CPU_FEATURE_PAN3, /*!< ARM: Support for SCTLR_ELx.EPAN */ + CPU_FEATURE_PMUV3P7, /*!< ARM: Armv8.7 PMU extensions */ + CPU_FEATURE_RPRES, /*!< ARM: Increased precision of FRECPE and FRSQRTE */ + CPU_FEATURE_SPEV1P2, /*!< ARM: Statistical Profiling Extensions version 1.2 */ + CPU_FEATURE_WFXT, /*!< ARM: WFE and WFI instructions with timeout */ + CPU_FEATURE_XS, /*!< ARM: XS attribute */ + CPU_FEATURE_CMOW, /*!< ARM: Control for cache maintenance permission */ + CPU_FEATURE_DEBUGV8P8, /*!< ARM: Debug v8.8 */ + CPU_FEATURE_HBC, /*!< ARM: Hinted conditional branches */ + CPU_FEATURE_MOPS, /*!< ARM: Standardization of memory operations */ + CPU_FEATURE_NMI, /*!< ARM: Non-maskable Interrupts */ + CPU_FEATURE_PMUV3P8, /*!< ARM: Armv8.8 PMU extensions */ + CPU_FEATURE_SCTLR2, /*!< ARM: Extension to SCTLR_ELx */ + CPU_FEATURE_SPEV1P3, /*!< ARM: Statistical Profiling Extensions version 1.3 */ + CPU_FEATURE_TCR2, /*!< ARM: Support for TCR2_ELx */ + CPU_FEATURE_TIDCP1, /*!< ARM: EL0 use of IMPLEMENTATION DEFINED functionality */ + CPU_FEATURE_ADERR, /*!< ARM: Asynchronous Device Error Exceptions */ + CPU_FEATURE_AIE, /*!< ARM: Memory Attribute Index Enhancement */ + CPU_FEATURE_ANERR, /*!< ARM: Asynchronous Normal Error Exceptions */ + CPU_FEATURE_ATS1A, /*!< ARM: Address Translation operations that ignore stage 1 permissions */ + CPU_FEATURE_CLRBHB, /*!< ARM: Support for Clear Branch History instruction */ + CPU_FEATURE_CSSC, /*!< ARM: Common Short Sequence Compression instructions */ + CPU_FEATURE_DEBUGV8P9, /*!< ARM: Debug v8.9 */ + CPU_FEATURE_DOUBLEFAULT2, /*!< ARM: Double Fault Extension v2 */ + CPU_FEATURE_ECBHB, /*!< ARM: Exploitative control using branch history information */ + CPU_FEATURE_FGT2, /*!< ARM: Fine-grained traps 2 */ + CPU_FEATURE_HAFT, /*!< ARM: Hardware managed Access Flag for Table descriptors */ + CPU_FEATURE_LRCPC3, /*!< ARM: Load-Acquire RCpc instructions version 3 */ + CPU_FEATURE_MTE4, /*!< ARM: Enhanced Memory Tagging Extension */ + CPU_FEATURE_MTE_ASYNC, /*!< ARM: Asynchronous reporting of Tag Check Fault */ + CPU_FEATURE_MTE_CANONICAL_TAGS, /*!< ARM: Canonical Tag checking for Untagged memory */ + CPU_FEATURE_MTE_NO_ADDRESS_TAGS, /*!< ARM: Memory tagging with Address tagging disabled */ + CPU_FEATURE_MTE_PERM, /*!< ARM: Allocation tag access permission */ + CPU_FEATURE_MTE_STORE_ONLY, /*!< ARM: Store-only Tag Checking */ + CPU_FEATURE_MTE_TAGGED_FAR, /*!< ARM: FAR_ELx on a Tag Check Fault */ + CPU_FEATURE_PFAR, /*!< ARM: Physical Fault Address Register Extension */ + CPU_FEATURE_PMUV3_ICNTR, /*!< ARM: Fixed-function instruction counter */ + CPU_FEATURE_PMUV3_SS, /*!< ARM: PMU Snapshot extension */ + CPU_FEATURE_PMUV3P9, /*!< ARM: Armv8.9 PMU extensions */ + CPU_FEATURE_PRFMSLC, /*!< ARM: SLC target support for PRFM instructions */ + CPU_FEATURE_RASV2, /*!< ARM: RAS Extension v2 */ + CPU_FEATURE_RPRFM, /*!< ARM: Support for Range Prefetch Memory instruction */ + CPU_FEATURE_S1PIE, /*!< ARM: Stage 1 permission indirections */ + CPU_FEATURE_S1POE, /*!< ARM: Stage 1 permission overlays */ + CPU_FEATURE_S2PIE, /*!< ARM: Stage 2 permission indirections */ + CPU_FEATURE_S2POE, /*!< ARM: Stage 1 permission overlays */ + CPU_FEATURE_SPECRES2, /*!< ARM: Enhanced speculation restriction instructions */ + CPU_FEATURE_SPE_DPFZS, /*!< ARM: Disable Cycle Counter on SPE Freeze */ + CPU_FEATURE_SPEV1P4, /*!< ARM: Statistical Profiling Extension version 1.4 */ + CPU_FEATURE_SPMU, /*!< ARM: System Performance Monitors Extension */ + CPU_FEATURE_THE, /*!< ARM: Translation Hardening Extension */ + CPU_FEATURE_SVE2, /*!< ARM: Scalable Vector Extension version 2 */ + CPU_FEATURE_SVE_AES, /*!< ARM: Scalable Vector AES instructions */ + CPU_FEATURE_SVE_BITPERM, /*!< ARM: Scalable Vector Bit Permutes instructions */ + CPU_FEATURE_SVE_PMULL128, /*!< ARM: Scalable Vector PMULL instructions */ + CPU_FEATURE_SVE_SHA3, /*!< ARM: Scalable Vector SHA3 instructions */ + CPU_FEATURE_SVE_SM4, /*!< ARM: Scalable Vector SM4 instructions */ + CPU_FEATURE_TME, /*!< ARM: Transactional Memory Extension */ + CPU_FEATURE_TRBE, /*!< ARM: Trace Buffer Extension */ + CPU_FEATURE_BRBE, /*!< ARM: Branch Record Buffer Extension */ + CPU_FEATURE_RME, /*!< ARM: Realm Management Extension */ + CPU_FEATURE_SME, /*!< ARM: Scalable Matrix Extension */ + CPU_FEATURE_SME_F64F64, /*!< ARM: Double-precision floating-point outer product instructions */ + CPU_FEATURE_SME_FA64, /*!< ARM: Full A64 instruction set support in Streaming SVE mode */ + CPU_FEATURE_SME_I16I64, /*!< ARM: 16-bit to 64-bit integer widening outer product instructions */ + CPU_FEATURE_BRBEV1P1, /*!< ARM: Branch Record Buffer Extension version 1.1 */ + CPU_FEATURE_MEC, /*!< ARM: Memory Encryption Contexts */ + CPU_FEATURE_SME2, /*!< ARM: Scalable Matrix Extensions version 2 */ + CPU_FEATURE_ABLE, /*!< ARM: Address Breakpoint Linking Extension */ + CPU_FEATURE_BWE, /*!< ARM: Breakpoint and watchpoint enhancements */ + CPU_FEATURE_D128, /*!< ARM: 128-bit Translation Tables, 56 bit PA */ + CPU_FEATURE_EBEP, /*!< ARM: Exception-based Event Profiling */ + CPU_FEATURE_GCS, /*!< ARM: Guarded Control Stack Extension */ + CPU_FEATURE_ITE, /*!< ARM: Instrumentation Trace Extension */ + CPU_FEATURE_LSE128, /*!< ARM: 128-bit Atomics */ + CPU_FEATURE_LVA3, /*!< ARM: 56-bit VA */ + CPU_FEATURE_SEBEP, /*!< ARM: Synchronous Exception-based Event Profiling */ + CPU_FEATURE_SME2P1, /*!< ARM: Scalable Matrix Extension version 2.1 */ + CPU_FEATURE_SME_F16F16, /*!< ARM: Non-widening half-precision FP16 to FP16 arithmetic for SME2. */ + CPU_FEATURE_SVE2P1, /*!< ARM: Scalable Vector Extensions version 2.1 */ + CPU_FEATURE_SVE_B16B16, /*!< ARM: Non-widening BFloat16 to BFloat16 arithmetic for SVE2 and SME2. */ + CPU_FEATURE_SYSINSTR128, /*!< ARM: 128-bit System instructions */ + CPU_FEATURE_SYSREG128, /*!< ARM: 128-bit System registers */ + CPU_FEATURE_TRBE_EXT, /*!< ARM: Trace Buffer external mode */ /* termination: */ NUM_CPU_FEATURES, } cpu_feature_t; @@ -924,6 +1336,13 @@ int cpu_request_core_type(cpu_purpose_t purpose, struct cpu_raw_data_array_t* ra */ const char* cpu_architecture_str(cpu_architecture_t architecture); +/** + * @brief Returns the short textual representation of a CPU feature level + * @param level - the feature level, whose textual representation is wanted. + * @returns a constant string like "ARMv8.0-A", "ARMv9.4-A", etc. + */ +const char* cpu_feature_level_str(cpu_feature_level_t level); + /** * @brief Returns the short textual representation of a CPU purpose * @param purpose - the purpose, whose textual representation is wanted. diff --git a/libcpuid/libcpuid.sym b/libcpuid/libcpuid.sym index b0b2e01..10b2cbc 100644 --- a/libcpuid/libcpuid.sym +++ b/libcpuid/libcpuid.sym @@ -43,3 +43,4 @@ cpuid_free_system_id affinity_mask_str_r cpuid_get_hypervisor cpu_clock_by_tsc +cpu_feature_level_str diff --git a/libcpuid/libcpuid_constants.h b/libcpuid/libcpuid_constants.h index a88a7d0..ae71e5a 100644 --- a/libcpuid/libcpuid_constants.h +++ b/libcpuid/libcpuid_constants.h @@ -35,7 +35,7 @@ #define VENDOR_STR_MAX 16 #define BRAND_STR_MAX 64 #define CODENAME_STR_MAX 64 -#define CPU_FLAGS_MAX 128 +#define CPU_FLAGS_MAX 384 #define MAX_CPUID_LEVEL 32 #define MAX_EXT_CPUID_LEVEL 32 #define MAX_INTELFN4_LEVEL 8 @@ -43,6 +43,12 @@ #define MAX_INTELFN12H_LEVEL 4 #define MAX_INTELFN14H_LEVEL 4 #define MAX_AMDFN8000001DH_LEVEL 4 +#define MAX_ARM_ID_AA64DFR_REGS 2 +#define MAX_ARM_ID_AA64ISAR_REGS 3 +#define MAX_ARM_ID_AA64MMFR_REGS 5 +#define MAX_ARM_ID_AA64PFR_REGS 3 +#define MAX_ARM_ID_AA64SMFR_REGS 1 +#define MAX_ARM_ID_AA64ZFR_REGS 1 #define CPU_HINTS_MAX 16 #define SGX_FLAGS_MAX 14 #define ADDRESS_EXT_CPUID_START 0x80000000 diff --git a/libcpuid/libcpuid_internal.h b/libcpuid/libcpuid_internal.h index 90e3d6b..9139a44 100644 --- a/libcpuid/libcpuid_internal.h +++ b/libcpuid/libcpuid_internal.h @@ -78,7 +78,7 @@ struct internal_id_info_t { int32_t cache_mask[NUM_CACHE_TYPES]; }; -struct internal_apic_info_t { +struct internal_topology_t { int32_t apic_id; int32_t package_id; int32_t core_id; diff --git a/libcpuid/libcpuid_util.c b/libcpuid/libcpuid_util.c index 34933ef..ce01278 100644 --- a/libcpuid/libcpuid_util.c +++ b/libcpuid/libcpuid_util.c @@ -97,16 +97,16 @@ static int score(const struct match_entry_t* entry, const struct cpu_id_t* data, { int i, tmp, res = 0; const struct { const char *field; int entry; int data; int score; } array[] = { - { "family", entry->family, data->family, 2 }, - { "model", entry->model, data->model, 2 }, - { "stepping", entry->stepping, data->stepping, 2 }, - { "ext_family", entry->ext_family, data->ext_family, 2 }, - { "ext_model", entry->ext_model, data->ext_model, 2 }, - { "ncores", entry->ncores, data->num_cores, 2 }, - { "l2cache", entry->l2cache, data->l2_cache, 1 }, - { "l3cache", entry->l3cache, data->l3_cache, 1 }, - { "brand_code", entry->brand_code, brand_code, 2 }, - { "model_code", entry->model_code, model_code, 2 }, + { "family", entry->family, data->x86.family, 2 }, + { "model", entry->model, data->x86.model, 2 }, + { "stepping", entry->stepping, data->x86.stepping, 2 }, + { "ext_family", entry->ext_family, data->x86.ext_family, 2 }, + { "ext_model", entry->ext_model, data->x86.ext_model, 2 }, + { "ncores", entry->ncores, data->num_cores, 2 }, + { "l2cache", entry->l2cache, data->l2_cache, 1 }, + { "l3cache", entry->l3cache, data->l3_cache, 1 }, + { "brand_code", entry->brand_code, brand_code, 2 }, + { "model_code", entry->model_code, model_code, 2 }, }; for (i = 0; i < sizeof(array) / sizeof(array[0]); i++) { if(array[i].entry == array[i].data) { @@ -130,8 +130,8 @@ int match_cpu_codename(const struct match_entry_t* matchtable, int count, int i, t; debugf(3, "Matching cpu f:%d, m:%d, s:%d, xf:%d, xm:%d, ncore:%d, l2:%d, bcode:%d, bits:%llu, code:%d\n", - data->family, data->model, data->stepping, data->ext_family, - data->ext_model, data->num_cores, data->l2_cache, brand_code, (unsigned long long) bits, model_code); + data->x86.family, data->x86.model, data->x86.stepping, data->x86.ext_family, + data->x86.ext_model, data->num_cores, data->l2_cache, brand_code, (unsigned long long) bits, model_code); for (i = 0; i < count; i++) { t = score(&matchtable[i], data, brand_code, bits, model_code); diff --git a/libcpuid/libcpuid_util.h b/libcpuid/libcpuid_util.h index 7c4d1be..dee960f 100644 --- a/libcpuid/libcpuid_util.h +++ b/libcpuid/libcpuid_util.h @@ -29,6 +29,7 @@ #include "libcpuid_internal.h" #define COUNT_OF(array) (sizeof(array) / sizeof(array[0])) +#define UNUSED(x) (void)(x) struct feature_map_t { unsigned bit; diff --git a/libcpuid/libcpuid_vc10.vcxproj b/libcpuid/libcpuid_vc10.vcxproj index 5e7ee47..8b18ed7 100644 --- a/libcpuid/libcpuid_vc10.vcxproj +++ b/libcpuid/libcpuid_vc10.vcxproj @@ -190,6 +190,7 @@ + @@ -200,6 +201,7 @@ + diff --git a/libcpuid/libcpuid_vc10.vcxproj.filters b/libcpuid/libcpuid_vc10.vcxproj.filters index 9e57fd3..831c159 100644 --- a/libcpuid/libcpuid_vc10.vcxproj.filters +++ b/libcpuid/libcpuid_vc10.vcxproj.filters @@ -30,6 +30,9 @@ Source Files + + Source Files + Source Files @@ -62,6 +65,9 @@ Header Files + + Header Files + Header Files diff --git a/libcpuid/libcpuid_vc71.vcproj b/libcpuid/libcpuid_vc71.vcproj index 25b90b7..47084e5 100644 --- a/libcpuid/libcpuid_vc71.vcproj +++ b/libcpuid/libcpuid_vc71.vcproj @@ -170,6 +170,9 @@ + + @@ -214,6 +217,9 @@ + + diff --git a/libcpuid/rdmsr.c b/libcpuid/rdmsr.c index b31de43..125a791 100644 --- a/libcpuid/rdmsr.c +++ b/libcpuid/rdmsr.c @@ -863,7 +863,7 @@ static int get_amd_multipliers(struct msr_info_t *info, uint32_t pstate, double const int num_dids = (int) COUNT_OF(divisor_t); /* Constant values for common families */ - const int magic_constant = (info->id->ext_family == 0x11) ? 0x8 : 0x10; + const int magic_constant = (info->id->x86.ext_family == 0x11) ? 0x8 : 0x10; const int is_apu = ((FUSION_C <= info->internal->code.amd) && (info->internal->code.amd <= FUSION_A)) || (info->internal->bits & _APU_); const double divisor = is_apu ? 1.0 : 2.0; @@ -872,7 +872,7 @@ static int get_amd_multipliers(struct msr_info_t *info, uint32_t pstate, double return 1; /* Overview of AMD CPU microarchitectures: https://en.wikipedia.org/wiki/List_of_AMD_CPU_microarchitectures#Nomenclature */ - switch (info->id->ext_family) { + switch (info->id->x86.ext_family) { case 0x12: /* K10 (Llano) / K12 */ /* BKDG 12h, page 469 MSRC001_00[6B:64][8:4] is CpuFid @@ -952,7 +952,7 @@ static int get_amd_multipliers(struct msr_info_t *info, uint32_t pstate, double *multiplier = ((double) CpuFid / CpuDid) * 2; break; default: - warnf("get_amd_multipliers(): unsupported CPU extended family: %xh\n", info->id->ext_family); + warnf("get_amd_multipliers(): unsupported CPU extended family: %xh\n", info->id->x86.ext_family); err = 1; break; } @@ -1131,9 +1131,9 @@ static double get_info_voltage(struct msr_info_t *info) BKDG 10h, page 49: voltage = 1.550V - 0.0125V * SviVid (SVI1) BKDG 15h, page 50: Voltage = 1.5500 - 0.00625 * Vid[7:0] (SVI2) SVI2 since Piledriver (Family 15h, 2nd-gen): Models 10h-1Fh Processors */ - VIDStep = ((info->id->ext_family < 0x15) || ((info->id->ext_family == 0x15) && (info->id->ext_model < 0x10))) ? 0.0125 : 0.00625; + VIDStep = ((info->id->x86.ext_family < 0x15) || ((info->id->x86.ext_family == 0x15) && (info->id->x86.ext_model < 0x10))) ? 0.0125 : 0.00625; err = cpu_rdmsr_range(info->handle, MSR_PSTATE_S, 2, 0, ®); - if(info->id->ext_family < 0x17) + if(info->id->x86.ext_family < 0x17) err += cpu_rdmsr_range(info->handle, MSR_PSTATE_0 + (uint32_t) reg, 15, 9, &CpuVid); else err += cpu_rdmsr_range(info->handle, MSR_PSTATE_0 + (uint32_t) reg, 21, 14, &CpuVid); diff --git a/libcpuid/rdtsc.c b/libcpuid/rdtsc.c index 7963e73..ce672a8 100644 --- a/libcpuid/rdtsc.c +++ b/libcpuid/rdtsc.c @@ -241,7 +241,7 @@ static void adjust_march_ic_multiplier(const struct cpu_id_t* id, int* numerator * 4. For Skylake and later, it is 1.6 IPC (we multiply by 5/8) */ // - if (id->sse_size < 128) { + if (id->x86.sse_size < 128) { debugf(1, "SSE execution path is 64-bit\n"); // on a CPU with half SSE unit length, SSE instructions execute at 0.5 IPC; // the resulting value must be multiplied by 2: @@ -251,14 +251,14 @@ static void adjust_march_ic_multiplier(const struct cpu_id_t* id, int* numerator } // // Bulldozer or later: assume 1.4 IPC - if ((id->vendor == VENDOR_AMD && id->ext_family >= 21) || (id->vendor == VENDOR_HYGON)) { + if ((id->vendor == VENDOR_AMD && id->x86.ext_family >= 21) || (id->vendor == VENDOR_HYGON)) { debugf(1, "cpu_clock_by_ic: Bulldozer (or later) detected, dividing result by 1.4\n"); *numerator = 5; *denom = 7; // multiply by 5/7, to divide by 1.4 } // // Skylake or later: assume 1.6 IPC - if (id->vendor == VENDOR_INTEL && id->ext_model >= 94) { + if (id->vendor == VENDOR_INTEL && id->x86.ext_model >= 94) { debugf(1, "cpu_clock_by_ic: Skylake (or later) detected, dividing result by 1.6\n"); *numerator = 5; *denom = 8; // to divide by 1.6, multiply by 5/8 @@ -354,9 +354,9 @@ int cpu_clock_by_tsc(struct cpu_raw_data_t* raw) /* If ECX is 0, the nominal core crystal clock frequency is not enumerated. For Intel processors in which CPUID.15H.EBX[31:0] ÷ CPUID.0x15.EAX[31:0] is enumerated but CPUID.15H.ECX is not enumerated, Table 20-91 can be used to look up the nominal core crystal clock frequency. */ - if ((nominal_freq_khz == 0) && (id.ext_family == 0x6)) { - debugf(1, "cpu_clock_by_tsc: nominal core crystal clock frequency is not enumerated, looking for CPUID signature %02X_%02XH\n", id.ext_family, id.ext_model); - switch (id.ext_model) { + if ((nominal_freq_khz == 0) && (id.x86.ext_family == 0x6)) { + debugf(1, "cpu_clock_by_tsc: nominal core crystal clock frequency is not enumerated, looking for CPUID signature %02X_%02XH\n", id.x86.ext_family, id.x86.ext_model); + switch (id.x86.ext_model) { case 0x55: /* Intel® Xeon® Scalable Processor Family with CPUID signature 06_55H */ nominal_freq_khz = 25000; // 25 MHz diff --git a/libcpuid/recog_amd.c b/libcpuid/recog_amd.c index 332a924..6be4bf2 100644 --- a/libcpuid/recog_amd.c +++ b/libcpuid/recog_amd.c @@ -439,11 +439,11 @@ static void load_amd_features(struct cpu_raw_data_t* raw, struct cpu_id_t* data) - bit 0: FP128 */ data->detection_hints[CPU_HINT_SSE_SIZE_AUTH] = 1; if ((raw->ext_cpuid[0x1a][EAX] >> 2) & 1) - data->sse_size = 256; + data->x86.sse_size = 256; else if ((raw->ext_cpuid[0x1a][EAX]) & 1) - data->sse_size = 128; + data->x86.sse_size = 128; else - data->sse_size = 64; + data->x86.sse_size = 64; } } @@ -496,7 +496,7 @@ static void decode_amd_number_of_cores(struct cpu_raw_data_t* raw, struct cpu_id } if (data->flags[CPU_FEATURE_HT]) { if (num_cores > 1) { - if ((data->ext_family >= 23) && (raw->ext_cpuid[0][EAX] >= 30)) + if ((data->x86.ext_family >= 23) && (raw->ext_cpuid[0][EAX] >= 30)) /* Ryzen 3 has SMT flag, but in fact cores count is equal to threads count. Ryzen 5/7 reports twice as many "real" cores (e.g. 16 cores instead of 8) because of SMT. */ /* On PPR 17h, page 82: diff --git a/libcpuid/recog_arm.c b/libcpuid/recog_arm.c new file mode 100644 index 0000000..488bf4f --- /dev/null +++ b/libcpuid/recog_arm.c @@ -0,0 +1,1011 @@ +/* + * Copyright 2024 Veselin Georgiev, + * anrieffNOSPAM @ mgail_DOT.com (convert to gmail) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include "libcpuid.h" +#include "libcpuid_util.h" +#include "libcpuid_internal.h" +#include "recog_arm.h" + +struct arm_feature_map_t { + uint8_t highbit, lowbit; + uint8_t value; + cpu_feature_t feature; + cpu_feature_level_t ver_optional, ver_mandatory; +}; + +struct arm_arch_feature_t { + uint8_t optional, mandatory; +}; + +struct arm_arch_extension_t { + struct arm_arch_feature_t present[NUM_CPU_FEATURE_LEVELS], total[NUM_CPU_FEATURE_LEVELS]; +}; + +struct arm_id_part { + const int id; + const char* name; + const char* codename; +}; + +struct arm_hw_impl { + const int32_t id; + const cpu_vendor_t vendor; + const struct arm_id_part *parts; + const char *name; +}; + +/* Decoded PartNum for all implementers + ID taken from lscpu-arm: https://github.com/util-linux/util-linux/blob/master/sys-utils/lscpu-arm.c +*/ +/* Codenames: https://en.wikichip.org/wiki/arm_holdings */ +static const struct arm_id_part arm_part[] = { + { 0x810, "ARM810", "" }, + { 0x920, "ARM920", "" }, + { 0x922, "ARM922", "" }, + { 0x926, "ARM926", "" }, + { 0x940, "ARM940", "" }, + { 0x946, "ARM946", "" }, + { 0x966, "ARM966", "" }, + { 0xa20, "ARM1020", "" }, + { 0xa22, "ARM1022", "" }, + { 0xa26, "ARM1026", "" }, + { 0xb02, "ARM11 MPCore", "" }, + { 0xb36, "ARM1136", "" }, + { 0xb56, "ARM1156", "" }, + { 0xb76, "ARM1176", "" }, + { 0xc05, "Cortex-A5", "Sparrow" }, + { 0xc07, "Cortex-A7", "Kingfisher" }, + { 0xc08, "Cortex-A8", "Tiger" }, + { 0xc09, "Cortex-A9", "Falcon" }, + { 0xc0d, "Cortex-A17", "Owl" }, /* Originally A12 */ + { 0xc0f, "Cortex-A15", "Eagle" }, + { 0xc0e, "Cortex-A17", "Owl" }, + { 0xc14, "Cortex-R4", "" }, + { 0xc15, "Cortex-R5", "" }, + { 0xc17, "Cortex-R7", "" }, + { 0xc18, "Cortex-R8", "" }, + { 0xc20, "Cortex-M0", "Swift" }, + { 0xc21, "Cortex-M1", "Proteus" }, + { 0xc23, "Cortex-M3", "Sandcat" }, + { 0xc24, "Cortex-M4", "Merlin" }, + { 0xc27, "Cortex-M7", "Pelican" }, + { 0xc60, "Cortex-M0+", "Flycatcher" }, + { 0xd01, "Cortex-A32", "Minerva" }, + { 0xd02, "Cortex-A34", "Metis" }, + { 0xd03, "Cortex-A53", "Apollo" }, + { 0xd04, "Cortex-A35", "Mercury" }, + { 0xd05, "Cortex-A55", "Ananke" }, + { 0xd06, "Cortex-A65", "Helios" }, + { 0xd07, "Cortex-A57", "Atlas" }, + { 0xd08, "Cortex-A72", "Maia" }, + { 0xd09, "Cortex-A73", "Artemis" }, + { 0xd0a, "Cortex-A75", "Prometheus" }, + { 0xd0b, "Cortex-A76", "Enyo" }, + { 0xd0c, "Neoverse-N1", "Ares" }, + { 0xd0d, "Cortex-A77", "Deimos" }, + { 0xd0e, "Cortex-A76AE", "Enyo-AE" }, + { 0xd13, "Cortex-R52", "" }, + { 0xd15, "Cortex-R82", "" }, + { 0xd16, "Cortex-R52+", "" }, + { 0xd20, "Cortex-M23", "Grebe" }, + { 0xd21, "Cortex-M33", "Teal" }, + { 0xd22, "Cortex-M55", "Yamin" }, + { 0xd23, "Cortex-M85", "" }, + { 0xd40, "Neoverse-V1", "Zeus" }, + { 0xd41, "Cortex-A78", "Hercules" }, + { 0xd42, "Cortex-A78AE", "Hercules-AE" }, + { 0xd43, "Cortex-A65AE", "Helios-AE" }, + { 0xd44, "Cortex-X1", "Hera" }, + { 0xd46, "Cortex-A510", "Klein" }, + { 0xd47, "Cortex-A710", "Matterhorn" }, + { 0xd48, "Cortex-X2", "Matterhorn ELP" }, + { 0xd49, "Neoverse-N2", "Perseus" }, + { 0xd4a, "Neoverse-E1", "Helios" }, + { 0xd4b, "Cortex-A78C", "Hercules-C" }, + { 0xd4c, "Cortex-X1C", "Hera-C" }, + { 0xd4d, "Cortex-A715", "Makalu" }, + { 0xd4e, "Cortex-X3", "Makalu ELP" }, + { 0xd4f, "Neoverse-V2", "Demeter" }, + { 0xd80, "Cortex-A520", "Hayes" }, + { 0xd81, "Cortex-A720", "Hunter" }, + { 0xd82, "Cortex-X4", "Hunter ELP" }, + { 0xd84, "Neoverse-V3", "Poseidon" }, + { 0xd8e, "Neoverse-N3", "Hermes" }, + { -1, "unknown", "" }, +}; + +static const struct arm_id_part brcm_part[] = { + { 0x0f, "Brahma-B15", "" }, + { 0x100, "Brahma-B53", "" }, + { 0x516, "ThunderX2", "" }, + { -1, "unknown", "" }, +}; + +static const struct arm_id_part dec_part[] = { + { 0xa10, "SA110", "" }, + { 0xa11, "SA1100", "" }, + { -1, "unknown", "" }, +}; + +static const struct arm_id_part cavium_part[] = { + { 0x0a0, "ThunderX", "" }, + { 0x0a1, "ThunderX-88XX", "" }, + { 0x0a2, "ThunderX-81XX", "" }, + { 0x0a3, "ThunderX-83XX", "" }, + { 0x0af, "ThunderX2-99xx", "" }, + { 0x0b0, "OcteonTX2", "" }, + { 0x0b1, "OcteonTX2-98XX", "" }, + { 0x0b2, "OcteonTX2-96XX", "" }, + { 0x0b3, "OcteonTX2-95XX", "" }, + { 0x0b4, "OcteonTX2-95XXN", "" }, + { 0x0b5, "OcteonTX2-95XXMM", "" }, + { 0x0b6, "OcteonTX2-95XXO", "" }, + { 0x0b8, "ThunderX3-T110", "" }, + { -1, "unknown", "" }, +}; + +static const struct arm_id_part apm_part[] = { + { 0x000, "X-Gene", "" }, + { -1, "unknown", "" }, +}; + +static const struct arm_id_part qcom_part[] = { + { 0x001, "Oryon", "" }, + { 0x00f, "Scorpion", "" }, + { 0x02d, "Scorpion", "" }, + { 0x04d, "Krait", "" }, + { 0x06f, "Krait", "" }, + { 0x201, "Kryo", "" }, + { 0x205, "Kryo", "" }, + { 0x211, "Kryo", "" }, + { 0x800, "Falkor-V1/Kryo", "" }, + { 0x801, "Kryo-V2", "" }, + { 0x802, "Kryo-3XX-Gold", "" }, + { 0x803, "Kryo-3XX-Silver", "" }, + { 0x804, "Kryo-4XX-Gold", "" }, + { 0x805, "Kryo-4XX-Silver", "" }, + { 0xc00, "Falkor", "" }, + { 0xc01, "Saphira", "" }, + { -1, "unknown", "" }, +}; + +static const struct arm_id_part samsung_part[] = { + { 0x001, "Exynos M1", "" }, + { 0x002, "Exynos M3", "" }, + { 0x003, "Exynos M4", "" }, + { 0x004, "Exynos M5", "" }, + { -1, "unknown", "" }, +}; + +static const struct arm_id_part nvidia_part[] = { + { 0x000, "Denver", "" }, + { 0x003, "Denver 2", "" }, + { 0x004, "Carmel", "" }, + { -1, "unknown", "" }, +}; + +static const struct arm_id_part marvell_part[] = { + { 0x131, "Feroceon-88FR131", "" }, + { 0x581, "PJ4/PJ4b", "" }, + { 0x584, "PJ4B-MP", "" }, + { -1, "unknown", "" }, +}; + +static const struct arm_id_part apple_part[] = { + { 0x000, "A6", "Swift" }, + { 0x001, "A7", "Cyclone" }, + { 0x002, "A8", "Typhoon" }, + { 0x003, "A8X", "Typhoon" }, + { 0x004, "A9", "Twister" }, + { 0x005, "A9X", "Twister" }, + { 0x006, "A10 Fusion", "Zephyr" }, + { 0x007, "A10 Fusion", "Hurricane" }, + { 0x008, "A11 Bionic", "Monsoon" }, + { 0x009, "A11 Bionic", "Mistral" }, + { 0x00b, "A12", "Vortex" }, + { 0x00c, "A12", "Tempest" }, + { 0x00f, "M9", "Tempest" }, + { 0x010, "A12X Bionic", "Vortex" }, + { 0x011, "A12X Bionic", "Tempest" }, + { 0x012, "A13 Bionic", "Lightning" }, + { 0x013, "A13 Bionic", "Thunder" }, + { 0x020, "A14", "Icestorm" }, + { 0x021, "A14", "Firestorm" }, + { 0x022, "M1", "Icestorm" }, + { 0x023, "M1", "Firestorm" }, + { 0x024, "M1 Pro", "Icestorm" }, + { 0x025, "M1 Pro", "Firestorm" }, + { 0x026, "M10", "Thunder" }, + { 0x028, "M1 Max", "Icestorm" }, + { 0x029, "M1 Max", "Firestorm" }, + { 0x030, "A15", "Blizzard" }, + { 0x031, "A15", "Avalanche" }, + { 0x032, "M2", "Blizzard" }, + { 0x033, "M2", "Avalanche" }, + { 0x034, "M2 Pro", "Blizzard" }, + { 0x035, "M2 Pro", "Avalanche" }, + { 0x036, "A16", "Sawtooth" }, + { 0x037, "A16", "Everest" }, + { 0x038, "M2 Max", "Blizzard" }, + { 0x039, "M2 Max", "Avalanche" }, + { -1, "unknown", "" }, +}; + +static const struct arm_id_part faraday_part[] = { + { 0x526, "FA526", "" }, + { 0x626, "FA626", "" }, + { -1, "unknown", "" }, +}; + +static const struct arm_id_part intel_part[] = { + { 0x200, "i80200", "" }, + { 0x210, "PXA250A", "" }, + { 0x212, "PXA210A", "" }, + { 0x242, "i80321-400", "" }, + { 0x243, "i80321-600", "" }, + { 0x290, "PXA250B/PXA26x", "" }, + { 0x292, "PXA210B", "" }, + { 0x2c2, "i80321-400-B0", "" }, + { 0x2c3, "i80321-600-B0", "" }, + { 0x2d0, "PXA250C/PXA255/PXA26x", "" }, + { 0x2d2, "PXA210C", "" }, + { 0x411, "PXA27x", "" }, + { 0x41c, "IPX425-533", "" }, + { 0x41d, "IPX425-400", "" }, + { 0x41f, "IPX425-266", "" }, + { 0x682, "PXA32x", "" }, + { 0x683, "PXA930/PXA935", "" }, + { 0x688, "PXA30x", "" }, + { 0x689, "PXA31x", "" }, + { 0xb11, "SA1110", "" }, + { 0xc12, "IPX1200", "" }, + { -1, "unknown", "" }, +}; + +static const struct arm_id_part fujitsu_part[] = { + { 0x001, "A64FX", "" }, + { -1, "unknown", "" }, +}; + +static const struct arm_id_part hisi_part[] = { + { 0xd01, "TaiShan-v110", "" }, /* used in Kunpeng-920 SoC */ + { 0xd02, "TaiShan-v120", "" }, /* used in Kirin 990A and 9000S SoCs */ + { 0xd40, "Cortex-A76", "" }, /* HiSilicon uses this ID though advertises A76 */ + { 0xd41, "Cortex-A77", "" }, /* HiSilicon uses this ID though advertises A77 */ + { -1, "unknown", "" }, +}; + +static const struct arm_id_part ampere_part[] = { + { 0xac3, "Ampere-1", "" }, + { 0xac4, "Ampere-1a", "" }, + { -1, "unknown", "" }, +}; + +static const struct arm_id_part ft_part[] = { + { 0x303, "FTC310", "" }, + { 0x660, "FTC660", "" }, + { 0x661, "FTC661", "" }, + { 0x662, "FTC662", "" }, + { 0x663, "FTC663", "" }, + { 0x664, "FTC664", "" }, + { 0x862, "FTC862", "" }, + { -1, "unknown", "" }, +}; + +static const struct arm_id_part ms_part[] = { + { 0xd49, "Azure-Cobalt-100", "" }, + { -1, "unknown", "" }, +}; + +static const struct arm_id_part unknown_part[] = { + { -1, "unknown", "" }, +}; + +/* Implementers list */ +static const struct arm_hw_impl hw_implementer[] = { + { 0x41, VENDOR_ARM, arm_part, "ARM" }, + { 0x42, VENDOR_BROADCOM, brcm_part, "Broadcom" }, + { 0x43, VENDOR_CAVIUM, cavium_part, "Cavium" }, + { 0x44, VENDOR_DEC, dec_part, "DEC" }, + { 0x46, VENDOR_FUJITSU, fujitsu_part, "FUJITSU" }, + { 0x48, VENDOR_HISILICON, hisi_part, "HiSilicon" }, + { 0x49, VENDOR_INFINEON, unknown_part, "Infineon" }, + { 0x4d, VENDOR_FREESCALE, unknown_part, "Motorola/Freescale" }, + { 0x4e, VENDOR_NVIDIA, nvidia_part, "NVIDIA" }, + { 0x50, VENDOR_APM, apm_part, "APM" }, + { 0x51, VENDOR_QUALCOMM, qcom_part, "Qualcomm" }, + { 0x53, VENDOR_SAMSUNG, samsung_part, "Samsung" }, + { 0x56, VENDOR_MARVELL, marvell_part, "Marvell" }, + { 0x61, VENDOR_APPLE, apple_part, "Apple" }, + { 0x66, VENDOR_FARADAY, faraday_part, "Faraday" }, + { 0x69, VENDOR_INTEL, intel_part, "Intel" }, + { 0x6d, VENDOR_MICROSOFT, ms_part, "Microsoft" }, + { 0x70, VENDOR_PHYTIUM, ft_part, "Phytium" }, + { 0xc0, VENDOR_AMPERE, ampere_part, "Ampere" }, + { -1, VENDOR_UNKNOWN, unknown_part, "unknown" }, +}; + +static const struct arm_hw_impl* get_cpu_implementer_from_code(uint8_t implementer) +{ + int i; + + for (i = 0; hw_implementer[i].id >= 0; i++) { + if (hw_implementer[i].id == implementer) + break; + } + + /* This function returns an item with VENDOR_UNKNOWN if implementer is not found in the "hw_implementer" array */ + return &hw_implementer[i]; +} + +static const struct arm_hw_impl* get_cpu_implementer_from_vendor(cpu_vendor_t vendor) +{ + int i; + + for (i = 0; hw_implementer[i].id >= 0; i++) { + if (hw_implementer[i].vendor == vendor) + break; + } + + /* This function returns an item with VENDOR_UNKNOWN if implementer is not found in the "hw_implementer" array */ + return &hw_implementer[i]; +} + +static const struct arm_id_part* get_cpu_implementer_parts(const struct arm_hw_impl* hw_impl, uint16_t part_num) +{ + int i; + + for (i = 0; hw_impl->parts[i].id >= 0; i++) { + if (hw_impl->parts[i].id == part_num) + break; + } + + /* This function retuns "unknown" if PartNum is not found in the "parts" array */ + return &hw_impl->parts[i]; +} + +static void set_feature_status(struct cpu_id_t* data, struct arm_arch_extension_t* ext_status, bool is_present, cpu_feature_t feature, cpu_feature_level_t optional_from, cpu_feature_level_t mandatory_from) +{ + if (optional_from >= 0) + ext_status->total[optional_from].optional++; + if (mandatory_from >= 0) + ext_status->total[mandatory_from].mandatory++; + + if (is_present) { + data->flags[feature] = 1; + debugf(3, "feature %s is present", cpu_feature_str(feature)); + if (optional_from >= 0) { + ext_status->present[optional_from].optional++; + debugf(3, " (optional from %s", cpu_feature_level_str(optional_from)); + if (mandatory_from >= 0) { + ext_status->present[mandatory_from].mandatory++; + debugf(3, ", mandatory from %s", cpu_feature_level_str(mandatory_from)); + } + debugf(3, ")"); + } + debugf(3, "\n"); + } +} + +static void match_arm_features(const struct arm_feature_map_t* matchtable, const char* reg_name, const int reg_number, uint32_t reg_value, struct cpu_id_t* data, struct arm_arch_extension_t* ext_status) +{ + int i; + bool feature_is_present; + + for (i = 0; matchtable[i].feature != -1; i++) { + feature_is_present = (EXTRACTS_BITS(reg_value, matchtable[i].highbit, matchtable[i].lowbit) == matchtable[i].value); + if (feature_is_present) + debugf(3, "Register %8s%i (0x%016X): match value %u for bits [%2u:%2u], ", reg_name, reg_number, reg_value, matchtable[i].value, matchtable[i].highbit, matchtable[i].lowbit); + set_feature_status(data, ext_status, feature_is_present, matchtable[i].feature, matchtable[i].ver_optional, matchtable[i].ver_mandatory); + } +} + +static void load_arm_feature_pauth(struct cpu_id_t* data, struct arm_arch_extension_t* ext_status) +{ + /* FEAT_PAuth, Pointer authentication + When FEAT_PAuth is implemented, one of the following must be true: + - Exactly one of the PAC algorithms is implemented. + - If the PACGA instruction and other Pointer authentication instructions use different PAC algorithms, exactly two PAC algorithms are implemented. + The PAC algorithm features are: + - FEAT_PACQARMA5. + - FEAT_PACIMP. + - FEAT_PACQARMA3. */ + set_feature_status(data, ext_status, + (data->flags[CPU_FEATURE_PACIMP] || + data->flags[CPU_FEATURE_PACQARMA3] || + data->flags[CPU_FEATURE_PACQARMA5]), + CPU_FEATURE_PAUTH, FEATURE_LEVEL_ARM_V8_2_A, FEATURE_LEVEL_ARM_V8_3_A); +} + +static void load_arm_feature_mpam(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct arm_arch_extension_t* ext_status) +{ + /* FEAT_MPAM, Memory Partitioning and Monitoring Extension + MPAM Extension version: MPAM | MPAM_frac + Not implemented: 0b0000 | 0b0000 + v0.1 is implemented: 0b0000 | 0b0001 + v1.0 is implemented: 0b0001 | 0b0000 + v1.1 is implemented: 0b0001 | 0b0001 */ + const uint8_t mpam = EXTRACTS_BITS(raw->arm_id_aa64pfr[0], 43, 40); + const uint8_t mpam_frac = EXTRACTS_BITS(raw->arm_id_aa64pfr[1], 19, 16); + if ((mpam != 0b0000) || (mpam_frac != 0b0000)) { + debugf(2, "MPAM Extension version is %u.%u\n", mpam, mpam_frac); + set_feature_status(data, ext_status, true, CPU_FEATURE_MPAM, FEATURE_LEVEL_ARM_V8_2_A, -1); + set_feature_status(data, ext_status, (mpam == 0b0000) && (mpam_frac == 0b0001), CPU_FEATURE_MPAMV0P1, FEATURE_LEVEL_ARM_V8_5_A, -1); + set_feature_status(data, ext_status, (mpam == 0b0001) && (mpam_frac == 0b0001), CPU_FEATURE_MPAMV1P1, FEATURE_LEVEL_ARM_V8_5_A, -1); + } +} + +static void load_arm_feature_mte4(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct arm_arch_extension_t* ext_status) +{ + /* FEAT_MTE4, Enhanced Memory Tagging Extension */ + const uint8_t mte = EXTRACTS_BITS(raw->arm_id_aa64pfr[1], 11, 8); + if (mte >= 0b0010) { + /* These fields are valid only if ID_AA64PFR1_EL1.MTE >= 0b0010 */ + const uint8_t mte_frac = EXTRACTS_BITS(raw->arm_id_aa64pfr[1], 43, 40); + const uint8_t mtex = EXTRACTS_BITS(raw->arm_id_aa64pfr[1], 55, 52); + set_feature_status(data, ext_status, (mte_frac == 0b0000), CPU_FEATURE_MTE_ASYNC, FEATURE_LEVEL_ARM_V8_5_A, -1); + set_feature_status(data, ext_status, (mtex == 0b0001), CPU_FEATURE_MTE_CANONICAL_TAGS, FEATURE_LEVEL_ARM_V8_7_A, -1); + set_feature_status(data, ext_status, (mtex == 0b0001), CPU_FEATURE_MTE_NO_ADDRESS_TAGS, FEATURE_LEVEL_ARM_V8_7_A, -1); + } + /* If FEAT_MTE4 is implemented, then FEAT_MTE_CANONICAL_TAGS, + FEAT_MTE_NO_ADDRESS_TAGS, FEAT_MTE_TAGGED_FAR, and + FEAT_MTE_STORE_ONLY are implemented. */ + set_feature_status(data, ext_status, + (data->flags[CPU_FEATURE_MTE_CANONICAL_TAGS] && + data->flags[CPU_FEATURE_MTE_NO_ADDRESS_TAGS] && + data->flags[CPU_FEATURE_MTE_TAGGED_FAR] && + data->flags[CPU_FEATURE_MTE_STORE_ONLY]), + CPU_FEATURE_MTE4, FEATURE_LEVEL_ARM_V8_7_A, -1); +} + +static void decode_arm_architecture_version(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct arm_arch_extension_t* ext_status) +{ + int i; + cpu_feature_level_t feature_level = FEATURE_LEVEL_UNKNOWN; + const cpu_feature_level_t *architecture_arm = NULL; + const uint8_t architecture = EXTRACTS_BITS(raw->arm_midr, 19, 16); + + const struct { uint8_t raw_value; cpu_feature_level_t enum_value; } + architecture_matchtable[] = { + { 0b0000, FEATURE_LEVEL_UNKNOWN }, + { 0b0001, FEATURE_LEVEL_ARM_V4 }, + { 0b0010, FEATURE_LEVEL_ARM_V4T }, + { 0b0011, FEATURE_LEVEL_ARM_V5 }, + { 0b0100, FEATURE_LEVEL_ARM_V5T }, + { 0b0101, FEATURE_LEVEL_ARM_V5TE }, + { 0b0110, FEATURE_LEVEL_ARM_V5TEJ }, + { 0b0111, FEATURE_LEVEL_ARM_V6 }, + { 0b1000, FEATURE_LEVEL_UNKNOWN }, + { 0b1001, FEATURE_LEVEL_UNKNOWN }, + { 0b1010, FEATURE_LEVEL_UNKNOWN }, + { 0b1011, FEATURE_LEVEL_UNKNOWN }, + { 0b1100, FEATURE_LEVEL_ARM_V6_M }, + { 0b1101, FEATURE_LEVEL_UNKNOWN }, + { 0b1110, FEATURE_LEVEL_UNKNOWN } + }; + + /** + * The Armv8.0 architecture extension + * + * The original Armv8-A architecture is called Armv8.0. It contains mandatory and optional architectural features. + * Some features must be implemented together. An implementation is Armv8.0 compliant if it includes all of the + * Armv8.0 architectural features that are mandatory. + * + * An Armv8.0 compliant implementation can additionally include: + * - Armv8.0 features that are optional. + * - Any arbitrary subset of the architectural features of Armv8.1, subject only to those constraints that require that certain features be implemented together. + */ + const cpu_feature_level_t architecture_arm_v8a[] = { + FEATURE_LEVEL_ARM_V8_0_A, /*!< ARMv8.0-A */ + FEATURE_LEVEL_ARM_V8_1_A, /*!< ARMv8.1-A */ + FEATURE_LEVEL_ARM_V8_2_A, /*!< ARMv8.2-A */ + FEATURE_LEVEL_ARM_V8_3_A, /*!< ARMv8.3-A */ + FEATURE_LEVEL_ARM_V8_4_A, /*!< ARMv8.4-A */ + FEATURE_LEVEL_ARM_V8_5_A, /*!< ARMv8.5-A */ + FEATURE_LEVEL_ARM_V8_6_A, /*!< ARMv8.6-A */ + FEATURE_LEVEL_ARM_V8_7_A, /*!< ARMv8.7-A */ + FEATURE_LEVEL_ARM_V8_8_A, /*!< ARMv8.8-A */ + FEATURE_LEVEL_ARM_V8_9_A, /*!< ARMv8.9-A */ + FEATURE_LEVEL_UNKNOWN, + }; + + /** + * The Armv9.0 architecture extension + * + * The Armv9.0 architecture extension adds mandatory and optional architectural features. Some features must be + * implemented together. An implementation is Armv9.0 compliant if all of the following apply: + * - It is Armv8.5 compliant. + * - It includes all of the Armv9.0 architectural features that are mandatory. + * + * An Armv9.0 compliant implementation can additionally include: + * - Armv9.0 features that are optional. + * - Any arbitrary subset of the architectural features of Armv9.1, subject only to those constraints that require that certain features be implemented together. + */ + const cpu_feature_level_t architecture_arm_v9a[] = { + FEATURE_LEVEL_ARM_V9_0_A, /*!< ARMv9.0-A */ + FEATURE_LEVEL_ARM_V9_1_A, /*!< ARMv9.1-A */ + FEATURE_LEVEL_ARM_V9_2_A, /*!< ARMv9.2-A */ + FEATURE_LEVEL_ARM_V9_3_A, /*!< ARMv9.3-A */ + FEATURE_LEVEL_ARM_V9_4_A, /*!< ARMv9.4-A */ + FEATURE_LEVEL_UNKNOWN, + }; + + /* Check if architecture level is explicit */ + for (i = 0; i < COUNT_OF(architecture_matchtable); i++) { + if (architecture == architecture_matchtable[i].raw_value) { + feature_level = architecture_matchtable[i].enum_value; + goto found; + } + } + + /* When architecture is 0b1111, architectural features are individually identified in the ID_* registers */ + //FIXME: it works only for A-profile architecture, M-profile and R-profile are not supported yet + if ((ext_status->present[FEATURE_LEVEL_ARM_V9_0_A].optional > 0) || (ext_status->present[FEATURE_LEVEL_ARM_V9_0_A].mandatory > 0)) + architecture_arm = architecture_arm_v9a; + else if ((ext_status->present[FEATURE_LEVEL_ARM_V8_0_A].optional > 0) || (ext_status->present[FEATURE_LEVEL_ARM_V8_0_A].mandatory > 0)) + architecture_arm = architecture_arm_v8a; + else + goto found; + + for (i = 0; architecture_arm[i] != FEATURE_LEVEL_UNKNOWN; i++) { + debugf(3, "Check if CPU is %s compliant: %2u/%2u optional features detected, %2u/%2u mandatory features required\n", + cpu_feature_level_str(architecture_arm[i]), + ext_status->present[ architecture_arm[i] ].optional, ext_status->total[ architecture_arm[i] ].optional, + ext_status->present[ architecture_arm[i] ].mandatory, ext_status->total[ architecture_arm[i] ].mandatory); + /* CPU is compliant when it includes all of the architectural features that are mandatory */ + if (ext_status->present[ architecture_arm[i] ].mandatory < ext_status->total[ architecture_arm[i] ].mandatory) + break; + /* If there are no mandatory features (like ARMv9.3-A), check that at least one optional feature is implemented */ + else if ((ext_status->total[ architecture_arm[i] ].mandatory == 0) && (ext_status->present[ architecture_arm[i] ].optional == 0)) + break; + else + feature_level = architecture_arm[i]; + } + +found: + data->feature_level = feature_level; + debugf(2, "ARM architecture version is %s\n", cpu_feature_level_str(feature_level)); +} + +#define MAX_MATCHTABLE_ITEMS 32 +#define MATCH_FEATURES_TABLE_WITH_RAW(reg) match_arm_features(matchtable_id_##reg[i], #reg, i, raw->arm_id_##reg[i], data, ext_status) +static void load_arm_features(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct arm_arch_extension_t* ext_status) +{ + int i; + + const struct arm_feature_map_t matchtable_id_aa64dfr[MAX_ARM_ID_AA64DFR_REGS][MAX_MATCHTABLE_ITEMS] = { + [0] /* ID_AA64DFR0 */ = { + { 59, 56, 0b0001, CPU_FEATURE_TRBE_EXT, FEATURE_LEVEL_ARM_V9_3_A, -1 }, + { 55, 52, 0b0001, CPU_FEATURE_BRBE, FEATURE_LEVEL_ARM_V9_1_A, -1 }, + { 55, 52, 0b0010, CPU_FEATURE_BRBEV1P1, FEATURE_LEVEL_ARM_V9_2_A, -1 }, + { 51, 48, 0b0001, CPU_FEATURE_MTPMU, FEATURE_LEVEL_ARM_V8_5_A, -1 }, + { 47, 47, 0b0001, CPU_FEATURE_TRBE, FEATURE_LEVEL_ARM_V9_0_A, -1 }, + { 43, 40, 0b0001, CPU_FEATURE_TRF, FEATURE_LEVEL_ARM_V8_3_A, -1 }, + { 39, 36, 0b0000, CPU_FEATURE_DOUBLELOCK, FEATURE_LEVEL_ARM_V8_0_A, -1 }, + { 35, 32, 0b0001, CPU_FEATURE_SPE, FEATURE_LEVEL_ARM_V8_1_A, -1 }, + { 35, 32, 0b0010, CPU_FEATURE_SPEV1P1, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { 35, 32, 0b0011, CPU_FEATURE_SPEV1P2, FEATURE_LEVEL_ARM_V8_6_A, -1 }, + { 35, 32, 0b0100, CPU_FEATURE_SPEV1P3, FEATURE_LEVEL_ARM_V8_7_A, -1 }, + { 35, 32, 0b0101, CPU_FEATURE_SPEV1P4, FEATURE_LEVEL_ARM_V8_8_A, -1 }, + { 27, 24, 0b0001, CPU_FEATURE_SEBEP, FEATURE_LEVEL_ARM_V9_3_A, -1 }, + { 19, 16, 0b0001, CPU_FEATURE_PMUV3_SS, FEATURE_LEVEL_ARM_V8_8_A, -1 }, + { 11, 8, 0b0001, CPU_FEATURE_PMUV3, FEATURE_LEVEL_ARM_V8_0_A, -1 }, /* Performance Monitors Extension, PMUv3 implemented. */ + { 11, 8, 0b0100, CPU_FEATURE_PMUV3P1, FEATURE_LEVEL_ARM_V8_1_A, -1 }, /* PMUv3 for Armv8.1 */ + { 11, 8, 0b0101, CPU_FEATURE_PMUV3P4, FEATURE_LEVEL_ARM_V8_3_A, -1 }, /* PMUv3 for Armv8.4 */ + { 11, 8, 0b0110, CPU_FEATURE_PMUV3P5, FEATURE_LEVEL_ARM_V8_4_A, -1 }, /* PMUv3 for Armv8.5 */ + { 11, 8, 0b0111, CPU_FEATURE_PMUV3P7, FEATURE_LEVEL_ARM_V8_6_A, -1 }, /* PMUv3 for Armv8.7 */ + { 11, 8, 0b1000, CPU_FEATURE_PMUV3P8, FEATURE_LEVEL_ARM_V8_7_A, -1 }, /* PMUv3 for Armv8.8 */ + { 11, 8, 0b1001, CPU_FEATURE_PMUV3P9, FEATURE_LEVEL_ARM_V8_8_A, -1 }, /* PMUv3 for Armv8.9 */ + { 3, 0, 0b1000, CPU_FEATURE_DEBUGV8P2, FEATURE_LEVEL_ARM_V8_1_A, FEATURE_LEVEL_ARM_V8_2_A }, /* Armv8.2 debug architecture */ + { 3, 0, 0b1001, CPU_FEATURE_DEBUGV8P4, FEATURE_LEVEL_ARM_V8_3_A, FEATURE_LEVEL_ARM_V8_4_A }, /* Armv8.4 debug architecture */ + { 3, 0, 0b1010, CPU_FEATURE_DEBUGV8P8, FEATURE_LEVEL_ARM_V8_7_A, FEATURE_LEVEL_ARM_V8_8_A }, /* Armv8.8 debug architecture */ + { 3, 0, 0b1011, CPU_FEATURE_DEBUGV8P9, FEATURE_LEVEL_ARM_V8_8_A, FEATURE_LEVEL_ARM_V8_9_A }, /* Armv8.9 debug architecture */ + { -1, -1, -1, -1, -1, -1 } + }, + [1] /* ID_AA64DFR1 */ = { + { 55, 52, 0b0001, CPU_FEATURE_SPE_DPFZS, FEATURE_LEVEL_ARM_V8_6_A, -1 }, + { 51, 48, 0b0001, CPU_FEATURE_EBEP, FEATURE_LEVEL_ARM_V9_3_A, -1 }, + { 47, 44, 0b0001, CPU_FEATURE_ITE, FEATURE_LEVEL_ARM_V9_3_A, -1 }, + { 43, 40, 0b0001, CPU_FEATURE_ABLE, FEATURE_LEVEL_ARM_V9_3_A, -1 }, + { 43, 40, 0b0001, CPU_FEATURE_BWE, FEATURE_LEVEL_ARM_V9_3_A, -1 }, + { 39, 36, 0b0001, CPU_FEATURE_PMUV3_ICNTR, FEATURE_LEVEL_ARM_V8_8_A, -1 }, + { 35, 32, 0b0001, CPU_FEATURE_SPMU, FEATURE_LEVEL_ARM_V8_8_A, -1 }, + { -1, -1, -1, -1, -1, -1 } + } + }; + + const struct arm_feature_map_t matchtable_id_aa64isar[MAX_ARM_ID_AA64ISAR_REGS][MAX_MATCHTABLE_ITEMS] = { + [0] /* ID_AA64ISAR0 */ = { + { 63, 60, 0b0001, CPU_FEATURE_RNG, FEATURE_LEVEL_ARM_V8_4_A, -1 }, + { 59, 56, 0b0001, CPU_FEATURE_TLBIOS, FEATURE_LEVEL_ARM_V8_3_A, FEATURE_LEVEL_ARM_V8_4_A }, /* Outer Shareable and TLB range maintenance instructions are not implemented */ + { 59, 56, 0b0010, CPU_FEATURE_TLBIOS, FEATURE_LEVEL_ARM_V8_3_A, FEATURE_LEVEL_ARM_V8_4_A }, /* Outer Shareable TLB maintenance instructions are implemented */ + { 59, 56, 0b0010, CPU_FEATURE_TLBIRANGE, FEATURE_LEVEL_ARM_V8_3_A, FEATURE_LEVEL_ARM_V8_4_A }, /* Outer Shareable TLB maintenance instructions are implemented */ + { 55, 52, 0b0001, CPU_FEATURE_FLAGM, FEATURE_LEVEL_ARM_V8_1_A, FEATURE_LEVEL_ARM_V8_4_A }, + { 55, 52, 0b0010, CPU_FEATURE_FLAGM2, FEATURE_LEVEL_ARM_V8_4_A, -1 }, + { 51, 48, 0b0001, CPU_FEATURE_FHM, FEATURE_LEVEL_ARM_V8_1_A, -1 }, + { 47, 44, 0b0001, CPU_FEATURE_DOTPROD, FEATURE_LEVEL_ARM_V8_1_A, -1 }, + { 43, 40, 0b0001, CPU_FEATURE_SM4, FEATURE_LEVEL_ARM_V8_1_A, -1 }, + { 39, 36, 0b0001, CPU_FEATURE_SM3, FEATURE_LEVEL_ARM_V8_1_A, -1 }, + { 35, 32, 0b0001, CPU_FEATURE_SHA3, FEATURE_LEVEL_ARM_V8_1_A, -1 }, + { 31, 28, 0b0001, CPU_FEATURE_RDM, FEATURE_LEVEL_ARM_V8_0_A, -1 }, + { 27, 24, 0b0001, CPU_FEATURE_TME, FEATURE_LEVEL_ARM_V9_0_A, -1 }, + { 23, 20, 0b0010, CPU_FEATURE_LSE, FEATURE_LEVEL_ARM_V8_0_A, FEATURE_LEVEL_ARM_V8_1_A }, + { 23, 20, 0b0011, CPU_FEATURE_LSE128, FEATURE_LEVEL_ARM_V9_3_A, -1 }, + { 19, 16, 0b0001, CPU_FEATURE_CRC32, FEATURE_LEVEL_ARM_V8_0_A, FEATURE_LEVEL_ARM_V8_1_A }, + { 15, 12, 0b0001, CPU_FEATURE_SHA256, FEATURE_LEVEL_ARM_V8_0_A, -1 }, + { 15, 12, 0b0010, CPU_FEATURE_SHA512, FEATURE_LEVEL_ARM_V8_1_A, -1 }, + { 11, 8, 0b0001, CPU_FEATURE_SHA1, FEATURE_LEVEL_ARM_V8_0_A, -1 }, + { 7, 4, 0b0001, CPU_FEATURE_AES, FEATURE_LEVEL_ARM_V8_0_A, -1 }, + { 7, 4, 0b0010, CPU_FEATURE_PMULL, FEATURE_LEVEL_ARM_V8_0_A, -1 }, + { -1, -1, -1, -1, -1, -1 } + }, + [1] /* ID_AA64ISAR1 */ = { + { 63, 60, 0b0001, CPU_FEATURE_LS64, FEATURE_LEVEL_ARM_V8_6_A, -1 }, + { 63, 60, 0b0010, CPU_FEATURE_LS64_V, FEATURE_LEVEL_ARM_V8_6_A, -1 }, + { 63, 60, 0b0011, CPU_FEATURE_LS64_ACCDATA, FEATURE_LEVEL_ARM_V8_6_A, -1 }, + { 59, 56, 0b0001, CPU_FEATURE_XS, FEATURE_LEVEL_ARM_V8_6_A, FEATURE_LEVEL_ARM_V8_7_A }, + { 55, 52, 0b0001, CPU_FEATURE_I8MM, FEATURE_LEVEL_ARM_V8_1_A, FEATURE_LEVEL_ARM_V8_6_A }, + { 51, 48, 0b0001, CPU_FEATURE_DGH, FEATURE_LEVEL_ARM_V8_0_A, -1 }, + { 47, 44, 0b0001, CPU_FEATURE_BF16, FEATURE_LEVEL_ARM_V8_2_A, FEATURE_LEVEL_ARM_V8_6_A }, + { 47, 44, 0b0010, CPU_FEATURE_EBF16, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { 43, 40, 0b0001, CPU_FEATURE_SPECRES, FEATURE_LEVEL_ARM_V8_0_A, FEATURE_LEVEL_ARM_V8_5_A }, + { 43, 40, 0b0010, CPU_FEATURE_SPECRES2, FEATURE_LEVEL_ARM_V8_0_A, FEATURE_LEVEL_ARM_V8_9_A }, + { 39, 36, 0b0001, CPU_FEATURE_SB, FEATURE_LEVEL_ARM_V8_0_A, FEATURE_LEVEL_ARM_V8_5_A }, + { 35, 32, 0b0001, CPU_FEATURE_FRINTTS, FEATURE_LEVEL_ARM_V8_4_A, -1 }, + { 31, 28, 0b0001, CPU_FEATURE_PACIMP, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { 27, 24, 0b0001, CPU_FEATURE_PACQARMA5, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { 23, 20, 0b0001, CPU_FEATURE_LRCPC, FEATURE_LEVEL_ARM_V8_2_A, FEATURE_LEVEL_ARM_V8_3_A }, + { 23, 20, 0b0010, CPU_FEATURE_LRCPC2, FEATURE_LEVEL_ARM_V8_2_A, FEATURE_LEVEL_ARM_V8_4_A }, + { 23, 20, 0b0011, CPU_FEATURE_LRCPC3, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { 19, 16, 0b0001, CPU_FEATURE_FCMA, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { 15, 12, 0b0001, CPU_FEATURE_JSCVT, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { 11, 8, 0b0001, CPU_FEATURE_PAUTH, FEATURE_LEVEL_ARM_V8_2_A, FEATURE_LEVEL_ARM_V8_3_A }, + { 11, 8, 0b0010, CPU_FEATURE_EPAC, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { 11, 8, 0b0011, CPU_FEATURE_PAUTH2, FEATURE_LEVEL_ARM_V8_2_A, FEATURE_LEVEL_ARM_V8_6_A }, + { 11, 8, 0b0100, CPU_FEATURE_FPAC, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { 11, 8, 0b0101, CPU_FEATURE_FPACCOMBINE, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { 7, 4, 0b0001, CPU_FEATURE_PAUTH, FEATURE_LEVEL_ARM_V8_2_A, FEATURE_LEVEL_ARM_V8_3_A }, + { 7, 4, 0b0010, CPU_FEATURE_EPAC, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { 7, 4, 0b0011, CPU_FEATURE_PAUTH2, FEATURE_LEVEL_ARM_V8_2_A, FEATURE_LEVEL_ARM_V8_6_A }, + { 7, 4, 0b0100, CPU_FEATURE_FPAC, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { 7, 4, 0b0101, CPU_FEATURE_FPACCOMBINE, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { 3, 0, 0b0001, CPU_FEATURE_DPB, FEATURE_LEVEL_ARM_V8_1_A, FEATURE_LEVEL_ARM_V8_2_A }, + { 3, 0, 0b0010, CPU_FEATURE_DPB2, FEATURE_LEVEL_ARM_V8_1_A, FEATURE_LEVEL_ARM_V8_5_A }, + { -1, -1, -1, -1, -1, -1 } + }, + [2] /* ID_AA64ISAR2 */ = { + { 63, 60, 0b0001, CPU_FEATURE_ATS1A, FEATURE_LEVEL_ARM_V8_8_A, -1 }, + { 55, 52, 0b0001, CPU_FEATURE_CSSC, FEATURE_LEVEL_ARM_V8_7_A, -1 }, + { 51, 48, 0b0001, CPU_FEATURE_RPRFM, FEATURE_LEVEL_ARM_V8_0_A, -1 }, + { 43, 40, 0b0001, CPU_FEATURE_PRFMSLC, FEATURE_LEVEL_ARM_V8_0_A, -1 }, + { 39, 36, 0b0001, CPU_FEATURE_SYSINSTR128, FEATURE_LEVEL_ARM_V9_3_A, -1 }, + { 35, 32, 0b0001, CPU_FEATURE_SYSREG128, FEATURE_LEVEL_ARM_V9_3_A, -1 }, + { 31, 28, 0b0001, CPU_FEATURE_CLRBHB, FEATURE_LEVEL_ARM_V8_0_A, FEATURE_LEVEL_ARM_V8_9_A }, + { 27, 24, 0b0001, CPU_FEATURE_CONSTPACFIELD, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { 23, 20, 0b0001, CPU_FEATURE_HBC, FEATURE_LEVEL_ARM_V8_7_A, FEATURE_LEVEL_ARM_V8_8_A }, + { 19, 16, 0b0001, CPU_FEATURE_MOPS, FEATURE_LEVEL_ARM_V8_7_A, FEATURE_LEVEL_ARM_V8_8_A }, + { 15, 12, 0b0001, CPU_FEATURE_PAUTH, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { 15, 12, 0b0010, CPU_FEATURE_EPAC, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { 15, 12, 0b0011, CPU_FEATURE_PAUTH2, FEATURE_LEVEL_ARM_V8_2_A, FEATURE_LEVEL_ARM_V8_6_A }, + { 15, 12, 0b0100, CPU_FEATURE_FPAC, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { 15, 12, 0b0101, CPU_FEATURE_FPACCOMBINE, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { 11, 8, 0b0001, CPU_FEATURE_PACQARMA3, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { 7, 4, 0b0001, CPU_FEATURE_RPRES, FEATURE_LEVEL_ARM_V8_6_A, -1 }, + { 3, 0, 0b0010, CPU_FEATURE_WFXT, FEATURE_LEVEL_ARM_V8_6_A, FEATURE_LEVEL_ARM_V8_7_A }, + { -1, -1, -1, -1, -1, -1 } + } + }; + + const struct arm_feature_map_t matchtable_id_aa64mmfr[MAX_ARM_ID_AA64MMFR_REGS][MAX_MATCHTABLE_ITEMS] = { + [0] /* ID_AA64MMFR0 */ = { + { 63, 60, 0b0001, CPU_FEATURE_ECV, FEATURE_LEVEL_ARM_V8_5_A, FEATURE_LEVEL_ARM_V8_6_A }, + { 63, 60, 0b0010, CPU_FEATURE_ECV, FEATURE_LEVEL_ARM_V8_5_A, FEATURE_LEVEL_ARM_V8_6_A }, + { 59, 56, 0b0001, CPU_FEATURE_FGT, FEATURE_LEVEL_ARM_V8_5_A, -1 }, + { 59, 56, 0b0010, CPU_FEATURE_FGT2, FEATURE_LEVEL_ARM_V8_8_A, -1 }, + { 47, 44, 0b0001, CPU_FEATURE_EXS, FEATURE_LEVEL_ARM_V8_4_A, -1 }, + { 31, 28, 0b0001, CPU_FEATURE_LPA2, FEATURE_LEVEL_ARM_V8_6_A, -1 }, + { 23, 20, 0b0001, CPU_FEATURE_LPA2, FEATURE_LEVEL_ARM_V8_6_A, -1 }, + { 19, 16, 0b0001, CPU_FEATURE_MIXEDENDEL0, FEATURE_LEVEL_ARM_V8_0_A, -1 }, + { 11, 8, 0b0001, CPU_FEATURE_MIXEDEND, FEATURE_LEVEL_ARM_V8_0_A, -1 }, + { 7, 4, 0b0010, CPU_FEATURE_ASID16, FEATURE_LEVEL_ARM_V8_0_A, -1 }, + { 3, 0, 0b0110, CPU_FEATURE_LPA, FEATURE_LEVEL_ARM_V8_1_A, -1 }, + { -1, -1, -1, -1, -1, -1 } + }, + [1] /* ID_AA64MMFR1 */ = { + { 63, 60, 0b0001, CPU_FEATURE_ECBHB, FEATURE_LEVEL_ARM_V8_0_A, FEATURE_LEVEL_ARM_V8_9_A }, + { 59, 56, 0b0001, CPU_FEATURE_CMOW, FEATURE_LEVEL_ARM_V8_7_A, FEATURE_LEVEL_ARM_V8_8_A }, + { 55, 52, 0b0001, CPU_FEATURE_TIDCP1, FEATURE_LEVEL_ARM_V8_7_A, FEATURE_LEVEL_ARM_V8_8_A }, + { 47, 44, 0b0001, CPU_FEATURE_AFP, FEATURE_LEVEL_ARM_V8_6_A, -1 }, + { 43, 40, 0b0001, CPU_FEATURE_HCX, FEATURE_LEVEL_ARM_V8_6_A, -1 }, + { 39, 36, 0b0010, CPU_FEATURE_ETS2, FEATURE_LEVEL_ARM_V8_0_A, FEATURE_LEVEL_ARM_V8_8_A }, + { 35, 32, 0b0001, CPU_FEATURE_TWED, FEATURE_LEVEL_ARM_V8_5_A, -1 }, + { 31, 28, 0b0001, CPU_FEATURE_XNX, FEATURE_LEVEL_ARM_V8_1_A, -1 }, + { 23, 20, 0b0001, CPU_FEATURE_PAN, FEATURE_LEVEL_ARM_V8_0_A, FEATURE_LEVEL_ARM_V8_1_A }, + { 23, 20, 0b0010, CPU_FEATURE_PAN2, FEATURE_LEVEL_ARM_V8_1_A, FEATURE_LEVEL_ARM_V8_2_A }, + { 23, 20, 0b0011, CPU_FEATURE_PAN3, FEATURE_LEVEL_ARM_V8_0_A, FEATURE_LEVEL_ARM_V8_7_A }, + { 19, 16, 0b0001, CPU_FEATURE_LOR, FEATURE_LEVEL_ARM_V8_0_A, FEATURE_LEVEL_ARM_V8_1_A }, + { 15, 12, 0b0001, CPU_FEATURE_HPDS, FEATURE_LEVEL_ARM_V8_0_A, FEATURE_LEVEL_ARM_V8_1_A }, + { 15, 12, 0b0010, CPU_FEATURE_HPDS2, FEATURE_LEVEL_ARM_V8_1_A, -1 }, + { 11, 8, 0b0001, CPU_FEATURE_VHE, FEATURE_LEVEL_ARM_V8_0_A, -1 }, + { 7, 4, 0b0010, CPU_FEATURE_VMID16, FEATURE_LEVEL_ARM_V8_0_A, -1 }, + { 3, 0, 0b0001, CPU_FEATURE_HAFDBS, FEATURE_LEVEL_ARM_V8_1_A, -1 }, + { 3, 0, 0b0010, CPU_FEATURE_HAFDBS, FEATURE_LEVEL_ARM_V8_1_A, -1 }, /* as 0b0001, and adds support for hardware update of the Access flag for Block and Page descriptors */ + { 3, 0, 0b0011, CPU_FEATURE_HAFT, FEATURE_LEVEL_ARM_V8_7_A, -1 }, + { -1, -1, -1, -1, -1, -1 } + }, + [2] /* ID_AA64MMFR2 */ = { + { 63, 60, 0b0001, CPU_FEATURE_E0PD, FEATURE_LEVEL_ARM_V8_4_A, FEATURE_LEVEL_ARM_V8_5_A }, + { 59, 56, 0b0001, CPU_FEATURE_EVT, FEATURE_LEVEL_ARM_V8_2_A, -1 }, /* HCR_EL2.{TOCU, TICAB, TID4} traps are supported. HCR_EL2.{TTLBOS,TTLBIS} traps are not supported */ + { 59, 56, 0b0010, CPU_FEATURE_EVT, FEATURE_LEVEL_ARM_V8_2_A, -1 }, /* HCR_EL2.{TTLBOS, TTLBIS, TOCU, TICAB, TID4} traps are supported */ + { 55, 52, 0b0000, CPU_FEATURE_BBM, FEATURE_LEVEL_ARM_V8_3_A, FEATURE_LEVEL_ARM_V8_4_A }, /* Level 0 support for changing block size is supported */ + { 55, 52, 0b0001, CPU_FEATURE_BBM, FEATURE_LEVEL_ARM_V8_3_A, FEATURE_LEVEL_ARM_V8_4_A }, /* Level 1 support for changing block size is supported */ + { 55, 52, 0b0010, CPU_FEATURE_BBM, FEATURE_LEVEL_ARM_V8_3_A, FEATURE_LEVEL_ARM_V8_4_A }, /* Level 2 support for changing block size is supported */ + { 51, 48, 0b0001, CPU_FEATURE_TTL, FEATURE_LEVEL_ARM_V8_3_A, FEATURE_LEVEL_ARM_V8_4_A }, + { 43, 40, 0b0001, CPU_FEATURE_S2FWB, FEATURE_LEVEL_ARM_V8_3_A, -1 }, + { 39, 36, 0b0001, CPU_FEATURE_IDST, FEATURE_LEVEL_ARM_V8_3_A, FEATURE_LEVEL_ARM_V8_4_A }, + { 35, 32, 0b0001, CPU_FEATURE_LSE2, FEATURE_LEVEL_ARM_V8_2_A, FEATURE_LEVEL_ARM_V8_4_A }, + { 31, 28, 0b0001, CPU_FEATURE_TTST, FEATURE_LEVEL_ARM_V8_3_A, -1 }, + { 23, 20, 0b0001, CPU_FEATURE_CCIDX, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { 19, 16, 0b0001, CPU_FEATURE_LVA, FEATURE_LEVEL_ARM_V8_1_A, -1 }, + { 19, 16, 0b0010, CPU_FEATURE_LVA3, FEATURE_LEVEL_ARM_V9_3_A, -1 }, + { 15, 12, 0b0001, CPU_FEATURE_IESB, FEATURE_LEVEL_ARM_V8_1_A, -1 }, + { 11, 8, 0b0001, CPU_FEATURE_LSMAOC, FEATURE_LEVEL_ARM_V8_1_A, -1 }, + { 7, 4, 0b0001, CPU_FEATURE_UAO, FEATURE_LEVEL_ARM_V8_1_A, FEATURE_LEVEL_ARM_V8_2_A }, + { 3, 0, 0b0001, CPU_FEATURE_TTCNP, FEATURE_LEVEL_ARM_V8_1_A, FEATURE_LEVEL_ARM_V8_2_A }, + { -1, -1, -1, -1, -1, -1 } + }, + [3] /* ID_AA64MMFR3 */ = { + { 59, 56, 0b0010, CPU_FEATURE_ADERR, FEATURE_LEVEL_ARM_V8_8_A, -1 }, + { 55, 52, 0b0010, CPU_FEATURE_ADERR, FEATURE_LEVEL_ARM_V8_8_A, -1 }, + { 47, 44, 0b0010, CPU_FEATURE_ANERR, FEATURE_LEVEL_ARM_V8_8_A, -1 }, + { 43, 40, 0b0010, CPU_FEATURE_ANERR, FEATURE_LEVEL_ARM_V8_8_A, -1 }, + { 35, 32, 0b0001, CPU_FEATURE_D128, FEATURE_LEVEL_ARM_V9_3_A, -1 }, + { 31, 28, 0b0001, CPU_FEATURE_MEC, FEATURE_LEVEL_ARM_V9_2_A, -1 }, + { 27, 24, 0b0001, CPU_FEATURE_AIE, FEATURE_LEVEL_ARM_V8_8_A, -1 }, + { 23, 20, 0b0001, CPU_FEATURE_S2POE, FEATURE_LEVEL_ARM_V8_8_A, -1 }, + { 19, 16, 0b0001, CPU_FEATURE_S1POE, FEATURE_LEVEL_ARM_V8_8_A, -1 }, + { 15, 12, 0b0001, CPU_FEATURE_S2PIE, FEATURE_LEVEL_ARM_V8_8_A, -1 }, + { 11, 8, 0b0001, CPU_FEATURE_S1PIE, FEATURE_LEVEL_ARM_V8_8_A, -1 }, + { 7, 4, 0b0001, CPU_FEATURE_SCTLR2, FEATURE_LEVEL_ARM_V8_0_A, FEATURE_LEVEL_ARM_V8_9_A }, + { 3, 0, 0b0001, CPU_FEATURE_TCR2, FEATURE_LEVEL_ARM_V8_0_A, FEATURE_LEVEL_ARM_V8_9_A }, + { -1, -1, -1, -1, -1, -1 } + }, + [4] /* ID_AA64MMFR4 */ = { + { -1, -1, -1, -1, -1, -1 } + } + }; + + const struct arm_feature_map_t matchtable_id_aa64pfr[MAX_ARM_ID_AA64PFR_REGS][MAX_MATCHTABLE_ITEMS] = { + [0] /* ID_AA64PFR0 */ = { + { 63, 60, 0b0001, CPU_FEATURE_CSV3, FEATURE_LEVEL_ARM_V8_0_A, FEATURE_LEVEL_ARM_V8_5_A }, + { 59, 56, 0b0001, CPU_FEATURE_CSV2, FEATURE_LEVEL_ARM_V8_0_A, FEATURE_LEVEL_ARM_V8_5_A }, + { 59, 56, 0b0010, CPU_FEATURE_CSV2_2, FEATURE_LEVEL_ARM_V8_0_A, -1 }, + { 59, 56, 0b0011, CPU_FEATURE_CSV2_3, FEATURE_LEVEL_ARM_V8_0_A, -1 }, + { 55, 52, 0b0001, CPU_FEATURE_RME, FEATURE_LEVEL_ARM_V9_1_A, -1 }, + { 51, 48, 0b0001, CPU_FEATURE_DIT, FEATURE_LEVEL_ARM_V8_3_A, FEATURE_LEVEL_ARM_V8_4_A }, + { 47, 44, 0b0001, CPU_FEATURE_AMUV1, FEATURE_LEVEL_ARM_V8_3_A, -1 }, + { 47, 44, 0b0010, CPU_FEATURE_AMUV1P1, FEATURE_LEVEL_ARM_V8_5_A, -1 }, + { 39, 36, 0b0001, CPU_FEATURE_SEL2, FEATURE_LEVEL_ARM_V8_3_A, -1 }, + { 35, 32, 0b0001, CPU_FEATURE_SVE, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { 31, 28, 0b0001, CPU_FEATURE_RAS, FEATURE_LEVEL_ARM_V8_0_A, FEATURE_LEVEL_ARM_V8_2_A }, + { 31, 28, 0b0010, CPU_FEATURE_DOUBLEFAULT, FEATURE_LEVEL_ARM_V8_4_A, -1 }, + { 31, 28, 0b0010, CPU_FEATURE_RASV1P1, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { 31, 28, 0b0011, CPU_FEATURE_RASV2, FEATURE_LEVEL_ARM_V8_8_A, -1 }, + { 23, 20, 0b0000, CPU_FEATURE_ADVSIMD, FEATURE_LEVEL_ARM_V8_0_A, -1 }, + { 23, 20, 0b0001, CPU_FEATURE_ADVSIMD, FEATURE_LEVEL_ARM_V8_0_A, -1 }, /* as for 0b0000, and also includes support for half-precision floating-point arithmetic */ + { 19, 16, 0b0000, CPU_FEATURE_FP, FEATURE_LEVEL_ARM_V8_0_A, -1 }, + { 19, 16, 0b0001, CPU_FEATURE_FP16, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { -1, -1, -1, -1, -1, -1 } + }, + [1] /* ID_AA64PFR1 */ = { + { 63, 60, 0b0001, CPU_FEATURE_PFAR, FEATURE_LEVEL_ARM_V8_8_A, -1 }, + { 59, 56, 0b0001, CPU_FEATURE_DOUBLEFAULT2, FEATURE_LEVEL_ARM_V8_8_A, -1 }, + { 51, 48, 0b0001, CPU_FEATURE_THE, FEATURE_LEVEL_ARM_V8_8_A, -1 }, + { 47, 44, 0b0001, CPU_FEATURE_GCS, FEATURE_LEVEL_ARM_V9_3_A, -1 }, + { 39, 36, 0b0001, CPU_FEATURE_NMI, FEATURE_LEVEL_ARM_V8_7_A, FEATURE_LEVEL_ARM_V8_8_A }, + { 35, 32, 0b0001, CPU_FEATURE_CSV2_1P1, FEATURE_LEVEL_ARM_V8_0_A, -1 }, + { 35, 32, 0b0010, CPU_FEATURE_CSV2_1P2, FEATURE_LEVEL_ARM_V8_0_A, -1 }, + { 31, 28, 0b0001, CPU_FEATURE_RNG_TRAP, FEATURE_LEVEL_ARM_V8_4_A, -1 }, + { 27, 24, 0b0001, CPU_FEATURE_SME, FEATURE_LEVEL_ARM_V9_2_A, -1 }, + { 27, 24, 0b0010, CPU_FEATURE_SME2, FEATURE_LEVEL_ARM_V9_2_A, -1 }, + { 11, 8, 0b0001, CPU_FEATURE_MTE, FEATURE_LEVEL_ARM_V8_4_A, -1 }, + { 11, 8, 0b0010, CPU_FEATURE_MTE2, FEATURE_LEVEL_ARM_V8_4_A, -1 }, + { 11, 8, 0b0011, CPU_FEATURE_MTE3, FEATURE_LEVEL_ARM_V8_5_A, -1 }, + { 11, 8, 0b0011, CPU_FEATURE_MTE_ASYM_FAULT, FEATURE_LEVEL_ARM_V8_7_A, -1 }, /* FEAT_MTE3 is implemented if and only if FEAT_MTE_ASYM_FAULT is implemented */ + { 7, 4, 0b0001, CPU_FEATURE_SSBS, FEATURE_LEVEL_ARM_V8_0_A, -1 }, + { 7, 4, 0b0010, CPU_FEATURE_SSBS2, FEATURE_LEVEL_ARM_V8_0_A, -1 }, + { 3, 0, 0b0001, CPU_FEATURE_BTI, FEATURE_LEVEL_ARM_V8_4_A, FEATURE_LEVEL_ARM_V8_5_A }, + { -1, -1, -1, -1, -1, -1 } + }, + [2] /* ID_AA64PFR2 */ = { + { 11, 8, 0b0001, CPU_FEATURE_MTE_TAGGED_FAR, FEATURE_LEVEL_ARM_V8_7_A, -1 }, + { 7, 4, 0b0001, CPU_FEATURE_MTE_STORE_ONLY, FEATURE_LEVEL_ARM_V8_7_A, -1 }, + { 3, 0, 0b0001, CPU_FEATURE_MTE_PERM, FEATURE_LEVEL_ARM_V8_7_A, -1 }, + { -1, -1, -1, -1, -1, -1 } + } + }; + + const struct arm_feature_map_t matchtable_id_aa64smfr[MAX_ARM_ID_AA64SMFR_REGS][MAX_MATCHTABLE_ITEMS] = { + [0] /* ID_AA64SMFR0 */ = { + { 63, 63, 0b1, CPU_FEATURE_SME_FA64, FEATURE_LEVEL_ARM_V9_2_A, -1 }, + { 59, 56, 0b0001, CPU_FEATURE_SME2, FEATURE_LEVEL_ARM_V9_2_A, -1 }, + { 59, 56, 0b0010, CPU_FEATURE_SME2P1, FEATURE_LEVEL_ARM_V9_2_A, -1 }, + { 55, 52, 0b1111, CPU_FEATURE_SME_I16I64, FEATURE_LEVEL_ARM_V9_2_A, -1 }, + { 48, 48, 0b1, CPU_FEATURE_SME_F64F64, FEATURE_LEVEL_ARM_V9_2_A, -1 }, + { 43, 43, 0b1, CPU_FEATURE_SVE_B16B16, FEATURE_LEVEL_ARM_V9_2_A, -1 }, + { 42, 42, 0b1, CPU_FEATURE_SME_F16F16, FEATURE_LEVEL_ARM_V9_2_A, -1 }, + { -1, -1, -1, -1, -1, -1 } + }, + }; + + const struct arm_feature_map_t matchtable_id_aa64zfr[MAX_ARM_ID_AA64ZFR_REGS][MAX_MATCHTABLE_ITEMS] = { + [0] /* ID_AA64ZFR0 */ = { + { 59, 56, 0b0001, CPU_FEATURE_F64MM, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { 55, 52, 0b0001, CPU_FEATURE_F32MM, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { 47, 44, 0b0001, CPU_FEATURE_I8MM, FEATURE_LEVEL_ARM_V8_1_A, FEATURE_LEVEL_ARM_V8_6_A }, + { 43, 40, 0b0001, CPU_FEATURE_SVE_SM4, FEATURE_LEVEL_ARM_V9_0_A, -1 }, + { 35, 32, 0b0001, CPU_FEATURE_SVE_SHA3, FEATURE_LEVEL_ARM_V9_0_A, -1 }, + { 27, 24, 0b0001, CPU_FEATURE_SVE_B16B16, FEATURE_LEVEL_ARM_V9_2_A, -1 }, + { 23, 20, 0b0001, CPU_FEATURE_BF16, FEATURE_LEVEL_ARM_V8_2_A, FEATURE_LEVEL_ARM_V8_6_A }, + { 23, 20, 0b0010, CPU_FEATURE_EBF16, FEATURE_LEVEL_ARM_V8_2_A, -1 }, + { 19, 16, 0b0001, CPU_FEATURE_SVE_BITPERM, FEATURE_LEVEL_ARM_V9_0_A, -1 }, + { 7, 4, 0b0001, CPU_FEATURE_SVE_AES, FEATURE_LEVEL_ARM_V9_0_A, -1 }, + { 7, 4, 0b0010, CPU_FEATURE_SVE_PMULL128, FEATURE_LEVEL_ARM_V9_0_A, -1 }, + { 3, 0, 0b0001, CPU_FEATURE_SVE2, FEATURE_LEVEL_ARM_V9_0_A, -1 }, + { 3, 0, 0b0001, CPU_FEATURE_SME, FEATURE_LEVEL_ARM_V9_2_A, -1 }, + { 3, 0, 0b0010, CPU_FEATURE_SME2P1, FEATURE_LEVEL_ARM_V9_2_A, -1 }, + { 3, 0, 0b0010, CPU_FEATURE_SVE2P1, FEATURE_LEVEL_ARM_V9_2_A, -1 }, + { -1, -1, -1, -1, -1, -1 } + }, + }; + + for (i = 0; i < MAX_ARM_ID_AA64DFR_REGS; i++) + MATCH_FEATURES_TABLE_WITH_RAW(aa64dfr); + + for (i = 0; i < MAX_ARM_ID_AA64ISAR_REGS; i++) + MATCH_FEATURES_TABLE_WITH_RAW(aa64isar); + + for (i = 0; i < MAX_ARM_ID_AA64MMFR_REGS; i++) + MATCH_FEATURES_TABLE_WITH_RAW(aa64mmfr); + + for (i = 0; i < MAX_ARM_ID_AA64PFR_REGS; i++) + MATCH_FEATURES_TABLE_WITH_RAW(aa64pfr); + + for (i = 0; i < MAX_ARM_ID_AA64SMFR_REGS; i++) + MATCH_FEATURES_TABLE_WITH_RAW(aa64smfr); + + for (i = 0; i < MAX_ARM_ID_AA64ZFR_REGS; i++) + MATCH_FEATURES_TABLE_WITH_RAW(aa64zfr); + + /* Some fields do not follow the standard ID scheme */ + load_arm_feature_pauth(data, ext_status); + load_arm_feature_mpam(raw, data, ext_status); + load_arm_feature_mte4(raw, data, ext_status); +} +#undef MAX_MATCHTABLE_ITEMS +#undef MATCH_FEATURES_TABLE_WITH_RAW + +int cpuid_identify_arm(struct cpu_raw_data_t* raw, struct cpu_id_t* data) +{ + struct arm_arch_extension_t ext_status; + memset(&ext_status, 0, sizeof(struct arm_arch_extension_t)); + + /* Basic values extraction + Based on "Arm Architecture Reference Manual for A-profile architecture", section D23.2.122 "MIDR_EL1, Main ID Register" + */ + data->arm.implementer = EXTRACTS_BITS(raw->arm_midr, 31, 24); + data->arm.variant = EXTRACTS_BITS(raw->arm_midr, 23, 20); + data->arm.part_num = EXTRACTS_BITS(raw->arm_midr, 15, 4); + data->arm.revision = EXTRACTS_BITS(raw->arm_midr, 3, 0); + data->purpose = cpuid_identify_purpose_arm(raw); + + /* Values decoding */ + const struct arm_hw_impl* hw_impl = get_cpu_implementer_from_code(data->arm.implementer); + const struct arm_id_part* id_part = get_cpu_implementer_parts(hw_impl, data->arm.part_num); + data->vendor = hw_impl->vendor; + strncpy(data->vendor_str, hw_impl->name, VENDOR_STR_MAX); + strncpy(data->brand_str, id_part->name, BRAND_STR_MAX); + strncpy(data->cpu_codename, id_part->codename, CODENAME_STR_MAX); + load_arm_features(raw, data, &ext_status); + decode_arm_architecture_version(raw, data, &ext_status); + + return 0; +} + +void cpuid_get_list_arm(cpu_vendor_t vendor, struct cpu_list_t* list) +{ + int i, j, n, good, sub_count, total_count; + char **tmp_names = NULL; + const struct arm_hw_impl* hw_impl = get_cpu_implementer_from_vendor(vendor); + + /* Get item count in hw_impl->parts */ + sub_count = 0; + for (i = 0; hw_impl->parts[i].id >= 0; i++) + sub_count++; + total_count = list->num_entries + sub_count; + if (sub_count == 0) + return; + + /* Grow current list */ + n = list->num_entries; + tmp_names = (char**) realloc(list->names, sizeof(char*) * total_count); + if (!tmp_names) { /* Memory allocation failure */ + cpuid_set_error(ERR_NO_MEM); + return; + } + list->names = tmp_names; + + /* Append item to list */ + for (i = 0; i < sub_count; i++) { + if (strstr(hw_impl->parts[i].name, "Unknown")) continue; + good = 1; + for (j = n - 1; j >= 0; j--) + if (!strcmp(list->names[j], hw_impl->parts[i].name)) { + good = 0; + break; + } + if (!good) continue; +#if defined(_MSC_VER) + list->names[n] = _strdup(hw_impl->parts[i].name); +#else + list->names[n] = strdup(hw_impl->parts[i].name); +#endif + if (!list->names[n]) { /* Memory allocation failure */ + cpuid_set_error(ERR_NO_MEM); + list->num_entries = 0; + for (j = 0; j < n; j++) { + free(list->names[j]); + } + free(list->names); + list->names = NULL; + return; + } + n++; + } + list->num_entries = n; +} + +cpu_purpose_t cpuid_identify_purpose_arm(struct cpu_raw_data_t* raw) +{ + const uint8_t implementer = EXTRACTS_BITS(raw->arm_midr, 31, 24); + const uint16_t part_num = EXTRACTS_BITS(raw->arm_midr, 15, 4); + const struct arm_hw_impl* hw_impl = get_cpu_implementer_from_code(implementer); + const struct arm_id_part* id_part = get_cpu_implementer_parts(hw_impl, part_num); + + /* ARM big.LITTLE Typical Processor Combinations: https://www.arm.com/technologies/big-little */ + if (match_pattern(id_part->name, "Cortex-X[012356789]")) + return PURPOSE_U_PERFORMANCE; + else if (match_pattern(id_part->name, "Cortex-A[67][012356789]") || match_pattern(id_part->name, "Cortex-A[5][6789]")) + return PURPOSE_PERFORMANCE; + else if (match_pattern(id_part->name, "Cortex-A[5][012345]") || match_pattern(id_part->name, "Cortex-A[3][0123456789]")) + return PURPOSE_EFFICIENCY; + + return PURPOSE_GENERAL; +} diff --git a/libcpuid/recog_arm.h b/libcpuid/recog_arm.h new file mode 100644 index 0000000..2655359 --- /dev/null +++ b/libcpuid/recog_arm.h @@ -0,0 +1,33 @@ +/* + * Copyright 2024 Veselin Georgiev, + * anrieffNOSPAM @ mgail_DOT.com (convert to gmail) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __RECOG_ARM_H__ +#define __RECOG_ARM_H__ + +int cpuid_identify_arm(struct cpu_raw_data_t* raw, struct cpu_id_t* data); +void cpuid_get_list_arm(cpu_vendor_t vendor, struct cpu_list_t* list); +cpu_purpose_t cpuid_identify_purpose_arm(struct cpu_raw_data_t* raw); + +#endif /* __RECOG_ARM_H__ */ diff --git a/libcpuid/recog_intel.c b/libcpuid/recog_intel.c index a091843..63a0e6f 100644 --- a/libcpuid/recog_intel.c +++ b/libcpuid/recog_intel.c @@ -694,7 +694,7 @@ static void decode_intel_oldstyle_cache_info(struct cpu_raw_data_t* raw, struct * CPUs (notably Conroe et al), this is L2 cache. In both cases * it means 4MB, 16-way associative, 64-byte line size. */ - if (data->family == 0xf && data->model == 0x6) { + if (data->x86.family == 0xf && data->x86.model == 0x6) { data->l3_cache = 4096; data->l3_assoc = 16; data->l3_cacheline = 64; @@ -874,7 +874,7 @@ static intel_code_and_bits_t get_brand_code_and_bits(struct cpu_id_t* data) code = GAINESTOWN; else if (match_pattern(bs, "[ELXW]56##")) code = WESTMERE; - else if (data->l3_cache > 0 && data->family == 16) + else if (data->l3_cache > 0 && data->x86.family == 16) /* restrict by family, since later Xeons also have L3 ... */ code = IRWIN; } @@ -911,14 +911,14 @@ static intel_code_and_bits_t get_brand_code_and_bits(struct cpu_id_t* data) } } - if (code == CORE_DUO && (bits & MOBILE_) && data->model != 14) { - if (data->ext_model < 23) { + if (code == CORE_DUO && (bits & MOBILE_) && data->x86.model != 14) { + if (data->x86.ext_model < 23) { code = MEROM; } else { code = PENRYN; } } - if (data->ext_model == 23 && + if (data->x86.ext_model == 23 && (code == CORE_DUO || code == PENTIUM_D || (bits & CELERON_))) { code = WOLFDALE; } @@ -1030,31 +1030,31 @@ static void decode_intel_sgx_features(const struct cpu_raw_data_t* raw, struct c if (raw->basic_cpuid[0x12][EAX] == 0) return; // no sub-leafs available, probably it's disabled by BIOS // decode sub-leaf 0: - if (raw->basic_cpuid[0x12][EAX] & 1) data->sgx.flags[INTEL_SGX1] = 1; - if (raw->basic_cpuid[0x12][EAX] & 2) data->sgx.flags[INTEL_SGX2] = 1; - if (data->sgx.flags[INTEL_SGX1] || data->sgx.flags[INTEL_SGX2]) - data->sgx.present = 1; - data->sgx.misc_select = raw->basic_cpuid[0x12][EBX]; - data->sgx.max_enclave_32bit = (raw->basic_cpuid[0x12][EDX] ) & 0xff; - data->sgx.max_enclave_64bit = (raw->basic_cpuid[0x12][EDX] >> 8) & 0xff; + if (raw->basic_cpuid[0x12][EAX] & 1) data->x86.sgx.flags[INTEL_SGX1] = 1; + if (raw->basic_cpuid[0x12][EAX] & 2) data->x86.sgx.flags[INTEL_SGX2] = 1; + if (data->x86.sgx.flags[INTEL_SGX1] || data->x86.sgx.flags[INTEL_SGX2]) + data->x86.sgx.present = 1; + data->x86.sgx.misc_select = raw->basic_cpuid[0x12][EBX]; + data->x86.sgx.max_enclave_32bit = (raw->basic_cpuid[0x12][EDX] ) & 0xff; + data->x86.sgx.max_enclave_64bit = (raw->basic_cpuid[0x12][EDX] >> 8) & 0xff; // decode sub-leaf 1: - data->sgx.secs_attributes = raw->intel_fn12h[1][EAX] | (((uint64_t) raw->intel_fn12h[1][EBX]) << 32); - data->sgx.secs_xfrm = raw->intel_fn12h[1][ECX] | (((uint64_t) raw->intel_fn12h[1][EDX]) << 32); + data->x86.sgx.secs_attributes = raw->intel_fn12h[1][EAX] | (((uint64_t) raw->intel_fn12h[1][EBX]) << 32); + data->x86.sgx.secs_xfrm = raw->intel_fn12h[1][ECX] | (((uint64_t) raw->intel_fn12h[1][EDX]) << 32); // decode higher-order subleafs, whenever present: - data->sgx.num_epc_sections = -1; + data->x86.sgx.num_epc_sections = -1; for (i = 0; i < 1000000; i++) { epc = cpuid_get_epc(i, raw); if (epc.length == 0) { debugf(2, "SGX: epc section request for %d returned null, no more EPC sections.\n", i); - data->sgx.num_epc_sections = i; + data->x86.sgx.num_epc_sections = i; break; } } - if (data->sgx.num_epc_sections == -1) { + if (data->x86.sgx.num_epc_sections == -1) { debugf(1, "SGX: warning: seems to be infinitude of EPC sections.\n"); - data->sgx.num_epc_sections = 1000000; + data->x86.sgx.num_epc_sections = 1000000; } } diff --git a/tests/arm/armv8a/cortex-a53.test b/tests/arm/armv8a/cortex-a53.test new file mode 100644 index 0000000..cba2fce --- /dev/null +++ b/tests/arm/armv8a/cortex-a53.test @@ -0,0 +1,87 @@ +_________________ Logical CPU #0 _________________ +arm_midr=00000000410fd030 +arm_mpidr=0000000080000000 +arm_revidr=0000000000000000 +arm_id_aa64dfr0=0000000000000006 +arm_id_aa64dfr1=0000000000000000 +arm_id_aa64isar0=0000000000010000 +arm_id_aa64isar1=0000000000000000 +arm_id_aa64isar2=0000000000000000 +arm_id_aa64mmfr0=00000111ff000000 +arm_id_aa64mmfr1=0000000000000000 +arm_id_aa64mmfr2=0000000000000000 +arm_id_aa64mmfr3=0000000000000000 +arm_id_aa64mmfr4=0000000000000000 +arm_id_aa64pfr0=0000000000000011 +arm_id_aa64pfr1=0000000000000000 +arm_id_aa64pfr2=0000000000000000 +arm_id_aa64smfr0=0000000000000000 +arm_id_aa64zfr0=0000000000000000 +_________________ Logical CPU #1 _________________ +arm_midr=00000000410fd030 +arm_mpidr=0000000080000000 +arm_revidr=0000000000000000 +arm_id_aa64dfr0=0000000000000006 +arm_id_aa64dfr1=0000000000000000 +arm_id_aa64isar0=0000000000010000 +arm_id_aa64isar1=0000000000000000 +arm_id_aa64isar2=0000000000000000 +arm_id_aa64mmfr0=00000111ff000000 +arm_id_aa64mmfr1=0000000000000000 +arm_id_aa64mmfr2=0000000000000000 +arm_id_aa64mmfr3=0000000000000000 +arm_id_aa64mmfr4=0000000000000000 +arm_id_aa64pfr0=0000000000000011 +arm_id_aa64pfr1=0000000000000000 +arm_id_aa64pfr2=0000000000000000 +arm_id_aa64smfr0=0000000000000000 +arm_id_aa64zfr0=0000000000000000 +_________________ Logical CPU #2 _________________ +arm_midr=00000000410fd030 +arm_mpidr=0000000080000000 +arm_revidr=0000000000000000 +arm_id_aa64dfr0=0000000000000006 +arm_id_aa64dfr1=0000000000000000 +arm_id_aa64isar0=0000000000010000 +arm_id_aa64isar1=0000000000000000 +arm_id_aa64isar2=0000000000000000 +arm_id_aa64mmfr0=00000111ff000000 +arm_id_aa64mmfr1=0000000000000000 +arm_id_aa64mmfr2=0000000000000000 +arm_id_aa64mmfr3=0000000000000000 +arm_id_aa64mmfr4=0000000000000000 +arm_id_aa64pfr0=0000000000000011 +arm_id_aa64pfr1=0000000000000000 +arm_id_aa64pfr2=0000000000000000 +arm_id_aa64smfr0=0000000000000000 +arm_id_aa64zfr0=0000000000000000 +_________________ Logical CPU #3 _________________ +arm_midr=00000000410fd030 +arm_mpidr=0000000080000000 +arm_revidr=0000000000000000 +arm_id_aa64dfr0=0000000000000006 +arm_id_aa64dfr1=0000000000000000 +arm_id_aa64isar0=0000000000010000 +arm_id_aa64isar1=0000000000000000 +arm_id_aa64isar2=0000000000000000 +arm_id_aa64mmfr0=00000111ff000000 +arm_id_aa64mmfr1=0000000000000000 +arm_id_aa64mmfr2=0000000000000000 +arm_id_aa64mmfr3=0000000000000000 +arm_id_aa64mmfr4=0000000000000000 +arm_id_aa64pfr0=0000000000000011 +arm_id_aa64pfr1=0000000000000000 +arm_id_aa64pfr2=0000000000000000 +arm_id_aa64smfr0=0000000000000000 +arm_id_aa64zfr0=0000000000000000 +-------------------------------------------------------------------------------- +ARM +efficiency +65 +0 +3331 +0 +1 +4 +Apollo +advsimd crc32 doublelock fp sve bbm fhm sel2 diff --git a/tests/arm/armv8a/cortex-a57-qemu.test b/tests/arm/armv8a/cortex-a57-qemu.test new file mode 100644 index 0000000..e8eeadc --- /dev/null +++ b/tests/arm/armv8a/cortex-a57-qemu.test @@ -0,0 +1,87 @@ +_________________ Logical CPU #0 _________________ +arm_midr=00000000411fd070 +arm_mpidr=0000000080000000 +arm_revidr=0000000000000000 +arm_id_aa64dfr0=0000000000000006 +arm_id_aa64dfr1=0000000000000000 +arm_id_aa64isar0=0000000000011120 +arm_id_aa64isar1=0000000000000000 +arm_id_aa64isar2=0000000000000000 +arm_id_aa64mmfr0=00000111ff000000 +arm_id_aa64mmfr1=0000000000000000 +arm_id_aa64mmfr2=0000000000000000 +arm_id_aa64mmfr3=0000000000000000 +arm_id_aa64mmfr4=0000000000000000 +arm_id_aa64pfr0=0000000000000011 +arm_id_aa64pfr1=0000000000000000 +arm_id_aa64pfr2=0000000000000000 +arm_id_aa64smfr0=0000000000000000 +arm_id_aa64zfr0=0000000000000000 +_________________ Logical CPU #1 _________________ +arm_midr=00000000411fd070 +arm_mpidr=0000000080000000 +arm_revidr=0000000000000000 +arm_id_aa64dfr0=0000000000000006 +arm_id_aa64dfr1=0000000000000000 +arm_id_aa64isar0=0000000000011120 +arm_id_aa64isar1=0000000000000000 +arm_id_aa64isar2=0000000000000000 +arm_id_aa64mmfr0=00000111ff000000 +arm_id_aa64mmfr1=0000000000000000 +arm_id_aa64mmfr2=0000000000000000 +arm_id_aa64mmfr3=0000000000000000 +arm_id_aa64mmfr4=0000000000000000 +arm_id_aa64pfr0=0000000000000011 +arm_id_aa64pfr1=0000000000000000 +arm_id_aa64pfr2=0000000000000000 +arm_id_aa64smfr0=0000000000000000 +arm_id_aa64zfr0=0000000000000000 +_________________ Logical CPU #2 _________________ +arm_midr=00000000411fd070 +arm_mpidr=0000000080000000 +arm_revidr=0000000000000000 +arm_id_aa64dfr0=0000000000000006 +arm_id_aa64dfr1=0000000000000000 +arm_id_aa64isar0=0000000000011120 +arm_id_aa64isar1=0000000000000000 +arm_id_aa64isar2=0000000000000000 +arm_id_aa64mmfr0=00000111ff000000 +arm_id_aa64mmfr1=0000000000000000 +arm_id_aa64mmfr2=0000000000000000 +arm_id_aa64mmfr3=0000000000000000 +arm_id_aa64mmfr4=0000000000000000 +arm_id_aa64pfr0=0000000000000011 +arm_id_aa64pfr1=0000000000000000 +arm_id_aa64pfr2=0000000000000000 +arm_id_aa64smfr0=0000000000000000 +arm_id_aa64zfr0=0000000000000000 +_________________ Logical CPU #3 _________________ +arm_midr=00000000411fd070 +arm_mpidr=0000000080000000 +arm_revidr=0000000000000000 +arm_id_aa64dfr0=0000000000000006 +arm_id_aa64dfr1=0000000000000000 +arm_id_aa64isar0=0000000000011120 +arm_id_aa64isar1=0000000000000000 +arm_id_aa64isar2=0000000000000000 +arm_id_aa64mmfr0=00000111ff000000 +arm_id_aa64mmfr1=0000000000000000 +arm_id_aa64mmfr2=0000000000000000 +arm_id_aa64mmfr3=0000000000000000 +arm_id_aa64mmfr4=0000000000000000 +arm_id_aa64pfr0=0000000000000011 +arm_id_aa64pfr1=0000000000000000 +arm_id_aa64pfr2=0000000000000000 +arm_id_aa64smfr0=0000000000000000 +arm_id_aa64zfr0=0000000000000000 +-------------------------------------------------------------------------------- +ARM +performance +65 +1 +3335 +0 +1 +4 +Atlas +advsimd crc32 doublelock fp pmull sha1 sha256 sm4 sve bbm dotprod fhm sel2 diff --git a/tests/arm/armv9a/neoverse-n2-qemu.test b/tests/arm/armv9a/neoverse-n2-qemu.test new file mode 100644 index 0000000..139718d --- /dev/null +++ b/tests/arm/armv9a/neoverse-n2-qemu.test @@ -0,0 +1,87 @@ +_________________ Logical CPU #0 _________________ +arm_midr=00000000410fd493 +arm_mpidr=0000000080000000 +arm_revidr=0000000000000000 +arm_id_aa64dfr0=0000000000000006 +arm_id_aa64dfr1=0000000000000000 +arm_id_aa64isar0=1021111110212120 +arm_id_aa64isar1=0011101101211052 +arm_id_aa64isar2=0000000000000000 +arm_id_aa64mmfr0=00000111ff000000 +arm_id_aa64mmfr1=0000000000000000 +arm_id_aa64mmfr2=0000000100000000 +arm_id_aa64mmfr3=0000000000000000 +arm_id_aa64mmfr4=0000000000000000 +arm_id_aa64pfr0=0001000100110011 +arm_id_aa64pfr1=0000000000000121 +arm_id_aa64pfr2=0000000000000000 +arm_id_aa64smfr0=0000000000000000 +arm_id_aa64zfr0=0000110100110021 +_________________ Logical CPU #1 _________________ +arm_midr=00000000410fd493 +arm_mpidr=0000000080000000 +arm_revidr=0000000000000000 +arm_id_aa64dfr0=0000000000000006 +arm_id_aa64dfr1=0000000000000000 +arm_id_aa64isar0=1021111110212120 +arm_id_aa64isar1=0011101101211052 +arm_id_aa64isar2=0000000000000000 +arm_id_aa64mmfr0=00000111ff000000 +arm_id_aa64mmfr1=0000000000000000 +arm_id_aa64mmfr2=0000000100000000 +arm_id_aa64mmfr3=0000000000000000 +arm_id_aa64mmfr4=0000000000000000 +arm_id_aa64pfr0=0001000100110011 +arm_id_aa64pfr1=0000000000000121 +arm_id_aa64pfr2=0000000000000000 +arm_id_aa64smfr0=0000000000000000 +arm_id_aa64zfr0=0000110100110021 +_________________ Logical CPU #2 _________________ +arm_midr=00000000410fd493 +arm_mpidr=0000000080000000 +arm_revidr=0000000000000000 +arm_id_aa64dfr0=0000000000000006 +arm_id_aa64dfr1=0000000000000000 +arm_id_aa64isar0=1021111110212120 +arm_id_aa64isar1=0011101101211052 +arm_id_aa64isar2=0000000000000000 +arm_id_aa64mmfr0=00000111ff000000 +arm_id_aa64mmfr1=0000000000000000 +arm_id_aa64mmfr2=0000000100000000 +arm_id_aa64mmfr3=0000000000000000 +arm_id_aa64mmfr4=0000000000000000 +arm_id_aa64pfr0=0001000100110011 +arm_id_aa64pfr1=0000000000000121 +arm_id_aa64pfr2=0000000000000000 +arm_id_aa64smfr0=0000000000000000 +arm_id_aa64zfr0=0000110100110021 +_________________ Logical CPU #3 _________________ +arm_midr=00000000410fd493 +arm_mpidr=0000000080000000 +arm_revidr=0000000000000000 +arm_id_aa64dfr0=0000000000000006 +arm_id_aa64dfr1=0000000000000000 +arm_id_aa64isar0=1021111110212120 +arm_id_aa64isar1=0011101101211052 +arm_id_aa64isar2=0000000000000000 +arm_id_aa64mmfr0=00000111ff000000 +arm_id_aa64mmfr1=0000000000000000 +arm_id_aa64mmfr2=0000000100000000 +arm_id_aa64mmfr3=0000000000000000 +arm_id_aa64mmfr4=0000000000000000 +arm_id_aa64pfr0=0001000100110011 +arm_id_aa64pfr1=0000000000000121 +arm_id_aa64pfr2=0000000000000000 +arm_id_aa64smfr0=0000000000000000 +arm_id_aa64zfr0=0000110100110021 +-------------------------------------------------------------------------------- +ARM +general +65 +0 +3401 +3 +1 +4 +Perseus +advsimd crc32 csv2_1p1 doublelock pmull sha1 lse rdm f32mm fp16 sha512 sm4 sve fcma fpaccombine jscvt pacqarma5 pauth bbm dit fhm lrcpc2 sel2 bti dpb2 flagm2 mte rng ssbs2 bf16 dgh xs sve2 sve_bitperm sve_pmull128 sve_sha3 rme sme diff --git a/tests/create_test.py b/tests/create_test.py index ba1332f..67f79ad 100755 --- a/tests/create_test.py +++ b/tests/create_test.py @@ -12,7 +12,11 @@ if len(args) != 3: def readRawFile(): rawdata = [] for line in open(args[1], "rt").readlines(): - lookfor = ["basic_cpuid", "ext_cpuid", "intel_fn4", "intel_fn11", "amd_fn8000001dh", "Logical CPU", "CPUID", "CPU#"] + lookfor = [ + "Logical CPU", "CPUID", "CPU#", # common + "basic_cpuid", "ext_cpuid", "intel_fn4", "intel_fn11", "amd_fn8000001dh", # x86 + "arm_midr", "arm_mpidr", "arm_revidr", "arm_id_aa64dfr", "arm_id_aa64isar", "arm_id_aa64mmfr", "arm_id_aa64pfr", "arm_id_aa64smfr", "arm_id_aa64zfr" # ARM + ] ignore = ["MSR Register"] good = False for match in lookfor: @@ -35,6 +39,7 @@ def readResultFile(): if s.find(":") == -1: continue numeric = ["family", "model", "stepping", "ext_family", "ext_model", + "implementer", "variant", "part_num", "revision", "num_cores", "num_logical", "L1 D cache", "L1 I cache", "L2 cache", "L3 cache", "L4 cache", "L1D assoc.", "L1I assoc.", "L2 assoc.", "L3 assoc.", "L4 assoc.", diff --git a/tests/run_tests.py b/tests/run_tests.py index 7464b6d..1cbbeca 100755 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -5,13 +5,16 @@ import os, sys, re, random ### Constants: -fields = [ "architecture", "purpose", "family", "model", "stepping", "extfamily", +fields_x86 = [ "architecture", "purpose", "family", "model", "stepping", "extfamily", "extmodel", "cores", "logical", "l1d-cache", "l1i-cache", "l2-cache", "l3-cache", "l4-cache", "l1d-assoc", "l1i-assoc", "l2-assoc", "l3-assoc", "l4-assoc", "l1d-cacheline", "l1i-cacheline", "l2-cacheline", "l3-cacheline", "l4-cacheline", "l1d-instances", "l1i-instances", "l2-instances", "l3-instances", "l4-instances", "sse-size", "codename", "flags" ] +fields_arm = [ "architecture", "purpose", "implementer", "variant", "part-num", "revision", + "cores", "logical", + "codename", "flags" ] args = sys.argv fix = False @@ -79,6 +82,13 @@ def do_test(inp, expected_out, binary, test_file_name, num_cpu_type): f = open(fninp, "wt") f.writelines([s + "\n" for s in inp]) f.close() + architecture = os.popen("%s --load=%s --architecture" % (binary, fninp)).read().splitlines()[-1] + if architecture == "x86": + fields = fields_x86 + elif architecture == "ARM": + fields = fields_arm + else: + fields = [] cmd = "%s --load=%s --outfile=%s %s" % (binary, fninp, fnoutp, " ".join(["--" + s for s in fields])) os.system(cmd) os.unlink(fninp) diff --git a/utils/parse_arm_arm_pdf.sh b/utils/parse_arm_arm_pdf.sh new file mode 100755 index 0000000..8adb1e0 --- /dev/null +++ b/utils/parse_arm_arm_pdf.sh @@ -0,0 +1,47 @@ +#!/bin/bash +# This script extracts some data from Arm Architecture Reference Manual PDF file +# PDF file can be downloaded here: https://developer.arm.com/documentation/ddi0487/latest/ + +print_help() { + echo "$(basename "$0") PDF_FILE" + echo -e "\n\033[1mPDF_FILE:\033[0m Arm Architecture Reference Manual PDF file" +} + +if [[ $# -lt 1 ]]; then + print_help + exit 1 +fi + +PDF_FILE="$1" +TMP_DIR="$(mktemp -d -t libcpuid.XXXXXX)" +TMP_LIBCPUID_H="$TMP_DIR/cpu_feature.h" +TMP_CPUID_MAIN_C="$TMP_DIR/matchtable.c" + +echo "typedef enum {" > "$TMP_LIBCPUID_H" +echo " matchtable[] = {" > "$TMP_CPUID_MAIN_C" + +IFS=' +' +for line in $(pdfgrep --cache -e 'A[0-9]+\.[0-9]+\.[0-9]+\s+The Armv[0-9]\.[0-9] architecture extension' -e ' FEAT_[a-zA-Z0-9_]+, ' "$PDF_FILE"); do + if [[ "$line" == "A"* ]]; then + echo "$line" + echo -e "\t/* $line */" >> "$TMP_LIBCPUID_H" + echo -e "\t\t/* $line */" >> "$TMP_CPUID_MAIN_C" + elif [[ "$line" == " FEAT_"* ]]; then + feat="$(echo "$line" | awk '{ print $1 }' | cut -d, -f1)" + #pdfgrep --cache "$feat implements the functionality identified by the value" "$PDF_FILE" + feat_upper="${feat^^}" + feat_lower="${feat,,}" + feat_enum="${feat_upper/FEAT_/CPU_FEATURE_}" + feat_name="$(echo $feat_lower | cut -d_ -f2-)" + feat_descr="$(echo "$line" | cut -d, -f2-)" + echo -e "\t$feat_enum, /*!< ARM:$feat_descr */" >> "$TMP_LIBCPUID_H" + echo -e "\t\t{ $feat_enum, \"$feat_name\" }," >> "$TMP_CPUID_MAIN_C" + fi +done + +echo "} cpu_feature_t;" >> "$TMP_LIBCPUID_H" +echo " };" >> "$TMP_CPUID_MAIN_C" + +echo "Extracted data for enum cpu_feature_t written to '$TMP_LIBCPUID_H' file." +echo "Extracted data for cpu_feature_str() matchtable written to '$TMP_CPUID_MAIN_C' file."