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