From 0d5f398c58066f2074c0d2659f348bc9306c6d28 Mon Sep 17 00:00:00 2001 From: Wang Xiang Date: Thu, 24 Aug 2023 02:35:29 +0800 Subject: [PATCH] Add loongarch64 Support (#314) * Add macros for LOONGARCH hwcaps * Update hwcaps.h * LoongArch Support * Remove unused definitions. * Add ignored feature in test. --- CMakeLists.txt | 5 + include/cpu_features_macros.h | 4 + include/cpuinfo_loongarch.h | 77 ++++++++++++++ include/internal/hwcaps.h | 16 +++ scripts/generate_badges.d | 1 + src/impl_loongarch_linux.c | 89 ++++++++++++++++ src/utils/list_cpu_features.c | 9 ++ test/CMakeLists.txt | 8 ++ test/cpuinfo_loongarch_test.cc | 179 +++++++++++++++++++++++++++++++++ 9 files changed, 388 insertions(+) create mode 100644 include/cpuinfo_loongarch.h create mode 100644 src/impl_loongarch_linux.c create mode 100644 test/cpuinfo_loongarch_test.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 0967200..7679ff5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,7 @@ set(PROCESSOR_IS_X86 FALSE) set(PROCESSOR_IS_POWER FALSE) set(PROCESSOR_IS_S390X FALSE) set(PROCESSOR_IS_RISCV FALSE) +set(PROCESSOR_IS_LOONGARCH FALSE) if(CMAKE_SYSTEM_PROCESSOR MATCHES "^mips") set(PROCESSOR_IS_MIPS TRUE) @@ -74,6 +75,8 @@ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(s390x)") set(PROCESSOR_IS_S390X TRUE) elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^riscv") set(PROCESSOR_IS_RISCV TRUE) +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^loongarch") + set(PROCESSOR_IS_LOONGARCH TRUE) endif() macro(add_cpu_features_headers_and_sources HDRS_LIST_NAME SRCS_LIST_NAME) @@ -98,6 +101,8 @@ macro(add_cpu_features_headers_and_sources HDRS_LIST_NAME SRCS_LIST_NAME) list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_s390x.h) elseif(PROCESSOR_IS_RISCV) list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_riscv.h) + elseif(PROCESSOR_IS_LOONGARCH) + list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_loongarch.h) else() message(FATAL_ERROR "Unsupported architectures ${CMAKE_SYSTEM_PROCESSOR}") endif() diff --git a/include/cpu_features_macros.h b/include/cpu_features_macros.h index 215b567..4fe7c3d 100644 --- a/include/cpu_features_macros.h +++ b/include/cpu_features_macros.h @@ -83,6 +83,10 @@ #define CPU_FEATURES_ARCH_RISCV128 #endif +#if defined(__loongarch64) +#define CPU_FEATURES_ARCH_LOONGARCH +#endif + //////////////////////////////////////////////////////////////////////////////// // Os //////////////////////////////////////////////////////////////////////////////// diff --git a/include/cpuinfo_loongarch.h b/include/cpuinfo_loongarch.h new file mode 100644 index 0000000..d166223 --- /dev/null +++ b/include/cpuinfo_loongarch.h @@ -0,0 +1,77 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CPU_FEATURES_INCLUDE_CPUINFO_LOONGARCH_H_ +#define CPU_FEATURES_INCLUDE_CPUINFO_LOONGARCH_H_ + +#include "cpu_features_cache_info.h" +#include "cpu_features_macros.h" + +#if !defined(CPU_FEATURES_ARCH_LOONGARCH) +#error "Including cpuinfo_loongarch.h from a non-loongarch target." +#endif + +CPU_FEATURES_START_CPP_NAMESPACE + +typedef struct { + // Base + int CPUCFG : 1; // Instruction for Identify CPU Features + + // Extension + int LAM : 1; // Extension for Atomic Memory Access Instructions + int UAL : 1; // Extension for Non-Aligned Memory Access + int FPU : 1; // Extension for Basic Floating-Point Instructions + int LSX : 1; // Extension for Loongson SIMD eXtension + int LASX : 1; // Extension for Loongson Advanced SIMD eXtension + int CRC32 : 1; // Extension for Cyclic Redundancy Check Instructions + int COMPLEX : 1; // Extension for Complex Vector Operation Instructions + int CRYPTO : 1; // Extension for Encryption And Decryption Vector Instructions + int LVZ : 1; // Extension for Virtualization + int LBT_X86 : 1; // Extension for X86 Binary Translation Extension + int LBT_ARM : 1; // Extension for ARM Binary Translation Extension + int LBT_MIPS : 1; // Extension for MIPS Binary Translation Extension + int PTW : 1; // Extension for Page Table Walker + +} LoongArchFeatures; + +typedef struct { + LoongArchFeatures features; +} LoongArchInfo; + +typedef enum { + LOONGARCH_CPUCFG, + LOONGARCH_LAM, + LOONGARCH_UAL, + LOONGARCH_FPU, + LOONGARCH_LSX, + LOONGARCH_LASX, + LOONGARCH_CRC32, + LOONGARCH_COMPLEX, + LOONGARCH_CRYPTO, + LOONGARCH_LVZ, + LOONGARCH_LBT_X86, + LOONGARCH_LBT_ARM, + LOONGARCH_LBT_MIPS, + LOONGARCH_PTW, + LOONGARCH_LAST_, +} LoongArchFeaturesEnum; + +LoongArchInfo GetLoongArchInfo(void); +int GetLoongArchFeaturesEnumValue(const LoongArchFeatures* features, + LoongArchFeaturesEnum value); +const char* GetLoongArchFeaturesEnumName(LoongArchFeaturesEnum); + +CPU_FEATURES_END_CPP_NAMESPACE + +#endif // CPU_FEATURES_INCLUDE_CPUINFO_LOONGARCH_H_ diff --git a/include/internal/hwcaps.h b/include/internal/hwcaps.h index e532979..59e1657 100644 --- a/include/internal/hwcaps.h +++ b/include/internal/hwcaps.h @@ -237,6 +237,22 @@ CPU_FEATURES_START_CPP_NAMESPACE #define RISCV_HWCAP_C (1UL << ('C' - 'A')) #define RISCV_HWCAP_V (1UL << ('V' - 'A')) +// https://github.com/torvalds/linux/blob/master/arch/loongarch/include/uapi/asm/hwcap.h +#define HWCAP_LOONGARCH_CPUCFG (1 << 0) +#define HWCAP_LOONGARCH_LAM (1 << 1) +#define HWCAP_LOONGARCH_UAL (1 << 2) +#define HWCAP_LOONGARCH_FPU (1 << 3) +#define HWCAP_LOONGARCH_LSX (1 << 4) +#define HWCAP_LOONGARCH_LASX (1 << 5) +#define HWCAP_LOONGARCH_CRC32 (1 << 6) +#define HWCAP_LOONGARCH_COMPLEX (1 << 7) +#define HWCAP_LOONGARCH_CRYPTO (1 << 8) +#define HWCAP_LOONGARCH_LVZ (1 << 9) +#define HWCAP_LOONGARCH_LBT_X86 (1 << 10) +#define HWCAP_LOONGARCH_LBT_ARM (1 << 11) +#define HWCAP_LOONGARCH_LBT_MIPS (1 << 12) +#define HWCAP_LOONGARCH_PTW (1 << 13) + typedef struct { unsigned long hwcaps; unsigned long hwcaps2; diff --git a/scripts/generate_badges.d b/scripts/generate_badges.d index bf5aa54..eef00ef 100644 --- a/scripts/generate_badges.d +++ b/scripts/generate_badges.d @@ -20,6 +20,7 @@ enum Cpu MIPS, POWER, RISCV, + LOONGARCH, s390x, } diff --git a/src/impl_loongarch_linux.c b/src/impl_loongarch_linux.c new file mode 100644 index 0000000..b9cea7b --- /dev/null +++ b/src/impl_loongarch_linux.c @@ -0,0 +1,89 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "cpu_features_macros.h" + +#ifdef CPU_FEATURES_ARCH_LOONGARCH +#if defined(CPU_FEATURES_OS_LINUX) + +#include "cpuinfo_loongarch.h" + +//////////////////////////////////////////////////////////////////////////////// +// Definitions for introspection. +//////////////////////////////////////////////////////////////////////////////// +#define INTROSPECTION_TABLE \ + LINE(LOONGARCH_CPUCFG, CPUCFG, "cfg", HWCAP_LOONGARCH_CPUCFG, 0) \ + LINE(LOONGARCH_LAM, LAM, "lam", HWCAP_LOONGARCH_LAM, 0) \ + LINE(LOONGARCH_UAL, UAL, "ual", HWCAP_LOONGARCH_UAL, 0) \ + LINE(LOONGARCH_FPU, FPU, "fpu", HWCAP_LOONGARCH_FPU, 0) \ + LINE(LOONGARCH_LSX, LSX, "lsx", HWCAP_LOONGARCH_LSX, 0) \ + LINE(LOONGARCH_LASX, LASX, "lasx", HWCAP_LOONGARCH_LASX, 0) \ + LINE(LOONGARCH_CRC32, CRC32, "crc32", HWCAP_LOONGARCH_CRC32, 0) \ + LINE(LOONGARCH_COMPLEX, COMPLEX, "complex", HWCAP_LOONGARCH_COMPLEX, 0) \ + LINE(LOONGARCH_CRYPTO, CRYPTO, "crypto", HWCAP_LOONGARCH_CRYPTO, 0) \ + LINE(LOONGARCH_LVZ, LVZ, "lvz", HWCAP_LOONGARCH_LVZ, 0) \ + LINE(LOONGARCH_LBT_X86, LBT_X86, "lbt_x86", HWCAP_LOONGARCH_LBT_X86, 0) \ + LINE(LOONGARCH_LBT_ARM, LBT_ARM, "lbt_arm", HWCAP_LOONGARCH_LBT_ARM, 0) \ + LINE(LOONGARCH_LBT_MIPS, LBT_MIPS, "lbt_mips", HWCAP_LOONGARCH_LBT_MIPS, 0) \ + LINE(LOONGARCH_PTW, PTW, "ptw", HWCAP_LOONGARCH_PTW, 0) +#define INTROSPECTION_PREFIX LoongArch +#define INTROSPECTION_ENUM_PREFIX LOONGARCH +#include "define_introspection_and_hwcaps.inl" + +//////////////////////////////////////////////////////////////////////////////// +// Implementation. +//////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "internal/filesystem.h" +#include "internal/stack_line_reader.h" + +static const LoongArchInfo kEmptyLoongArchInfo; + +static bool HandleLoongArchLine(const LineResult result, LoongArchInfo* const info) { + StringView line = result.line; + StringView key, value; + if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) { + if (CpuFeatures_StringView_IsEquals(key, str("Features"))) { + for (size_t i = 0; i < LOONGARCH_LAST_; ++i) { + kSetters[i](&info->features, CpuFeatures_StringView_HasWord( + value, kCpuInfoFlags[i], ' ')); + } + } + } + return !result.eof; +} + +static void FillProcCpuInfoData(LoongArchInfo* const info) { + const int fd = CpuFeatures_OpenFile("/proc/cpuinfo"); + if (fd >= 0) { + StackLineReader reader; + StackLineReader_Initialize(&reader, fd); + for (;;) { + if (!HandleLoongArchLine(StackLineReader_NextLine(&reader), info)) break; + } + CpuFeatures_CloseFile(fd); + } +} + +LoongArchInfo GetLoongArchInfo(void) { + LoongArchInfo info = kEmptyLoongArchInfo; + FillProcCpuInfoData(&info); + return info; +} + +#endif // defined(CPU_FEATURES_OS_LINUX) +#endif // CPU_FEATURES_ARCH_LOONGARCH diff --git a/src/utils/list_cpu_features.c b/src/utils/list_cpu_features.c index 8226d85..83cd387 100644 --- a/src/utils/list_cpu_features.c +++ b/src/utils/list_cpu_features.c @@ -39,6 +39,8 @@ #include "cpuinfo_s390x.h" #elif defined(CPU_FEATURES_ARCH_RISCV) #include "cpuinfo_riscv.h" +#elif defined(CPU_FEATURES_ARCH_LOONGARCH) +#include "cpuinfo_loongarch.h" #endif // Design principles @@ -215,6 +217,9 @@ DEFINE_ADD_FLAGS(GetS390XFeaturesEnumValue, GetS390XFeaturesEnumName, S390XFeatu #elif defined(CPU_FEATURES_ARCH_RISCV) DEFINE_ADD_FLAGS(GetRiscvFeaturesEnumValue, GetRiscvFeaturesEnumName, RiscvFeatures, RISCV_LAST_) +#elif defined(CPU_FEATURES_ARCH_LOONGARCH) +DEFINE_ADD_FLAGS(GetLoongArchFeaturesEnumValue, GetLoongArchFeaturesEnumName, LoongArchFeatures, + LOONGARCH_LAST_) #endif // Prints a json string with characters escaping. @@ -432,6 +437,10 @@ static Node* CreateTree(void) { AddMapEntry(root, "vendor", CreateString(info.vendor)); AddMapEntry(root, "microarchitecture", CreateString(info.uarch)); AddFlags(root, &info.features); +#elif defined(CPU_FEATURES_ARCH_LOONGARCH) + const LoongArchInfo info = GetLoongArchInfo(); + AddMapEntry(root, "arch", CreateString("loongarch")); + AddFlags(root, &info.features); #endif return root; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f627d74..97efdde 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -107,3 +107,11 @@ if(PROCESSOR_IS_RISCV) target_link_libraries(cpuinfo_riscv_test all_libraries) add_test(NAME cpuinfo_riscv_test COMMAND cpuinfo_riscv_test) endif() +##------------------------------------------------------------------------------ +## cpuinfo_loongarch_test +if(PROCESSOR_IS_LOONGARCH) + add_executable(cpuinfo_loongarch_test cpuinfo_loongarch_test.cc ../src/impl_loongarch_linux.c) + target_link_libraries(cpuinfo_loongarch_test all_libraries) + add_test(NAME cpuinfo_loongarch_test COMMAND cpuinfo_loongarch_test) +endif() + diff --git a/test/cpuinfo_loongarch_test.cc b/test/cpuinfo_loongarch_test.cc new file mode 100644 index 0000000..14f544f --- /dev/null +++ b/test/cpuinfo_loongarch_test.cc @@ -0,0 +1,179 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "cpuinfo_loongarch.h" + +#include "filesystem_for_testing.h" +#include "gtest/gtest.h" +#include "hwcaps_for_testing.h" + +namespace cpu_features { +namespace { + +TEST(CpuinfoLoongArchvTest, UnknownFromCpuInfo) { + ResetHwcaps(); + auto& fs = GetEmptyFilesystem(); + fs.CreateFile("/proc/cpuinfo", R"( +system type : generic-loongson-machine + +processor : 0 +package : 0 +core : 0 +CPU Family : Loongson-64bit +Model Name : Loongson-3A5000-HV +CPU Revision : 0x11 +FPU Revision : 0x00 +CPU MHz : 2500.00 +BogoMIPS : 5000.00 +TLB Entries : 2112 +Address Sizes : 48 bits physical, 48 bits virtual +ISA : loongarch32 loongarch64 +Features : cpucfg lam ual fpu lsx lasx crc32 complex crypto lvz lbt_x86 lbt_arm lbt_mips +Hardware Watchpoint : yes, iwatch count: 8, dwatch count: 8 + +processor : 1 +package : 0 +core : 1 +CPU Family : Loongson-64bit +Model Name : Loongson-3A5000-HV +CPU Revision : 0x11 +FPU Revision : 0x00 +CPU MHz : 2500.00 +BogoMIPS : 5000.00 +TLB Entries : 2112 +Address Sizes : 48 bits physical, 48 bits virtual +ISA : loongarch32 loongarch64 +Features : cpucfg lam ual fpu lsx lasx crc32 complex crypto lvz lbt_x86 lbt_arm lbt_mips +Hardware Watchpoint : yes, iwatch count: 8, dwatch count: 8 + +processor : 2 +package : 0 +core : 2 +CPU Family : Loongson-64bit +Model Name : Loongson-3A5000-HV +CPU Revision : 0x11 +FPU Revision : 0x00 +CPU MHz : 2500.00 +BogoMIPS : 5000.00 +TLB Entries : 2112 +Address Sizes : 48 bits physical, 48 bits virtual +ISA : loongarch32 loongarch64 +Features : cpucfg lam ual fpu lsx lasx crc32 complex crypto lvz lbt_x86 lbt_arm lbt_mips +Hardware Watchpoint : yes, iwatch count: 8, dwatch count: 8 + +processor : 3 +package : 0 +core : 3 +CPU Family : Loongson-64bit +Model Name : Loongson-3A5000-HV +CPU Revision : 0x11 +FPU Revision : 0x00 +CPU MHz : 2500.00 +BogoMIPS : 5000.00 +TLB Entries : 2112 +Address Sizes : 48 bits physical, 48 bits virtual +ISA : loongarch32 loongarch64 +Features : cpucfg lam ual fpu lsx lasx crc32 complex crypto lvz lbt_x86 lbt_arm lbt_mips +Hardware Watchpoint : yes, iwatch count: 8, dwatch count: 8)"); + const auto info = GetLoongArchInfo(); + EXPECT_FALSE(info.features.CPUCFG); + EXPECT_TRUE(info.features.LAM); + EXPECT_TRUE(info.features.UAL); + EXPECT_TRUE(info.features.FPU); + EXPECT_TRUE(info.features.LSX); + EXPECT_TRUE(info.features.LASX); + EXPECT_TRUE(info.features.CRC32); + EXPECT_TRUE(info.features.COMPLEX); + EXPECT_TRUE(info.features.CRYPTO); + EXPECT_TRUE(info.features.LVZ); + EXPECT_TRUE(info.features.LBT_X86); + EXPECT_TRUE(info.features.LBT_ARM); + EXPECT_TRUE(info.features.LBT_MIPS); +} + +TEST(CpuinfoLoongArchvTest, QemuCpuInfo) { + ResetHwcaps(); + auto& fs = GetEmptyFilesystem(); + fs.CreateFile("/proc/cpuinfo", R"( +system type : generic-loongson-machine + +processor : 0 +package : 0 +core : 0 +CPU Family : Loongson-64bit +Model Name : Loongson-3A5000 +CPU Revision : 0x10 +FPU Revision : 0x01 +CPU MHz : 2000.00 +BogoMIPS : 4000.00 +TLB Entries : 2112 +Address Sizes : 48 bits physical, 48 bits virtual +ISA : loongarch32 loongarch64 +Features : cpucfg lam ual fpu crc32 +Hardware Watchpoint : yes, iwatch count: 0, dwatch count: 0 + +processor : 1 +package : 0 +core : 1 +CPU Family : Loongson-64bit +Model Name : Loongson-3A5000 +CPU Revision : 0x10 +FPU Revision : 0x01 +CPU MHz : 2000.00 +BogoMIPS : 4000.00 +TLB Entries : 2112 +Address Sizes : 48 bits physical, 48 bits virtual +ISA : loongarch32 loongarch64 +Features : cpucfg lam ual fpu crc32 +Hardware Watchpoint : yes, iwatch count: 0, dwatch count: 0 + +processor : 2 +package : 0 +core : 2 +CPU Family : Loongson-64bit +Model Name : Loongson-3A5000 +CPU Revision : 0x10 +FPU Revision : 0x01 +CPU MHz : 2000.00 +BogoMIPS : 4000.00 +TLB Entries : 2112 +Address Sizes : 48 bits physical, 48 bits virtual +ISA : loongarch32 loongarch64 +Features : cpucfg lam ual fpu crc32 +Hardware Watchpoint : yes, iwatch count: 0, dwatch count: 0 + +processor : 3 +package : 0 +core : 3 +CPU Family : Loongson-64bit +Model Name : Loongson-3A5000 +CPU Revision : 0x10 +FPU Revision : 0x01 +CPU MHz : 2000.00 +BogoMIPS : 4000.00 +TLB Entries : 2112 +Address Sizes : 48 bits physical, 48 bits virtual +ISA : loongarch32 loongarch64 +Features : cpucfg lam ual fpu crc32 +Hardware Watchpoint : yes, iwatch count: 0, dwatch count: 0)"); + const auto info = GetLoongArchInfo(); + EXPECT_FALSE(info.features.CPUCFG); + EXPECT_TRUE(info.features.LAM); + EXPECT_TRUE(info.features.UAL); + EXPECT_TRUE(info.features.FPU); + EXPECT_TRUE(info.features.CRC32); +} + +} // namespace +} // namespace cpu_features