Ian Rogers | 8afeb85 | 2014-04-02 14:55:49 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2011 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.h" |
| 18 | |
Ian Rogers | ad69bcd | 2014-10-16 23:05:10 -0700 | [diff] [blame] | 19 | #include <signal.h> |
Ian Rogers | 6f3dbba | 2014-10-14 17:41:57 -0700 | [diff] [blame] | 20 | #include <fstream> |
| 21 | |
| 22 | #include "base/casts.h" |
| 23 | #include "base/stringprintf.h" |
| 24 | #include "utils.h" |
| 25 | |
Ian Rogers | 8afeb85 | 2014-04-02 14:55:49 -0700 | [diff] [blame] | 26 | namespace art { |
| 27 | |
Narayan Kamath | 11d9f06 | 2014-04-23 20:24:57 +0100 | [diff] [blame] | 28 | const char* GetInstructionSetString(const InstructionSet isa) { |
| 29 | switch (isa) { |
| 30 | case kArm: |
| 31 | case kThumb2: |
| 32 | return "arm"; |
| 33 | case kArm64: |
| 34 | return "arm64"; |
| 35 | case kX86: |
| 36 | return "x86"; |
| 37 | case kX86_64: |
| 38 | return "x86_64"; |
| 39 | case kMips: |
| 40 | return "mips"; |
| 41 | case kNone: |
| 42 | return "none"; |
| 43 | default: |
| 44 | LOG(FATAL) << "Unknown ISA " << isa; |
Ian Rogers | 6f3dbba | 2014-10-14 17:41:57 -0700 | [diff] [blame] | 45 | UNREACHABLE(); |
Narayan Kamath | 11d9f06 | 2014-04-23 20:24:57 +0100 | [diff] [blame] | 46 | } |
| 47 | } |
| 48 | |
| 49 | InstructionSet GetInstructionSetFromString(const char* isa_str) { |
| 50 | CHECK(isa_str != nullptr); |
| 51 | |
Andreas Gampe | 20c8930 | 2014-08-19 17:28:06 -0700 | [diff] [blame] | 52 | if (strcmp("arm", isa_str) == 0) { |
Narayan Kamath | 11d9f06 | 2014-04-23 20:24:57 +0100 | [diff] [blame] | 53 | return kArm; |
Andreas Gampe | 20c8930 | 2014-08-19 17:28:06 -0700 | [diff] [blame] | 54 | } else if (strcmp("arm64", isa_str) == 0) { |
Narayan Kamath | 11d9f06 | 2014-04-23 20:24:57 +0100 | [diff] [blame] | 55 | return kArm64; |
Andreas Gampe | 20c8930 | 2014-08-19 17:28:06 -0700 | [diff] [blame] | 56 | } else if (strcmp("x86", isa_str) == 0) { |
Narayan Kamath | 11d9f06 | 2014-04-23 20:24:57 +0100 | [diff] [blame] | 57 | return kX86; |
Andreas Gampe | 20c8930 | 2014-08-19 17:28:06 -0700 | [diff] [blame] | 58 | } else if (strcmp("x86_64", isa_str) == 0) { |
Narayan Kamath | 11d9f06 | 2014-04-23 20:24:57 +0100 | [diff] [blame] | 59 | return kX86_64; |
Andreas Gampe | 20c8930 | 2014-08-19 17:28:06 -0700 | [diff] [blame] | 60 | } else if (strcmp("mips", isa_str) == 0) { |
Narayan Kamath | 11d9f06 | 2014-04-23 20:24:57 +0100 | [diff] [blame] | 61 | return kMips; |
Narayan Kamath | 11d9f06 | 2014-04-23 20:24:57 +0100 | [diff] [blame] | 62 | } |
| 63 | |
Narayan Kamath | 11d9f06 | 2014-04-23 20:24:57 +0100 | [diff] [blame] | 64 | return kNone; |
| 65 | } |
| 66 | |
Andreas Gampe | af13ad9 | 2014-04-11 12:07:48 -0700 | [diff] [blame] | 67 | size_t GetInstructionSetAlignment(InstructionSet isa) { |
| 68 | switch (isa) { |
| 69 | case kArm: |
| 70 | // Fall-through. |
| 71 | case kThumb2: |
| 72 | return kArmAlignment; |
| 73 | case kArm64: |
| 74 | return kArm64Alignment; |
| 75 | case kX86: |
| 76 | // Fall-through. |
| 77 | case kX86_64: |
| 78 | return kX86Alignment; |
| 79 | case kMips: |
| 80 | return kMipsAlignment; |
| 81 | case kNone: |
| 82 | LOG(FATAL) << "ISA kNone does not have alignment."; |
| 83 | return 0; |
| 84 | default: |
| 85 | LOG(FATAL) << "Unknown ISA " << isa; |
| 86 | return 0; |
| 87 | } |
| 88 | } |
| 89 | |
Andreas Gampe | 7ea6f79 | 2014-07-14 16:21:44 -0700 | [diff] [blame] | 90 | |
| 91 | static constexpr size_t kDefaultStackOverflowReservedBytes = 16 * KB; |
| 92 | static constexpr size_t kMipsStackOverflowReservedBytes = kDefaultStackOverflowReservedBytes; |
| 93 | |
Dave Allison | 648d711 | 2014-07-25 16:15:27 -0700 | [diff] [blame] | 94 | static constexpr size_t kArmStackOverflowReservedBytes = 8 * KB; |
| 95 | static constexpr size_t kArm64StackOverflowReservedBytes = 8 * KB; |
| 96 | static constexpr size_t kX86StackOverflowReservedBytes = 8 * KB; |
| 97 | static constexpr size_t kX86_64StackOverflowReservedBytes = 8 * KB; |
Andreas Gampe | 7ea6f79 | 2014-07-14 16:21:44 -0700 | [diff] [blame] | 98 | |
| 99 | size_t GetStackOverflowReservedBytes(InstructionSet isa) { |
| 100 | switch (isa) { |
| 101 | case kArm: // Intentional fall-through. |
| 102 | case kThumb2: |
| 103 | return kArmStackOverflowReservedBytes; |
| 104 | |
| 105 | case kArm64: |
| 106 | return kArm64StackOverflowReservedBytes; |
| 107 | |
| 108 | case kMips: |
| 109 | return kMipsStackOverflowReservedBytes; |
| 110 | |
| 111 | case kX86: |
| 112 | return kX86StackOverflowReservedBytes; |
| 113 | |
| 114 | case kX86_64: |
| 115 | return kX86_64StackOverflowReservedBytes; |
| 116 | |
| 117 | case kNone: |
| 118 | LOG(FATAL) << "kNone has no stack overflow size"; |
| 119 | return 0; |
| 120 | |
| 121 | default: |
| 122 | LOG(FATAL) << "Unknown instruction set" << isa; |
| 123 | return 0; |
| 124 | } |
| 125 | } |
| 126 | |
Ian Rogers | 6f3dbba | 2014-10-14 17:41:57 -0700 | [diff] [blame] | 127 | const InstructionSetFeatures* InstructionSetFeatures::FromVariant(InstructionSet isa, |
| 128 | const std::string& variant, |
| 129 | std::string* error_msg) { |
| 130 | const InstructionSetFeatures* result; |
| 131 | switch (isa) { |
| 132 | case kArm: |
| 133 | case kThumb2: |
| 134 | result = ArmInstructionSetFeatures::FromVariant(variant, error_msg); |
| 135 | break; |
| 136 | default: |
| 137 | result = UnknownInstructionSetFeatures::Unknown(isa); |
| 138 | break; |
Ian Rogers | 8afeb85 | 2014-04-02 14:55:49 -0700 | [diff] [blame] | 139 | } |
Ian Rogers | 6f3dbba | 2014-10-14 17:41:57 -0700 | [diff] [blame] | 140 | CHECK_EQ(result == nullptr, error_msg->size() != 0); |
| 141 | return result; |
| 142 | } |
| 143 | |
| 144 | const InstructionSetFeatures* InstructionSetFeatures::FromFeatureString(InstructionSet isa, |
| 145 | const std::string& feature_list, |
| 146 | std::string* error_msg) { |
| 147 | const InstructionSetFeatures* result; |
| 148 | switch (isa) { |
| 149 | case kArm: |
| 150 | case kThumb2: |
| 151 | result = ArmInstructionSetFeatures::FromFeatureString(feature_list, error_msg); |
| 152 | break; |
| 153 | default: |
| 154 | result = UnknownInstructionSetFeatures::Unknown(isa); |
| 155 | break; |
| 156 | } |
| 157 | // TODO: warn if feature_list doesn't agree with result's GetFeatureList(). |
| 158 | CHECK_EQ(result == nullptr, error_msg->size() != 0); |
| 159 | return result; |
| 160 | } |
| 161 | |
| 162 | const InstructionSetFeatures* InstructionSetFeatures::FromBitmap(InstructionSet isa, |
| 163 | uint32_t bitmap) { |
| 164 | const InstructionSetFeatures* result; |
| 165 | switch (isa) { |
| 166 | case kArm: |
| 167 | case kThumb2: |
| 168 | result = ArmInstructionSetFeatures::FromBitmap(bitmap); |
| 169 | break; |
| 170 | default: |
| 171 | result = UnknownInstructionSetFeatures::Unknown(isa); |
| 172 | break; |
| 173 | } |
| 174 | CHECK_EQ(bitmap, result->AsBitmap()); |
| 175 | return result; |
| 176 | } |
| 177 | |
| 178 | const InstructionSetFeatures* InstructionSetFeatures::FromCppDefines() { |
| 179 | const InstructionSetFeatures* result; |
| 180 | switch (kRuntimeISA) { |
| 181 | case kArm: |
| 182 | case kThumb2: |
| 183 | result = ArmInstructionSetFeatures::FromCppDefines(); |
| 184 | break; |
| 185 | default: |
| 186 | result = UnknownInstructionSetFeatures::Unknown(kRuntimeISA); |
| 187 | break; |
Ian Rogers | 8afeb85 | 2014-04-02 14:55:49 -0700 | [diff] [blame] | 188 | } |
| 189 | return result; |
| 190 | } |
| 191 | |
Ian Rogers | 6f3dbba | 2014-10-14 17:41:57 -0700 | [diff] [blame] | 192 | |
| 193 | const InstructionSetFeatures* InstructionSetFeatures::FromCpuInfo() { |
| 194 | const InstructionSetFeatures* result; |
| 195 | switch (kRuntimeISA) { |
| 196 | case kArm: |
| 197 | case kThumb2: |
| 198 | result = ArmInstructionSetFeatures::FromCpuInfo(); |
| 199 | break; |
| 200 | default: |
| 201 | result = UnknownInstructionSetFeatures::Unknown(kRuntimeISA); |
| 202 | break; |
| 203 | } |
| 204 | return result; |
| 205 | } |
| 206 | |
| 207 | const InstructionSetFeatures* InstructionSetFeatures::FromHwcap() { |
| 208 | const InstructionSetFeatures* result; |
| 209 | switch (kRuntimeISA) { |
| 210 | case kArm: |
| 211 | case kThumb2: |
| 212 | result = ArmInstructionSetFeatures::FromHwcap(); |
| 213 | break; |
| 214 | default: |
| 215 | result = UnknownInstructionSetFeatures::Unknown(kRuntimeISA); |
| 216 | break; |
| 217 | } |
| 218 | return result; |
| 219 | } |
| 220 | |
| 221 | const InstructionSetFeatures* InstructionSetFeatures::FromAssembly() { |
| 222 | const InstructionSetFeatures* result; |
| 223 | switch (kRuntimeISA) { |
| 224 | case kArm: |
| 225 | case kThumb2: |
| 226 | result = ArmInstructionSetFeatures::FromAssembly(); |
| 227 | break; |
| 228 | default: |
| 229 | result = UnknownInstructionSetFeatures::Unknown(kRuntimeISA); |
| 230 | break; |
| 231 | } |
| 232 | return result; |
| 233 | } |
| 234 | |
| 235 | const ArmInstructionSetFeatures* InstructionSetFeatures::AsArmInstructionSetFeatures() const { |
| 236 | DCHECK_EQ(kArm, GetInstructionSet()); |
| 237 | return down_cast<const ArmInstructionSetFeatures*>(this); |
| 238 | } |
| 239 | |
| 240 | std::ostream& operator<<(std::ostream& os, const InstructionSetFeatures& rhs) { |
| 241 | os << "ISA: " << rhs.GetInstructionSet() << " Feature string: " << rhs.GetFeatureString(); |
| 242 | return os; |
| 243 | } |
| 244 | |
| 245 | const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromFeatureString( |
| 246 | const std::string& feature_list, std::string* error_msg) { |
| 247 | std::vector<std::string> features; |
| 248 | Split(feature_list, ',', &features); |
| 249 | bool has_lpae = false; |
| 250 | bool has_div = false; |
| 251 | for (auto i = features.begin(); i != features.end(); i++) { |
| 252 | std::string feature = Trim(*i); |
| 253 | if (feature == "default" || feature == "none") { |
| 254 | // Nothing to do. |
| 255 | } else if (feature == "div") { |
| 256 | has_div = true; |
| 257 | } else if (feature == "nodiv") { |
| 258 | has_div = false; |
| 259 | } else if (feature == "lpae") { |
| 260 | has_lpae = true; |
| 261 | } else if (feature == "nolpae") { |
| 262 | has_lpae = false; |
| 263 | } else { |
| 264 | *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str()); |
| 265 | return nullptr; |
| 266 | } |
| 267 | } |
| 268 | return new ArmInstructionSetFeatures(has_lpae, has_div); |
| 269 | } |
| 270 | |
| 271 | const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromVariant( |
| 272 | const std::string& variant, std::string* error_msg) { |
| 273 | // Look for variants that have divide support. |
| 274 | bool has_div = false; |
| 275 | { |
| 276 | static const char* arm_variants_with_div[] = { |
| 277 | "cortex-a7", "cortex-a12", "cortex-a15", "cortex-a17", "cortex-a53", "cortex-a57", |
| 278 | "cortex-m3", "cortex-m4", "cortex-r4", "cortex-r5", |
| 279 | "cyclone", "denver", "krait", "swift" |
| 280 | }; |
| 281 | for (const char* div_variant : arm_variants_with_div) { |
| 282 | if (variant == div_variant) { |
| 283 | has_div = true; |
| 284 | break; |
| 285 | } |
| 286 | } |
| 287 | } |
| 288 | // Look for variants that have LPAE support. |
| 289 | bool has_lpae = false; |
| 290 | { |
| 291 | static const char* arm_variants_with_lpae[] = { |
| 292 | "cortex-a7", "cortex-a15", "krait", "denver" |
| 293 | }; |
| 294 | for (const char* lpae_variant : arm_variants_with_lpae) { |
| 295 | if (variant == lpae_variant) { |
| 296 | has_lpae = true; |
| 297 | break; |
| 298 | } |
| 299 | } |
| 300 | } |
| 301 | if (has_div == false && has_lpae == false) { |
| 302 | // Avoid unsupported variants. |
| 303 | static const char* unsupported_arm_variants[] = { |
| 304 | // ARM processors that aren't ARMv7 compatible aren't supported. |
| 305 | "arm2", "arm250", "arm3", "arm6", "arm60", "arm600", "arm610", "arm620", |
| 306 | "cortex-m0", "cortex-m0plus", "cortex-m1", |
| 307 | "fa526", "fa626", "fa606te", "fa626te", "fmp626", "fa726te", |
| 308 | "iwmmxt", "iwmmxt2", |
| 309 | "strongarm", "strongarm110", "strongarm1100", "strongarm1110", |
| 310 | "xscale" |
| 311 | }; |
| 312 | for (const char* us_variant : unsupported_arm_variants) { |
| 313 | if (variant == us_variant) { |
| 314 | *error_msg = StringPrintf("Attempt to use unsupported ARM variant: %s", us_variant); |
| 315 | return nullptr; |
| 316 | } |
| 317 | } |
| 318 | // Warn if the variant is unknown. |
| 319 | // TODO: some of the variants below may have feature support, but that support is currently |
| 320 | // unknown so we'll choose conservative (sub-optimal) defaults without warning. |
| 321 | // TODO: some of the architectures may not support all features required by ART and should be |
| 322 | // moved to unsupported_arm_variants[] above. |
| 323 | static const char* arm_variants_without_known_features[] = { |
| 324 | "arm7", "arm7m", "arm7d", "arm7dm", "arm7di", "arm7dmi", "arm70", "arm700", "arm700i", |
| 325 | "arm710", "arm710c", "arm7100", "arm720", "arm7500", "arm7500fe", "arm7tdmi", "arm7tdmi-s", |
| 326 | "arm710t", "arm720t", "arm740t", |
| 327 | "arm8", "arm810", |
| 328 | "arm9", "arm9e", "arm920", "arm920t", "arm922t", "arm946e-s", "arm966e-s", "arm968e-s", |
| 329 | "arm926ej-s", "arm940t", "arm9tdmi", |
| 330 | "arm10tdmi", "arm1020t", "arm1026ej-s", "arm10e", "arm1020e", "arm1022e", |
| 331 | "arm1136j-s", "arm1136jf-s", |
| 332 | "arm1156t2-s", "arm1156t2f-s", "arm1176jz-s", "arm1176jzf-s", |
| 333 | "cortex-a5", "cortex-a8", "cortex-a9", "cortex-a9-mp", "cortex-r4f", |
| 334 | "marvell-pj4", "mpcore", "mpcorenovfp" |
| 335 | }; |
| 336 | bool found = false; |
| 337 | for (const char* ff_variant : arm_variants_without_known_features) { |
| 338 | if (variant == ff_variant) { |
| 339 | found = true; |
| 340 | break; |
| 341 | } |
| 342 | } |
| 343 | if (!found) { |
| 344 | LOG(WARNING) << "Unknown instruction set features for ARM CPU variant (" << variant |
| 345 | << ") using conservative defaults"; |
| 346 | } |
| 347 | } |
| 348 | return new ArmInstructionSetFeatures(has_lpae, has_div); |
| 349 | } |
| 350 | |
| 351 | const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromBitmap(uint32_t bitmap) { |
| 352 | bool has_lpae = (bitmap & kLpaeBitfield) != 0; |
| 353 | bool has_div = (bitmap & kDivBitfield) != 0; |
| 354 | return new ArmInstructionSetFeatures(has_lpae, has_div); |
| 355 | } |
| 356 | |
| 357 | const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromCppDefines() { |
| 358 | #if defined(__ARM_ARCH_EXT_IDIV__) |
| 359 | bool has_div = true; |
| 360 | #else |
| 361 | bool has_div = false; |
| 362 | #endif |
| 363 | #if defined(__ARM_FEATURE_LPAE) |
| 364 | bool has_lpae = true; |
| 365 | #else |
| 366 | bool has_lpae = false; |
| 367 | #endif |
| 368 | return new ArmInstructionSetFeatures(has_lpae, has_div); |
| 369 | } |
| 370 | |
| 371 | const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromCpuInfo() { |
| 372 | // Look in /proc/cpuinfo for features we need. Only use this when we can guarantee that |
| 373 | // the kernel puts the appropriate feature flags in here. Sometimes it doesn't. |
| 374 | bool has_lpae = false; |
| 375 | bool has_div = false; |
| 376 | |
| 377 | std::ifstream in("/proc/cpuinfo"); |
| 378 | if (!in.fail()) { |
| 379 | while (!in.eof()) { |
| 380 | std::string line; |
| 381 | std::getline(in, line); |
| 382 | if (!in.eof()) { |
| 383 | LOG(INFO) << "cpuinfo line: " << line; |
| 384 | if (line.find("Features") != std::string::npos) { |
| 385 | LOG(INFO) << "found features"; |
| 386 | if (line.find("idivt") != std::string::npos) { |
| 387 | // We always expect both ARM and Thumb divide instructions to be available or not |
| 388 | // available. |
| 389 | CHECK_NE(line.find("idiva"), std::string::npos); |
| 390 | has_div = true; |
| 391 | } |
| 392 | if (line.find("lpae") != std::string::npos) { |
| 393 | has_lpae = true; |
| 394 | } |
| 395 | } |
| 396 | } |
| 397 | } |
| 398 | in.close(); |
| 399 | } else { |
| 400 | LOG(INFO) << "Failed to open /proc/cpuinfo"; |
| 401 | } |
| 402 | return new ArmInstructionSetFeatures(has_lpae, has_div); |
| 403 | } |
| 404 | |
| 405 | #if defined(HAVE_ANDROID_OS) && defined(__arm__) |
| 406 | #include <sys/auxv.h> |
| 407 | #include <asm/hwcap.h> |
| 408 | #endif |
| 409 | |
| 410 | const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromHwcap() { |
| 411 | bool has_lpae = false; |
| 412 | bool has_div = false; |
| 413 | |
| 414 | #if defined(HAVE_ANDROID_OS) && defined(__arm__) |
| 415 | uint64_t hwcaps = getauxval(AT_HWCAP); |
| 416 | LOG(INFO) << "hwcaps=" << hwcaps; |
| 417 | if ((hwcaps & HWCAP_IDIVT) != 0) { |
| 418 | // We always expect both ARM and Thumb divide instructions to be available or not |
| 419 | // available. |
| 420 | CHECK_NE(hwcaps & HWCAP_IDIVA, 0U); |
| 421 | has_div = true; |
| 422 | } |
| 423 | if ((hwcaps & HWCAP_LPAE) != 0) { |
| 424 | has_lpae = true; |
| 425 | } |
| 426 | #endif |
| 427 | |
| 428 | return new ArmInstructionSetFeatures(has_lpae, has_div); |
| 429 | } |
| 430 | |
| 431 | // A signal handler called by a fault for an illegal instruction. We record the fact in r0 |
| 432 | // and then increment the PC in the signal context to return to the next instruction. We know the |
| 433 | // instruction is an sdiv (4 bytes long). |
Ian Rogers | 6a3c1fc | 2014-10-31 00:33:20 -0700 | [diff] [blame] | 434 | static void bad_divide_inst_handle(int signo ATTRIBUTE_UNUSED, siginfo_t* si ATTRIBUTE_UNUSED, |
| 435 | void* data) { |
Ian Rogers | 6f3dbba | 2014-10-14 17:41:57 -0700 | [diff] [blame] | 436 | #if defined(__arm__) |
| 437 | struct ucontext *uc = (struct ucontext *)data; |
| 438 | struct sigcontext *sc = &uc->uc_mcontext; |
| 439 | sc->arm_r0 = 0; // Set R0 to #0 to signal error. |
| 440 | sc->arm_pc += 4; // Skip offending instruction. |
| 441 | #else |
| 442 | UNUSED(data); |
| 443 | #endif |
| 444 | } |
| 445 | |
| 446 | #if defined(__arm__) |
| 447 | extern "C" bool artCheckForARMSDIVInstruction(); |
| 448 | #endif |
| 449 | |
| 450 | const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromAssembly() { |
| 451 | // See if have a sdiv instruction. Register a signal handler and try to execute an sdiv |
| 452 | // instruction. If we get a SIGILL then it's not supported. |
| 453 | struct sigaction sa, osa; |
| 454 | sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO; |
| 455 | sa.sa_sigaction = bad_divide_inst_handle; |
| 456 | sigaction(SIGILL, &sa, &osa); |
| 457 | |
| 458 | bool has_div = false; |
| 459 | #if defined(__arm__) |
| 460 | if (artCheckForARMSDIVInstruction()) { |
| 461 | has_div = true; |
| 462 | } |
| 463 | #endif |
| 464 | |
| 465 | // Restore the signal handler. |
| 466 | sigaction(SIGILL, &osa, nullptr); |
| 467 | |
| 468 | // Use compile time features to "detect" LPAE support. |
| 469 | // TODO: write an assembly LPAE support test. |
| 470 | #if defined(__ARM_FEATURE_LPAE) |
| 471 | bool has_lpae = true; |
| 472 | #else |
| 473 | bool has_lpae = false; |
| 474 | #endif |
| 475 | return new ArmInstructionSetFeatures(has_lpae, has_div); |
| 476 | } |
| 477 | |
| 478 | |
| 479 | bool ArmInstructionSetFeatures::Equals(const InstructionSetFeatures* other) const { |
| 480 | if (kArm != other->GetInstructionSet()) { |
| 481 | return false; |
| 482 | } |
| 483 | const ArmInstructionSetFeatures* other_as_arm = other->AsArmInstructionSetFeatures(); |
| 484 | return has_lpae_ == other_as_arm->has_lpae_ && has_div_ == other_as_arm->has_div_; |
| 485 | } |
| 486 | |
| 487 | uint32_t ArmInstructionSetFeatures::AsBitmap() const { |
| 488 | return (has_lpae_ ? kLpaeBitfield : 0) | (has_div_ ? kDivBitfield : 0); |
| 489 | } |
| 490 | |
| 491 | std::string ArmInstructionSetFeatures::GetFeatureString() const { |
| 492 | std::string result; |
| 493 | if (has_div_) { |
| 494 | result += ",div"; |
| 495 | } |
| 496 | if (has_lpae_) { |
| 497 | result += ",lpae"; |
| 498 | } |
| 499 | if (result.size() == 0) { |
| 500 | return "none"; |
| 501 | } else { |
| 502 | // Strip leading comma. |
| 503 | return result.substr(1, result.size()); |
| 504 | } |
| 505 | } |
| 506 | |
Ian Rogers | 8afeb85 | 2014-04-02 14:55:49 -0700 | [diff] [blame] | 507 | } // namespace art |