1d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers/* 2d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers * Copyright (C) 2014 The Android Open Source Project 3d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers * 4d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers * Licensed under the Apache License, Version 2.0 (the "License"); 5d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers * you may not use this file except in compliance with the License. 6d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers * You may obtain a copy of the License at 7d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers * 8d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers * http://www.apache.org/licenses/LICENSE-2.0 9d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers * 10d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers * Unless required by applicable law or agreed to in writing, software 11d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers * distributed under the License is distributed on an "AS IS" BASIS, 12d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers * See the License for the specific language governing permissions and 14d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers * limitations under the License. 15d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers */ 16d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 17d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers#include "instruction_set_features_arm.h" 18d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 19c60e1b755c5632dfeb04c333489ede52ee5c945fAndreas Gampe#if defined(__ANDROID__) && defined(__arm__) 20d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers#include <sys/auxv.h> 21d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers#include <asm/hwcap.h> 22d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers#endif 23d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 24d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers#include "signal.h" 25d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers#include <fstream> 26d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 27d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers#include "base/stringprintf.h" 28d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers#include "utils.h" // For Trim. 29d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 30d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers#if defined(__arm__) 31d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogersextern "C" bool artCheckForArmSdivInstruction(); 32d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers#endif 33d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 34d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogersnamespace art { 35d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 36d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogersconst ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromVariant( 37d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers const std::string& variant, std::string* error_msg) { 38d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers // Assume all ARM processors are SMP. 39d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers // TODO: set the SMP support based on variant. 40d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers const bool smp = true; 41d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 42d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers // Look for variants that have divide support. 43d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers static const char* arm_variants_with_div[] = { 44d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers "cortex-a7", "cortex-a12", "cortex-a15", "cortex-a17", "cortex-a53", "cortex-a57", 45901c55e439038f5a677dee2da493ae40f8a2b1e1Andreas Gampe "cortex-a53.a57", "cortex-m3", "cortex-m4", "cortex-r4", "cortex-r5", 46901c55e439038f5a677dee2da493ae40f8a2b1e1Andreas Gampe "cyclone", "denver", "krait", "swift" }; 47d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 48d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers bool has_div = FindVariantInArray(arm_variants_with_div, arraysize(arm_variants_with_div), 49d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers variant); 50d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 51d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers // Look for variants that have LPAE support. 52d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers static const char* arm_variants_with_lpae[] = { 53901c55e439038f5a677dee2da493ae40f8a2b1e1Andreas Gampe "cortex-a7", "cortex-a15", "krait", "denver", "cortex-a53", "cortex-a57", "cortex-a53.a57" 54d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers }; 55d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers bool has_lpae = FindVariantInArray(arm_variants_with_lpae, arraysize(arm_variants_with_lpae), 56d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers variant); 57d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 58d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers if (has_div == false && has_lpae == false) { 59d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers // Avoid unsupported variants. 60d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers static const char* unsupported_arm_variants[] = { 61d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers // ARM processors that aren't ARMv7 compatible aren't supported. 62d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers "arm2", "arm250", "arm3", "arm6", "arm60", "arm600", "arm610", "arm620", 63d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers "cortex-m0", "cortex-m0plus", "cortex-m1", 64d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers "fa526", "fa626", "fa606te", "fa626te", "fmp626", "fa726te", 65d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers "iwmmxt", "iwmmxt2", 66d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers "strongarm", "strongarm110", "strongarm1100", "strongarm1110", 67d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers "xscale" 68d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers }; 69d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers if (FindVariantInArray(unsupported_arm_variants, arraysize(unsupported_arm_variants), 70d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers variant)) { 71d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers *error_msg = StringPrintf("Attempt to use unsupported ARM variant: %s", variant.c_str()); 72d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers return nullptr; 73d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } 74d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers // Warn if the variant is unknown. 75d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers // TODO: some of the variants below may have feature support, but that support is currently 76d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers // unknown so we'll choose conservative (sub-optimal) defaults without warning. 77d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers // TODO: some of the architectures may not support all features required by ART and should be 78d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers // moved to unsupported_arm_variants[] above. 79d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers static const char* arm_variants_without_known_features[] = { 80d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers "default", 81d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers "arm7", "arm7m", "arm7d", "arm7dm", "arm7di", "arm7dmi", "arm70", "arm700", "arm700i", 82d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers "arm710", "arm710c", "arm7100", "arm720", "arm7500", "arm7500fe", "arm7tdmi", "arm7tdmi-s", 83d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers "arm710t", "arm720t", "arm740t", 84d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers "arm8", "arm810", 85d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers "arm9", "arm9e", "arm920", "arm920t", "arm922t", "arm946e-s", "arm966e-s", "arm968e-s", 86d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers "arm926ej-s", "arm940t", "arm9tdmi", 87d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers "arm10tdmi", "arm1020t", "arm1026ej-s", "arm10e", "arm1020e", "arm1022e", 88d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers "arm1136j-s", "arm1136jf-s", 89d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers "arm1156t2-s", "arm1156t2f-s", "arm1176jz-s", "arm1176jzf-s", 90d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers "cortex-a5", "cortex-a8", "cortex-a9", "cortex-a9-mp", "cortex-r4f", 91d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers "marvell-pj4", "mpcore", "mpcorenovfp" 92d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers }; 93d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers if (!FindVariantInArray(arm_variants_without_known_features, 94d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers arraysize(arm_variants_without_known_features), 95d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers variant)) { 96d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers LOG(WARNING) << "Unknown instruction set features for ARM CPU variant (" << variant 97d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers << ") using conservative defaults"; 98d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } 99d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } 100d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers return new ArmInstructionSetFeatures(smp, has_div, has_lpae); 101d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers} 102d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 103d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogersconst ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromBitmap(uint32_t bitmap) { 104d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers bool smp = (bitmap & kSmpBitfield) != 0; 105d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers bool has_div = (bitmap & kDivBitfield) != 0; 106d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers bool has_atomic_ldrd_strd = (bitmap & kAtomicLdrdStrdBitfield) != 0; 107d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers return new ArmInstructionSetFeatures(smp, has_div, has_atomic_ldrd_strd); 108d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers} 109d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 110d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogersconst ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromCppDefines() { 111d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers const bool smp = true; 112d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers#if defined(__ARM_ARCH_EXT_IDIV__) 113d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers const bool has_div = true; 114d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers#else 115d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers const bool has_div = false; 116d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers#endif 117d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers#if defined(__ARM_FEATURE_LPAE) 118d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers const bool has_lpae = true; 119d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers#else 120d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers const bool has_lpae = false; 121d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers#endif 122d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers return new ArmInstructionSetFeatures(smp, has_div, has_lpae); 123d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers} 124d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 125d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogersconst ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromCpuInfo() { 126d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers // Look in /proc/cpuinfo for features we need. Only use this when we can guarantee that 127d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers // the kernel puts the appropriate feature flags in here. Sometimes it doesn't. 128d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers bool smp = false; 129d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers bool has_lpae = false; 130d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers bool has_div = false; 131d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 132d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers std::ifstream in("/proc/cpuinfo"); 133d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers if (!in.fail()) { 134d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers while (!in.eof()) { 135d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers std::string line; 136d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers std::getline(in, line); 137d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers if (!in.eof()) { 138d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers LOG(INFO) << "cpuinfo line: " << line; 139d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers if (line.find("Features") != std::string::npos) { 140d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers LOG(INFO) << "found features"; 141d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers if (line.find("idivt") != std::string::npos) { 142d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers // We always expect both ARM and Thumb divide instructions to be available or not 143d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers // available. 144d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers CHECK_NE(line.find("idiva"), std::string::npos); 145d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers has_div = true; 146d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } 147d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers if (line.find("lpae") != std::string::npos) { 148d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers has_lpae = true; 149d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } 150d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } else if (line.find("processor") != std::string::npos && 151d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers line.find(": 1") != std::string::npos) { 152d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers smp = true; 153d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } 154d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } 155d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } 156d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers in.close(); 157d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } else { 158d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers LOG(ERROR) << "Failed to open /proc/cpuinfo"; 159d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } 160d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers return new ArmInstructionSetFeatures(smp, has_div, has_lpae); 161d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers} 162d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 163d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogersconst ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromHwcap() { 164d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers bool smp = sysconf(_SC_NPROCESSORS_CONF) > 1; 165d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 166d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers bool has_div = false; 167d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers bool has_lpae = false; 168d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 169c60e1b755c5632dfeb04c333489ede52ee5c945fAndreas Gampe#if defined(__ANDROID__) && defined(__arm__) 170d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers uint64_t hwcaps = getauxval(AT_HWCAP); 171d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers LOG(INFO) << "hwcaps=" << hwcaps; 172d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers if ((hwcaps & HWCAP_IDIVT) != 0) { 173d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers // We always expect both ARM and Thumb divide instructions to be available or not 174d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers // available. 175d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers CHECK_NE(hwcaps & HWCAP_IDIVA, 0U); 176d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers has_div = true; 177d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } 178d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers if ((hwcaps & HWCAP_LPAE) != 0) { 179d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers has_lpae = true; 180d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } 181d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers#endif 182d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 183d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers return new ArmInstructionSetFeatures(smp, has_div, has_lpae); 184d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers} 185d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 186d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers// A signal handler called by a fault for an illegal instruction. We record the fact in r0 187d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers// and then increment the PC in the signal context to return to the next instruction. We know the 188d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers// instruction is an sdiv (4 bytes long). 189d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogersstatic void bad_divide_inst_handle(int signo ATTRIBUTE_UNUSED, siginfo_t* si ATTRIBUTE_UNUSED, 190d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers void* data) { 191d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers#if defined(__arm__) 192d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers struct ucontext *uc = (struct ucontext *)data; 193d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers struct sigcontext *sc = &uc->uc_mcontext; 194d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers sc->arm_r0 = 0; // Set R0 to #0 to signal error. 195d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers sc->arm_pc += 4; // Skip offending instruction. 196d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers#else 197d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers UNUSED(data); 198d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers#endif 199d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers} 200d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 201d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogersconst ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromAssembly() { 202d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers const bool smp = true; 2038366ca0d7ba3b80a2d5be65ba436446cc32440bdElliott Hughes 204d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers // See if have a sdiv instruction. Register a signal handler and try to execute an sdiv 205d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers // instruction. If we get a SIGILL then it's not supported. 206d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers struct sigaction sa, osa; 207d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO; 208d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers sa.sa_sigaction = bad_divide_inst_handle; 209d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers sigaction(SIGILL, &sa, &osa); 210d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 211d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers bool has_div = false; 212d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers#if defined(__arm__) 213d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers if (artCheckForArmSdivInstruction()) { 214d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers has_div = true; 215d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } 216d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers#endif 217d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 218d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers // Restore the signal handler. 219d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers sigaction(SIGILL, &osa, nullptr); 220d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 221d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers // Use compile time features to "detect" LPAE support. 222d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers // TODO: write an assembly LPAE support test. 223d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers#if defined(__ARM_FEATURE_LPAE) 224d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers const bool has_lpae = true; 225d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers#else 226d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers const bool has_lpae = false; 227d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers#endif 228d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers return new ArmInstructionSetFeatures(smp, has_div, has_lpae); 229d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers} 230d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 231d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogersbool ArmInstructionSetFeatures::Equals(const InstructionSetFeatures* other) const { 232d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers if (kArm != other->GetInstructionSet()) { 233d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers return false; 234d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } 235d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers const ArmInstructionSetFeatures* other_as_arm = other->AsArmInstructionSetFeatures(); 236d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers return IsSmp() == other_as_arm->IsSmp() && 237d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers has_div_ == other_as_arm->has_div_ && 238d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers has_atomic_ldrd_strd_ == other_as_arm->has_atomic_ldrd_strd_; 239d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers} 240d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 241d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogersuint32_t ArmInstructionSetFeatures::AsBitmap() const { 242d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers return (IsSmp() ? kSmpBitfield : 0) | 243d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers (has_div_ ? kDivBitfield : 0) | 244d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers (has_atomic_ldrd_strd_ ? kAtomicLdrdStrdBitfield : 0); 245d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers} 246d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 247d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogersstd::string ArmInstructionSetFeatures::GetFeatureString() const { 248d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers std::string result; 249d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers if (IsSmp()) { 250d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers result += "smp"; 251d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } else { 252d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers result += "-smp"; 253d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } 254d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers if (has_div_) { 255d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers result += ",div"; 256d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } else { 257d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers result += ",-div"; 258d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } 259d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers if (has_atomic_ldrd_strd_) { 260d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers result += ",atomic_ldrd_strd"; 261d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } else { 262d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers result += ",-atomic_ldrd_strd"; 263d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } 264d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers return result; 265d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers} 266d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 267d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogersconst InstructionSetFeatures* ArmInstructionSetFeatures::AddFeaturesFromSplitString( 268d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers const bool smp, const std::vector<std::string>& features, std::string* error_msg) const { 269d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers bool has_atomic_ldrd_strd = has_atomic_ldrd_strd_; 270d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers bool has_div = has_div_; 271d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers for (auto i = features.begin(); i != features.end(); i++) { 272d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers std::string feature = Trim(*i); 273d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers if (feature == "div") { 274d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers has_div = true; 275d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } else if (feature == "-div") { 276d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers has_div = false; 277d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } else if (feature == "atomic_ldrd_strd") { 278d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers has_atomic_ldrd_strd = true; 279d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } else if (feature == "-atomic_ldrd_strd") { 280d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers has_atomic_ldrd_strd = false; 281d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } else { 282d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str()); 283d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers return nullptr; 284d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } 285d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers } 286d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers return new ArmInstructionSetFeatures(smp, has_div, has_atomic_ldrd_strd); 287d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers} 288d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers 289d582fa4ea62083a7598dded5b82dc2198b3daac7Ian Rogers} // namespace art 290