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