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 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", "kryo", "exynos-m1" 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 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 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 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 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 101 const Arm64InstructionSetFeatures* Arm64InstructionSetFeatures::FromAssembly() { 102 UNIMPLEMENTED(WARNING); 103 return FromCppDefines(); 104 } 105 106 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 114 uint32_t Arm64InstructionSetFeatures::AsBitmap() const { 115 return (IsSmp() ? kSmpBitfield : 0) | (fix_cortex_a53_835769_ ? kA53Bitfield : 0); 116 } 117 118 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 133 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