1 // Copyright 2017 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "cpuinfo_aarch64.h"
16
17 #include "internal/filesystem.h"
18 #include "internal/hwcaps.h"
19 #include "internal/stack_line_reader.h"
20 #include "internal/string_view.h"
21 #include "internal/unix_features_aggregator.h"
22
23 #include <assert.h>
24 #include <ctype.h>
25
26 DECLARE_SETTER(Aarch64Features, fp)
27 DECLARE_SETTER(Aarch64Features, asimd)
28 DECLARE_SETTER(Aarch64Features, aes)
29 DECLARE_SETTER(Aarch64Features, pmull)
30 DECLARE_SETTER(Aarch64Features, sha1)
31 DECLARE_SETTER(Aarch64Features, sha2)
32 DECLARE_SETTER(Aarch64Features, crc32)
33
34 static const CapabilityConfig kConfigs[] = {
35 [AARCH64_FP] = {{AARCH64_HWCAP_FP, 0}, "fp", &set_fp}, //
36 [AARCH64_ASIMD] = {{AARCH64_HWCAP_ASIMD, 0}, "asimd", &set_asimd}, //
37 [AARCH64_AES] = {{AARCH64_HWCAP_AES, 0}, "aes", &set_aes}, //
38 [AARCH64_PMULL] = {{AARCH64_HWCAP_PMULL, 0}, "pmull", &set_pmull}, //
39 [AARCH64_SHA1] = {{AARCH64_HWCAP_SHA1, 0}, "sha1", &set_sha1}, //
40 [AARCH64_SHA2] = {{AARCH64_HWCAP_SHA2, 0}, "sha2", &set_sha2}, //
41 [AARCH64_CRC32] {{AARCH64_HWCAP_CRC32, 0}, "crc32", &set_crc32}, //
42 };
43
44 static const size_t kConfigsSize = sizeof(kConfigs) / sizeof(CapabilityConfig);
45
HandleAarch64Line(const LineResult result,Aarch64Info * const info)46 static bool HandleAarch64Line(const LineResult result,
47 Aarch64Info* const info) {
48 StringView line = result.line;
49 StringView key, value;
50 if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
51 if (CpuFeatures_StringView_IsEquals(key, str("Features"))) {
52 CpuFeatures_SetFromFlags(kConfigsSize, kConfigs, value, &info->features);
53 } else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer"))) {
54 info->implementer = CpuFeatures_StringView_ParsePositiveNumber(value);
55 } else if (CpuFeatures_StringView_IsEquals(key, str("CPU variant"))) {
56 info->variant = CpuFeatures_StringView_ParsePositiveNumber(value);
57 } else if (CpuFeatures_StringView_IsEquals(key, str("CPU part"))) {
58 info->part = CpuFeatures_StringView_ParsePositiveNumber(value);
59 } else if (CpuFeatures_StringView_IsEquals(key, str("CPU revision"))) {
60 info->revision = CpuFeatures_StringView_ParsePositiveNumber(value);
61 }
62 }
63 return !result.eof;
64 }
65
FillProcCpuInfoData(Aarch64Info * const info)66 static void FillProcCpuInfoData(Aarch64Info* const info) {
67 const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
68 if (fd >= 0) {
69 StackLineReader reader;
70 StackLineReader_Initialize(&reader, fd);
71 for (;;) {
72 if (!HandleAarch64Line(StackLineReader_NextLine(&reader), info)) {
73 break;
74 }
75 }
76 CpuFeatures_CloseFile(fd);
77 }
78 }
79
80 static const Aarch64Info kEmptyAarch64Info;
81
GetAarch64Info(void)82 Aarch64Info GetAarch64Info(void) {
83 assert(kConfigsSize == AARCH64_LAST_);
84
85 // capabilities are fetched from both getauxval and /proc/cpuinfo so we can
86 // have some information if the executable is sandboxed (aka no access to
87 // /proc/cpuinfo).
88 Aarch64Info info = kEmptyAarch64Info;
89
90 FillProcCpuInfoData(&info);
91 CpuFeatures_OverrideFromHwCaps(kConfigsSize, kConfigs,
92 CpuFeatures_GetHardwareCapabilities(),
93 &info.features);
94
95 return info;
96 }
97
98 ////////////////////////////////////////////////////////////////////////////////
99 // Introspection functions
100
GetAarch64FeaturesEnumValue(const Aarch64Features * features,Aarch64FeaturesEnum value)101 int GetAarch64FeaturesEnumValue(const Aarch64Features* features,
102 Aarch64FeaturesEnum value) {
103 switch (value) {
104 case AARCH64_FP:
105 return features->fp;
106 case AARCH64_ASIMD:
107 return features->asimd;
108 case AARCH64_AES:
109 return features->aes;
110 case AARCH64_PMULL:
111 return features->pmull;
112 case AARCH64_SHA1:
113 return features->sha1;
114 case AARCH64_SHA2:
115 return features->sha2;
116 case AARCH64_CRC32:
117 return features->crc32;
118 case AARCH64_LAST_:
119 break;
120 }
121 return false;
122 }
123
GetAarch64FeaturesEnumName(Aarch64FeaturesEnum value)124 const char* GetAarch64FeaturesEnumName(Aarch64FeaturesEnum value) {
125 if(value >= kConfigsSize)
126 return "unknown feature";
127 return kConfigs[value].proc_cpuinfo_flag;
128 }
129