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 
25 namespace art {
26 
27 // An enum for the Mips revision.
28 enum class MipsLevel {
29   kBase,
30   kR2,
31   kR5,
32   kR6
33 };
34 
35 #if defined(_MIPS_ARCH_MIPS32R6)
36 static constexpr MipsLevel kRuntimeMipsLevel = MipsLevel::kR6;
37 #elif defined(_MIPS_ARCH_MIPS32R5)
38 static constexpr MipsLevel kRuntimeMipsLevel = MipsLevel::kR5;
39 #elif defined(_MIPS_ARCH_MIPS32R2)
40 static constexpr MipsLevel kRuntimeMipsLevel = MipsLevel::kR2;
41 #else
42 static constexpr MipsLevel kRuntimeMipsLevel = MipsLevel::kBase;
43 #endif
44 
GetFlagsFromCppDefined(bool * mips_isa_gte2,bool * r6,bool * fpu_32bit)45 static 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 
FromVariant(const std::string & variant,std::string * error_msg ATTRIBUTE_UNUSED)66 const 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 
FromBitmap(uint32_t bitmap)102 const 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 
FromCppDefines()110 const 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 
FromCpuInfo()122 const 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 
FromHwcap()152 const MipsInstructionSetFeatures* MipsInstructionSetFeatures::FromHwcap() {
153   UNIMPLEMENTED(WARNING);
154   return FromCppDefines();
155 }
156 
FromAssembly()157 const MipsInstructionSetFeatures* MipsInstructionSetFeatures::FromAssembly() {
158   UNIMPLEMENTED(WARNING);
159   return FromCppDefines();
160 }
161 
Equals(const InstructionSetFeatures * other) const162 bool 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 
AsBitmap() const173 uint32_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 
GetFeatureString() const180 std::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 
AddFeaturesFromSplitString(const bool smp,const std::vector<std::string> & features,std::string * error_msg) const203 const 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