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 #if defined(CPU_FEATURES_OS_LINUX)
29 // No particular implementation for Linux as we use /proc/cpuinfo
30 #elif defined(CPU_FEATURES_OS_MACOS)
31 std::set<std::string> darwin_sysctlbyname_;
32 std::map<std::string, int> darwin_sysctlbynamevalue_;
33
34 public:
35 bool GetDarwinSysCtlByName(std::string name) const {
36 return darwin_sysctlbyname_.count(name);
37 }
38
39 int GetDarwinSysCtlByNameValue(std::string name) const {
40 const auto iter = darwin_sysctlbynamevalue_.find(name);
41 if (iter != darwin_sysctlbynamevalue_.end()) return iter->second;
42 return 0;
43 }
44
45 void SetDarwinSysCtlByName(std::string name) {
46 darwin_sysctlbyname_.insert(name);
47 }
48
49 void SetDarwinSysCtlByNameValue(std::string name, int value) {
50 darwin_sysctlbynamevalue_[name] = value;
51 }
52 #elif defined(CPU_FEATURES_OS_WINDOWS)
53 std::set<DWORD> windows_isprocessorfeaturepresent_;
54 WORD processor_revision_{};
55
56 public:
57 bool GetWindowsIsProcessorFeaturePresent(DWORD dwProcessorFeature) {
58 return windows_isprocessorfeaturepresent_.count(dwProcessorFeature);
59 }
60
61 void SetWindowsIsProcessorFeaturePresent(DWORD dwProcessorFeature) {
62 windows_isprocessorfeaturepresent_.insert(dwProcessorFeature);
63 }
64
65 WORD GetWindowsNativeSystemInfoProcessorRevision() const {
66 return processor_revision_;
67 }
68
69 void SetWindowsNativeSystemInfoProcessorRevision(WORD wProcessorRevision) {
70 processor_revision_ = wProcessorRevision;
71 }
72 #endif
73 };
74
75 static FakeCpuAarch64* g_fake_cpu_instance = nullptr;
76
cpu()77 static FakeCpuAarch64& cpu() {
78 assert(g_fake_cpu_instance != nullptr);
79 return *g_fake_cpu_instance;
80 }
81
82 // Define OS dependent mock functions
83 #if defined(CPU_FEATURES_OS_LINUX)
84 // No particular functions to implement for Linux as we use /proc/cpuinfo
85 #elif defined(CPU_FEATURES_OS_MACOS)
GetDarwinSysCtlByName(const char * name)86 extern "C" bool GetDarwinSysCtlByName(const char* name) {
87 return cpu().GetDarwinSysCtlByName(name);
88 }
89
GetDarwinSysCtlByNameValue(const char * name)90 extern "C" int GetDarwinSysCtlByNameValue(const char* name) {
91 return cpu().GetDarwinSysCtlByNameValue(name);
92 }
93 #elif defined(CPU_FEATURES_OS_WINDOWS)
GetWindowsIsProcessorFeaturePresent(DWORD dwProcessorFeature)94 extern "C" bool GetWindowsIsProcessorFeaturePresent(DWORD dwProcessorFeature) {
95 return cpu().GetWindowsIsProcessorFeaturePresent(dwProcessorFeature);
96 }
97
GetWindowsNativeSystemInfoProcessorRevision()98 extern "C" WORD GetWindowsNativeSystemInfoProcessorRevision() {
99 return cpu().GetWindowsNativeSystemInfoProcessorRevision();
100 }
101 #endif
102
103 namespace {
104
105 class CpuidAarch64Test : public ::testing::Test {
106 protected:
SetUp()107 void SetUp() override {
108 assert(g_fake_cpu_instance == nullptr);
109 g_fake_cpu_instance = new FakeCpuAarch64();
110 }
TearDown()111 void TearDown() override {
112 delete g_fake_cpu_instance;
113 g_fake_cpu_instance = nullptr;
114 }
115 };
116
TEST_F(CpuidAarch64Test,Aarch64FeaturesEnum)117 TEST_F(CpuidAarch64Test, Aarch64FeaturesEnum) {
118 const char* last_name = GetAarch64FeaturesEnumName(AARCH64_LAST_);
119 EXPECT_STREQ(last_name, "unknown_feature");
120 for (int i = static_cast<int>(AARCH64_FP);
121 i != static_cast<int>(AARCH64_LAST_); ++i) {
122 const auto feature = static_cast<Aarch64FeaturesEnum>(i);
123 const char* name = GetAarch64FeaturesEnumName(feature);
124 ASSERT_FALSE(name == nullptr);
125 EXPECT_STRNE(name, "");
126 EXPECT_STRNE(name, last_name);
127 }
128 }
129
130 // OS dependent tests
131 #if defined(CPU_FEATURES_OS_LINUX)
TEST_F(CpuidAarch64Test,FromHardwareCap)132 TEST_F(CpuidAarch64Test, FromHardwareCap) {
133 ResetHwcaps();
134 SetHardwareCapabilities(AARCH64_HWCAP_FP | AARCH64_HWCAP_AES, 0);
135 GetEmptyFilesystem(); // disabling /proc/cpuinfo
136 const auto info = GetAarch64Info();
137 EXPECT_TRUE(info.features.fp);
138 EXPECT_FALSE(info.features.asimd);
139 EXPECT_FALSE(info.features.evtstrm);
140 EXPECT_TRUE(info.features.aes);
141 EXPECT_FALSE(info.features.pmull);
142 EXPECT_FALSE(info.features.sha1);
143 EXPECT_FALSE(info.features.sha2);
144 EXPECT_FALSE(info.features.crc32);
145 EXPECT_FALSE(info.features.atomics);
146 EXPECT_FALSE(info.features.fphp);
147 EXPECT_FALSE(info.features.asimdhp);
148 EXPECT_FALSE(info.features.cpuid);
149 EXPECT_FALSE(info.features.asimdrdm);
150 EXPECT_FALSE(info.features.jscvt);
151 EXPECT_FALSE(info.features.fcma);
152 EXPECT_FALSE(info.features.lrcpc);
153 EXPECT_FALSE(info.features.dcpop);
154 EXPECT_FALSE(info.features.sha3);
155 EXPECT_FALSE(info.features.sm3);
156 EXPECT_FALSE(info.features.sm4);
157 EXPECT_FALSE(info.features.asimddp);
158 EXPECT_FALSE(info.features.sha512);
159 EXPECT_FALSE(info.features.sve);
160 EXPECT_FALSE(info.features.asimdfhm);
161 EXPECT_FALSE(info.features.dit);
162 EXPECT_FALSE(info.features.uscat);
163 EXPECT_FALSE(info.features.ilrcpc);
164 EXPECT_FALSE(info.features.flagm);
165 EXPECT_FALSE(info.features.ssbs);
166 EXPECT_FALSE(info.features.sb);
167 EXPECT_FALSE(info.features.paca);
168 EXPECT_FALSE(info.features.pacg);
169 }
170
TEST_F(CpuidAarch64Test,FromHardwareCap2)171 TEST_F(CpuidAarch64Test, FromHardwareCap2) {
172 ResetHwcaps();
173 SetHardwareCapabilities(AARCH64_HWCAP_FP,
174 AARCH64_HWCAP2_SVE2 | AARCH64_HWCAP2_BTI);
175 GetEmptyFilesystem(); // disabling /proc/cpuinfo
176 const auto info = GetAarch64Info();
177 EXPECT_TRUE(info.features.fp);
178
179 EXPECT_TRUE(info.features.sve2);
180 EXPECT_TRUE(info.features.bti);
181
182 EXPECT_FALSE(info.features.dcpodp);
183 EXPECT_FALSE(info.features.sveaes);
184 EXPECT_FALSE(info.features.svepmull);
185 EXPECT_FALSE(info.features.svebitperm);
186 EXPECT_FALSE(info.features.svesha3);
187 EXPECT_FALSE(info.features.svesm4);
188 EXPECT_FALSE(info.features.flagm2);
189 EXPECT_FALSE(info.features.frint);
190 EXPECT_FALSE(info.features.svei8mm);
191 EXPECT_FALSE(info.features.svef32mm);
192 EXPECT_FALSE(info.features.svef64mm);
193 EXPECT_FALSE(info.features.svebf16);
194 EXPECT_FALSE(info.features.i8mm);
195 EXPECT_FALSE(info.features.bf16);
196 EXPECT_FALSE(info.features.dgh);
197 EXPECT_FALSE(info.features.rng);
198 }
199
TEST_F(CpuidAarch64Test,ARMCortexA53)200 TEST_F(CpuidAarch64Test, ARMCortexA53) {
201 ResetHwcaps();
202 auto& fs = GetEmptyFilesystem();
203 fs.CreateFile("/proc/cpuinfo",
204 R"(Processor : AArch64 Processor rev 3 (aarch64)
205 processor : 0
206 processor : 1
207 processor : 2
208 processor : 3
209 processor : 4
210 processor : 5
211 processor : 6
212 processor : 7
213 Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
214 CPU implementer : 0x41
215 CPU architecture: AArch64
216 CPU variant : 0x0
217 CPU part : 0xd03
218 CPU revision : 3)");
219 const auto info = GetAarch64Info();
220 EXPECT_EQ(info.implementer, 0x41);
221 EXPECT_EQ(info.variant, 0x0);
222 EXPECT_EQ(info.part, 0xd03);
223 EXPECT_EQ(info.revision, 3);
224
225 EXPECT_TRUE(info.features.fp);
226 EXPECT_TRUE(info.features.asimd);
227 EXPECT_TRUE(info.features.evtstrm);
228 EXPECT_TRUE(info.features.aes);
229 EXPECT_TRUE(info.features.pmull);
230 EXPECT_TRUE(info.features.sha1);
231 EXPECT_TRUE(info.features.sha2);
232 EXPECT_TRUE(info.features.crc32);
233
234 EXPECT_FALSE(info.features.atomics);
235 EXPECT_FALSE(info.features.fphp);
236 EXPECT_FALSE(info.features.asimdhp);
237 EXPECT_FALSE(info.features.cpuid);
238 EXPECT_FALSE(info.features.asimdrdm);
239 EXPECT_FALSE(info.features.jscvt);
240 EXPECT_FALSE(info.features.fcma);
241 EXPECT_FALSE(info.features.lrcpc);
242 EXPECT_FALSE(info.features.dcpop);
243 EXPECT_FALSE(info.features.sha3);
244 EXPECT_FALSE(info.features.sm3);
245 EXPECT_FALSE(info.features.sm4);
246 EXPECT_FALSE(info.features.asimddp);
247 EXPECT_FALSE(info.features.sha512);
248 EXPECT_FALSE(info.features.sve);
249 EXPECT_FALSE(info.features.asimdfhm);
250 EXPECT_FALSE(info.features.dit);
251 EXPECT_FALSE(info.features.uscat);
252 EXPECT_FALSE(info.features.ilrcpc);
253 EXPECT_FALSE(info.features.flagm);
254 EXPECT_FALSE(info.features.ssbs);
255 EXPECT_FALSE(info.features.sb);
256 EXPECT_FALSE(info.features.paca);
257 EXPECT_FALSE(info.features.pacg);
258 EXPECT_FALSE(info.features.dcpodp);
259 EXPECT_FALSE(info.features.sve2);
260 EXPECT_FALSE(info.features.sveaes);
261 EXPECT_FALSE(info.features.svepmull);
262 EXPECT_FALSE(info.features.svebitperm);
263 EXPECT_FALSE(info.features.svesha3);
264 EXPECT_FALSE(info.features.svesm4);
265 EXPECT_FALSE(info.features.flagm2);
266 EXPECT_FALSE(info.features.frint);
267 EXPECT_FALSE(info.features.svei8mm);
268 EXPECT_FALSE(info.features.svef32mm);
269 EXPECT_FALSE(info.features.svef64mm);
270 EXPECT_FALSE(info.features.svebf16);
271 EXPECT_FALSE(info.features.i8mm);
272 EXPECT_FALSE(info.features.bf16);
273 EXPECT_FALSE(info.features.dgh);
274 EXPECT_FALSE(info.features.rng);
275 EXPECT_FALSE(info.features.bti);
276 EXPECT_FALSE(info.features.mte);
277 EXPECT_FALSE(info.features.ecv);
278 EXPECT_FALSE(info.features.afp);
279 EXPECT_FALSE(info.features.rpres);
280 EXPECT_FALSE(info.features.mte3);
281 EXPECT_FALSE(info.features.sme);
282 EXPECT_FALSE(info.features.smei16i64);
283 EXPECT_FALSE(info.features.smef64f64);
284 EXPECT_FALSE(info.features.smei8i32);
285 EXPECT_FALSE(info.features.smef16f32);
286 EXPECT_FALSE(info.features.smeb16f32);
287 EXPECT_FALSE(info.features.smef32f32);
288 EXPECT_FALSE(info.features.smefa64);
289 EXPECT_FALSE(info.features.wfxt);
290 EXPECT_FALSE(info.features.ebf16);
291 EXPECT_FALSE(info.features.sveebf16);
292 EXPECT_FALSE(info.features.cssc);
293 EXPECT_FALSE(info.features.rprfm);
294 EXPECT_FALSE(info.features.sve2p1);
295 EXPECT_FALSE(info.features.sme2);
296 EXPECT_FALSE(info.features.sme2p1);
297 EXPECT_FALSE(info.features.smei16i32);
298 EXPECT_FALSE(info.features.smebi32i32);
299 EXPECT_FALSE(info.features.smeb16b16);
300 EXPECT_FALSE(info.features.smef16f16);
301 }
302 #elif defined(CPU_FEATURES_OS_MACOS)
TEST_F(CpuidAarch64Test,FromDarwinSysctlFromName)303 TEST_F(CpuidAarch64Test, FromDarwinSysctlFromName) {
304 cpu().SetDarwinSysCtlByName("hw.optional.floatingpoint");
305 cpu().SetDarwinSysCtlByName("hw.optional.neon");
306 cpu().SetDarwinSysCtlByName("hw.optional.AdvSIMD_HPFPCvt");
307 cpu().SetDarwinSysCtlByName("hw.optional.arm.FEAT_FP16");
308 cpu().SetDarwinSysCtlByName("hw.optional.arm.FEAT_LSE");
309 cpu().SetDarwinSysCtlByName("hw.optional.armv8_crc32");
310 cpu().SetDarwinSysCtlByName("hw.optional.arm.FEAT_FHM");
311 cpu().SetDarwinSysCtlByName("hw.optional.arm.FEAT_SHA512");
312 cpu().SetDarwinSysCtlByName("hw.optional.arm.FEAT_SHA3");
313 cpu().SetDarwinSysCtlByName("hw.optional.amx_version");
314 cpu().SetDarwinSysCtlByName("hw.optional.ucnormal_mem");
315 cpu().SetDarwinSysCtlByName("hw.optional.arm64");
316
317 cpu().SetDarwinSysCtlByNameValue("hw.cputype", 16777228);
318 cpu().SetDarwinSysCtlByNameValue("hw.cpusubtype", 2);
319 cpu().SetDarwinSysCtlByNameValue("hw.cpu64bit", 1);
320 cpu().SetDarwinSysCtlByNameValue("hw.cpufamily", 458787763);
321 cpu().SetDarwinSysCtlByNameValue("hw.cpusubfamily", 2);
322
323 const auto info = GetAarch64Info();
324
325 EXPECT_EQ(info.implementer, 0x100000C);
326 EXPECT_EQ(info.variant, 2);
327 EXPECT_EQ(info.part, 0x1B588BB3);
328 EXPECT_EQ(info.revision, 2);
329
330 EXPECT_TRUE(info.features.fp);
331 EXPECT_FALSE(info.features.asimd);
332 EXPECT_FALSE(info.features.evtstrm);
333 EXPECT_FALSE(info.features.aes);
334 EXPECT_FALSE(info.features.pmull);
335 EXPECT_FALSE(info.features.sha1);
336 EXPECT_FALSE(info.features.sha2);
337 EXPECT_TRUE(info.features.crc32);
338 EXPECT_TRUE(info.features.atomics);
339 EXPECT_TRUE(info.features.fphp);
340 EXPECT_FALSE(info.features.asimdhp);
341 EXPECT_FALSE(info.features.cpuid);
342 EXPECT_FALSE(info.features.asimdrdm);
343 EXPECT_FALSE(info.features.jscvt);
344 EXPECT_FALSE(info.features.fcma);
345 EXPECT_FALSE(info.features.lrcpc);
346 EXPECT_FALSE(info.features.dcpop);
347 EXPECT_TRUE(info.features.sha3);
348 EXPECT_FALSE(info.features.sm3);
349 EXPECT_FALSE(info.features.sm4);
350 EXPECT_FALSE(info.features.asimddp);
351 EXPECT_TRUE(info.features.sha512);
352 EXPECT_FALSE(info.features.sve);
353 EXPECT_TRUE(info.features.asimdfhm);
354 EXPECT_FALSE(info.features.dit);
355 EXPECT_FALSE(info.features.uscat);
356 EXPECT_FALSE(info.features.ilrcpc);
357 EXPECT_FALSE(info.features.flagm);
358 EXPECT_FALSE(info.features.ssbs);
359 EXPECT_FALSE(info.features.sb);
360 EXPECT_FALSE(info.features.paca);
361 EXPECT_FALSE(info.features.pacg);
362 }
363 #elif defined(CPU_FEATURES_OS_WINDOWS)
TEST_F(CpuidAarch64Test,WINDOWS_AARCH64_RPI4)364 TEST_F(CpuidAarch64Test, WINDOWS_AARCH64_RPI4) {
365 cpu().SetWindowsNativeSystemInfoProcessorRevision(0x03);
366 cpu().SetWindowsIsProcessorFeaturePresent(PF_ARM_VFP_32_REGISTERS_AVAILABLE);
367 cpu().SetWindowsIsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE);
368 cpu().SetWindowsIsProcessorFeaturePresent(
369 PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE);
370
371 const auto info = GetAarch64Info();
372
373 EXPECT_EQ(info.revision, 0x03);
374 EXPECT_TRUE(info.features.fp);
375 EXPECT_TRUE(info.features.asimd);
376 EXPECT_TRUE(info.features.crc32);
377 EXPECT_FALSE(info.features.aes);
378 EXPECT_FALSE(info.features.sha1);
379 EXPECT_FALSE(info.features.sha2);
380 EXPECT_FALSE(info.features.pmull);
381 EXPECT_FALSE(info.features.atomics);
382 EXPECT_FALSE(info.features.asimddp);
383 EXPECT_FALSE(info.features.jscvt);
384 EXPECT_FALSE(info.features.lrcpc);
385 }
386 #endif // CPU_FEATURES_OS_WINDOWS
387 } // namespace
388 } // namespace cpu_features
389