• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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