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