1 #include <stdint.h>
2
3 #if CPUINFO_MOCK
4 #include <cpuinfo-mock.h>
5 #endif
6 #include <arm/linux/api.h>
7 #include <arm/linux/cp.h>
8 #include <arm/midr.h>
9 #include <cpuinfo/log.h>
10
11 #if CPUINFO_MOCK
12 uint32_t cpuinfo_arm_fpsid = 0;
13 uint32_t cpuinfo_arm_mvfr0 = 0;
14 uint32_t cpuinfo_arm_wcid = 0;
15
cpuinfo_set_fpsid(uint32_t fpsid)16 void cpuinfo_set_fpsid(uint32_t fpsid) {
17 cpuinfo_arm_fpsid = fpsid;
18 }
19
cpuinfo_set_wcid(uint32_t wcid)20 void cpuinfo_set_wcid(uint32_t wcid) {
21 cpuinfo_arm_wcid = wcid;
22 }
23 #endif
24
cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo(uint32_t features,uint64_t features2,uint32_t midr,uint32_t architecture_version,uint32_t architecture_flags,const struct cpuinfo_arm_chipset chipset[restrict static1],struct cpuinfo_arm_isa isa[restrict static1])25 void cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo(
26 uint32_t features,
27 uint64_t features2,
28 uint32_t midr,
29 uint32_t architecture_version,
30 uint32_t architecture_flags,
31 const struct cpuinfo_arm_chipset chipset[restrict static 1],
32 struct cpuinfo_arm_isa isa[restrict static 1]) {
33 if (architecture_version < 8) {
34 const uint32_t armv8_features2_mask = CPUINFO_ARM_LINUX_FEATURE2_AES |
35 CPUINFO_ARM_LINUX_FEATURE2_PMULL | CPUINFO_ARM_LINUX_FEATURE2_SHA1 |
36 CPUINFO_ARM_LINUX_FEATURE2_SHA2 | CPUINFO_ARM_LINUX_FEATURE2_CRC32;
37 if (features2 & armv8_features2_mask) {
38 architecture_version = 8;
39 }
40 }
41 if (architecture_version >= 8) {
42 /*
43 * ARMv7 code running on ARMv8: IDIV, VFP, NEON are always
44 * supported, but may be not reported in /proc/cpuinfo features.
45 */
46 isa->armv5e = true;
47 isa->armv6 = true;
48 isa->armv6k = true;
49 isa->armv7 = true;
50 isa->armv7mp = true;
51 isa->armv8 = true;
52 isa->thumb = true;
53 isa->thumb2 = true;
54 isa->idiv = true;
55 isa->vfpv3 = true;
56 isa->d32 = true;
57 isa->fp16 = true;
58 isa->fma = true;
59 isa->neon = true;
60
61 /*
62 * NEON FP16 compute extension and VQRDMLAH/VQRDMLSH
63 * instructions are not indicated in /proc/cpuinfo. Use a
64 * MIDR-based heuristic to whitelist processors known to support
65 * it:
66 * - Processors with Cortex-A55 cores
67 * - Processors with Cortex-A75 cores
68 * - Processors with Cortex-A76 cores
69 * - Processors with Cortex-A77 cores
70 * - Processors with Cortex-A78 cores
71 * - Processors with Cortex-A510 cores
72 * - Processors with Cortex-A710 cores
73 * - Processors with Cortex-A715 cores
74 * - Processors with Cortex-X1 cores
75 * - Processors with Cortex-X2 cores
76 * - Processors with Cortex-X3 cores
77 * - Processors with Exynos M4 cores
78 * - Processors with Exynos M5 cores
79 * - Neoverse N1 cores
80 * - Neoverse N2 cores
81 * - Neoverse V1 cores
82 * - Neoverse V2 cores
83 */
84 if (chipset->series == cpuinfo_arm_chipset_series_samsung_exynos && chipset->model == 9810) {
85 /* Only little cores of Exynos 9810 support FP16 & RDM
86 */
87 cpuinfo_log_warning(
88 "FP16 arithmetics and RDM disabled: only little cores in Exynos 9810 support these extensions");
89 } else {
90 switch (midr & (CPUINFO_ARM_MIDR_IMPLEMENTER_MASK | CPUINFO_ARM_MIDR_PART_MASK)) {
91 case UINT32_C(0x4100D050): /* Cortex-A55 */
92 case UINT32_C(0x4100D0A0): /* Cortex-A75 */
93 case UINT32_C(0x4100D0B0): /* Cortex-A76 */
94 case UINT32_C(0x4100D0C0): /* Neoverse N1 */
95 case UINT32_C(0x4100D0D0): /* Cortex-A77 */
96 case UINT32_C(0x4100D0E0): /* Cortex-A76AE */
97 case UINT32_C(0x4100D400): /* Neoverse V1 */
98 case UINT32_C(0x4100D410): /* Cortex-A78 */
99 case UINT32_C(0x4100D440): /* Cortex-X1 */
100 case UINT32_C(0x4100D460): /* Cortex-A510 */
101 case UINT32_C(0x4100D470): /* Cortex-A710 */
102 case UINT32_C(0x4100D480): /* Cortex-X2 */
103 case UINT32_C(0x4100D490): /* Neoverse N2 */
104 case UINT32_C(0x4100D4D0): /* Cortex-A715 */
105 case UINT32_C(0x4100D4E0): /* Cortex-X3 */
106 case UINT32_C(0x4100D4F0): /* Neoverse V2 */
107 case UINT32_C(0x4800D400): /* Cortex-A76
108 (HiSilicon) */
109 case UINT32_C(0x51008020): /* Kryo 385 Gold
110 (Cortex-A75) */
111 case UINT32_C(0x51008030): /* Kryo 385 Silver
112 (Cortex-A55) */
113 case UINT32_C(0x51008040): /* Kryo 485 Gold
114 (Cortex-A76) */
115 case UINT32_C(0x51008050): /* Kryo 485 Silver
116 (Cortex-A55) */
117 case UINT32_C(0x53000030): /* Exynos M4 */
118 case UINT32_C(0x53000040): /* Exynos M5 */
119 isa->fp16arith = true;
120 isa->rdm = true;
121 break;
122 }
123 }
124
125 /*
126 * NEON VDOT instructions are not indicated in /proc/cpuinfo.
127 * Use a MIDR-based heuristic to whitelist processors known to
128 * support it:
129 * - Processors with Cortex-A76 cores
130 * - Processors with Cortex-A77 cores
131 * - Processors with Cortex-A78 cores
132 * - Processors with Cortex-A510 cores
133 * - Processors with Cortex-A710 cores
134 * - Processors with Cortex-A715 cores
135 * - Processors with Cortex-X1 cores
136 * - Processors with Cortex-X2 cores
137 * - Processors with Cortex-X3 cores
138 * - Processors with Exynos M4 cores
139 * - Processors with Exynos M5 cores
140 * - Neoverse N1 cores
141 * - Neoverse N2 cores
142 * - Neoverse V1 cores
143 * - Neoverse V2 cores
144 */
145 if (chipset->series == cpuinfo_arm_chipset_series_spreadtrum_sc && chipset->model == 9863) {
146 cpuinfo_log_warning(
147 "VDOT instructions disabled: cause occasional SIGILL on Spreadtrum SC9863A");
148 } else if (chipset->series == cpuinfo_arm_chipset_series_unisoc_t && chipset->model == 310) {
149 cpuinfo_log_warning("VDOT instructions disabled: cause occasional SIGILL on Unisoc T310");
150 } else if (chipset->series == cpuinfo_arm_chipset_series_unisoc_ums && chipset->model == 312) {
151 cpuinfo_log_warning("VDOT instructions disabled: cause occasional SIGILL on Unisoc UMS312");
152 } else {
153 switch (midr & (CPUINFO_ARM_MIDR_IMPLEMENTER_MASK | CPUINFO_ARM_MIDR_PART_MASK)) {
154 case UINT32_C(0x4100D0B0): /* Cortex-A76 */
155 case UINT32_C(0x4100D0C0): /* Neoverse N1 */
156 case UINT32_C(0x4100D0D0): /* Cortex-A77 */
157 case UINT32_C(0x4100D0E0): /* Cortex-A76AE */
158 case UINT32_C(0x4100D400): /* Neoverse V1 */
159 case UINT32_C(0x4100D410): /* Cortex-A78 */
160 case UINT32_C(0x4100D440): /* Cortex-X1 */
161 case UINT32_C(0x4100D460): /* Cortex-A510 */
162 case UINT32_C(0x4100D470): /* Cortex-A710 */
163 case UINT32_C(0x4100D480): /* Cortex-X2 */
164 case UINT32_C(0x4100D490): /* Neoverse N2 */
165 case UINT32_C(0x4100D4D0): /* Cortex-A715 */
166 case UINT32_C(0x4100D4E0): /* Cortex-X3 */
167 case UINT32_C(0x4100D4F0): /* Neoverse V2 */
168 case UINT32_C(0x4800D400): /* Cortex-A76
169 (HiSilicon) */
170 case UINT32_C(0x51008040): /* Kryo 485 Gold
171 (Cortex-A76) */
172 case UINT32_C(0x51008050): /* Kryo 485 Silver
173 (Cortex-A55) */
174 case UINT32_C(0x53000030): /* Exynos M4 */
175 case UINT32_C(0x53000040): /* Exynos M5 */
176 isa->dot = true;
177 break;
178 case UINT32_C(0x4100D050): /* Cortex A55: revision 1
179 or later only */
180 isa->dot = !!(midr_get_variant(midr) >= 1);
181 break;
182 case UINT32_C(0x4100D0A0): /* Cortex A75: revision 2
183 or later only */
184 isa->dot = !!(midr_get_variant(midr) >= 2);
185 break;
186 }
187 }
188 } else {
189 /* ARMv7 or lower: use feature flags to detect optional features
190 */
191
192 /*
193 * ARM11 (ARM 1136/1156/1176/11 MPCore) processors can report v7
194 * architecture even though they support only ARMv6 instruction
195 * set.
196 */
197 if (architecture_version == 7 && midr_is_arm11(midr)) {
198 cpuinfo_log_warning(
199 "kernel-reported architecture ARMv7 ignored due to mismatch with processor microarchitecture (ARM11)");
200 architecture_version = 6;
201 }
202
203 if (architecture_version < 7) {
204 const uint32_t armv7_features_mask = CPUINFO_ARM_LINUX_FEATURE_VFPV3 |
205 CPUINFO_ARM_LINUX_FEATURE_VFPV3D16 | CPUINFO_ARM_LINUX_FEATURE_VFPD32 |
206 CPUINFO_ARM_LINUX_FEATURE_VFPV4 | CPUINFO_ARM_LINUX_FEATURE_NEON |
207 CPUINFO_ARM_LINUX_FEATURE_IDIVT | CPUINFO_ARM_LINUX_FEATURE_IDIVA;
208 if (features & armv7_features_mask) {
209 architecture_version = 7;
210 }
211 }
212 if ((architecture_version >= 6) || (features & CPUINFO_ARM_LINUX_FEATURE_EDSP) ||
213 (architecture_flags & CPUINFO_ARM_LINUX_ARCH_E)) {
214 isa->armv5e = true;
215 }
216 if (architecture_version >= 6) {
217 isa->armv6 = true;
218 }
219 if (architecture_version >= 7) {
220 isa->armv6k = true;
221 isa->armv7 = true;
222
223 /*
224 * ARMv7 MP extension (PLDW instruction) is not
225 * indicated in /proc/cpuinfo. Use heuristic list of
226 * supporting processors:
227 * - Processors supporting UDIV/SDIV instructions
228 * ("idiva" + "idivt" features in /proc/cpuinfo)
229 * - Cortex-A5
230 * - Cortex-A9
231 * - Dual-Core Scorpion
232 * - Krait (supports UDIV/SDIV, but kernels may not
233 * report it in /proc/cpuinfo)
234 *
235 * TODO: check single-core Qualcomm Scorpion.
236 */
237 switch (midr & (CPUINFO_ARM_MIDR_IMPLEMENTER_MASK | CPUINFO_ARM_MIDR_PART_MASK)) {
238 case UINT32_C(0x4100C050): /* Cortex-A5 */
239 case UINT32_C(0x4100C090): /* Cortex-A9 */
240 case UINT32_C(0x510002D0): /* Scorpion (dual-core) */
241 case UINT32_C(0x510004D0): /* Krait (dual-core) */
242 case UINT32_C(0x510006F0): /* Krait (quad-core) */
243 isa->armv7mp = true;
244 break;
245 default:
246 /* In practice IDIV instruction implies
247 * ARMv7+MP ISA */
248 isa->armv7mp = (features & CPUINFO_ARM_LINUX_FEATURE_IDIV) ==
249 CPUINFO_ARM_LINUX_FEATURE_IDIV;
250 break;
251 }
252 }
253
254 if (features & CPUINFO_ARM_LINUX_FEATURE_IWMMXT) {
255 #if !defined(__ARM_ARCH_8A__) && !(defined(__ARM_ARCH) && (__ARM_ARCH >= 8))
256 const uint32_t wcid = read_wcid();
257 cpuinfo_log_debug("WCID = 0x%08" PRIx32, wcid);
258 const uint32_t coprocessor_type = (wcid >> 8) & UINT32_C(0xFF);
259 if (coprocessor_type >= 0x10) {
260 isa->wmmx = true;
261 if (coprocessor_type >= 0x20) {
262 isa->wmmx2 = true;
263 }
264 } else {
265 cpuinfo_log_warning(
266 "WMMX ISA disabled: OS reported iwmmxt feature, "
267 "but WCID coprocessor type 0x%" PRIx32 " indicates no WMMX support",
268 coprocessor_type);
269 }
270 #else
271 cpuinfo_log_warning(
272 "WMMX ISA disabled: OS reported iwmmxt feature, "
273 "but there is no iWMMXt coprocessor");
274 #endif
275 }
276
277 if ((features & CPUINFO_ARM_LINUX_FEATURE_THUMB) || (architecture_flags & CPUINFO_ARM_LINUX_ARCH_T)) {
278 isa->thumb = true;
279
280 /*
281 * There is no separate feature flag for Thumb 2.
282 * All ARMv7 processors and ARM 1156 support Thumb 2.
283 */
284 if (architecture_version >= 7 || midr_is_arm1156(midr)) {
285 isa->thumb2 = true;
286 }
287 }
288 if (features & CPUINFO_ARM_LINUX_FEATURE_THUMBEE) {
289 isa->thumbee = true;
290 }
291 if ((features & CPUINFO_ARM_LINUX_FEATURE_JAVA) || (architecture_flags & CPUINFO_ARM_LINUX_ARCH_J)) {
292 isa->jazelle = true;
293 }
294
295 /* Qualcomm Krait may have buggy kernel configuration that
296 * doesn't report IDIV */
297 if ((features & CPUINFO_ARM_LINUX_FEATURE_IDIV) == CPUINFO_ARM_LINUX_FEATURE_IDIV ||
298 midr_is_krait(midr)) {
299 isa->idiv = true;
300 }
301
302 const uint32_t vfp_mask = CPUINFO_ARM_LINUX_FEATURE_VFP | CPUINFO_ARM_LINUX_FEATURE_VFPV3 |
303 CPUINFO_ARM_LINUX_FEATURE_VFPV3D16 | CPUINFO_ARM_LINUX_FEATURE_VFPD32 |
304 CPUINFO_ARM_LINUX_FEATURE_VFPV4 | CPUINFO_ARM_LINUX_FEATURE_NEON;
305 if (features & vfp_mask) {
306 const uint32_t vfpv3_mask = CPUINFO_ARM_LINUX_FEATURE_VFPV3 |
307 CPUINFO_ARM_LINUX_FEATURE_VFPV3D16 | CPUINFO_ARM_LINUX_FEATURE_VFPD32 |
308 CPUINFO_ARM_LINUX_FEATURE_VFPV4 | CPUINFO_ARM_LINUX_FEATURE_NEON;
309 if ((architecture_version >= 7) || (features & vfpv3_mask)) {
310 isa->vfpv3 = true;
311
312 const uint32_t d32_mask =
313 CPUINFO_ARM_LINUX_FEATURE_VFPD32 | CPUINFO_ARM_LINUX_FEATURE_NEON;
314 if (features & d32_mask) {
315 isa->d32 = true;
316 }
317 } else {
318 #if defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_8A__) || defined(__ARM_ARCH) && (__ARM_ARCH >= 7)
319 isa->vfpv3 = true;
320 #else
321 const uint32_t fpsid = read_fpsid();
322 cpuinfo_log_debug("FPSID = 0x%08" PRIx32, fpsid);
323 const uint32_t subarchitecture = (fpsid >> 16) & UINT32_C(0x7F);
324 if (subarchitecture >= 0x01) {
325 isa->vfpv2 = true;
326 }
327 #endif
328 }
329 }
330 if (features & CPUINFO_ARM_LINUX_FEATURE_NEON) {
331 isa->neon = true;
332 }
333
334 /*
335 * There is no separate feature flag for FP16 support.
336 * VFPv4 implies VFPv3-FP16 support (and in practice, NEON-HP as
337 * well). Additionally, ARM Cortex-A9 and Qualcomm Scorpion
338 * support FP16.
339 */
340 if ((features & CPUINFO_ARM_LINUX_FEATURE_VFPV4) || midr_is_cortex_a9(midr) || midr_is_scorpion(midr)) {
341 isa->fp16 = true;
342 }
343
344 if (features & CPUINFO_ARM_LINUX_FEATURE_VFPV4) {
345 isa->fma = true;
346 }
347 }
348
349 if (features2 & CPUINFO_ARM_LINUX_FEATURE2_AES) {
350 isa->aes = true;
351 }
352 if (features2 & CPUINFO_ARM_LINUX_FEATURE2_PMULL) {
353 isa->pmull = true;
354 }
355 if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SHA1) {
356 isa->sha1 = true;
357 }
358 if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SHA2) {
359 isa->sha2 = true;
360 }
361 if (features2 & CPUINFO_ARM_LINUX_FEATURE2_CRC32) {
362 isa->crc32 = true;
363 }
364 }
365