// SPDX-FileCopyrightText: 2022 Google LLC // SPDX-License-Identifier: Apache-2.0 #include "cpu_features_macros.h" #ifdef CPU_FEATURES_ARCH_RISCV #if defined(CPU_FEATURES_OS_LINUX) #include "cpuinfo_riscv.h" // According to // https://elixir.bootlin.com/linux/latest/source/Documentation/devicetree/bindings/riscv/cpus.yaml // isa string should match the following regex // ^rv(?:64|32)imaf?d?q?c?b?v?k?h?(?:_[hsxz](?:[a-z])+)*$ // // This means we can test for features in this exact order except for Z // extensions. //////////////////////////////////////////////////////////////////////////////// // Definitions for introspection. //////////////////////////////////////////////////////////////////////////////// #define INTROSPECTION_TABLE \ LINE(RISCV_RV32I, RV32I, "rv32i", RISCV_HWCAP_32, 0) \ LINE(RISCV_RV64I, RV64I, "rv64i", RISCV_HWCAP_64, 0) \ LINE(RISCV_M, M, "m", RISCV_HWCAP_M, 0) \ LINE(RISCV_A, A, "a", RISCV_HWCAP_A, 0) \ LINE(RISCV_F, F, "f", RISCV_HWCAP_F, 0) \ LINE(RISCV_D, D, "d", RISCV_HWCAP_D, 0) \ LINE(RISCV_Q, Q, "q", RISCV_HWCAP_Q, 0) \ LINE(RISCV_C, C, "c", RISCV_HWCAP_C, 0) \ LINE(RISCV_V, V, "v", RISCV_HWCAP_V, 0) \ LINE(RISCV_Zicsr, Zicsr, "_zicsr", 0, 0) \ LINE(RISCV_Zifencei, Zifencei, "_zifencei", 0, 0) #define INTROSPECTION_PREFIX Riscv #define INTROSPECTION_ENUM_PREFIX RISCV #include "define_introspection_and_hwcaps.inl" //////////////////////////////////////////////////////////////////////////////// // Implementation. //////////////////////////////////////////////////////////////////////////////// #include "internal/filesystem.h" #include "internal/stack_line_reader.h" #include #include static const RiscvInfo kEmptyRiscvInfo; static void HandleRiscVIsaLine(StringView line, RiscvFeatures* const features) { for (size_t i = 0; i < RISCV_LAST_; ++i) { StringView flag = str(kCpuInfoFlags[i]); int index_of_flag = CpuFeatures_StringView_IndexOf(line, flag); bool is_set = index_of_flag != -1; kSetters[i](features, is_set); if (is_set) line = CpuFeatures_StringView_PopFront(line, index_of_flag + flag.size); } } static bool HandleRiscVLine(const LineResult result, RiscvInfo* const info) { StringView line = result.line; StringView key, value; if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) { if (CpuFeatures_StringView_IsEquals(key, str("isa"))) { HandleRiscVIsaLine(value, &info->features); } else if (CpuFeatures_StringView_IsEquals(key, str("uarch"))) { int index = CpuFeatures_StringView_IndexOfChar(value, ','); if (index == -1) return true; StringView vendor = CpuFeatures_StringView_KeepFront(value, index); StringView uarch = CpuFeatures_StringView_PopFront(value, index + 1); CpuFeatures_StringView_CopyString(vendor, info->vendor, sizeof(info->vendor)); CpuFeatures_StringView_CopyString(uarch, info->uarch, sizeof(info->uarch)); } } return !result.eof; } static void FillProcCpuInfoData(RiscvInfo* const info) { const int fd = CpuFeatures_OpenFile("/proc/cpuinfo"); if (fd >= 0) { StackLineReader reader; StackLineReader_Initialize(&reader, fd); for (;;) { if (!HandleRiscVLine(StackLineReader_NextLine(&reader), info)) break; } CpuFeatures_CloseFile(fd); } } RiscvInfo GetRiscvInfo(void) { RiscvInfo info = kEmptyRiscvInfo; FillProcCpuInfoData(&info); return info; } #endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID) #endif // CPU_FEATURES_ARCH_RISCV