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_arm64.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 
FromVariant(const std::string & variant,std::string * error_msg)27 const Arm64InstructionSetFeatures* Arm64InstructionSetFeatures::FromVariant(
28     const std::string& variant, std::string* error_msg) {
29   const bool smp = true;  // Conservative default.
30 
31   // Look for variants that need a fix for a53 erratum 835769.
32   static const char* arm64_variants_with_a53_835769_bug[] = {
33       "default", "generic", "cortex-a53"  // Pessimistically assume all generic ARM64s are A53s.
34   };
35   bool needs_a53_835769_fix = FindVariantInArray(arm64_variants_with_a53_835769_bug,
36                                                  arraysize(arm64_variants_with_a53_835769_bug),
37                                                  variant);
38 
39   if (!needs_a53_835769_fix) {
40     // Check to see if this is an expected variant.
41     static const char* arm64_known_variants[] = {
42         "denver64"
43     };
44     if (!FindVariantInArray(arm64_known_variants, arraysize(arm64_known_variants), variant)) {
45       std::ostringstream os;
46       os << "Unexpected CPU variant for Arm64: " << variant;
47       *error_msg = os.str();
48       return nullptr;
49     }
50   }
51 
52   // The variants that need a fix for 843419 are the same that need a fix for 835769.
53   bool needs_a53_843419_fix = needs_a53_835769_fix;
54 
55   return new Arm64InstructionSetFeatures(smp, needs_a53_835769_fix, needs_a53_843419_fix);
56 }
57 
FromBitmap(uint32_t bitmap)58 const Arm64InstructionSetFeatures* Arm64InstructionSetFeatures::FromBitmap(uint32_t bitmap) {
59   bool smp = (bitmap & kSmpBitfield) != 0;
60   bool is_a53 = (bitmap & kA53Bitfield) != 0;
61   return new Arm64InstructionSetFeatures(smp, is_a53, is_a53);
62 }
63 
FromCppDefines()64 const Arm64InstructionSetFeatures* Arm64InstructionSetFeatures::FromCppDefines() {
65   const bool smp = true;
66   const bool is_a53 = true;  // Pessimistically assume all ARM64s are A53s.
67   return new Arm64InstructionSetFeatures(smp, is_a53, is_a53);
68 }
69 
FromCpuInfo()70 const Arm64InstructionSetFeatures* Arm64InstructionSetFeatures::FromCpuInfo() {
71   // Look in /proc/cpuinfo for features we need.  Only use this when we can guarantee that
72   // the kernel puts the appropriate feature flags in here.  Sometimes it doesn't.
73   bool smp = false;
74   const bool is_a53 = true;  // Conservative default.
75 
76   std::ifstream in("/proc/cpuinfo");
77   if (!in.fail()) {
78     while (!in.eof()) {
79       std::string line;
80       std::getline(in, line);
81       if (!in.eof()) {
82         LOG(INFO) << "cpuinfo line: " << line;
83         if (line.find("processor") != std::string::npos && line.find(": 1") != std::string::npos) {
84           smp = true;
85         }
86       }
87     }
88     in.close();
89   } else {
90     LOG(ERROR) << "Failed to open /proc/cpuinfo";
91   }
92   return new Arm64InstructionSetFeatures(smp, is_a53, is_a53);
93 }
94 
FromHwcap()95 const Arm64InstructionSetFeatures* Arm64InstructionSetFeatures::FromHwcap() {
96   bool smp = sysconf(_SC_NPROCESSORS_CONF) > 1;
97   const bool is_a53 = true;  // Pessimistically assume all ARM64s are A53s.
98   return new Arm64InstructionSetFeatures(smp, is_a53, is_a53);
99 }
100 
FromAssembly()101 const Arm64InstructionSetFeatures* Arm64InstructionSetFeatures::FromAssembly() {
102   UNIMPLEMENTED(WARNING);
103   return FromCppDefines();
104 }
105 
Equals(const InstructionSetFeatures * other) const106 bool Arm64InstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
107   if (kArm64 != other->GetInstructionSet()) {
108     return false;
109   }
110   const Arm64InstructionSetFeatures* other_as_arm = other->AsArm64InstructionSetFeatures();
111   return fix_cortex_a53_835769_ == other_as_arm->fix_cortex_a53_835769_;
112 }
113 
AsBitmap() const114 uint32_t Arm64InstructionSetFeatures::AsBitmap() const {
115   return (IsSmp() ? kSmpBitfield : 0) | (fix_cortex_a53_835769_ ? kA53Bitfield : 0);
116 }
117 
GetFeatureString() const118 std::string Arm64InstructionSetFeatures::GetFeatureString() const {
119   std::string result;
120   if (IsSmp()) {
121     result += "smp";
122   } else {
123     result += "-smp";
124   }
125   if (fix_cortex_a53_835769_) {
126     result += ",a53";
127   } else {
128     result += ",-a53";
129   }
130   return result;
131 }
132 
AddFeaturesFromSplitString(const bool smp,const std::vector<std::string> & features,std::string * error_msg) const133 const InstructionSetFeatures* Arm64InstructionSetFeatures::AddFeaturesFromSplitString(
134     const bool smp, const std::vector<std::string>& features, std::string* error_msg) const {
135   bool is_a53 = fix_cortex_a53_835769_;
136   for (auto i = features.begin(); i != features.end(); i++) {
137     std::string feature = Trim(*i);
138     if (feature == "a53") {
139       is_a53 = true;
140     } else if (feature == "-a53") {
141       is_a53 = false;
142     } else {
143       *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
144       return nullptr;
145     }
146   }
147   return new Arm64InstructionSetFeatures(smp, is_a53, is_a53);
148 }
149 
150 }  // namespace art
151