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