1 // Copyright 2017 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 "cpuinfo_aarch64.h"
16
17 #include <set>
18
19 #include "filesystem_for_testing.h"
20 #include "gtest/gtest.h"
21 #include "hwcaps_for_testing.h"
22 #if defined(CPU_FEATURES_OS_WINDOWS)
23 #include "internal/windows_utils.h"
24 #endif // CPU_FEATURES_OS_WINDOWS
25
26 namespace cpu_features {
27 class FakeCpuAarch64 {
28 public:
29 #if defined(CPU_FEATURES_OS_WINDOWS)
GetWindowsIsProcessorFeaturePresent(DWORD dwProcessorFeature)30 bool GetWindowsIsProcessorFeaturePresent(DWORD dwProcessorFeature) {
31 return windows_isprocessorfeaturepresent_.count(dwProcessorFeature);
32 }
33
SetWindowsIsProcessorFeaturePresent(DWORD dwProcessorFeature)34 void SetWindowsIsProcessorFeaturePresent(DWORD dwProcessorFeature) {
35 windows_isprocessorfeaturepresent_.insert(dwProcessorFeature);
36 }
37
GetWindowsNativeSystemInfoProcessorRevision() const38 WORD GetWindowsNativeSystemInfoProcessorRevision() const {
39 return processor_revision_;
40 }
41
SetWindowsNativeSystemInfoProcessorRevision(WORD wProcessorRevision)42 void SetWindowsNativeSystemInfoProcessorRevision(WORD wProcessorRevision) {
43 processor_revision_ = wProcessorRevision;
44 }
45
46 private:
47 std::set<DWORD> windows_isprocessorfeaturepresent_;
48 WORD processor_revision_{};
49 #endif // CPU_FEATURES_OS_WINDOWS
50 };
51
52 static FakeCpuAarch64* g_fake_cpu_instance = nullptr;
53
cpu()54 static FakeCpuAarch64& cpu() {
55 assert(g_fake_cpu_instance != nullptr);
56 return *g_fake_cpu_instance;
57 }
58
59 #if defined(CPU_FEATURES_OS_WINDOWS)
GetWindowsIsProcessorFeaturePresent(DWORD dwProcessorFeature)60 extern "C" bool GetWindowsIsProcessorFeaturePresent(DWORD dwProcessorFeature) {
61 return cpu().GetWindowsIsProcessorFeaturePresent(dwProcessorFeature);
62 }
63
GetWindowsNativeSystemInfoProcessorRevision()64 extern "C" WORD GetWindowsNativeSystemInfoProcessorRevision() {
65 return cpu().GetWindowsNativeSystemInfoProcessorRevision();
66 }
67 #endif // CPU_FEATURES_OS_WINDOWS
68
69 namespace {
70
71 class CpuidAarch64Test : public ::testing::Test {
72 protected:
SetUp()73 void SetUp() override {
74 assert(g_fake_cpu_instance == nullptr);
75 g_fake_cpu_instance = new FakeCpuAarch64();
76 }
TearDown()77 void TearDown() override {
78 delete g_fake_cpu_instance;
79 g_fake_cpu_instance = nullptr;
80 }
81 };
82
TEST(CpuinfoAarch64Test,Aarch64FeaturesEnum)83 TEST(CpuinfoAarch64Test, Aarch64FeaturesEnum) {
84 const char* last_name = GetAarch64FeaturesEnumName(AARCH64_LAST_);
85 EXPECT_STREQ(last_name, "unknown_feature");
86 for (int i = static_cast<int>(AARCH64_FP);
87 i != static_cast<int>(AARCH64_LAST_); ++i) {
88 const auto feature = static_cast<Aarch64FeaturesEnum>(i);
89 const char* name = GetAarch64FeaturesEnumName(feature);
90 ASSERT_FALSE(name == nullptr);
91 EXPECT_STRNE(name, "");
92 EXPECT_STRNE(name, last_name);
93 }
94 }
95
96 #if defined(CPU_FEATURES_OS_LINUX)
DisableHardwareCapabilities()97 void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); }
98
TEST(CpuinfoAarch64Test,FromHardwareCap)99 TEST(CpuinfoAarch64Test, FromHardwareCap) {
100 ResetHwcaps();
101 SetHardwareCapabilities(AARCH64_HWCAP_FP | AARCH64_HWCAP_AES, 0);
102 GetEmptyFilesystem(); // disabling /proc/cpuinfo
103 const auto info = GetAarch64Info();
104 EXPECT_TRUE(info.features.fp);
105 EXPECT_FALSE(info.features.asimd);
106 EXPECT_FALSE(info.features.evtstrm);
107 EXPECT_TRUE(info.features.aes);
108 EXPECT_FALSE(info.features.pmull);
109 EXPECT_FALSE(info.features.sha1);
110 EXPECT_FALSE(info.features.sha2);
111 EXPECT_FALSE(info.features.crc32);
112 EXPECT_FALSE(info.features.atomics);
113 EXPECT_FALSE(info.features.fphp);
114 EXPECT_FALSE(info.features.asimdhp);
115 EXPECT_FALSE(info.features.cpuid);
116 EXPECT_FALSE(info.features.asimdrdm);
117 EXPECT_FALSE(info.features.jscvt);
118 EXPECT_FALSE(info.features.fcma);
119 EXPECT_FALSE(info.features.lrcpc);
120 EXPECT_FALSE(info.features.dcpop);
121 EXPECT_FALSE(info.features.sha3);
122 EXPECT_FALSE(info.features.sm3);
123 EXPECT_FALSE(info.features.sm4);
124 EXPECT_FALSE(info.features.asimddp);
125 EXPECT_FALSE(info.features.sha512);
126 EXPECT_FALSE(info.features.sve);
127 EXPECT_FALSE(info.features.asimdfhm);
128 EXPECT_FALSE(info.features.dit);
129 EXPECT_FALSE(info.features.uscat);
130 EXPECT_FALSE(info.features.ilrcpc);
131 EXPECT_FALSE(info.features.flagm);
132 EXPECT_FALSE(info.features.ssbs);
133 EXPECT_FALSE(info.features.sb);
134 EXPECT_FALSE(info.features.paca);
135 EXPECT_FALSE(info.features.pacg);
136 }
137
TEST(CpuinfoAarch64Test,FromHardwareCap2)138 TEST(CpuinfoAarch64Test, FromHardwareCap2) {
139 ResetHwcaps();
140 SetHardwareCapabilities(AARCH64_HWCAP_FP,
141 AARCH64_HWCAP2_SVE2 | AARCH64_HWCAP2_BTI);
142 GetEmptyFilesystem(); // disabling /proc/cpuinfo
143 const auto info = GetAarch64Info();
144 EXPECT_TRUE(info.features.fp);
145
146 EXPECT_TRUE(info.features.sve2);
147 EXPECT_TRUE(info.features.bti);
148
149 EXPECT_FALSE(info.features.dcpodp);
150 EXPECT_FALSE(info.features.sveaes);
151 EXPECT_FALSE(info.features.svepmull);
152 EXPECT_FALSE(info.features.svebitperm);
153 EXPECT_FALSE(info.features.svesha3);
154 EXPECT_FALSE(info.features.svesm4);
155 EXPECT_FALSE(info.features.flagm2);
156 EXPECT_FALSE(info.features.frint);
157 EXPECT_FALSE(info.features.svei8mm);
158 EXPECT_FALSE(info.features.svef32mm);
159 EXPECT_FALSE(info.features.svef64mm);
160 EXPECT_FALSE(info.features.svebf16);
161 EXPECT_FALSE(info.features.i8mm);
162 EXPECT_FALSE(info.features.bf16);
163 EXPECT_FALSE(info.features.dgh);
164 EXPECT_FALSE(info.features.rng);
165 }
166
TEST(CpuinfoAarch64Test,ARMCortexA53)167 TEST(CpuinfoAarch64Test, ARMCortexA53) {
168 ResetHwcaps();
169 auto& fs = GetEmptyFilesystem();
170 fs.CreateFile("/proc/cpuinfo",
171 R"(Processor : AArch64 Processor rev 3 (aarch64)
172 processor : 0
173 processor : 1
174 processor : 2
175 processor : 3
176 processor : 4
177 processor : 5
178 processor : 6
179 processor : 7
180 Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
181 CPU implementer : 0x41
182 CPU architecture: AArch64
183 CPU variant : 0x0
184 CPU part : 0xd03
185 CPU revision : 3)");
186 const auto info = GetAarch64Info();
187 EXPECT_EQ(info.implementer, 0x41);
188 EXPECT_EQ(info.variant, 0x0);
189 EXPECT_EQ(info.part, 0xd03);
190 EXPECT_EQ(info.revision, 3);
191
192 EXPECT_TRUE(info.features.fp);
193 EXPECT_TRUE(info.features.asimd);
194 EXPECT_TRUE(info.features.evtstrm);
195 EXPECT_TRUE(info.features.aes);
196 EXPECT_TRUE(info.features.pmull);
197 EXPECT_TRUE(info.features.sha1);
198 EXPECT_TRUE(info.features.sha2);
199 EXPECT_TRUE(info.features.crc32);
200
201 EXPECT_FALSE(info.features.atomics);
202 EXPECT_FALSE(info.features.fphp);
203 EXPECT_FALSE(info.features.asimdhp);
204 EXPECT_FALSE(info.features.cpuid);
205 EXPECT_FALSE(info.features.asimdrdm);
206 EXPECT_FALSE(info.features.jscvt);
207 EXPECT_FALSE(info.features.fcma);
208 EXPECT_FALSE(info.features.lrcpc);
209 EXPECT_FALSE(info.features.dcpop);
210 EXPECT_FALSE(info.features.sha3);
211 EXPECT_FALSE(info.features.sm3);
212 EXPECT_FALSE(info.features.sm4);
213 EXPECT_FALSE(info.features.asimddp);
214 EXPECT_FALSE(info.features.sha512);
215 EXPECT_FALSE(info.features.sve);
216 EXPECT_FALSE(info.features.asimdfhm);
217 EXPECT_FALSE(info.features.dit);
218 EXPECT_FALSE(info.features.uscat);
219 EXPECT_FALSE(info.features.ilrcpc);
220 EXPECT_FALSE(info.features.flagm);
221 EXPECT_FALSE(info.features.ssbs);
222 EXPECT_FALSE(info.features.sb);
223 EXPECT_FALSE(info.features.paca);
224 EXPECT_FALSE(info.features.pacg);
225 EXPECT_FALSE(info.features.dcpodp);
226 EXPECT_FALSE(info.features.sve2);
227 EXPECT_FALSE(info.features.sveaes);
228 EXPECT_FALSE(info.features.svepmull);
229 EXPECT_FALSE(info.features.svebitperm);
230 EXPECT_FALSE(info.features.svesha3);
231 EXPECT_FALSE(info.features.svesm4);
232 EXPECT_FALSE(info.features.flagm2);
233 EXPECT_FALSE(info.features.frint);
234 EXPECT_FALSE(info.features.svei8mm);
235 EXPECT_FALSE(info.features.svef32mm);
236 EXPECT_FALSE(info.features.svef64mm);
237 EXPECT_FALSE(info.features.svebf16);
238 EXPECT_FALSE(info.features.i8mm);
239 EXPECT_FALSE(info.features.bf16);
240 EXPECT_FALSE(info.features.dgh);
241 EXPECT_FALSE(info.features.rng);
242 EXPECT_FALSE(info.features.bti);
243 EXPECT_FALSE(info.features.mte);
244 EXPECT_FALSE(info.features.ecv);
245 EXPECT_FALSE(info.features.afp);
246 EXPECT_FALSE(info.features.rpres);
247 }
248 #endif // CPU_FEATURES_OS_LINUX
249
250 #if defined(CPU_FEATURES_OS_WINDOWS)
TEST_F(CpuidAarch64Test,WINDOWS_AARCH64_RPI4)251 TEST_F(CpuidAarch64Test, WINDOWS_AARCH64_RPI4) {
252 cpu().SetWindowsNativeSystemInfoProcessorRevision(0x03);
253 cpu().SetWindowsIsProcessorFeaturePresent(PF_ARM_VFP_32_REGISTERS_AVAILABLE);
254 cpu().SetWindowsIsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE);
255 cpu().SetWindowsIsProcessorFeaturePresent(
256 PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE);
257
258 const auto info = GetAarch64Info();
259
260 EXPECT_EQ(info.revision, 0x03);
261 EXPECT_TRUE(info.features.fp);
262 EXPECT_TRUE(info.features.asimd);
263 EXPECT_TRUE(info.features.crc32);
264 EXPECT_FALSE(info.features.aes);
265 EXPECT_FALSE(info.features.sha1);
266 EXPECT_FALSE(info.features.sha2);
267 EXPECT_FALSE(info.features.pmull);
268 EXPECT_FALSE(info.features.atomics);
269 EXPECT_FALSE(info.features.asimddp);
270 EXPECT_FALSE(info.features.jscvt);
271 EXPECT_FALSE(info.features.lrcpc);
272 }
273 #endif // CPU_FEATURES_OS_WINDOWS
274
275 } // namespace
276 } // namespace cpu_features
277