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