1 // Copyright 2022 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "cpu_features_macros.h"
16
17 #ifdef CPU_FEATURES_ARCH_RISCV
18 #if defined(CPU_FEATURES_OS_LINUX)
19
20 #include "cpuinfo_riscv.h"
21
22 // According to
23 // https://elixir.bootlin.com/linux/latest/source/Documentation/devicetree/bindings/riscv/cpus.yaml
24 // isa string should match the following regex
25 // ^rv(?:64|32)imaf?d?q?c?b?v?k?h?(?:_[hsxz](?:[a-z])+)*$
26 //
27 // This means we can test for features in this exact order except for Z
28 // extensions.
29
30 ////////////////////////////////////////////////////////////////////////////////
31 // Definitions for introspection.
32 ////////////////////////////////////////////////////////////////////////////////
33 #define INTROSPECTION_TABLE \
34 LINE(RISCV_RV32I, RV32I, "rv32i", RISCV_HWCAP_32, 0) \
35 LINE(RISCV_RV64I, RV64I, "rv64i", RISCV_HWCAP_64, 0) \
36 LINE(RISCV_M, M, "m", RISCV_HWCAP_M, 0) \
37 LINE(RISCV_A, A, "a", RISCV_HWCAP_A, 0) \
38 LINE(RISCV_F, F, "f", RISCV_HWCAP_F, 0) \
39 LINE(RISCV_D, D, "d", RISCV_HWCAP_D, 0) \
40 LINE(RISCV_Q, Q, "q", RISCV_HWCAP_Q, 0) \
41 LINE(RISCV_C, C, "c", RISCV_HWCAP_C, 0) \
42 LINE(RISCV_V, V, "v", RISCV_HWCAP_V, 0) \
43 LINE(RISCV_Zicsr, Zicsr, "_zicsr", 0, 0) \
44 LINE(RISCV_Zifencei, Zifencei, "_zifencei", 0, 0)
45 #define INTROSPECTION_PREFIX Riscv
46 #define INTROSPECTION_ENUM_PREFIX RISCV
47 #include "define_introspection_and_hwcaps.inl"
48
49 ////////////////////////////////////////////////////////////////////////////////
50 // Implementation.
51 ////////////////////////////////////////////////////////////////////////////////
52
53 #include <stdbool.h>
54 #include <stdio.h>
55
56 #include "internal/filesystem.h"
57 #include "internal/stack_line_reader.h"
58
59 static const RiscvInfo kEmptyRiscvInfo;
60
HandleRiscVIsaLine(StringView line,RiscvFeatures * const features)61 static void HandleRiscVIsaLine(StringView line, RiscvFeatures* const features) {
62 for (size_t i = 0; i < RISCV_LAST_; ++i) {
63 StringView flag = str(kCpuInfoFlags[i]);
64 int index_of_flag = CpuFeatures_StringView_IndexOf(line, flag);
65 bool is_set = index_of_flag != -1;
66 kSetters[i](features, is_set);
67 if (is_set)
68 line = CpuFeatures_StringView_PopFront(line, index_of_flag + flag.size);
69 }
70 }
71
HandleRiscVLine(const LineResult result,RiscvInfo * const info)72 static bool HandleRiscVLine(const LineResult result, RiscvInfo* const info) {
73 StringView line = result.line;
74 StringView key, value;
75 if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
76 if (CpuFeatures_StringView_IsEquals(key, str("isa"))) {
77 HandleRiscVIsaLine(value, &info->features);
78 } else if (CpuFeatures_StringView_IsEquals(key, str("uarch"))) {
79 int index = CpuFeatures_StringView_IndexOfChar(value, ',');
80 if (index == -1) return true;
81 StringView vendor = CpuFeatures_StringView_KeepFront(value, index);
82 StringView uarch = CpuFeatures_StringView_PopFront(value, index + 1);
83 CpuFeatures_StringView_CopyString(vendor, info->vendor,
84 sizeof(info->vendor));
85 CpuFeatures_StringView_CopyString(uarch, info->uarch,
86 sizeof(info->uarch));
87 }
88 }
89 return !result.eof;
90 }
91
FillProcCpuInfoData(RiscvInfo * const info)92 static void FillProcCpuInfoData(RiscvInfo* const info) {
93 const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
94 if (fd >= 0) {
95 StackLineReader reader;
96 StackLineReader_Initialize(&reader, fd);
97 for (;;) {
98 if (!HandleRiscVLine(StackLineReader_NextLine(&reader), info)) break;
99 }
100 CpuFeatures_CloseFile(fd);
101 }
102 }
103
GetRiscvInfo(void)104 RiscvInfo GetRiscvInfo(void) {
105 RiscvInfo info = kEmptyRiscvInfo;
106 FillProcCpuInfoData(&info);
107 return info;
108 }
109
110 #endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
111 #endif // CPU_FEATURES_ARCH_RISCV
112