1/*
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_mips.h"
18
19#include <fstream>
20#include <sstream>
21
22#include "base/stringprintf.h"
23#include "utils.h"  // For Trim.
24
25namespace art {
26
27// An enum for the Mips revision.
28enum class MipsLevel {
29  kBase,
30  kR2,
31  kR5,
32  kR6
33};
34
35#if defined(_MIPS_ARCH_MIPS32R6)
36static constexpr MipsLevel kRuntimeMipsLevel = MipsLevel::kR6;
37#elif defined(_MIPS_ARCH_MIPS32R5)
38static constexpr MipsLevel kRuntimeMipsLevel = MipsLevel::kR5;
39#elif defined(_MIPS_ARCH_MIPS32R2)
40static constexpr MipsLevel kRuntimeMipsLevel = MipsLevel::kR2;
41#else
42static constexpr MipsLevel kRuntimeMipsLevel = MipsLevel::kBase;
43#endif
44
45static void GetFlagsFromCppDefined(bool* mips_isa_gte2, bool* r6, bool* fpu_32bit) {
46  // Override defaults based on compiler flags.
47  if (kRuntimeMipsLevel >= MipsLevel::kR2) {
48    *mips_isa_gte2 = true;
49  } else {
50    *mips_isa_gte2 = false;
51  }
52
53  if (kRuntimeMipsLevel >= MipsLevel::kR5) {
54    *fpu_32bit = false;
55  } else {
56    *fpu_32bit = true;
57  }
58
59  if (kRuntimeMipsLevel >= MipsLevel::kR6) {
60    *r6 = true;
61  } else {
62    *r6 = false;
63  }
64}
65
66const MipsInstructionSetFeatures* MipsInstructionSetFeatures::FromVariant(
67    const std::string& variant, std::string* error_msg ATTRIBUTE_UNUSED) {
68
69  bool smp = true;  // Conservative default.
70
71  // Override defaults based on compiler flags.
72  // This is needed when running ART test where the variant is not defined.
73  bool fpu_32bit;
74  bool mips_isa_gte2;
75  bool r6;
76  GetFlagsFromCppDefined(&mips_isa_gte2, &r6, &fpu_32bit);
77
78  // Override defaults based on variant string.
79  // Only care if it is R1, R2 or R6 and we assume all CPUs will have a FP unit.
80  constexpr const char* kMips32Prefix = "mips32r";
81  const size_t kPrefixLength = strlen(kMips32Prefix);
82  if (variant.compare(0, kPrefixLength, kMips32Prefix, kPrefixLength) == 0 &&
83      variant.size() > kPrefixLength) {
84    if (variant[kPrefixLength] >= '6') {
85      fpu_32bit = false;
86      r6 = true;
87    }
88    if (variant[kPrefixLength] >= '2') {
89      mips_isa_gte2 = true;
90    }
91  } else if (variant == "default") {
92    // Default variant is: smp = true, has fpu, is gte2, is not r6. This is the traditional
93    // setting.
94    mips_isa_gte2 = true;
95  } else {
96    LOG(WARNING) << "Unexpected CPU variant for Mips32 using defaults: " << variant;
97  }
98
99  return new MipsInstructionSetFeatures(smp, fpu_32bit, mips_isa_gte2, r6);
100}
101
102const MipsInstructionSetFeatures* MipsInstructionSetFeatures::FromBitmap(uint32_t bitmap) {
103  bool smp = (bitmap & kSmpBitfield) != 0;
104  bool fpu_32bit = (bitmap & kFpu32Bitfield) != 0;
105  bool mips_isa_gte2 = (bitmap & kIsaRevGte2Bitfield) != 0;
106  bool r6 = (bitmap & kR6) != 0;
107  return new MipsInstructionSetFeatures(smp, fpu_32bit, mips_isa_gte2, r6);
108}
109
110const MipsInstructionSetFeatures* MipsInstructionSetFeatures::FromCppDefines() {
111  // Assume conservative defaults.
112  const bool smp = true;
113
114  bool fpu_32bit;
115  bool mips_isa_gte2;
116  bool r6;
117  GetFlagsFromCppDefined(&mips_isa_gte2, &r6, &fpu_32bit);
118
119  return new MipsInstructionSetFeatures(smp, fpu_32bit, mips_isa_gte2, r6);
120}
121
122const MipsInstructionSetFeatures* MipsInstructionSetFeatures::FromCpuInfo() {
123  // Look in /proc/cpuinfo for features we need.  Only use this when we can guarantee that
124  // the kernel puts the appropriate feature flags in here.  Sometimes it doesn't.
125  // Assume conservative defaults.
126  bool smp = false;
127
128  bool fpu_32bit;
129  bool mips_isa_gte2;
130  bool r6;
131  GetFlagsFromCppDefined(&mips_isa_gte2, &r6, &fpu_32bit);
132
133  std::ifstream in("/proc/cpuinfo");
134  if (!in.fail()) {
135    while (!in.eof()) {
136      std::string line;
137      std::getline(in, line);
138      if (!in.eof()) {
139        LOG(INFO) << "cpuinfo line: " << line;
140        if (line.find("processor") != std::string::npos && line.find(": 1") != std::string::npos) {
141          smp = true;
142        }
143      }
144    }
145    in.close();
146  } else {
147    LOG(ERROR) << "Failed to open /proc/cpuinfo";
148  }
149  return new MipsInstructionSetFeatures(smp, fpu_32bit, mips_isa_gte2, r6);
150}
151
152const MipsInstructionSetFeatures* MipsInstructionSetFeatures::FromHwcap() {
153  UNIMPLEMENTED(WARNING);
154  return FromCppDefines();
155}
156
157const MipsInstructionSetFeatures* MipsInstructionSetFeatures::FromAssembly() {
158  UNIMPLEMENTED(WARNING);
159  return FromCppDefines();
160}
161
162bool MipsInstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
163  if (kMips != other->GetInstructionSet()) {
164    return false;
165  }
166  const MipsInstructionSetFeatures* other_as_mips = other->AsMipsInstructionSetFeatures();
167  return (IsSmp() == other->IsSmp()) &&
168      (fpu_32bit_ == other_as_mips->fpu_32bit_) &&
169      (mips_isa_gte2_ == other_as_mips->mips_isa_gte2_) &&
170      (r6_ == other_as_mips->r6_);
171}
172
173uint32_t MipsInstructionSetFeatures::AsBitmap() const {
174  return (IsSmp() ? kSmpBitfield : 0) |
175      (fpu_32bit_ ? kFpu32Bitfield : 0) |
176      (mips_isa_gte2_ ? kIsaRevGte2Bitfield : 0) |
177      (r6_ ? kR6 : 0);
178}
179
180std::string MipsInstructionSetFeatures::GetFeatureString() const {
181  std::string result;
182  if (IsSmp()) {
183    result += "smp";
184  } else {
185    result += "-smp";
186  }
187  if (fpu_32bit_) {
188    result += ",fpu32";
189  } else {
190    result += ",-fpu32";
191  }
192  if (mips_isa_gte2_) {
193    result += ",mips2";
194  } else {
195    result += ",-mips2";
196  }
197  if (r6_) {
198    result += ",r6";
199  }  // Suppress non-r6.
200  return result;
201}
202
203const InstructionSetFeatures* MipsInstructionSetFeatures::AddFeaturesFromSplitString(
204    const bool smp, const std::vector<std::string>& features, std::string* error_msg) const {
205  bool fpu_32bit = fpu_32bit_;
206  bool mips_isa_gte2 = mips_isa_gte2_;
207  bool r6 = r6_;
208  for (auto i = features.begin(); i != features.end(); i++) {
209    std::string feature = Trim(*i);
210    if (feature == "fpu32") {
211      fpu_32bit = true;
212    } else if (feature == "-fpu32") {
213      fpu_32bit = false;
214    } else if (feature == "mips2") {
215      mips_isa_gte2 = true;
216    } else if (feature == "-mips2") {
217      mips_isa_gte2 = false;
218    } else if (feature == "r6") {
219      r6 = true;
220    } else if (feature == "-r6") {
221      r6 = false;
222    } else {
223      *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
224      return nullptr;
225    }
226  }
227  return new MipsInstructionSetFeatures(smp, fpu_32bit, mips_isa_gte2, r6);
228}
229
230}  // namespace art
231