blob: 249696883a8a6de3ebf27d0b9783ed3ad56d8b3c [file] [log] [blame]
Ian Rogersd582fa42014-11-05 23:46:43 -08001/*
2 * Copyright (C) 2014 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 "instruction_set_features_arm.h"
18
Bilyan Borisovbb661c02016-04-04 16:27:32 +010019#if defined(ART_TARGET_ANDROID) && defined(__arm__)
Ian Rogersd582fa42014-11-05 23:46:43 -080020#include <asm/hwcap.h>
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070021#include <sys/auxv.h>
Ian Rogersd582fa42014-11-05 23:46:43 -080022#endif
23
24#include "signal.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070025
Ian Rogersd582fa42014-11-05 23:46:43 -080026#include <fstream>
27
Andreas Gampe46ee31b2016-12-14 10:11:49 -080028#include "android-base/stringprintf.h"
Andreas Gampe9186ced2016-12-12 14:28:21 -080029#include "android-base/strings.h"
30
Andreas Gampe46ee31b2016-12-14 10:11:49 -080031#include "base/logging.h"
Ian Rogersd582fa42014-11-05 23:46:43 -080032
33#if defined(__arm__)
34extern "C" bool artCheckForArmSdivInstruction();
Serban Constantinescud747c132016-10-26 09:30:21 +010035extern "C" bool artCheckForArmv8AInstructions();
Ian Rogersd582fa42014-11-05 23:46:43 -080036#endif
37
38namespace art {
39
Andreas Gampe46ee31b2016-12-14 10:11:49 -080040using android::base::StringPrintf;
41
Andreas Gampe0415b4e2015-01-06 15:17:07 -080042ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromVariant(
Ian Rogersd582fa42014-11-05 23:46:43 -080043 const std::string& variant, std::string* error_msg) {
Serban Constantinescud747c132016-10-26 09:30:21 +010044 static const char* arm_variants_with_armv8a[] = {
45 "cortex-a32",
46 "cortex-a35",
47 "cortex-a53",
48 "cortex-a53.a57",
49 "cortex-a53.a72",
50 "cortex-a57",
51 "cortex-a72",
52 "cortex-a73",
53 "exynos-m1",
54 "denver",
55 "kryo"
56 };
57 bool has_armv8a = FindVariantInArray(arm_variants_with_armv8a,
58 arraysize(arm_variants_with_armv8a),
59 variant);
60
Ian Rogersd582fa42014-11-05 23:46:43 -080061 // Look for variants that have divide support.
62 static const char* arm_variants_with_div[] = {
Serban Constantinescub8472ee2016-10-26 11:15:00 +010063 "cortex-a7",
64 "cortex-a12",
65 "cortex-a15",
66 "cortex-a17",
Serban Constantinescub8472ee2016-10-26 11:15:00 +010067 "krait",
68 };
Serban Constantinescud747c132016-10-26 09:30:21 +010069 bool has_div = has_armv8a || FindVariantInArray(arm_variants_with_div,
70 arraysize(arm_variants_with_div),
71 variant);
Ian Rogersd582fa42014-11-05 23:46:43 -080072
73 // Look for variants that have LPAE support.
74 static const char* arm_variants_with_lpae[] = {
Serban Constantinescub8472ee2016-10-26 11:15:00 +010075 "cortex-a7",
76 "cortex-a12",
77 "cortex-a15",
78 "cortex-a17",
Serban Constantinescub8472ee2016-10-26 11:15:00 +010079 "krait",
Ian Rogersd582fa42014-11-05 23:46:43 -080080 };
Serban Constantinescud747c132016-10-26 09:30:21 +010081 bool has_atomic_ldrd_strd = has_armv8a || FindVariantInArray(arm_variants_with_lpae,
82 arraysize(arm_variants_with_lpae),
83 variant);
Ian Rogersd582fa42014-11-05 23:46:43 -080084
Serban Constantinescud747c132016-10-26 09:30:21 +010085 if (has_armv8a == false && has_div == false && has_atomic_ldrd_strd == false) {
Serban Constantinescub8472ee2016-10-26 11:15:00 +010086 static const char* arm_variants_with_default_features[] = {
87 "cortex-a5",
88 "cortex-a8",
89 "cortex-a9",
90 "cortex-a9-mp",
Ian Rogersd582fa42014-11-05 23:46:43 -080091 "default",
Serban Constantinescub8472ee2016-10-26 11:15:00 +010092 "generic"
Ian Rogersd582fa42014-11-05 23:46:43 -080093 };
Serban Constantinescub8472ee2016-10-26 11:15:00 +010094 if (!FindVariantInArray(arm_variants_with_default_features,
95 arraysize(arm_variants_with_default_features),
Ian Rogersd582fa42014-11-05 23:46:43 -080096 variant)) {
Serban Constantinescub8472ee2016-10-26 11:15:00 +010097 *error_msg = StringPrintf("Attempt to use unsupported ARM variant: %s", variant.c_str());
98 return nullptr;
99 } else {
100 // Warn if we use the default features.
101 LOG(WARNING) << "Using default instruction set features for ARM CPU variant (" << variant
Ian Rogersd582fa42014-11-05 23:46:43 -0800102 << ") using conservative defaults";
103 }
104 }
Serban Constantinescud747c132016-10-26 09:30:21 +0100105 return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(has_div,
106 has_atomic_ldrd_strd,
107 has_armv8a));
Ian Rogersd582fa42014-11-05 23:46:43 -0800108}
109
Andreas Gampe0415b4e2015-01-06 15:17:07 -0800110ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromBitmap(uint32_t bitmap) {
Ian Rogersd582fa42014-11-05 23:46:43 -0800111 bool has_div = (bitmap & kDivBitfield) != 0;
112 bool has_atomic_ldrd_strd = (bitmap & kAtomicLdrdStrdBitfield) != 0;
Serban Constantinescud747c132016-10-26 09:30:21 +0100113 bool has_armv8a = (bitmap & kARMv8A) != 0;
114 return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(has_div,
115 has_atomic_ldrd_strd,
116 has_armv8a));
Ian Rogersd582fa42014-11-05 23:46:43 -0800117}
118
Andreas Gampe0415b4e2015-01-06 15:17:07 -0800119ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromCppDefines() {
Serban Constantinescud747c132016-10-26 09:30:21 +0100120// Note: This will not work for now since we still build the 32-bit as __ARCH_ARM_7A__.
121#if defined(__ARM_ARCH_8A__)
122 const bool has_armv8a = true;
123#else
124 const bool has_armv8a = false;
125#endif
126#if defined (__ARM_ARCH_8A__) || defined(__ARM_ARCH_EXT_IDIV__)
Ian Rogersd582fa42014-11-05 23:46:43 -0800127 const bool has_div = true;
128#else
129 const bool has_div = false;
130#endif
Serban Constantinescud747c132016-10-26 09:30:21 +0100131#if defined (__ARM_ARCH_8A__) || defined(__ARM_FEATURE_LPAE)
132 const bool has_atomic_ldrd_strd = true;
Ian Rogersd582fa42014-11-05 23:46:43 -0800133#else
Serban Constantinescud747c132016-10-26 09:30:21 +0100134 const bool has_atomic_ldrd_strd = false;
Ian Rogersd582fa42014-11-05 23:46:43 -0800135#endif
Serban Constantinescud747c132016-10-26 09:30:21 +0100136 return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(has_div,
137 has_atomic_ldrd_strd,
138 has_armv8a));
Ian Rogersd582fa42014-11-05 23:46:43 -0800139}
140
Andreas Gampe0415b4e2015-01-06 15:17:07 -0800141ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromCpuInfo() {
Ian Rogersd582fa42014-11-05 23:46:43 -0800142 // Look in /proc/cpuinfo for features we need. Only use this when we can guarantee that
143 // the kernel puts the appropriate feature flags in here. Sometimes it doesn't.
Serban Constantinescud747c132016-10-26 09:30:21 +0100144 bool has_atomic_ldrd_strd = false;
Ian Rogersd582fa42014-11-05 23:46:43 -0800145 bool has_div = false;
Serban Constantinescud747c132016-10-26 09:30:21 +0100146 bool has_armv8a = false;
Ian Rogersd582fa42014-11-05 23:46:43 -0800147
148 std::ifstream in("/proc/cpuinfo");
149 if (!in.fail()) {
150 while (!in.eof()) {
151 std::string line;
152 std::getline(in, line);
153 if (!in.eof()) {
154 LOG(INFO) << "cpuinfo line: " << line;
155 if (line.find("Features") != std::string::npos) {
156 LOG(INFO) << "found features";
157 if (line.find("idivt") != std::string::npos) {
158 // We always expect both ARM and Thumb divide instructions to be available or not
159 // available.
160 CHECK_NE(line.find("idiva"), std::string::npos);
161 has_div = true;
162 }
163 if (line.find("lpae") != std::string::npos) {
Serban Constantinescud747c132016-10-26 09:30:21 +0100164 has_atomic_ldrd_strd = true;
Ian Rogersd582fa42014-11-05 23:46:43 -0800165 }
Ian Rogersd582fa42014-11-05 23:46:43 -0800166 }
Serban Constantinescud747c132016-10-26 09:30:21 +0100167 if (line.find("architecture") != std::string::npos
168 && line.find(": 8") != std::string::npos) {
169 LOG(INFO) << "found architecture ARMv8";
170 // Android is only run on A cores, so ARMv8 implies ARMv8-A.
171 has_armv8a = true;
172 // ARMv8 CPUs have LPAE and div support.
173 has_div = true;
174 has_atomic_ldrd_strd = true;
175 }
Ian Rogersd582fa42014-11-05 23:46:43 -0800176 }
177 }
178 in.close();
179 } else {
180 LOG(ERROR) << "Failed to open /proc/cpuinfo";
181 }
Serban Constantinescud747c132016-10-26 09:30:21 +0100182 return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(has_div,
183 has_atomic_ldrd_strd,
184 has_armv8a));
Ian Rogersd582fa42014-11-05 23:46:43 -0800185}
186
Andreas Gampe0415b4e2015-01-06 15:17:07 -0800187ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromHwcap() {
Ian Rogersd582fa42014-11-05 23:46:43 -0800188 bool has_div = false;
Serban Constantinescud747c132016-10-26 09:30:21 +0100189 bool has_atomic_ldrd_strd = false;
190 bool has_armv8a = false;
Ian Rogersd582fa42014-11-05 23:46:43 -0800191
Bilyan Borisovbb661c02016-04-04 16:27:32 +0100192#if defined(ART_TARGET_ANDROID) && defined(__arm__)
Ian Rogersd582fa42014-11-05 23:46:43 -0800193 uint64_t hwcaps = getauxval(AT_HWCAP);
194 LOG(INFO) << "hwcaps=" << hwcaps;
195 if ((hwcaps & HWCAP_IDIVT) != 0) {
196 // We always expect both ARM and Thumb divide instructions to be available or not
197 // available.
198 CHECK_NE(hwcaps & HWCAP_IDIVA, 0U);
199 has_div = true;
200 }
201 if ((hwcaps & HWCAP_LPAE) != 0) {
Serban Constantinescud747c132016-10-26 09:30:21 +0100202 has_atomic_ldrd_strd = true;
203 }
204 // TODO: Fix this once FPMISC makes it upstream.
205 // For now we detect if we run on an ARMv8 CPU by looking for CRC32 and SHA1
206 // (only available on ARMv8 CPUs).
207 if ((hwcaps & HWCAP2_CRC32) != 0 && (hwcaps & HWCAP2_SHA1) != 0) {
208 has_armv8a = true;
Ian Rogersd582fa42014-11-05 23:46:43 -0800209 }
210#endif
211
Serban Constantinescud747c132016-10-26 09:30:21 +0100212 return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(has_div,
213 has_atomic_ldrd_strd,
214 has_armv8a));
Ian Rogersd582fa42014-11-05 23:46:43 -0800215}
216
217// A signal handler called by a fault for an illegal instruction. We record the fact in r0
218// and then increment the PC in the signal context to return to the next instruction. We know the
Serban Constantinescud747c132016-10-26 09:30:21 +0100219// instruction is 4 bytes long.
220static void bad_instr_handle(int signo ATTRIBUTE_UNUSED,
221 siginfo_t* si ATTRIBUTE_UNUSED,
222 void* data) {
Ian Rogersd582fa42014-11-05 23:46:43 -0800223#if defined(__arm__)
224 struct ucontext *uc = (struct ucontext *)data;
225 struct sigcontext *sc = &uc->uc_mcontext;
226 sc->arm_r0 = 0; // Set R0 to #0 to signal error.
227 sc->arm_pc += 4; // Skip offending instruction.
228#else
229 UNUSED(data);
230#endif
231}
232
Andreas Gampe0415b4e2015-01-06 15:17:07 -0800233ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromAssembly() {
Ian Rogersd582fa42014-11-05 23:46:43 -0800234 // See if have a sdiv instruction. Register a signal handler and try to execute an sdiv
235 // instruction. If we get a SIGILL then it's not supported.
236 struct sigaction sa, osa;
237 sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO;
Serban Constantinescud747c132016-10-26 09:30:21 +0100238 sa.sa_sigaction = bad_instr_handle;
Andreas Gampeeeca2b22016-06-14 17:24:51 -0700239 sigemptyset(&sa.sa_mask);
Ian Rogersd582fa42014-11-05 23:46:43 -0800240 sigaction(SIGILL, &sa, &osa);
241
242 bool has_div = false;
Serban Constantinescud747c132016-10-26 09:30:21 +0100243 bool has_armv8a = false;
Ian Rogersd582fa42014-11-05 23:46:43 -0800244#if defined(__arm__)
245 if (artCheckForArmSdivInstruction()) {
246 has_div = true;
247 }
Serban Constantinescud747c132016-10-26 09:30:21 +0100248 if (artCheckForArmv8AInstructions()) {
249 has_armv8a = true;
250 }
Ian Rogersd582fa42014-11-05 23:46:43 -0800251#endif
252
253 // Restore the signal handler.
254 sigaction(SIGILL, &osa, nullptr);
255
256 // Use compile time features to "detect" LPAE support.
257 // TODO: write an assembly LPAE support test.
258#if defined(__ARM_FEATURE_LPAE)
Serban Constantinescud747c132016-10-26 09:30:21 +0100259 const bool has_atomic_ldrd_strd = true;
Ian Rogersd582fa42014-11-05 23:46:43 -0800260#else
Serban Constantinescud747c132016-10-26 09:30:21 +0100261 const bool has_atomic_ldrd_strd = false;
Ian Rogersd582fa42014-11-05 23:46:43 -0800262#endif
Serban Constantinescud747c132016-10-26 09:30:21 +0100263 return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(has_div,
264 has_atomic_ldrd_strd,
265 has_armv8a));
Ian Rogersd582fa42014-11-05 23:46:43 -0800266}
267
268bool ArmInstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
269 if (kArm != other->GetInstructionSet()) {
270 return false;
271 }
272 const ArmInstructionSetFeatures* other_as_arm = other->AsArmInstructionSetFeatures();
Serban Constantinescud747c132016-10-26 09:30:21 +0100273 return has_div_ == other_as_arm->has_div_
274 && has_atomic_ldrd_strd_ == other_as_arm->has_atomic_ldrd_strd_
275 && has_armv8a_ == other_as_arm->has_armv8a_;
276}
277
278bool ArmInstructionSetFeatures::HasAtLeast(const InstructionSetFeatures* other) const {
279 if (kArm != other->GetInstructionSet()) {
280 return false;
281 }
282 const ArmInstructionSetFeatures* other_as_arm = other->AsArmInstructionSetFeatures();
Aart Bik5354af92017-07-19 11:13:27 -0700283 return (has_div_ || !other_as_arm->has_div_)
284 && (has_atomic_ldrd_strd_ || !other_as_arm->has_atomic_ldrd_strd_)
285 && (has_armv8a_ || !other_as_arm->has_armv8a_);
Ian Rogersd582fa42014-11-05 23:46:43 -0800286}
287
288uint32_t ArmInstructionSetFeatures::AsBitmap() const {
Serban Constantinescud747c132016-10-26 09:30:21 +0100289 return (has_div_ ? kDivBitfield : 0)
290 | (has_atomic_ldrd_strd_ ? kAtomicLdrdStrdBitfield : 0)
291 | (has_armv8a_ ? kARMv8A : 0);
Ian Rogersd582fa42014-11-05 23:46:43 -0800292}
293
294std::string ArmInstructionSetFeatures::GetFeatureString() const {
295 std::string result;
Ian Rogersd582fa42014-11-05 23:46:43 -0800296 if (has_div_) {
Serban Constantinescub595b402016-09-23 11:06:03 +0100297 result += "div";
Ian Rogersd582fa42014-11-05 23:46:43 -0800298 } else {
Serban Constantinescub595b402016-09-23 11:06:03 +0100299 result += "-div";
Ian Rogersd582fa42014-11-05 23:46:43 -0800300 }
301 if (has_atomic_ldrd_strd_) {
302 result += ",atomic_ldrd_strd";
303 } else {
304 result += ",-atomic_ldrd_strd";
305 }
Serban Constantinescud747c132016-10-26 09:30:21 +0100306 if (has_armv8a_) {
307 result += ",armv8a";
308 } else {
309 result += ",-armv8a";
310 }
Ian Rogersd582fa42014-11-05 23:46:43 -0800311 return result;
312}
313
Andreas Gampe0415b4e2015-01-06 15:17:07 -0800314std::unique_ptr<const InstructionSetFeatures>
315ArmInstructionSetFeatures::AddFeaturesFromSplitString(
Serban Constantinescub595b402016-09-23 11:06:03 +0100316 const std::vector<std::string>& features, std::string* error_msg) const {
Ian Rogersd582fa42014-11-05 23:46:43 -0800317 bool has_atomic_ldrd_strd = has_atomic_ldrd_strd_;
318 bool has_div = has_div_;
Serban Constantinescud747c132016-10-26 09:30:21 +0100319 bool has_armv8a = has_armv8a_;
Ian Rogersd582fa42014-11-05 23:46:43 -0800320 for (auto i = features.begin(); i != features.end(); i++) {
Andreas Gampe9186ced2016-12-12 14:28:21 -0800321 std::string feature = android::base::Trim(*i);
Ian Rogersd582fa42014-11-05 23:46:43 -0800322 if (feature == "div") {
323 has_div = true;
324 } else if (feature == "-div") {
325 has_div = false;
326 } else if (feature == "atomic_ldrd_strd") {
327 has_atomic_ldrd_strd = true;
328 } else if (feature == "-atomic_ldrd_strd") {
329 has_atomic_ldrd_strd = false;
Serban Constantinescud747c132016-10-26 09:30:21 +0100330 } else if (feature == "armv8a") {
331 has_armv8a = true;
332 } else if (feature == "-armv8a") {
333 has_armv8a = false;
Ian Rogersd582fa42014-11-05 23:46:43 -0800334 } else {
335 *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
336 return nullptr;
337 }
338 }
Andreas Gampe0415b4e2015-01-06 15:17:07 -0800339 return std::unique_ptr<const InstructionSetFeatures>(
Serban Constantinescud747c132016-10-26 09:30:21 +0100340 new ArmInstructionSetFeatures(has_div, has_atomic_ldrd_strd, has_armv8a));
Ian Rogersd582fa42014-11-05 23:46:43 -0800341}
342
343} // namespace art