From f5173ca9bf78858159a4a9822e6498a8809e7847 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Fri, 23 Aug 2024 01:52:59 +0300 Subject: [PATCH] aarch64 - Decode CPU brand information --- rpcs3/Emu/CMakeLists.txt | 1 + .../CPU/Backends/AArch64/AArch64Common.cpp | 197 ++++++++++++++++++ .../Emu/CPU/Backends/AArch64/AArch64Common.h | 2 + rpcs3/util/sysinfo.cpp | 16 +- 4 files changed, 211 insertions(+), 5 deletions(-) create mode 100644 rpcs3/Emu/CPU/Backends/AArch64/AArch64Common.cpp diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index a0c949ab91..c05fbdcb2f 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -392,6 +392,7 @@ target_sources(rpcs3_emu PRIVATE if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|aarch64") target_sources(rpcs3_emu PRIVATE CPU/Backends/AArch64/AArch64ASM.cpp + CPU/Backends/AArch64/AArch64Common.cpp CPU/Backends/AArch64/AArch64JIT.cpp CPU/Backends/AArch64/AArch64Signal.cpp ) diff --git a/rpcs3/Emu/CPU/Backends/AArch64/AArch64Common.cpp b/rpcs3/Emu/CPU/Backends/AArch64/AArch64Common.cpp new file mode 100644 index 0000000000..4dec233dbc --- /dev/null +++ b/rpcs3/Emu/CPU/Backends/AArch64/AArch64Common.cpp @@ -0,0 +1,197 @@ +#include "stdafx.h" +#include "AArch64Common.h" + +#include +#include + +namespace aarch64 +{ + struct cpu_entry_t + { + u32 vendor; + u32 part; + const char* arch; + const char* family; + const char* name; + }; + + struct cpu_vendor_t + { + u32 id; + const char* name; + const char* short_name; + }; + + static cpu_vendor_t s_vendors_list[] = + { + { 0x41, "Arm Limited.", "ARM" }, + { 0x42, "Broadcom Corporation.", "Broadcom" }, + { 0x43, "Cavium Inc.", "Cavium" }, + { 0x44, "Digital Equipment Corporation.", "DEC" }, + { 0x46, "Fujitsu Ltd.", "Fujitsu" }, + { 0x49, "Infineon Technologies AG.", "Infineon" }, + { 0x4D, "Motorola or Freescale Semiconductor Inc.", "Motorola" }, + { 0x4E, "NVIDIA Corporation.", "NVIDIA" }, + { 0x50, "Applied Micro Circuits Corporation.", "AMCC" }, + { 0x51, "Qualcomm Inc.", "Qualcomm" }, + { 0x56, "Marvell International Ltd.", "Marvell" }, + { 0x69, "Intel Corporation.", "Intel" }, + { 0xC0, "Ampere Computing", "Ampere" }, + + // Unofficial but existing in the wild + { 0x61, "Apple Inc.", "Apple" }, + }; + + static cpu_entry_t s_cpu_list[] = + { + // ARM + { 0x41, 0xd01, "armv8-a+crc+simd", "", "Cortex-A32" }, + { 0x41, 0xd04, "armv8-a+crc+simd", "", "Cortex-A35" }, + { 0x41, 0xd03, "armv8-a+crc+simd", "", "Cortex-A53" }, + { 0x41, 0xd07, "armv8-a+crc+simd", "", "Cortex-A57" }, + { 0x41, 0xd08, "armv8-a+crc+simd", "", "Cortex-A72" }, + { 0x41, 0xd09, "armv8-a+crc+simd", "", "Cortex-A73" }, + { 0x41, 0xd05, "armv8.2-a+fp16+dotprod", "", "Cortex-A55" }, + { 0x41, 0xd0a, "armv8.2-a+fp16+dotprod", "", "Cortex-A75" }, + { 0x41, 0xd0b, "armv8.2-a+fp16+dotprod", "", "Cortex-A76" }, + { 0x41, 0xd0e, "armv8.2-a+fp16+dotprod", "", "Cortex-A76ae" }, + { 0x41, 0xd0d, "armv8.2-a+fp16+dotprod", "", "Cortex-A77" }, + { 0x41, 0xd41, "armv8.2-a+fp16+dotprod", "", "Cortex-A78" }, + { 0x41, 0xd42, "armv8.2-a+fp16+dotprod", "", "Cortex-A78ae" }, + { 0x41, 0xd4b, "armv8.2-a+fp16+dotprod", "", "Cortex-A78c" }, + { 0x41, 0xd47, "armv9-a+fp16+bf16+i8mm", "", "Cortex-A710" }, + { 0x41, 0xd44, "armv8.2-a+fp16+dotprod", "", "Cortex-X1" }, + { 0x41, 0xd4c, "armv8.2-a+fp16+dotprod", "", "Cortex-X1c" }, + { 0x41, 0xd0c, "armv8.2-a+fp16+dotprod", "", "Neoverse-N1" }, + { 0x41, 0xd40, "armv8.4-a+fp16+bf16+i8mm", "", "Neoverse-V1" }, + { 0x41, 0xd49, "armv8.5-a+fp16+bf16+i8mm", "", "Neoverse-N2" }, + { 0x41, 0xd23, "armv8.1-m.main+pacbti+mve.fp+fp.dp", "", "Cortex-M85" }, + { 0x41, 0xd13, "armv8-r+crc+simd", "", "Cortex-R52" }, + { 0x41, 0xd16, "armv8-r+crc+simd", "", "Cortex-R52+" }, + + // APPLE + { 0x61, 0x22, "armv8.5-a", "M1", "Firestorm" }, + { 0x61, 0x23, "armv8.5-a", "M1", "IceStorm" }, + { 0x61, 0x28, "armv8.5-a", "M1 Max", "Firestorm" }, + { 0x61, 0x28, "armv8.5-a", "M1 Max", "Icestorm" }, + { 0x61, 0x24, "armv8.5-a", "M1 Pro", "Firestorm" }, + { 0x61, 0x25, "armv8.5-a", "M1 Pro", "Icestorm" }, + { 0x61, 0x32, "armv8.5-a", "M2", "Avalanche" }, + { 0x61, 0x32, "armv8.5-a", "M2", "Blizzard" }, + + // QUALCOMM + { 0x51, 0x01, "armv8.5-a", "Snapdragon", "X-Elite" }, + }; + + static const cpu_vendor_t* find_cpu_vendor(u64 id) + { + for (const auto& vendor : s_vendors_list) + { + if (id == vendor.id) + { + return &vendor; + } + } + + return nullptr; + } + + static const cpu_entry_t* find_cpu_part(u64 vendor, u64 part) + { + for (const auto& cpu : s_cpu_list) + { + if (cpu.vendor == vendor && cpu.part == part) + { + return &cpu; + } + } + + return nullptr; + } + + // Read main ID register + static u64 read_MIDR_EL1(u32 cpu_id) + { +#if defined(__linux__) + std::string path = fmt::format("/sys/devices/system/cpu/cpu%u/regs/identification/midr_el1", cpu_id); + if (!fs::is_file(path)) + { + return umax; + } + + std::string value; + if (!fs::file(path, fs::read).read(value, 18)) + { + return 0; + } + return std::stoull(value, nullptr, 16); +#else + // Unimplemented + return 0; +#endif + } + + std::string get_cpu_brand() + { + // Fetch vendor and part numbers. ARM CPUs often have more than 1 architecture on the SoC, so we check all of them. + std::map core_layout; + for (u32 i = 0; i < std::thread::hardware_concurrency(); ++i) + { + const auto midr = read_MIDR_EL1(i); + if (midr == umax) + { + break; + } + + core_layout[midr]++; + } + + if (core_layout.empty()) + { + return "Unidentified CPU"; + } + + std::string vendor_name; + std::string part_family; + std::vector core_names; + for (const auto& [midr, count] : core_layout) + { + const auto implementer_id = (midr >> 24) & 0xff; + const auto part_id = (midr >> 4) & 0xfff; + + if (vendor_name.empty()) + { + const auto vendor_info = find_cpu_vendor(implementer_id); + vendor_name = vendor_info ? vendor_info->short_name : "Unknown"; + } + + const auto part_info = find_cpu_part(implementer_id, part_id); + if (!part_info) + { + core_names.push_back(fmt::format("%dx\"Unidentified cores\"", count)); + continue; + } + + if (part_family.empty() && part_info->family) + { + part_family = part_info->family; + } + + core_names.push_back(fmt::format("%dx\"%s\"", count, part_info->name)); + } + + // Assemble everything + std::string result = vendor_name + " "; + std::string suffix; + if (!part_family.empty()) + { + // Since we have a known family name, the core layout is just extra info. + // Wrap core layout in brackets. + result += part_family + " ("; + suffix = ")"; + } + result += fmt::merge(core_names, " + "); + result += suffix; + return result; + } +} diff --git a/rpcs3/Emu/CPU/Backends/AArch64/AArch64Common.h b/rpcs3/Emu/CPU/Backends/AArch64/AArch64Common.h index 9b77e5eb36..b0d64947ae 100644 --- a/rpcs3/Emu/CPU/Backends/AArch64/AArch64Common.h +++ b/rpcs3/Emu/CPU/Backends/AArch64/AArch64Common.h @@ -36,4 +36,6 @@ namespace aarch64 { "xzr", ".", "sp" }; + + std::string get_cpu_brand(); } diff --git a/rpcs3/util/sysinfo.cpp b/rpcs3/util/sysinfo.cpp index 108450ab30..6f37614d75 100755 --- a/rpcs3/util/sysinfo.cpp +++ b/rpcs3/util/sysinfo.cpp @@ -4,6 +4,10 @@ #include "Emu/vfs_config.h" #include "Utilities/Thread.h" +#if defined(ARCH_ARM64) +#include "Emu/CPU/Backends/AArch64/AArch64Common.h" +#endif + #ifdef _WIN32 #include "windows.h" #include "sysinfoapi.h" @@ -387,9 +391,8 @@ u32 utils::get_rep_movsb_threshold() std::string utils::get_cpu_brand() { - std::string brand; - #if defined(ARCH_X64) + std::string brand; if (get_cpuid(0x80000000, 0)[0] >= 0x80000004) { for (u32 i = 0; i < 3; i++) @@ -401,9 +404,6 @@ std::string utils::get_cpu_brand() { brand = "Unknown CPU"; } -#else - brand = "Unidentified CPU"; -#endif brand.erase(brand.find_last_not_of('\0') + 1); brand.erase(brand.find_last_not_of(' ') + 1); @@ -415,6 +415,12 @@ std::string utils::get_cpu_brand() } return brand; +#elif defined(ARCH_ARM64) + static const auto g_cpu_brand = aarch64::get_cpu_brand(); + return g_cpu_brand; +#else + return "Unidentified CPU"; +#endif } std::string utils::get_system_info()