1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "gtest/gtest.h"
18 
19 #include <asm/hwcap.h>
20 #include <cpu-features.h>
21 #include <sys/auxv.h>
22 #include <sys/system_properties.h>
23 
24 #include <fstream>
25 #include <string>
26 
27 namespace {
28 
29 // Test CPU features interfaces from
30 // https://developer.android.com/ndk/guides/cpu-features
31 //
32 // Required features for armeabi-v7a from
33 // https://developer.android.com/ndk/guides/abis
34 // are only:
35 // - armeabi
36 // - thumb-2
37 // - vfpv3-d16
38 //
39 // For ndk-translation we check that we get all the values as expected.
40 
41 class ProcCpuinfoFeatures {
42  public:
ProcCpuinfoFeatures()43   ProcCpuinfoFeatures() {
44     std::ifstream cpuinfo("/proc/cpuinfo");
45     std::string line;
46     while (std::getline(cpuinfo, line)) {
47       // Warning: line caption for features is architecture dependent!
48       if (line.find("Features") != std::string::npos) {
49         features_ = line;
50         features_ += " ";  // add feature delimiter at the end.
51       } else if (line.find("Hardware") != std::string::npos) {
52         hardware_ = line;
53       }
54     }
55   }
56 
Empty() const57   bool Empty() const { return features_.empty(); }
58 
Get(const char * name) const59   bool Get(const char* name) const {
60     // Search for name surrounded by delimiters.
61     std::string value = " ";
62     value += name;
63     value += " ";
64     return features_.find(name) != std::string::npos;
65   }
66 
IsNdkTranslation() const67   bool IsNdkTranslation() const { return hardware_.find("ndk_translation") != std::string::npos; }
68 
69  private:
70   std::string features_;
71   std::string hardware_;
72 };
73 
74 class BitFeatures {
75  public:
BitFeatures(uint64_t features)76   explicit BitFeatures(uint64_t features) : features_(features) {}
77 
Empty() const78   bool Empty() const { return features_ == 0; }
79 
Get(uint64_t bits) const80   bool Get(uint64_t bits) const { return (features_ & bits) != 0; }
81 
82  private:
83   uint64_t features_;
84 };
85 
IsNdkTranslation()86 bool IsNdkTranslation() {
87   char value[PROP_VALUE_MAX];
88   __system_property_get("ro.dalvik.vm.native.bridge", value);
89   return std::string(value) == "libndk_translation.so";
90 }
91 
TEST(CpuFeatures,proc_cpuinfo)92 TEST(CpuFeatures, proc_cpuinfo) {
93   ProcCpuinfoFeatures cpuinfo;
94   // Attention: ART mounts guest cpuinfo in case of native bridge. No one does
95   // that in case of standalone executable, so we observe the host one.
96   if (cpuinfo.Empty()) {
97     GTEST_LOG_(INFO) << "skipping test, /proc/cpuinfo features are empty.\n";
98     return;
99   }
100 
101   EXPECT_TRUE(cpuinfo.Get("vfpv3"));
102   EXPECT_TRUE(cpuinfo.Get("thumb"));
103 
104   if (!IsNdkTranslation()) {
105     GTEST_LOG_(INFO) << "skipping test, not under ndk_translation.\n";
106     return;
107   }
108 
109   EXPECT_TRUE(cpuinfo.Get("neon"));
110   EXPECT_TRUE(cpuinfo.Get("vfp"));
111   EXPECT_TRUE(cpuinfo.Get("swp"));
112   EXPECT_TRUE(cpuinfo.Get("half"));
113   EXPECT_TRUE(cpuinfo.Get("thumb"));
114   EXPECT_TRUE(cpuinfo.Get("fastmult"));
115   EXPECT_TRUE(cpuinfo.Get("edsp"));
116   EXPECT_TRUE(cpuinfo.Get("vfpv3"));
117   EXPECT_TRUE(cpuinfo.Get("vfpv4"));
118   EXPECT_TRUE(cpuinfo.Get("idiva"));
119   EXPECT_TRUE(cpuinfo.Get("idivt"));
120 }
121 
TEST(CpuFeatures,getauxval_AT_HWCAP)122 TEST(CpuFeatures, getauxval_AT_HWCAP) {
123   BitFeatures hwcap(getauxval(AT_HWCAP));
124 
125   EXPECT_TRUE(hwcap.Get(HWCAP_THUMB));
126   EXPECT_TRUE(hwcap.Get(HWCAP_VFPv3 | HWCAP_VFPv3D16));
127 
128   if (!IsNdkTranslation()) {
129     GTEST_LOG_(INFO) << "skipping test, not under ndk_translation.\n";
130     return;
131   }
132 
133   EXPECT_TRUE(hwcap.Get(HWCAP_SWP));
134   EXPECT_TRUE(hwcap.Get(HWCAP_HALF));
135   EXPECT_TRUE(hwcap.Get(HWCAP_FAST_MULT));
136   EXPECT_TRUE(hwcap.Get(HWCAP_VFP));
137   EXPECT_TRUE(hwcap.Get(HWCAP_EDSP));
138   EXPECT_TRUE(hwcap.Get(HWCAP_NEON));
139   EXPECT_TRUE(hwcap.Get(HWCAP_VFPv3));
140   EXPECT_TRUE(hwcap.Get(HWCAP_VFPv4));
141   EXPECT_TRUE(hwcap.Get(HWCAP_IDIVA));
142   EXPECT_TRUE(hwcap.Get(HWCAP_IDIVT));
143   EXPECT_TRUE(hwcap.Get(HWCAP_IDIV));
144 
145   EXPECT_FALSE(hwcap.Get(HWCAP_26BIT));
146   EXPECT_FALSE(hwcap.Get(HWCAP_FPA));
147   EXPECT_FALSE(hwcap.Get(HWCAP_JAVA));
148   EXPECT_FALSE(hwcap.Get(HWCAP_IWMMXT));
149   EXPECT_FALSE(hwcap.Get(HWCAP_CRUNCH));
150   EXPECT_FALSE(hwcap.Get(HWCAP_THUMBEE));
151   EXPECT_FALSE(hwcap.Get(HWCAP_VFPv3D16));
152   EXPECT_FALSE(hwcap.Get(HWCAP_TLS));
153   EXPECT_FALSE(hwcap.Get(HWCAP_VFPD32));
154   EXPECT_FALSE(hwcap.Get(HWCAP_LPAE));
155   EXPECT_FALSE(hwcap.Get(HWCAP_EVTSTRM));
156 }
157 
TEST(CpuFeatures,getauxval_AT_HWCAP2)158 TEST(CpuFeatures, getauxval_AT_HWCAP2) {
159   BitFeatures hwcap2(getauxval(AT_HWCAP2));
160 
161   if (!IsNdkTranslation()) {
162     GTEST_LOG_(INFO) << "skipping test, not under ndk_translation.\n";
163     return;
164   }
165 
166   EXPECT_FALSE(hwcap2.Get(HWCAP2_AES));
167   EXPECT_FALSE(hwcap2.Get(HWCAP2_PMULL));
168   EXPECT_FALSE(hwcap2.Get(HWCAP2_SHA1));
169   EXPECT_FALSE(hwcap2.Get(HWCAP2_SHA2));
170   EXPECT_FALSE(hwcap2.Get(HWCAP2_CRC32));
171 }
172 
TEST(CpuFeatures,android_getCpuFeatures)173 TEST(CpuFeatures, android_getCpuFeatures) {
174   AndroidCpuFamily cpu_family = android_getCpuFamily();
175   ASSERT_EQ(cpu_family, ANDROID_CPU_FAMILY_ARM);
176 
177   BitFeatures android_cpu_features(android_getCpuFeatures());
178 
179   EXPECT_TRUE(android_cpu_features.Get(ANDROID_CPU_ARM_FEATURE_ARMv7));
180 
181   // VFPv3 here means at least 16 FP registers.
182   EXPECT_TRUE(android_cpu_features.Get(ANDROID_CPU_ARM_FEATURE_VFPv3));
183 
184   if (!IsNdkTranslation()) {
185     GTEST_LOG_(INFO) << "skipping test, not under ndk_translation.\n";
186     return;
187   }
188 
189   EXPECT_TRUE(android_cpu_features.Get(ANDROID_CPU_ARM_FEATURE_NEON));
190 
191   EXPECT_TRUE(android_cpu_features.Get(ANDROID_CPU_ARM_FEATURE_VFPv2));
192   EXPECT_TRUE(android_cpu_features.Get(ANDROID_CPU_ARM_FEATURE_VFP_D32));
193   EXPECT_TRUE(android_cpu_features.Get(ANDROID_CPU_ARM_FEATURE_VFP_FP16));
194   EXPECT_TRUE(android_cpu_features.Get(ANDROID_CPU_ARM_FEATURE_VFP_FMA));
195 
196   // TODO(b/118179742): We claim it but don't actually implement.
197   EXPECT_TRUE(android_cpu_features.Get(ANDROID_CPU_ARM_FEATURE_NEON_FMA));
198 
199   EXPECT_TRUE(android_cpu_features.Get(ANDROID_CPU_ARM_FEATURE_IDIV_ARM));
200   EXPECT_TRUE(android_cpu_features.Get(ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2));
201 
202   EXPECT_FALSE(android_cpu_features.Get(ANDROID_CPU_ARM_FEATURE_iWMMXt));
203   EXPECT_FALSE(android_cpu_features.Get(ANDROID_CPU_ARM_FEATURE_AES));
204   EXPECT_FALSE(android_cpu_features.Get(ANDROID_CPU_ARM_FEATURE_PMULL));
205   EXPECT_FALSE(android_cpu_features.Get(ANDROID_CPU_ARM_FEATURE_SHA1));
206   EXPECT_FALSE(android_cpu_features.Get(ANDROID_CPU_ARM_FEATURE_SHA2));
207   EXPECT_FALSE(android_cpu_features.Get(ANDROID_CPU_ARM_FEATURE_CRC32));
208 
209   ProcCpuinfoFeatures cpuinfo;
210   if (!cpuinfo.IsNdkTranslation()) {
211     GTEST_LOG_(INFO) << "skipping test, ndk_translation /proc/cpuinfo is not mounted.\n";
212     return;
213   }
214 
215   // android_getCpuFeatures enables ANDROID_CPU_ARM_FEATURE_LDREX_STREX by 'CPU architecture' field
216   // from /proc/cpuinfo, so the check fails when we don't have it mounted.
217   EXPECT_TRUE(android_cpu_features.Get(ANDROID_CPU_ARM_FEATURE_LDREX_STREX));
218 }
219 
220 }  // namespace
221