• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <ctype.h>
2 #include <stdbool.h>
3 #include <stdint.h>
4 #include <stdio.h>
5 #include <string.h>
6 
7 #include <arm/linux/api.h>
8 #ifdef __ANDROID__
9 	#include <arm/android/api.h>
10 #endif
11 #include <cpuinfo/log.h>
12 #include <cpuinfo/common.h>
13 
14 
is_ascii_whitespace(char c)15 static inline bool is_ascii_whitespace(char c) {
16 	switch (c) {
17 		case ' ':
18 		case '\t':
19 		case '\r':
20 		case '\n':
21 			return true;
22 		default:
23 			return false;
24 	}
25 }
26 
is_ascii_alphabetic(char c)27 static inline bool is_ascii_alphabetic(char c) {
28 	const char lower_c = c | '\x20';
29 	return (uint8_t) (lower_c - 'a') <= (uint8_t) ('z' - 'a');
30 }
31 
is_ascii_alphabetic_uppercase(char c)32 static inline bool is_ascii_alphabetic_uppercase(char c) {
33 	return (uint8_t) (c - 'A') <= (uint8_t) ('Z' - 'A');
34 }
35 
is_ascii_numeric(char c)36 static inline bool is_ascii_numeric(char c) {
37 	return (uint8_t) (c - '0') < 10;
38 }
39 
load_u16le(const void * ptr)40 static inline uint16_t load_u16le(const void* ptr) {
41 #if defined(__ARM_ARCH_7A__) || defined(__aarch64__)
42     return *((const uint16_t*) ptr);
43 #else
44 	const uint8_t* byte_ptr = (const uint8_t*) ptr;
45 	return ((uint16_t) byte_ptr[1] << 8) | (uint16_t) byte_ptr[0];
46 #endif
47 }
48 
load_u24le(const void * ptr)49 static inline uint32_t load_u24le(const void* ptr) {
50 #if defined(__ARM_ARCH_7A__) || defined(__aarch64__)
51     return ((uint32_t) ((const uint8_t*) ptr)[2] << 16) | ((uint32_t) *((const uint16_t*) ptr));
52 #else
53 	const uint8_t* byte_ptr = (const uint8_t*) ptr;
54 	return ((uint32_t) byte_ptr[2] << 16) | ((uint32_t) byte_ptr[1] << 8) | (uint32_t) byte_ptr[0];
55 #endif
56 }
57 
load_u32le(const void * ptr)58 static inline uint32_t load_u32le(const void* ptr) {
59 #if defined(__ARM_ARCH_7A__) || defined(__aarch64__)
60     return *((const uint32_t*) ptr);
61 #else
62 	return ((uint32_t) ((const uint8_t*) ptr)[3] << 24) | load_u24le(ptr);
63 #endif
64 }
65 
66 /*
67  * Map from ARM chipset series ID to ARM chipset vendor ID.
68  * This map is used to avoid storing vendor IDs in tables.
69  */
70 static enum cpuinfo_arm_chipset_vendor chipset_series_vendor[cpuinfo_arm_chipset_series_max] = {
71 	[cpuinfo_arm_chipset_series_unknown]                = cpuinfo_arm_chipset_vendor_unknown,
72 	[cpuinfo_arm_chipset_series_qualcomm_qsd]           = cpuinfo_arm_chipset_vendor_qualcomm,
73 	[cpuinfo_arm_chipset_series_qualcomm_msm]           = cpuinfo_arm_chipset_vendor_qualcomm,
74 	[cpuinfo_arm_chipset_series_qualcomm_apq]           = cpuinfo_arm_chipset_vendor_qualcomm,
75 	[cpuinfo_arm_chipset_series_qualcomm_snapdragon]    = cpuinfo_arm_chipset_vendor_qualcomm,
76 	[cpuinfo_arm_chipset_series_mediatek_mt]            = cpuinfo_arm_chipset_vendor_mediatek,
77 	[cpuinfo_arm_chipset_series_samsung_exynos]         = cpuinfo_arm_chipset_vendor_samsung,
78 	[cpuinfo_arm_chipset_series_hisilicon_k3v]          = cpuinfo_arm_chipset_vendor_hisilicon,
79 	[cpuinfo_arm_chipset_series_hisilicon_hi]           = cpuinfo_arm_chipset_vendor_hisilicon,
80 	[cpuinfo_arm_chipset_series_hisilicon_kirin]        = cpuinfo_arm_chipset_vendor_hisilicon,
81 	[cpuinfo_arm_chipset_series_actions_atm]            = cpuinfo_arm_chipset_vendor_actions,
82 	[cpuinfo_arm_chipset_series_allwinner_a]            = cpuinfo_arm_chipset_vendor_allwinner,
83 	[cpuinfo_arm_chipset_series_amlogic_aml]            = cpuinfo_arm_chipset_vendor_amlogic,
84 	[cpuinfo_arm_chipset_series_amlogic_s]              = cpuinfo_arm_chipset_vendor_amlogic,
85 	[cpuinfo_arm_chipset_series_broadcom_bcm]           = cpuinfo_arm_chipset_vendor_broadcom,
86 	[cpuinfo_arm_chipset_series_lg_nuclun]              = cpuinfo_arm_chipset_vendor_lg,
87 	[cpuinfo_arm_chipset_series_leadcore_lc]            = cpuinfo_arm_chipset_vendor_leadcore,
88 	[cpuinfo_arm_chipset_series_marvell_pxa]            = cpuinfo_arm_chipset_vendor_marvell,
89 	[cpuinfo_arm_chipset_series_mstar_6a]               = cpuinfo_arm_chipset_vendor_mstar,
90 	[cpuinfo_arm_chipset_series_novathor_u]             = cpuinfo_arm_chipset_vendor_novathor,
91 	[cpuinfo_arm_chipset_series_nvidia_tegra_t]         = cpuinfo_arm_chipset_vendor_nvidia,
92 	[cpuinfo_arm_chipset_series_nvidia_tegra_ap]        = cpuinfo_arm_chipset_vendor_nvidia,
93 	[cpuinfo_arm_chipset_series_nvidia_tegra_sl]        = cpuinfo_arm_chipset_vendor_nvidia,
94 	[cpuinfo_arm_chipset_series_pinecone_surge_s]       = cpuinfo_arm_chipset_vendor_pinecone,
95 	[cpuinfo_arm_chipset_series_renesas_mp]             = cpuinfo_arm_chipset_vendor_renesas,
96 	[cpuinfo_arm_chipset_series_rockchip_rk]            = cpuinfo_arm_chipset_vendor_rockchip,
97 	[cpuinfo_arm_chipset_series_spreadtrum_sc]          = cpuinfo_arm_chipset_vendor_spreadtrum,
98 	[cpuinfo_arm_chipset_series_telechips_tcc]          = cpuinfo_arm_chipset_vendor_telechips,
99 	[cpuinfo_arm_chipset_series_texas_instruments_omap] = cpuinfo_arm_chipset_vendor_texas_instruments,
100 	[cpuinfo_arm_chipset_series_wondermedia_wm]         = cpuinfo_arm_chipset_vendor_wondermedia,
101 };
102 
103 /**
104  * Tries to match /(MSM|APQ)\d{4}([A-Z\-]*)/ signature (case-insensitive) for Qualcomm MSM and APQ chipsets.
105  * If match successful, extracts model information into \p chipset argument.
106  *
107  * @param start - start of the platform identifier (/proc/cpuinfo Hardware string, ro.product.board, ro.board.platform
108  *                or ro.chipname) to match.
109  * @param end - end of the platform identifier (/proc/cpuinfo Hardware string, ro.product.board, ro.board.platform or
110  *              ro.chipname) to match.
111  * @param[out] chipset - location where chipset information will be stored upon a successful match.
112  *
113  * @returns true if signature matched, false otherwise.
114  */
match_msm_apq(const char * start,const char * end,struct cpuinfo_arm_chipset chipset[restrict static1])115 static bool match_msm_apq(
116 	const char* start, const char* end,
117 	struct cpuinfo_arm_chipset chipset[restrict static 1])
118 {
119 	/* Expect at least 7 symbols: 3 symbols "MSM" or "APQ" + 4 digits */
120 	if (start + 7 > end) {
121 		return false;
122 	}
123 
124 	/* Check that string starts with "MSM" or "APQ", case-insensitive.
125 	 * The first three characters are loaded as 24-bit little endian word, binary ORed with 0x20 to convert to lower
126 	 * case, and compared to "MSM" and "APQ" strings as integers.
127 	 */
128 	const uint32_t series_signature = UINT32_C(0x00202020) | load_u24le(start);
129 	enum cpuinfo_arm_chipset_series series;
130 	switch (series_signature) {
131 		case UINT32_C(0x6D736D): /* "msm" = reverse("msm") */
132 			series = cpuinfo_arm_chipset_series_qualcomm_msm;
133 			break;
134 		case UINT32_C(0x717061): /* "qpa" = reverse("apq") */
135 			series = cpuinfo_arm_chipset_series_qualcomm_apq;
136 			break;
137 		default:
138 			return false;
139 	}
140 
141 	/* Sometimes there is a space ' ' following the MSM/APQ series */
142 	const char* pos = start + 3;
143 	if (*pos == ' ') {
144 		pos++;
145 
146 		/* Expect at least 4 more symbols (4-digit model number) */
147 		if (pos + 4 > end) {
148 			return false;
149 		}
150 	}
151 
152 	/* Validate and parse 4-digit model number */
153 	uint32_t model = 0;
154 	for (uint32_t i = 0; i < 4; i++) {
155 		const uint32_t digit = (uint32_t) (uint8_t) (*pos++) - '0';
156 		if (digit >= 10) {
157 			/* Not really a digit */
158 			return false;
159 		}
160 		model = model * 10 + digit;
161 	}
162 
163 	/* Suffix is optional, so if we got to this point, parsing is successful. Commit parsed chipset. */
164 	*chipset = (struct cpuinfo_arm_chipset) {
165 		.vendor = cpuinfo_arm_chipset_vendor_qualcomm,
166 		.series = series,
167 		.model = model,
168 	};
169 
170 	/* Parse as many suffix characters as match the pattern [A-Za-z\-] */
171 	for (uint32_t i = 0; i < CPUINFO_ARM_CHIPSET_SUFFIX_MAX; i++) {
172 		if (pos + i == end) {
173 			break;
174 		}
175 
176 		const char c = pos[i];
177 		if (is_ascii_alphabetic(c)) {
178 			/* Matched a letter [A-Za-z] */
179 			chipset->suffix[i] = c & '\xDF';
180 		} else if (c == '-') {
181 			/* Matched a dash '-' */
182 			chipset->suffix[i] = c;
183 		} else {
184 			/* Neither of [A-Za-z\-] */
185 			break;
186 		}
187 	}
188 	return true;
189 }
190 
191 /**
192  * Tries to match /SDM\d{3}$/ signature for Qualcomm Snapdragon chipsets.
193  * If match successful, extracts model information into \p chipset argument.
194  *
195  * @param start - start of the /proc/cpuinfo Hardware string to match.
196  * @param end - end of the /proc/cpuinfo Hardware string to match.
197  * @param[out] chipset - location where chipset information will be stored upon a successful match.
198  *
199  * @returns true if signature matched, false otherwise.
200  */
match_sdm(const char * start,const char * end,struct cpuinfo_arm_chipset chipset[restrict static1])201 static bool match_sdm(
202 	const char* start, const char* end,
203 	struct cpuinfo_arm_chipset chipset[restrict static 1])
204 {
205 	/* Expect exactly 6 symbols: 3 symbols "SDM" + 3 digits */
206 	if (start + 6 != end) {
207 		return false;
208 	}
209 
210 	/* Check that string starts with "SDM".
211 	 * The first three characters are loaded and compared as 24-bit little endian word.
212 	 */
213 	const uint32_t expected_sdm = load_u24le(start);
214 	if (expected_sdm != UINT32_C(0x004D4453) /* "MDS" = reverse("SDM") */) {
215 		return false;
216 	}
217 
218 	/* Validate and parse 3-digit model number */
219 	uint32_t model = 0;
220 	for (uint32_t i = 3; i < 6; i++) {
221 		const uint32_t digit = (uint32_t) (uint8_t) start[i] - '0';
222 		if (digit >= 10) {
223 			/* Not really a digit */
224 			return false;
225 		}
226 		model = model * 10 + digit;
227 	}
228 
229 	/* Return parsed chipset. */
230 	*chipset = (struct cpuinfo_arm_chipset) {
231 		.vendor = cpuinfo_arm_chipset_vendor_qualcomm,
232 		.series = cpuinfo_arm_chipset_series_qualcomm_snapdragon,
233 		.model = model,
234 	};
235 	return true;
236 }
237 
238 /**
239  * Tries to match /SM\d{4}$/ signature for Qualcomm Snapdragon chipsets.
240  * If match successful, extracts model information into \p chipset argument.
241  *
242  * @param start - start of the /proc/cpuinfo Hardware string to match.
243  * @param end - end of the /proc/cpuinfo Hardware string to match.
244  * @param[out] chipset - location where chipset information will be stored upon a successful match.
245  *
246  * @returns true if signature matched, false otherwise.
247  */
match_sm(const char * start,const char * end,struct cpuinfo_arm_chipset chipset[restrict static1])248 static bool match_sm(
249 	const char* start, const char* end,
250 	struct cpuinfo_arm_chipset chipset[restrict static 1])
251 {
252 	/* Expect exactly 6 symbols: 2 symbols "SM" + 4 digits */
253 	if (start + 6 != end) {
254 		return false;
255 	}
256 
257 	/* Check that string starts with "SM".
258 	 * The first three characters are loaded and compared as 16-bit little endian word.
259 	 */
260 	const uint32_t expected_sm = load_u16le(start);
261 	if (expected_sm != UINT16_C(0x4D53) /* "MS" = reverse("SM") */) {
262 		return false;
263 	}
264 
265 	/* Validate and parse 4-digit model number */
266 	uint32_t model = 0;
267 	for (uint32_t i = 2; i < 6; i++) {
268 		const uint32_t digit = (uint32_t) (uint8_t) start[i] - '0';
269 		if (digit >= 10) {
270 			/* Not really a digit */
271 			return false;
272 		}
273 		model = model * 10 + digit;
274 	}
275 
276 	/* Return parsed chipset. */
277 	*chipset = (struct cpuinfo_arm_chipset) {
278 		.vendor = cpuinfo_arm_chipset_vendor_qualcomm,
279 		.series = cpuinfo_arm_chipset_series_qualcomm_snapdragon,
280 		.model = model,
281 	};
282 	return true;
283 }
284 
285 
286 struct special_map_entry {
287 	const char* platform;
288 	uint16_t model;
289 	uint8_t series;
290 	char suffix;
291 };
292 
293 static const struct special_map_entry qualcomm_hardware_map_entries[] = {
294 		{
295 				/* "Kona" -> Qualcomm Kona */
296 				.platform = "Kona",
297 				.series = cpuinfo_arm_chipset_series_qualcomm_snapdragon,
298 				.model = 865,
299 		},
300 		{
301 				/* "Bengal" -> Qualcomm Bengal */
302 				.platform = "Bengal",
303 				.series = cpuinfo_arm_chipset_series_qualcomm_snapdragon,
304 				.model = 662,
305 		},
306 		{
307 				/* "Bengalp" -> Qualcomm Bengalp */
308 				.platform = "Bengalp",
309 				.series = cpuinfo_arm_chipset_series_qualcomm_snapdragon,
310 				.model = 662,
311 		},
312 		{
313 				/* "Lito" -> Qualcomm Lito */
314 				.platform = "Lito",
315 				.series = cpuinfo_arm_chipset_series_qualcomm_snapdragon,
316 				.model = 765,
317 				.suffix = 'G'
318 		},
319 		{
320 				/* "Lagoon" -> Qualcomm Lagoon */
321 				.platform = "Lagoon",
322 				.series = cpuinfo_arm_chipset_series_qualcomm_snapdragon,
323 				.model = 0,
324 		},
325 };
326 
327 
strcicmp(char const * a,char const * b)328 int strcicmp(char const *a, char const *b)
329 {
330 	for (;; a++, b++) {
331 		int d = tolower((unsigned char)*a) - tolower((unsigned char)*b);
332 		if (d != 0 || !*a)
333 			return d;
334 	}
335 }
336 
match_qualcomm_special(const char * start,const char * end,struct cpuinfo_arm_chipset chipset[restrict static1])337 static bool match_qualcomm_special(
338 		const char* start, const char* end,
339 		struct cpuinfo_arm_chipset chipset[restrict static 1])
340 {
341 	for (size_t i = 0; i < CPUINFO_COUNT_OF(qualcomm_hardware_map_entries); i++) {
342 		int length = end - start;
343 		if (strcicmp(qualcomm_hardware_map_entries[i].platform, start) == 0 &&
344 			qualcomm_hardware_map_entries[i].platform[length] == 0)
345 		{
346 			*chipset = (struct cpuinfo_arm_chipset) {
347 					.vendor = chipset_series_vendor[qualcomm_hardware_map_entries[i].series],
348 					.series = (enum cpuinfo_arm_chipset_series) qualcomm_hardware_map_entries[i].series,
349 					.model = qualcomm_hardware_map_entries[i].model,
350 					.suffix = {
351 							[0] = qualcomm_hardware_map_entries[i].suffix,
352 					},
353 			};
354 			return true;
355 		}
356 	}
357 	return false;
358 
359 }
360 
361 /**
362  * Tries to match /Samsung Exynos\d{4}$/ signature (case-insensitive) for Samsung Exynos chipsets.
363  * If match successful, extracts model information into \p chipset argument.
364  *
365  * @param start - start of the /proc/cpuinfo Hardware string to match.
366  * @param end - end of the /proc/cpuinfo Hardware string to match.
367  * @param[out] chipset - location where chipset information will be stored upon a successful match.
368  *
369  * @returns true if signature matched, false otherwise.
370  */
match_samsung_exynos(const char * start,const char * end,struct cpuinfo_arm_chipset chipset[restrict static1])371 static bool match_samsung_exynos(
372 	const char* start, const char* end,
373 	struct cpuinfo_arm_chipset chipset[restrict static 1])
374 {
375 	/*
376 	 * Expect at 18-19 symbols:
377 	 * - "Samsung" (7 symbols) + space + "Exynos" (6 symbols) + optional space 4-digit model number
378 	 */
379 	const size_t length = end - start;
380 	switch (length) {
381 		case 18:
382 		case 19:
383 			break;
384 		default:
385 			return false;
386 	}
387 
388 	/*
389 	 * Check that the string starts with "samsung exynos", case-insensitive.
390 	 * Blocks of 4 characters are loaded and compared as little-endian 32-bit word.
391 	 * Case-insensitive characters are binary ORed with 0x20 to convert them to lowercase.
392 	 */
393 	const uint32_t expected_sams = UINT32_C(0x20202000) | load_u32le(start);
394 	if (expected_sams != UINT32_C(0x736D6153) /* "smaS" = reverse("Sams") */) {
395 		return false;
396 	}
397 	const uint32_t expected_ung = UINT32_C(0x00202020) | load_u32le(start + 4);
398 	if (expected_ung != UINT32_C(0x20676E75) /* " ung" = reverse("ung ") */) {
399 		return false;
400 	}
401 	const uint32_t expected_exyn = UINT32_C(0x20202000) | load_u32le(start + 8);
402 	if (expected_exyn != UINT32_C(0x6E797845) /* "nyxE" = reverse("Exyn") */) {
403 		return false;
404 	}
405 	const uint16_t expected_os = UINT16_C(0x2020) | load_u16le(start + 12);
406 	if (expected_os != UINT16_C(0x736F) /* "so" = reverse("os") */) {
407 		return false;
408 	}
409 
410 	const char* pos = start + 14;
411 
412 	/* There can be a space ' ' following the "Exynos" string */
413 	if (*pos == ' ') {
414 		pos++;
415 
416 		/* If optional space if present, we expect exactly 19 characters */
417 		if (length != 19) {
418 			return false;
419 		}
420 	}
421 
422 	/* Validate and parse 4-digit model number */
423 	uint32_t model = 0;
424 	for (uint32_t i = 0; i < 4; i++) {
425 		const uint32_t digit = (uint32_t) (uint8_t) (*pos++) - '0';
426 		if (digit >= 10) {
427 			/* Not really a digit */
428 			return false;
429 		}
430 		model = model * 10 + digit;
431 	}
432 
433 	/* Return parsed chipset */
434 	*chipset = (struct cpuinfo_arm_chipset) {
435 		.vendor = cpuinfo_arm_chipset_vendor_samsung,
436 		.series = cpuinfo_arm_chipset_series_samsung_exynos,
437 		.model = model,
438 	};
439 	return true;
440 }
441 
442 /**
443  * Tries to match /exynos\d{4}$/ signature for Samsung Exynos chipsets.
444  * If match successful, extracts model information into \p chipset argument.
445  *
446  * @param start - start of the platform identifier (ro.board.platform or ro.chipname) to match.
447  * @param end - end of the platform identifier (ro.board.platform or ro.chipname) to match.
448  * @param[out] chipset - location where chipset information will be stored upon a successful match.
449  *
450  * @returns true if signature matched, false otherwise.
451  */
match_exynos(const char * start,const char * end,struct cpuinfo_arm_chipset chipset[restrict static1])452 static bool match_exynos(
453 	const char* start, const char* end,
454 	struct cpuinfo_arm_chipset chipset[restrict static 1])
455 {
456 	/* Expect exactly 10 symbols: "exynos" (6 symbols) + 4-digit model number */
457 	if (start + 10 != end) {
458 		return false;
459 	}
460 
461 	/* Load first 4 bytes as little endian 32-bit word */
462 	const uint32_t expected_exyn = load_u32le(start);
463 	if (expected_exyn != UINT32_C(0x6E797865) /* "nyxe" = reverse("exyn") */ ) {
464 		return false;
465 	}
466 
467 	/* Load next 2 bytes as little endian 16-bit word */
468 	const uint16_t expected_os = load_u16le(start + 4);
469 	if (expected_os != UINT16_C(0x736F) /* "so" = reverse("os") */ ) {
470 		return false;
471 	}
472 
473 	/* Check and parse 4-digit model number */
474 	uint32_t model = 0;
475 	for (uint32_t i = 6; i < 10; i++) {
476 		const uint32_t digit = (uint32_t) (uint8_t) start[i] - '0';
477 		if (digit >= 10) {
478 			/* Not really a digit */
479 			return false;
480 		}
481 		model = model * 10 + digit;
482 	}
483 
484 	/* Return parsed chipset. */
485 	*chipset = (struct cpuinfo_arm_chipset) {
486 		.vendor = cpuinfo_arm_chipset_vendor_samsung,
487 		.series = cpuinfo_arm_chipset_series_samsung_exynos,
488 		.model = model,
489 	};
490 	return true;
491 }
492 
493 /**
494  * Tries to match /universal\d{4}$/ signature for Samsung Exynos chipsets.
495  * If match successful, extracts model information into \p chipset argument.
496  *
497  * @param start - start of the platform identifier (/proc/cpuinfo Hardware string, ro.product.board or ro.chipname)
498  *                to match.
499  * @param end - end of the platform identifier (/proc/cpuinfo Hardware string, ro.product.board or ro.chipname)
500  *              to match.
501  * @param[out] chipset - location where chipset information will be stored upon a successful match.
502  *
503  * @returns true if signature matched, false otherwise.
504  */
match_universal(const char * start,const char * end,struct cpuinfo_arm_chipset chipset[restrict static1])505 static bool match_universal(
506 	const char* start, const char* end,
507 	struct cpuinfo_arm_chipset chipset[restrict static 1])
508 {
509 	/* Expect exactly 13 symbols: "universal" (9 symbols) + 4-digit model number */
510 	if (start + 13 != end) {
511 		return false;
512 	}
513 
514 	/*
515 	 * Check that the string starts with "universal".
516 	 * Blocks of 4 characters are loaded and compared as little-endian 32-bit word.
517 	 * Case-insensitive characters are binary ORed with 0x20 to convert them to lowercase.
518 	 */
519 	const uint8_t expected_u = UINT8_C(0x20) | (uint8_t) start[0];
520 	if (expected_u != UINT8_C(0x75) /* "u" */) {
521 		return false;
522 	}
523 	const uint32_t expected_nive = UINT32_C(0x20202020) | load_u32le(start + 1);
524 	if (expected_nive != UINT32_C(0x6576696E) /* "evin" = reverse("nive") */ ) {
525 		return false;
526 	}
527 	const uint32_t expected_ersa = UINT32_C(0x20202020) | load_u32le(start + 5);
528 	if (expected_ersa != UINT32_C(0x6C617372) /* "lasr" = reverse("rsal") */) {
529 		return false;
530 	}
531 
532 	/* Validate and parse 4-digit model number */
533 	uint32_t model = 0;
534 	for (uint32_t i = 9; i < 13; i++) {
535 		const uint32_t digit = (uint32_t) (uint8_t) start[i] - '0';
536 		if (digit >= 10) {
537 			/* Not really a digit */
538 			return false;
539 		}
540 		model = model * 10 + digit;
541 	}
542 
543 	/* Return parsed chipset. */
544 	*chipset = (struct cpuinfo_arm_chipset) {
545 		.vendor = cpuinfo_arm_chipset_vendor_samsung,
546 		.series = cpuinfo_arm_chipset_series_samsung_exynos,
547 		.model = model,
548 	};
549 	return true;
550 }
551 
552 /**
553  * Compares, case insensitively, a string to known values "SMDK4210" and "SMDK4x12" for Samsung Exynos chipsets.
554  * If platform identifier matches one of the SMDK* values, extracts model information into \p chipset argument.
555  * For "SMDK4x12" match, decodes the chipset name using number of cores.
556  *
557  * @param start - start of the platform identifier (/proc/cpuinfo Hardware string or ro.product.board) to match.
558  * @param end - end of the platform identifier (/proc/cpuinfo Hardware string or ro.product.board) to match.
559  * @param cores - number of cores in the chipset.
560  * @param[out] chipset - location where chipset information will be stored upon a successful match.
561  *
562  * @returns true if signature matched, false otherwise.
563  */
match_and_parse_smdk(const char * start,const char * end,uint32_t cores,struct cpuinfo_arm_chipset chipset[restrict static1])564 static bool match_and_parse_smdk(
565 	const char* start, const char* end, uint32_t cores,
566 	struct cpuinfo_arm_chipset chipset[restrict static 1])
567 {
568 	/* Expect exactly 8 symbols: "SMDK" (4 symbols) + 4-digit model number */
569 	if (start + 8 != end) {
570 		return false;
571 	}
572 
573 	/*
574 	 * Check that string starts with "MT" (case-insensitive).
575 	 * The first four characters are loaded as a 32-bit little endian word and converted to lowercase.
576 	 */
577 	const uint32_t expected_smdk = UINT32_C(0x20202020) | load_u32le(start);
578 	if (expected_smdk != UINT32_C(0x6B646D73) /* "kdms" = reverse("smdk") */) {
579 		return false;
580 	}
581 
582 	/*
583 	 * Check that string ends with "4210" or "4x12".
584 	 * The last four characters are loaded and compared as a 32-bit little endian word.
585 	 */
586 	uint32_t model = 0;
587 	const uint32_t expected_model = load_u32le(start + 4);
588 	switch (expected_model) {
589 		case UINT32_C(0x30313234): /* "0124" = reverse("4210") */
590 			model = 4210;
591 			break;
592 		case UINT32_C(0x32317834): /* "21x4" = reverse("4x12") */
593 			switch (cores) {
594 				case 2:
595 					model = 4212;
596 					break;
597 				case 4:
598 					model = 4412;
599 					break;
600 				default:
601 					cpuinfo_log_warning("system reported invalid %"PRIu32"-core Exynos 4x12 chipset", cores);
602 			}
603 	}
604 
605 	if (model == 0) {
606 		return false;
607 	}
608 
609 	*chipset = (struct cpuinfo_arm_chipset) {
610 		.vendor = cpuinfo_arm_chipset_vendor_samsung,
611 		.series = cpuinfo_arm_chipset_series_samsung_exynos,
612 		.model = model,
613 	};
614 	return true;
615 }
616 
617 /**
618  * Tries to match /MTK?\d{4}[A-Z/]*$/ signature for MediaTek MT chipsets.
619  * If match successful, extracts model information into \p chipset argument.
620  *
621  * @param start - start of the platform identifier (/proc/cpuinfo Hardware string, ro.product.board, ro.board.platform,
622  *                ro.mediatek.platform, or ro.chipname) to match.
623  * @param end - end of the platform identifier (/proc/cpuinfo Hardware string, ro.product.board, ro.board.platform,
624  *              ro.mediatek.platform, or ro.chipname) to match.
625  * @param match_end - indicates if the function should attempt to match through the end of the string and fail if there
626  *                    are unparsed characters in the end, or match only MTK signature, model number, and some of the
627  *                    suffix characters (the ones that pass validation).
628  * @param[out] chipset - location where chipset information will be stored upon a successful match.
629  *
630  * @returns true if signature matched, false otherwise.
631  */
match_mt(const char * start,const char * end,bool match_end,struct cpuinfo_arm_chipset chipset[restrict static1])632 static bool match_mt(
633 	const char* start, const char* end, bool match_end,
634 	struct cpuinfo_arm_chipset chipset[restrict static 1])
635 {
636 	/* Expect at least 6 symbols: "MT" (2 symbols) + 4-digit model number */
637 	if (start + 6 > end) {
638 		return false;
639 	}
640 
641 	/*
642 	 * Check that string starts with "MT" (case-insensitive).
643 	 * The first two characters are loaded as 16-bit little endian word and converted to lowercase.
644 	 */
645 	const uint16_t mt = UINT16_C(0x2020) | load_u16le(start);
646 	if (mt != UINT16_C(0x746D) /* "tm" */) {
647 		return false;
648 	}
649 
650 
651 	/* Some images report "MTK" rather than "MT" */
652 	const char* pos = start + 2;
653 	if (((uint8_t) *pos | UINT8_C(0x20)) == (uint8_t) 'k') {
654 		pos++;
655 
656 		/* Expect 4 more symbols after "MTK" (4-digit model number) */
657 		if (pos + 4 > end) {
658 			return false;
659 		}
660 	}
661 
662 	/* Validate and parse 4-digit model number */
663 	uint32_t model = 0;
664 	for (uint32_t i = 0; i < 4; i++) {
665 		const uint32_t digit = (uint32_t) (uint8_t) (*pos++) - '0';
666 		if (digit >= 10) {
667 			/* Not really a digit */
668 			return false;
669 		}
670 		model = model * 10 + digit;
671 	}
672 
673 	/* Record parsed chipset. This implicitly zeroes-out suffix, which will be parsed later. */
674 	*chipset = (struct cpuinfo_arm_chipset) {
675 		.vendor = cpuinfo_arm_chipset_vendor_mediatek,
676 		.series = cpuinfo_arm_chipset_series_mediatek_mt,
677 		.model = model,
678 	};
679 
680 	if (match_end) {
681 		/* Check that the potential suffix does not exceed maximum length */
682 		const size_t suffix_length = end - pos;
683 		if (suffix_length > CPUINFO_ARM_CHIPSET_SUFFIX_MAX) {
684 			return false;
685 		}
686 
687 		/* Validate suffix characters and copy them to chipset structure */
688 		for (size_t i = 0; i < suffix_length; i++) {
689 			const char c = (*pos++);
690 			if (is_ascii_alphabetic(c)) {
691 				/* Matched a letter [A-Za-z], convert to uppercase */
692 				chipset->suffix[i] = c & '\xDF';
693 			} else if (c == '/') {
694 				/* Matched a slash '/' */
695 				chipset->suffix[i] = c;
696 			} else {
697 				/* Invalid suffix character (neither of [A-Za-z/]) */
698 				return false;
699 			}
700 		}
701 	} else {
702 		/* Validate and parse as many suffix characters as we can */
703 		for (size_t i = 0; i < CPUINFO_ARM_CHIPSET_SUFFIX_MAX; i++) {
704 			if (pos + i == end) {
705 				break;
706 			}
707 
708 			const char c = pos[i];
709 			if (is_ascii_alphabetic(c)) {
710 				/* Matched a letter [A-Za-z], convert to uppercase */
711 				chipset->suffix[i] = c & '\xDF';
712 			} else if (c == '/') {
713 				/* Matched a slash '/' */
714 				chipset->suffix[i] = c;
715 			} else {
716 				/* Invalid suffix character (neither of [A-Za-z/]). This marks the end of the suffix. */
717 				break;
718 			}
719 		}
720 	}
721 	/* All suffix characters successfully validated and copied to chipset data */
722 	return true;
723 }
724 
725 /**
726  * Tries to match /[Kk]irin\s?\d{3}$/ signature for HiSilicon Kirin chipsets.
727  * If match successful, extracts model information into \p chipset argument.
728  *
729  * @param start - start of the /proc/cpuinfo Hardware string to match.
730  * @param end - end of the /proc/cpuinfo Hardware string to match.
731  * @param[out] chipset - location where chipset information will be stored upon a successful match.
732  *
733  * @returns true if signature matched, false otherwise.
734  */
match_kirin(const char * start,const char * end,struct cpuinfo_arm_chipset chipset[restrict static1])735 static bool match_kirin(
736 	const char* start, const char* end,
737 	struct cpuinfo_arm_chipset chipset[restrict static 1])
738 {
739 	/* Expect 8-9 symbols: "Kirin" (5 symbols) + optional whitespace (1 symbol) + 3-digit model number */
740 	const size_t length = end - start;
741 	switch (length) {
742 		case 8:
743 		case 9:
744 			break;
745 		default:
746 			return false;
747 	}
748 
749 	/* Check that the string starts with "Kirin" or "kirin". */
750 	if (((uint8_t) start[0] | UINT8_C(0x20)) != (uint8_t) 'k') {
751 		return false;
752 	}
753 	/* Symbols 1-5 are loaded and compared as little-endian 32-bit word. */
754 	const uint32_t irin = load_u32le(start + 1);
755 	if (irin != UINT32_C(0x6E697269) /* "niri" = reverse("irin") */) {
756 		return false;
757 	}
758 
759 	/* Check for optional whitespace after "Kirin" */
760 	if (is_ascii_whitespace(start[5])) {
761 		/* When whitespace is present after "Kirin", expect 9 symbols total */
762 		if (length != 9) {
763 			return false;
764 		}
765 	}
766 
767 	/* Validate and parse 3-digit model number */
768 	uint32_t model = 0;
769 	for (int32_t i = 0; i < 3; i++) {
770 		const uint32_t digit = (uint32_t) (uint8_t) end[i - 3] - '0';
771 		if (digit >= 10) {
772 			/* Not really a digit */
773 			return false;
774 		}
775 		model = model * 10 + digit;
776 	}
777 
778 	/*
779 	 * Thats it, return parsed chipset.
780 	 * Technically, Kirin 910T has a suffix, but it never appears in the form of "910T" string.
781 	 * Instead, Kirin 910T devices report "hi6620oem" string (handled outside of this function).
782 	 */
783 	*chipset = (struct cpuinfo_arm_chipset) {
784 		.vendor = cpuinfo_arm_chipset_vendor_hisilicon,
785 		.series = cpuinfo_arm_chipset_series_hisilicon_kirin,
786 		.model = model,
787 	};
788 	return true;
789 }
790 
791 /**
792  * Tries to match /rk\d{4}[a-z]?$/ signature for Rockchip RK chipsets.
793  * If match successful, extracts model information into \p chipset argument.
794  *
795  * @param start - start of the platform identifier (/proc/cpuinfo Hardware string or ro.board.platform) to match.
796  * @param end - end of the platform identifier (/proc/cpuinfo Hardware string or ro.board.platform) to match.
797  * @param[out] chipset - location where chipset information will be stored upon a successful match.
798  *
799  * @returns true if signature matched, false otherwise.
800  */
match_rk(const char * start,const char * end,struct cpuinfo_arm_chipset chipset[restrict static1])801 static bool match_rk(
802 	const char* start, const char* end,
803 	struct cpuinfo_arm_chipset chipset[restrict static 1])
804 {
805 	/* Expect 6-7 symbols: "RK" (2 symbols) + 4-digit model number + optional 1-letter suffix */
806 	const size_t length = end - start;
807 	switch (length) {
808 		case 6:
809 		case 7:
810 			break;
811 		default:
812 			return false;
813 	}
814 
815 	/*
816 	 * Check that string starts with "RK" (case-insensitive).
817 	 * The first two characters are loaded as 16-bit little endian word and converted to lowercase.
818 	 */
819 	const uint16_t expected_rk = UINT16_C(0x2020) | load_u16le(start);
820 	if (expected_rk != UINT16_C(0x6B72) /* "kr" = reverse("rk") */) {
821 		return false;
822 	}
823 
824 	/* Validate and parse 4-digit model number */
825 	uint32_t model = 0;
826 	for (uint32_t i = 2; i < 6; i++) {
827 		const uint32_t digit = (uint32_t) (uint8_t) start[i] - '0';
828 		if (digit >= 10) {
829 			/* Not really a digit */
830 			return false;
831 		}
832 		model = model * 10 + digit;
833 	}
834 
835 	/* Parse optional suffix */
836 	char suffix = 0;
837 	if (length == 7) {
838 		/* Parse the suffix letter */
839 		const char c = start[6];
840 		if (is_ascii_alphabetic(c)) {
841 			/* Convert to upper case */
842 			suffix = c & '\xDF';
843 		} else {
844 			/* Invalid suffix character */
845 			return false;
846 		}
847 	}
848 
849 	/* Return parsed chipset */
850 	*chipset = (struct cpuinfo_arm_chipset) {
851 		.vendor = cpuinfo_arm_chipset_vendor_rockchip,
852 		.series = cpuinfo_arm_chipset_series_rockchip_rk,
853 		.model = model,
854 		.suffix = {
855 			[0] = suffix,
856 		},
857 	};
858 	return true;
859 }
860 
861 /**
862  * Tries to match, case-insentitively, /s[cp]\d{4}[a-z]*|scx15$/ signature for Spreadtrum SC chipsets.
863  * If match successful, extracts model information into \p chipset argument.
864  *
865  * @param start - start of the platform identifier (/proc/cpuinfo Hardware string, ro.product.board,
866  *                ro.board.platform, or ro.chipname) to match.
867  * @param end - end of the platform identifier (/proc/cpuinfo Hardware string, ro.product.board,
868  *              ro.board.platform, or ro.chipname) to match.
869  * @param[out] chipset - location where chipset information will be stored upon a successful match.
870  *
871  * @returns true if signature matched, false otherwise.
872  */
match_sc(const char * start,const char * end,struct cpuinfo_arm_chipset chipset[restrict static1])873 static bool match_sc(
874 	const char* start, const char* end,
875 	struct cpuinfo_arm_chipset chipset[restrict static 1])
876 {
877 	/* Expect at least 5 symbols: "scx15" */
878 	if (start + 5 > end) {
879 		return false;
880 	}
881 
882 	/*
883 	 * Check that string starts with "S[CP]" (case-insensitive).
884 	 * The first two characters are loaded as 16-bit little endian word and converted to lowercase.
885 	 */
886 	const uint16_t expected_sc_or_sp = UINT16_C(0x2020) | load_u16le(start);
887 	switch (expected_sc_or_sp) {
888 		case UINT16_C(0x6373): /* "cs" = reverse("sc") */
889 		case UINT16_C(0x7073): /* "ps" = reverse("sp") */
890 			break;
891 		default:
892 			return false;
893 	}
894 
895 	/* Special case: "scx" prefix (SC7715 reported as "scx15") */
896 	if ((start[2] | '\x20') == 'x') {
897 		/* Expect exactly 5 characters: "scx15" */
898 		if (start + 5 != end) {
899 			return false;
900 		}
901 
902 		/* Check that string ends with "15" */
903 		const uint16_t expected_15 = load_u16le(start + 3);
904 		if (expected_15 != UINT16_C(0x3531) /* "51" = reverse("15") */ ) {
905 			return false;
906 		}
907 
908 		*chipset = (struct cpuinfo_arm_chipset) {
909 			.vendor = cpuinfo_arm_chipset_vendor_spreadtrum,
910 			.series = cpuinfo_arm_chipset_series_spreadtrum_sc,
911 			.model = 7715,
912 		};
913 		return true;
914 	}
915 
916 	/* Expect at least 6 symbols: "S[CP]" (2 symbols) + 4-digit model number */
917 	if (start + 6 > end) {
918 		return false;
919 	}
920 
921 	/* Validate and parse 4-digit model number */
922 	uint32_t model = 0;
923 	for (uint32_t i = 2; i < 6; i++) {
924 		const uint32_t digit = (uint32_t) (uint8_t) start[i] - '0';
925 		if (digit >= 10) {
926 			/* Not really a digit */
927 			return false;
928 		}
929 		model = model * 10 + digit;
930 	}
931 
932 	/* Write parsed chipset */
933 	*chipset = (struct cpuinfo_arm_chipset) {
934 		.vendor = cpuinfo_arm_chipset_vendor_spreadtrum,
935 		.series = cpuinfo_arm_chipset_series_spreadtrum_sc,
936 		.model = model,
937 	};
938 
939 	/* Validate and copy suffix letters. If suffix is too long, truncate at CPUINFO_ARM_CHIPSET_SUFFIX_MAX letters. */
940 	const char* suffix = start + 6;
941 	for (size_t i = 0; i < CPUINFO_ARM_CHIPSET_SUFFIX_MAX; i++) {
942 		if (suffix + i == end) {
943 			break;
944 		}
945 
946 		const char c = suffix[i];
947 		if (!is_ascii_alphabetic(c)) {
948 			/* Invalid suffix character */
949 			return false;
950 		}
951 		/* Convert suffix letter to uppercase */
952 		chipset->suffix[i] = c & '\xDF';
953 	}
954 	return true;
955 }
956 
957 /**
958  * Tries to match /lc\d{4}[a-z]?$/ signature for Leadcore LC chipsets.
959  * If match successful, extracts model information into \p chipset argument.
960  *
961  * @param start - start of the platform identifier (ro.product.board or ro.board.platform) to match.
962  * @param end - end of the platform identifier (ro.product.board or ro.board.platform) to match.
963  * @param[out] chipset - location where chipset information will be stored upon a successful match.
964  *
965  * @returns true if signature matched, false otherwise.
966  */
match_lc(const char * start,const char * end,struct cpuinfo_arm_chipset chipset[restrict static1])967 static bool match_lc(
968 	const char* start, const char* end,
969 	struct cpuinfo_arm_chipset chipset[restrict static 1])
970 {
971 	/* Expect at 6-7 symbols: "lc" (2 symbols) + 4-digit model number + optional 1-letter suffix */
972 	const size_t length = end - start;
973 	switch (length) {
974 		case 6:
975 		case 7:
976 			break;
977 		default:
978 			return false;
979 	}
980 
981 	/* Check that string starts with "lc". The first two characters are loaded as 16-bit little endian word */
982 	const uint16_t expected_lc = load_u16le(start);
983 	if (expected_lc != UINT16_C(0x636C) /* "cl" = reverse("lc") */) {
984 		return false;
985 	}
986 
987 	/* Validate and parse 4-digit model number */
988 	uint32_t model = 0;
989 	for (uint32_t i = 2; i < 6; i++) {
990 		const uint32_t digit = (uint32_t) (uint8_t) start[i] - '0';
991 		if (digit >= 10) {
992 			/* Not really a digit */
993 			return false;
994 		}
995 		model = model * 10 + digit;
996 	}
997 
998 	/* Parse optional suffix letter */
999 	char suffix = 0;
1000 	if (length == 7) {
1001 		const char c = start[6];
1002 		if (is_ascii_alphabetic(c)) {
1003 			/* Convert to uppercase */
1004 			chipset->suffix[0] = c & '\xDF';
1005 		} else {
1006 			/* Invalid suffix character */
1007 			return false;
1008 		}
1009 	}
1010 
1011 	/* Return parsed chipset */
1012 	*chipset = (struct cpuinfo_arm_chipset) {
1013 		.vendor = cpuinfo_arm_chipset_vendor_leadcore,
1014 		.series = cpuinfo_arm_chipset_series_leadcore_lc,
1015 		.model = model,
1016 		.suffix = {
1017 			[0] = suffix,
1018 		},
1019 	};
1020 	return true;
1021 }
1022 
1023 /**
1024  * Tries to match /PXA(\d{3,4}|1L88)$/ signature for Marvell PXA chipsets.
1025  * If match successful, extracts model information into \p chipset argument.
1026  *
1027  * @param start - start of the platform identifier (/proc/cpuinfo Hardware string, ro.product.board or ro.chipname)
1028  *                to match.
1029  * @param end - end of the platform identifier (/proc/cpuinfo Hardaware string, ro.product.board or ro.chipname) to
1030  *              match.
1031  * @param[out] chipset - location where chipset information will be stored upon a successful match.
1032  *
1033  * @returns true if signature matched, false otherwise.
1034  */
match_pxa(const char * start,const char * end,struct cpuinfo_arm_chipset chipset[restrict static1])1035 static bool match_pxa(
1036 	const char* start, const char* end,
1037 	struct cpuinfo_arm_chipset chipset[restrict static 1])
1038 {
1039 	/* Expect 6-7 symbols: "PXA" (3 symbols) + 3-4 digit model number */
1040 	const size_t length = end - start;
1041 	switch (length) {
1042 		case 6:
1043 		case 7:
1044 			break;
1045 		default:
1046 			return false;
1047 	}
1048 
1049 	/* Check that the string starts with "PXA". Symbols 1-3 are loaded and compared as little-endian 16-bit word. */
1050 	if (start[0] != 'P') {
1051 		return false;
1052 	}
1053 	const uint16_t expected_xa = load_u16le(start + 1);
1054 	if (expected_xa != UINT16_C(0x4158) /* "AX" = reverse("XA") */) {
1055 		return false;
1056 	}
1057 
1058 	uint32_t model = 0;
1059 
1060 
1061 	/* Check for a very common typo: "PXA1L88" for "PXA1088" */
1062 	if (length == 7) {
1063 		/* Load 4 model "number" symbols as a little endian 32-bit word and compare to "1L88" */
1064 		const uint32_t expected_1L88 = load_u32le(start + 3);
1065 		if (expected_1L88 == UINT32_C(0x38384C31) /* "88L1" = reverse("1L88") */) {
1066 			model = 1088;
1067 			goto write_chipset;
1068 		}
1069 	}
1070 
1071 	/* Check and parse 3-4 digit model number */
1072 	for (uint32_t i = 3; i < length; i++) {
1073 		const uint32_t digit = (uint32_t) (uint8_t) start[i] - '0';
1074 		if (digit >= 10) {
1075 			/* Not really a digit */
1076 			return false;
1077 		}
1078 		model = model * 10 + digit;
1079 	}
1080 
1081 	/* Return parsed chipset. */
1082 write_chipset:
1083 	*chipset = (struct cpuinfo_arm_chipset) {
1084 		.vendor = cpuinfo_arm_chipset_vendor_marvell,
1085 		.series = cpuinfo_arm_chipset_series_marvell_pxa,
1086 		.model = model,
1087 	};
1088 	return true;
1089 }
1090 
1091 /**
1092  * Tries to match /BCM\d{4}$/ signature for Broadcom BCM chipsets.
1093  * If match successful, extracts model information into \p chipset argument.
1094  *
1095  * @param start - start of the /proc/cpuinfo Hardware string to match.
1096  * @param end - end of the /proc/cpuinfo Hardware string to match.
1097  * @param[out] chipset - location where chipset information will be stored upon a successful match.
1098  *
1099  * @returns true if signature matched, false otherwise.
1100  */
match_bcm(const char * start,const char * end,struct cpuinfo_arm_chipset chipset[restrict static1])1101 static bool match_bcm(
1102 	const char* start, const char* end,
1103 	struct cpuinfo_arm_chipset chipset[restrict static 1])
1104 {
1105 	/* Expect exactly 7 symbols: "BCM" (3 symbols) + 4-digit model number */
1106 	if (start + 7 != end) {
1107 		return false;
1108 	}
1109 
1110 	/* Check that the string starts with "BCM".
1111 	 * The first three characters are loaded and compared as a 24-bit little endian word.
1112 	 */
1113 	const uint32_t expected_bcm = load_u24le(start);
1114 	if (expected_bcm != UINT32_C(0x004D4342) /* "MCB" = reverse("BCM") */) {
1115 		return false;
1116 	}
1117 
1118 	/* Validate and parse 4-digit model number */
1119 	uint32_t model = 0;
1120 	for (uint32_t i = 3; i < 7; i++) {
1121 		const uint32_t digit = (uint32_t) (uint8_t) start[i] - '0';
1122 		if (digit >= 10) {
1123 			/* Not really a digit */
1124 			return false;
1125 		}
1126 		model = model * 10 + digit;
1127 	}
1128 
1129 	/* Return parsed chipset. */
1130 	*chipset = (struct cpuinfo_arm_chipset) {
1131 		.vendor = cpuinfo_arm_chipset_vendor_broadcom,
1132 		.series = cpuinfo_arm_chipset_series_broadcom_bcm,
1133 		.model = model,
1134 	};
1135 	return true;
1136 }
1137 
1138 /**
1139  * Tries to match /OMAP\d{4}$/ signature for Texas Instruments OMAP chipsets.
1140  * If match successful, extracts model information into \p chipset argument.
1141  *
1142  * @param start - start of the /proc/cpuinfo Hardware string to match.
1143  * @param end - end of the /proc/cpuinfo Hardware string to match.
1144  * @param[out] chipset - location where chipset information will be stored upon a successful match.
1145  *
1146  * @returns true if signature matched, false otherwise.
1147  */
match_omap(const char * start,const char * end,struct cpuinfo_arm_chipset chipset[restrict static1])1148 static bool match_omap(
1149 	const char* start, const char* end,
1150 	struct cpuinfo_arm_chipset chipset[restrict static 1])
1151 {
1152 	/* Expect exactly 8 symbols: "OMAP" (4 symbols) + 4-digit model number */
1153 	if (start + 8 != end) {
1154 		return false;
1155 	}
1156 
1157 	/* Check that the string starts with "OMAP". Symbols 0-4 are loaded and compared as little-endian 32-bit word. */
1158 	const uint32_t expected_omap = load_u32le(start);
1159 	if (expected_omap != UINT32_C(0x50414D4F) /* "PAMO" = reverse("OMAP") */) {
1160 		return false;
1161 	}
1162 
1163 	/* Validate and parse 4-digit model number */
1164 	uint32_t model = 0;
1165 	for (uint32_t i = 4; i < 8; i++) {
1166 		const uint32_t digit = (uint32_t) (uint8_t) start[i] - '0';
1167 		if (digit >= 10) {
1168 			/* Not really a digit */
1169 			return false;
1170 		}
1171 		model = model * 10 + digit;
1172 	}
1173 
1174 	/* Return parsed chipset. */
1175 	*chipset = (struct cpuinfo_arm_chipset) {
1176 		.vendor = cpuinfo_arm_chipset_vendor_texas_instruments,
1177 		.series = cpuinfo_arm_chipset_series_texas_instruments_omap,
1178 		.model = model,
1179 	};
1180 	return true;
1181 }
1182 
1183 /**
1184  * Compares platform identifier string to known values for Broadcom chipsets.
1185  * If the string matches one of the known values, the function decodes Broadcom chipset from frequency and number of
1186  * cores into \p chipset argument.
1187  *
1188  * @param start - start of the platform identifier (ro.product.board or ro.board.platform) to match.
1189  * @param end - end of the platform identifier (ro.product.board or ro.board.platform) to match.
1190  * @param cores - number of cores in the chipset.
1191  * @param max_cpu_freq_max - maximum of /sys/devices/system/cpu/cpu<number>/cpofreq/cpu_freq_max values.
1192  * @param[out] chipset - location where chipset information will be stored upon a successful match and decoding.
1193  *
1194  * @returns true if signature matched (even if exact model can't be decoded), false otherwise.
1195  */
match_and_parse_broadcom(const char * start,const char * end,uint32_t cores,uint32_t max_cpu_freq_max,struct cpuinfo_arm_chipset chipset[restrict static1])1196 static bool match_and_parse_broadcom(
1197 	const char* start, const char* end, uint32_t cores, uint32_t max_cpu_freq_max,
1198 	struct cpuinfo_arm_chipset chipset[restrict static 1])
1199 {
1200 	/* Expect 4-6 symbols: "java" (4 symbols), "rhea" (4 symbols), "capri" (5 symbols), or "hawaii" (6 symbols) */
1201 	const size_t length = end - start;
1202 	switch (length) {
1203 		case 4:
1204 		case 5:
1205 		case 6:
1206 			break;
1207 		default:
1208 			return false;
1209 	}
1210 
1211 	/*
1212 	 * Compare the platform identifier to known values for Broadcom chipsets:
1213 	 * - "rhea"
1214 	 * - "java"
1215 	 * - "capri"
1216 	 * - "hawaii"
1217 	 * Upon a successful match, decode chipset name from frequency and number of cores.
1218 	 */
1219 	uint32_t model = 0;
1220 	char suffix = 0;
1221 	const uint32_t expected_platform = load_u32le(start);
1222 	switch (expected_platform) {
1223 		case UINT32_C(0x61656872): /* "aehr" = reverse("rhea") */
1224 			if (length == 4) {
1225 				/*
1226 				 * Detected "rhea" platform:
1227 				 * - 1 core @ 849999 KHz -> BCM21654
1228 				 * - 1 core @ 999999 KHz -> BCM21654G
1229 				 */
1230 				if (cores == 1) {
1231 					model = 21654;
1232 					if (max_cpu_freq_max >= 999999) {
1233 						suffix = 'G';
1234 					}
1235 				}
1236 			}
1237 			break;
1238 		case UINT32_C(0x6176616A): /* "avaj" = reverse("java") */
1239 			if (length == 4) {
1240 				/*
1241 				 * Detected "java" platform:
1242 				 * - 4 cores -> BCM23550
1243 				 */
1244 				if (cores == 4) {
1245 					model = 23550;
1246 				}
1247 			}
1248 			break;
1249 		case UINT32_C(0x61776168): /* "awah" = reverse("hawa") */
1250 			if (length == 6) {
1251 				/* Check that string equals "hawaii" */
1252 				const uint16_t expected_ii = load_u16le(start + 4);
1253 				if (expected_ii == UINT16_C(0x6969) /* "ii" */ ) {
1254 					/*
1255 					 * Detected "hawaii" platform:
1256 					 * - 1 core -> BCM21663
1257 					 * - 2 cores @ 999999 KHz -> BCM21664
1258 					 * - 2 cores @ 1200000 KHz -> BCM21664T
1259 					 */
1260 					switch (cores) {
1261 						case 1:
1262 							model = 21663;
1263 							break;
1264 						case 2:
1265 							model = 21664;
1266 							if (max_cpu_freq_max >= 1200000) {
1267 								suffix = 'T';
1268 							}
1269 							break;
1270 					}
1271 				}
1272 			}
1273 			break;
1274 		case UINT32_C(0x72706163): /* "rpac" = reverse("capr") */
1275 			if (length == 5) {
1276 				/* Check that string equals "capri" */
1277 				if (start[4] == 'i') {
1278 					/*
1279 					 * Detected "capri" platform:
1280 					 * - 2 cores -> BCM28155
1281 					 */
1282 					if (cores == 2) {
1283 						model = 28155;
1284 					}
1285 				}
1286 			}
1287 			break;
1288 	}
1289 
1290 	if (model != 0) {
1291 		/* Chipset was successfully decoded */
1292 		*chipset = (struct cpuinfo_arm_chipset) {
1293 			.vendor = cpuinfo_arm_chipset_vendor_broadcom,
1294 			.series = cpuinfo_arm_chipset_series_broadcom_bcm,
1295 			.model = model,
1296 			.suffix = {
1297 				[0] = suffix,
1298 			},
1299 		};
1300 	}
1301 	return model != 0;
1302 }
1303 
1304 struct sunxi_map_entry {
1305 	uint8_t sunxi;
1306 	uint8_t cores;
1307 	uint8_t model;
1308 	char suffix;
1309 };
1310 
1311 static const struct sunxi_map_entry sunxi_map_entries[] = {
1312 #if CPUINFO_ARCH_ARM
1313 	{
1314 		/* ("sun4i", 1) -> "A10" */
1315 		.sunxi = 4,
1316 		.cores = 1,
1317 		.model = 10,
1318 	},
1319 	{
1320 		/* ("sun5i", 1) -> "A13" */
1321 		.sunxi = 5,
1322 		.cores = 1,
1323 		.model = 13,
1324 	},
1325 	{
1326 		/* ("sun6i", 4) -> "A31" */
1327 		.sunxi = 6,
1328 		.cores = 4,
1329 		.model = 31,
1330 	},
1331 	{
1332 		/* ("sun7i", 2) -> "A20" */
1333 		.sunxi = 7,
1334 		.cores = 2,
1335 		.model = 20,
1336 
1337 	},
1338 	{
1339 		/* ("sun8i", 2) -> "A23" */
1340 		.sunxi = 8,
1341 		.cores = 2,
1342 		.model = 23,
1343 	},
1344 	{
1345 		/* ("sun8i", 4) -> "A33" */
1346 		.sunxi = 8,
1347 		.cores = 4,
1348 		.model = 33,
1349 	},
1350 	{
1351 		/* ("sun8i", 8) -> "A83T" */
1352 		.sunxi = 8,
1353 		.cores = 8,
1354 		.model = 83,
1355 		.suffix = 'T',
1356 	},
1357 	{
1358 		/* ("sun9i", 8) -> "A80" */
1359 		.sunxi = 9,
1360 		.cores = 8,
1361 		.model = 80,
1362 	},
1363 #endif /* CPUINFO_ARCH_ARM */
1364 	{
1365 		/* ("sun50i", 4) -> "A64" */
1366 		.sunxi = 50,
1367 		.cores = 4,
1368 		.model = 64,
1369 	},
1370 };
1371 
1372 /**
1373  * Tries to match /proc/cpuinfo Hardware string to Allwinner /sun\d+i/ signature.
1374  * If the string matches signature, the function decodes Allwinner chipset from the number in the signature and the
1375  * number of cores, and stores it in \p chipset argument.
1376  *
1377  * @param start - start of the /proc/cpuinfo Hardware string to match.
1378  * @param end - end of the /proc/cpuinfo Hardware string to match.
1379  * @param cores - number of cores in the chipset.
1380  * @param[out] chipset - location where chipset information will be stored upon a successful match and decoding.
1381  *
1382  * @returns true if signature matched (even if exact model can't be decoded), false otherwise.
1383  */
match_and_parse_sunxi(const char * start,const char * end,uint32_t cores,struct cpuinfo_arm_chipset chipset[restrict static1])1384 static bool match_and_parse_sunxi(
1385 	const char* start, const char* end, uint32_t cores,
1386 	struct cpuinfo_arm_chipset chipset[restrict static 1])
1387 {
1388 	/* Expect at least 5 symbols: "sun" (3 symbols) + platform id (1-2 digits) + "i" (1 symbol) */
1389 	if (start + 5 > end) {
1390 		return false;
1391 	}
1392 
1393 	/* Compare the first 3 characters to "sun" */
1394 	if (start[0] != 's') {
1395 		return false;
1396 	}
1397 	const uint16_t expected_un = load_u16le(start + 1);
1398 	if (expected_un != UINT16_C(0x6E75) /* "nu" = reverse("un") */) {
1399 		return false;
1400 	}
1401 
1402 	/* Check and parse the first (required) digit of the sunXi platform id */
1403 	uint32_t sunxi_platform = 0;
1404 	{
1405 		const uint32_t digit = (uint32_t) (uint8_t) start[3] - '0';
1406 		if (digit >= 10) {
1407 			/* Not really a digit */
1408 			return false;
1409 		}
1410 		sunxi_platform = digit;
1411 	}
1412 
1413 	/* Parse optional second digit of the sunXi platform id */
1414 	const char* pos = start + 4;
1415 	{
1416 		const uint32_t digit = (uint32_t) (uint8_t) (*pos) - '0';
1417 		if (digit < 10) {
1418 			sunxi_platform = sunxi_platform * 10 + digit;
1419 			if (++pos == end) {
1420 				/* Expected one more character, final 'i' letter */
1421 				return false;
1422 			}
1423 		}
1424 	}
1425 
1426 	/* Validate the final 'i' letter */
1427 	if (*pos != 'i') {
1428 		return false;
1429 	}
1430 
1431 	/* Compare sunXi platform id and number of cores to tabulated values to decode chipset name */
1432 	uint32_t model = 0;
1433 	char suffix = 0;
1434 	for (size_t i = 0; i < CPUINFO_COUNT_OF(sunxi_map_entries); i++) {
1435 		if (sunxi_platform == sunxi_map_entries[i].sunxi && cores == sunxi_map_entries[i].cores) {
1436 			model = sunxi_map_entries[i].model;
1437 			suffix = sunxi_map_entries[i].suffix;
1438 			break;
1439 		}
1440 	}
1441 
1442 	if (model == 0) {
1443 		cpuinfo_log_info("unrecognized %"PRIu32"-core Allwinner sun%"PRIu32" platform", cores, sunxi_platform);
1444 	}
1445 	/* Create chipset name from decoded data */
1446 	*chipset = (struct cpuinfo_arm_chipset) {
1447 		.vendor = cpuinfo_arm_chipset_vendor_allwinner,
1448 		.series = cpuinfo_arm_chipset_series_allwinner_a,
1449 		.model = model,
1450 		.suffix = {
1451 			[0] = suffix,
1452 		},
1453 	};
1454 	return true;
1455 }
1456 
1457 /**
1458  * Compares /proc/cpuinfo Hardware string to "WMT" signature.
1459  * If the string matches signature, the function decodes WonderMedia chipset from frequency and number of cores into
1460  * \p chipset argument.
1461  *
1462  * @param start - start of the /proc/cpuinfo Hardware string to match.
1463  * @param end - end of the /proc/cpuinfo Hardware string to match.
1464  * @param cores - number of cores in the chipset.
1465  * @param max_cpu_freq_max - maximum of /sys/devices/system/cpu/cpu<number>/cpofreq/cpu_freq_max values.
1466  * @param[out] chipset - location where chipset information will be stored upon a successful match and decoding.
1467  *
1468  * @returns true if signature matched (even if exact model can't be decoded), false otherwise.
1469  */
match_and_parse_wmt(const char * start,const char * end,uint32_t cores,uint32_t max_cpu_freq_max,struct cpuinfo_arm_chipset chipset[restrict static1])1470 static bool match_and_parse_wmt(
1471 	const char* start, const char* end, uint32_t cores, uint32_t max_cpu_freq_max,
1472 	struct cpuinfo_arm_chipset chipset[restrict static 1])
1473 {
1474 	/* Expected 3 symbols: "WMT" */
1475 	if (start + 3 != end) {
1476 		return false;
1477 	}
1478 
1479 	/* Compare string to "WMT" */
1480 	if (start[0] != 'W') {
1481 		return false;
1482 	}
1483 	const uint16_t expected_mt = load_u16le(start + 1);
1484 	if (expected_mt != UINT16_C(0x544D) /* "TM" = reverse("MT") */) {
1485 		return false;
1486 	}
1487 
1488 	/* Decode chipset name from frequency and number of cores */
1489 	uint32_t model = 0;
1490 	switch (cores) {
1491 		case 1:
1492 			switch (max_cpu_freq_max) {
1493 				case 1008000:
1494 					/* 1 core @ 1008000 KHz -> WM8950 */
1495 					model = 8950;
1496 					break;
1497 				case 1200000:
1498 					/* 1 core @ 1200000 KHz -> WM8850 */
1499 					model = 8850;
1500 					break;
1501 			}
1502 			break;
1503 		case 2:
1504 			if (max_cpu_freq_max == 1500000) {
1505 				/* 2 cores @ 1500000 KHz -> WM8880 */
1506 				model = 8880;
1507 			}
1508 			break;
1509 	}
1510 
1511 	if (model == 0) {
1512 		cpuinfo_log_info("unrecognized WonderMedia platform with %"PRIu32" cores at %"PRIu32" KHz",
1513 			cores, max_cpu_freq_max);
1514 	}
1515 	*chipset = (struct cpuinfo_arm_chipset) {
1516 		.vendor = cpuinfo_arm_chipset_vendor_wondermedia,
1517 		.series = cpuinfo_arm_chipset_series_wondermedia_wm,
1518 		.model = model,
1519 	};
1520 	return true;
1521 }
1522 
1523 struct huawei_map_entry {
1524 	uint32_t platform;
1525 	uint32_t model;
1526 };
1527 
1528 static const struct huawei_map_entry huawei_platform_map[] = {
1529 	{
1530 		/* "ALP" -> Kirin 970 */
1531 		.platform = UINT32_C(0x00504C41), /* "\0PLA" = reverse("ALP\0") */
1532 		.model = 970,
1533 	},
1534 	{
1535 		/* "BAC" -> Kirin 659 */
1536 		.platform = UINT32_C(0x00434142), /* "\0CAB" = reverse("BAC\0") */
1537 		.model = 659,
1538 	},
1539 	{
1540 		/* "BLA" -> Kirin 970 */
1541 		.platform = UINT32_C(0x00414C42), /* "\0ALB" = reverse("BLA\0") */
1542 		.model = 970,
1543 	},
1544 	{
1545 		/* "BKL" -> Kirin 970 */
1546 		.platform = UINT32_C(0x004C4B42), /* "\0LKB" = reverse("BKL\0") */
1547 		.model = 970,
1548 	},
1549 	{
1550 		/* "CLT" -> Kirin 970 */
1551 		.platform = UINT32_C(0x00544C43), /* "\0TLC" = reverse("CLT\0") */
1552 		.model = 970,
1553 	},
1554 	{
1555 		/* "COL" -> Kirin 970 */
1556 		.platform = UINT32_C(0x004C4F43), /* "\0LOC" = reverse("COL\0") */
1557 		.model = 970,
1558 	},
1559 	{
1560 		/* "COR" -> Kirin 970 */
1561 		.platform = UINT32_C(0x00524F43), /* "\0ROC" = reverse("COR\0") */
1562 		.model = 970,
1563 	},
1564 	{
1565 		/* "DUK" -> Kirin 960 */
1566 		.platform = UINT32_C(0x004B5544), /* "\0KUD" = reverse("DUK\0") */
1567 		.model = 960,
1568 	},
1569 	{
1570 		/* "EML" -> Kirin 970 */
1571 		.platform = UINT32_C(0x004C4D45), /* "\0LME" = reverse("EML\0") */
1572 		.model = 970,
1573 	},
1574 	{
1575 		/* "EVA" -> Kirin 955 */
1576 		.platform = UINT32_C(0x00415645), /* "\0AVE" = reverse("EVA\0") */
1577 		.model = 955,
1578 	},
1579 	{
1580 		/* "FRD" -> Kirin 950 */
1581 		.platform = UINT32_C(0x00445246), /* "\0DRF" = reverse("FRD\0") */
1582 		.model = 950,
1583 	},
1584 	{
1585 		/* "INE" -> Kirin 710 */
1586 		.platform = UINT32_C(0x00454E49), /* "\0ENI" = reverse("INE\0") */
1587 		.model = 710,
1588 	},
1589 	{
1590 		/* "KNT" -> Kirin 950 */
1591 		.platform = UINT32_C(0x00544E4B), /* "\0TNK" = reverse("KNT\0") */
1592 		.model = 950,
1593 	},
1594 	{
1595 		/* "LON" -> Kirin 960 */
1596 		.platform = UINT32_C(0x004E4F4C), /* "\0NOL" = reverse("LON\0") */
1597 		.model = 960,
1598 	},
1599 	{
1600 		/* "LYA" -> Kirin 980 */
1601 		.platform = UINT32_C(0x0041594C), /* "\0AYL" = reverse("LYA\0") */
1602 		.model = 980,
1603 	},
1604 	{
1605 		/* "MCN" -> Kirin 980 */
1606 		.platform = UINT32_C(0x004E434D), /* "\0NCM" = reverse("MCN\0") */
1607 		.model = 980,
1608 	},
1609 	{
1610 		/* "MHA" -> Kirin 960 */
1611 		.platform = UINT32_C(0x0041484D), /* "\0AHM" = reverse("MHA\0") */
1612 		.model = 960,
1613 	},
1614 	{
1615 		/* "NEO" -> Kirin 970 */
1616 		.platform = UINT32_C(0x004F454E), /* "\0OEN" = reverse("NEO\0") */
1617 		.model = 970,
1618 	},
1619 	{
1620 		/* "NXT" -> Kirin 950 */
1621 		.platform = UINT32_C(0x0054584E), /* "\0TXN" = reverse("NXT\0") */
1622 		.model = 950,
1623 	},
1624 	{
1625 		/* "PAN" -> Kirin 980 */
1626 		.platform = UINT32_C(0x004E4150), /* "\0NAP" = reverse("PAN\0") */
1627 		.model = 980,
1628 	},
1629 	{
1630 		/* "PAR" -> Kirin 970 */
1631 		.platform = UINT32_C(0x00524150), /* "\0RAP" = reverse("PAR\0") */
1632 		.model = 970,
1633 	},
1634 	{
1635 		/* "RVL" -> Kirin 970 */
1636 		.platform = UINT32_C(0x004C5652), /* "\0LVR" = reverse("RVL\0") */
1637 		.model = 970,
1638 	},
1639 	{
1640 		/* "STF" -> Kirin 960 */
1641 		.platform = UINT32_C(0x00465453), /* "\0FTS" = reverse("STF\0") */
1642 		.model = 960,
1643 	},
1644 	{
1645 		/* "SUE" -> Kirin 980 */
1646 		.platform = UINT32_C(0x00455553), /* "\0EUS" = reverse("SUE\0") */
1647 		.model = 980,
1648 	},
1649 	{
1650 		/* "VIE" -> Kirin 955 */
1651 		.platform = UINT32_C(0x00454956), /* "\0EIV" = reverse("VIE\0") */
1652 		.model = 955,
1653 	},
1654 	{
1655 		/* "VKY" -> Kirin 960 */
1656 		.platform = UINT32_C(0x00594B56), /* "\0YKV" = reverse("VKY\0") */
1657 		.model = 960,
1658 	},
1659 	{
1660 		/* "VTR" -> Kirin 960 */
1661 		.platform = UINT32_C(0x00525456), /* "\0RTV" = reverse("VTR\0") */
1662 		.model = 960,
1663 	},
1664 };
1665 
1666 /**
1667  * Tries to match ro.product.board string to Huawei /([A-Z]{3})(\-[A-Z]?L\d{2})$/ signature where \1 is one of the
1668  * known values for Huawei devices, which do not report chipset name elsewhere.
1669  * If the string matches signature, the function decodes chipset (always HiSilicon Kirin for matched devices) from
1670  * the Huawei platform ID in the signature and stores it in \p chipset argument.
1671  *
1672  * @param start - start of the ro.product.board string to match.
1673  * @param end - end of the ro.product.board string to match.
1674  * @param[out] chipset - location where chipset information will be stored upon a successful match and decoding.
1675  *
1676  * @returns true if signature matched, false otherwise.
1677  */
match_and_parse_huawei(const char * start,const char * end,struct cpuinfo_arm_chipset chipset[restrict static1])1678 static bool match_and_parse_huawei(
1679 	const char* start, const char* end,
1680 	struct cpuinfo_arm_chipset chipset[restrict static 1])
1681 {
1682 	/*
1683 	 * Expect length of either 3, 7 or 8, exactly:
1684 	 * - 3-letter platform identifier (see huawei_platform_map)
1685 	 * - 3-letter platform identifier + '-' + 'L' + two digits
1686 	 * - 3-letter platform identifier + '-' + capital letter + 'L' + two digits
1687 	 */
1688 	const size_t length = end - start;
1689 	switch (length) {
1690 		case 3:
1691 		case 7:
1692 		case 8:
1693 			break;
1694 		default:
1695 			return false;
1696 	}
1697 
1698 	/*
1699 	 * Try to find the first three-letter substring in among the tabulated entries for Huawei devices.
1700 	 * The first three letters are loaded and compared as a little-endian 24-bit word.
1701 	 */
1702 	uint32_t model = 0;
1703 	const uint32_t target_platform_id = load_u24le(start);
1704 	for (uint32_t i = 0; i < CPUINFO_COUNT_OF(huawei_platform_map); i++) {
1705 		if (huawei_platform_map[i].platform == target_platform_id) {
1706 			model = huawei_platform_map[i].model;
1707 			break;
1708 		}
1709 	}
1710 
1711 	if (model == 0) {
1712 		/* Platform does not match the tabulated Huawei entries */
1713 		return false;
1714 	}
1715 
1716 	if (length > 3) {
1717 		/*
1718 		 * Check that:
1719 		 * - The symbol after platform id is a dash
1720 		 * - The symbol after it is an uppercase letter. For 7-symbol strings, the symbol is just 'L'.
1721 		 */
1722 		if (start[3] != '-' || !is_ascii_alphabetic_uppercase(start[4])) {
1723 			return false;
1724 		}
1725 
1726 		/* Check that the last 3 entries are /L\d\d/ */
1727 		if (end[-3] != 'L' || !is_ascii_numeric(end[-2]) || !is_ascii_numeric(end[-1])) {
1728 			return false;
1729 		}
1730 	}
1731 
1732 	/* All checks succeeded, commit chipset name */
1733 	*chipset = (struct cpuinfo_arm_chipset) {
1734 		.vendor = cpuinfo_arm_chipset_vendor_hisilicon,
1735 		.series = cpuinfo_arm_chipset_series_hisilicon_kirin,
1736 		.model = model,
1737 	};
1738 	return true;
1739 }
1740 
1741 /**
1742  * Tries to match /tcc\d{3}x$/ signature for Telechips TCCXXXx chipsets.
1743  * If match successful, extracts model information into \p chipset argument.
1744  *
1745  * @param start - start of the /proc/cpuinfo Hardware string to match.
1746  * @param end - end of the /proc/cpuinfo Hardware string to match.
1747  * @param[out] chipset - location where chipset information will be stored upon a successful match.
1748  *
1749  * @returns true if signature matched, false otherwise.
1750  */
match_tcc(const char * start,const char * end,struct cpuinfo_arm_chipset chipset[restrict static1])1751 static bool match_tcc(
1752 	const char* start, const char* end,
1753 	struct cpuinfo_arm_chipset chipset[restrict static 1])
1754 {
1755 	/* Expect exactly 7 symbols: "tcc" (3 symbols) + 3-digit model number + fixed "x" suffix */
1756 	if (start + 7 != end) {
1757 		return false;
1758 	}
1759 
1760 	/* Quick check for the first character */
1761 	if (start[0] != 't') {
1762 		return false;
1763 	}
1764 
1765 	/* Load the next 2 bytes as little endian 16-bit word */
1766 	const uint16_t expected_cc = load_u16le(start + 1);
1767 	if (expected_cc != UINT16_C(0x6363) /* "cc" */ ) {
1768 		return false;
1769 	}
1770 
1771 	/* Check and parse 3-digit model number */
1772 	uint32_t model = 0;
1773 	for (uint32_t i = 3; i < 6; i++) {
1774 		const uint32_t digit = (uint32_t) (uint8_t) start[i] - '0';
1775 		if (digit >= 10) {
1776 			/* Not really a digit */
1777 			return false;
1778 		}
1779 		model = model * 10 + digit;
1780 	}
1781 
1782 	/* Check the fixed 'x' suffix in the end */
1783 	if (start[6] != 'x') {
1784 		return false;
1785 	}
1786 
1787 	/* Commit parsed chipset. */
1788 	*chipset = (struct cpuinfo_arm_chipset) {
1789 		.vendor = cpuinfo_arm_chipset_vendor_telechips,
1790 		.series = cpuinfo_arm_chipset_series_telechips_tcc,
1791 		.model = model,
1792 		.suffix = {
1793 			[0] = 'X'
1794 		},
1795 	};
1796 	return true;
1797 }
1798 
1799 /*
1800  * Compares ro.board.platform string to Nvidia Tegra signatures ("tegra" and "tegra3")
1801  * This check has effect on how /proc/cpuinfo Hardware string is interpreted.
1802  *
1803  * @param start - start of the ro.board.platform string to check.
1804  * @param end - end of the ro.board.platform string to check.
1805  *
1806  * @returns true if the string matches an Nvidia Tegra signature, and false otherwise
1807  */
is_tegra(const char * start,const char * end)1808 static bool is_tegra(const char* start, const char* end) {
1809 	/* Expect 5 ("tegra") or 6 ("tegra3") symbols */
1810 	const size_t length = end - start;
1811 	switch (length) {
1812 		case 5:
1813 		case 6:
1814 			break;
1815 		default:
1816 			return false;
1817 	}
1818 
1819 	/* Check that the first 5 characters match "tegra" */
1820 	if (start[0] != 't') {
1821 		return false;
1822 	}
1823 	const uint32_t expected_egra = load_u32le(start + 1);
1824 	if (expected_egra != UINT32_C(0x61726765) /* "arge" = reverse("egra") */) {
1825 		return false;
1826 	}
1827 
1828 	/* Check if the string is either "tegra" (length = 5) or "tegra3" (length != 5) and last character is '3' */
1829 	return (length == 5 || start[5] == '3');
1830 }
1831 
1832 static const struct special_map_entry special_hardware_map_entries[] = {
1833 #if CPUINFO_ARCH_ARM
1834 	{
1835 		/* "k3v2oem1" -> HiSilicon K3V2 */
1836 		.platform = "k3v2oem1",
1837 		.series = cpuinfo_arm_chipset_series_hisilicon_k3v,
1838 		.model = 2,
1839 	},
1840 	{
1841 		/* "hi6620oem" -> HiSilicon Kirin 910T */
1842 		.platform = "hi6620oem",
1843 		.series = cpuinfo_arm_chipset_series_hisilicon_kirin,
1844 		.model = 910,
1845 		.suffix = 'T'
1846 	},
1847 #endif /* CPUINFO_ARCH_ARM */
1848 	{
1849 		/* "hi6250" -> HiSilicon Kirin 650 */
1850 		.platform = "hi6250",
1851 		.series = cpuinfo_arm_chipset_series_hisilicon_kirin,
1852 		.model = 650,
1853 	},
1854 	{
1855 		/* "hi6210sft" -> HiSilicon Kirin 620 */
1856 		.platform = "hi6210sft",
1857 		.series = cpuinfo_arm_chipset_series_hisilicon_kirin,
1858 		.model = 620,
1859 	},
1860 	{
1861 		/* "hi3751" -> HiSilicon Hi3751 */
1862 		.platform = "hi3751",
1863 		.series = cpuinfo_arm_chipset_series_hisilicon_hi,
1864 		.model = 3751,
1865 	},
1866 #if CPUINFO_ARCH_ARM
1867 	{
1868 		/* "hi3630" -> HiSilicon Kirin 920 */
1869 		.platform = "hi3630",
1870 		.series = cpuinfo_arm_chipset_series_hisilicon_kirin,
1871 		.model = 920,
1872 	},
1873 #endif /* CPUINFO_ARCH_ARM */
1874 	{
1875 		/* "hi3635" -> HiSilicon Kirin 930 */
1876 		.platform = "hi3635",
1877 		.series = cpuinfo_arm_chipset_series_hisilicon_kirin,
1878 		.model = 930,
1879 	},
1880 #if CPUINFO_ARCH_ARM
1881 	{
1882 		/* "gs702a" -> Actions ATM7029 (Cortex-A5 + GC1000) */
1883 		.platform = "gs702a",
1884 		.series = cpuinfo_arm_chipset_series_actions_atm,
1885 		.model = 7029,
1886 	},
1887 	{
1888 		/* "gs702c" -> Actions ATM7029B (Cortex-A5 + SGX540) */
1889 		.platform = "gs702c",
1890 		.series = cpuinfo_arm_chipset_series_actions_atm,
1891 		.model = 7029,
1892 		.suffix = 'B',
1893 	},
1894 	{
1895 		/* "gs703d" -> Actions ATM7039S */
1896 		.platform = "gs703d",
1897 		.series = cpuinfo_arm_chipset_series_actions_atm,
1898 		.model = 7039,
1899 		.suffix = 'S',
1900 	},
1901 	{
1902 		/* "gs705a" -> Actions ATM7059A */
1903 		.platform = "gs705a",
1904 		.series = cpuinfo_arm_chipset_series_actions_atm,
1905 		.model = 7059,
1906 		.suffix = 'A',
1907 	},
1908 	{
1909 		/* "Amlogic Meson8" -> Amlogic S812 */
1910 		.platform = "Amlogic Meson8",
1911 		.series = cpuinfo_arm_chipset_series_amlogic_s,
1912 		.model = 812,
1913 	},
1914 	{
1915 		/* "Amlogic Meson8B" -> Amlogic S805 */
1916 		.platform = "Amlogic Meson8B",
1917 		.series = cpuinfo_arm_chipset_series_amlogic_s,
1918 		.model = 805,
1919 	},
1920 	{
1921 		/* "mapphone_CDMA" -> Texas Instruments OMAP4430 */
1922 		.platform = "mapphone_CDMA",
1923 		.series = cpuinfo_arm_chipset_series_texas_instruments_omap,
1924 		.model = 4430,
1925 	},
1926 	{
1927 		/* "Superior" -> Texas Instruments OMAP4470 */
1928 		.platform = "Superior",
1929 		.series = cpuinfo_arm_chipset_series_texas_instruments_omap,
1930 		.model = 4470,
1931 	},
1932 	{
1933 		/* "Tuna" (Samsung Galaxy Nexus) -> Texas Instruments OMAP4460 */
1934 		.platform = "Tuna",
1935 		.series = cpuinfo_arm_chipset_series_texas_instruments_omap,
1936 		.model = 4460,
1937 	},
1938 	{
1939 		/* "Manta" (Samsung Nexus 10) -> Samsung Exynos 5250 */
1940 		.platform = "Manta",
1941 		.series = cpuinfo_arm_chipset_series_samsung_exynos,
1942 		.model = 5250,
1943 	},
1944 	{
1945 		/* "Odin" -> LG Nuclun 7111 */
1946 		.platform = "Odin",
1947 		.series = cpuinfo_arm_chipset_series_lg_nuclun,
1948 		.model = 7111,
1949 	},
1950 	{
1951 		/* "Madison" -> MStar 6A338 */
1952 		.platform = "Madison",
1953 		.series = cpuinfo_arm_chipset_series_mstar_6a,
1954 		.model = 338,
1955 	},
1956 #endif /* CPUINFO_ARCH_ARM */
1957 };
1958 
1959 static const struct special_map_entry tegra_hardware_map_entries[] = {
1960 #if CPUINFO_ARCH_ARM
1961 	{
1962 		/* "cardhu" (Nvidia Cardhu developer tablet) -> Tegra T30 */
1963 		.platform = "cardhu",
1964 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1965 		.model = 30,
1966 	},
1967 	{
1968 		/* "kai" -> Tegra T30L */
1969 		.platform = "kai",
1970 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1971 		.model = 30,
1972 		.suffix = 'L',
1973 	},
1974 	{
1975 		/* "p3" (Samsung Galaxy Tab 8.9) -> Tegra T20 */
1976 		.platform = "p3",
1977 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1978 		.model = 20,
1979 	},
1980 	{
1981 		/* "n1" (Samsung Galaxy R / Samsung Captivate Glide) -> Tegra AP20H */
1982 		.platform = "n1",
1983 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_ap,
1984 		.model = 20,
1985 		.suffix = 'H',
1986 	},
1987 	{
1988 		/* "SHW-M380S" (Samsung Galaxy Tab 10.1) -> Tegra T20 */
1989 		.platform = "SHW-M380S",
1990 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1991 		.model = 20,
1992 	},
1993 	{
1994 		/* "m470" (Hisense Sero 7 Pro) -> Tegra T30L */
1995 		.platform = "m470",
1996 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1997 		.model = 30,
1998 		.suffix = 'L',
1999 	},
2000 	{
2001 		/* "endeavoru" (HTC One X) -> Tegra AP33 */
2002 		.platform = "endeavoru",
2003 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_ap,
2004 		.model = 33,
2005 	},
2006 	{
2007 		/* "evitareul" (HTC One X+) -> Tegra T33 */
2008 		.platform = "evitareul",
2009 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2010 		.model = 33,
2011 	},
2012 	{
2013 		/* "enrc2b" (HTC One X+) -> Tegra T33 */
2014 		.platform = "enrc2b",
2015 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2016 		.model = 33,
2017 	},
2018 	{
2019 		/* "mozart" (Asus Transformer Pad TF701T) -> Tegra T114 */
2020 		.platform = "mozart",
2021 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2022 		.model = 114,
2023 	},
2024 	{
2025 		/* "tegratab" (Tegra Note 7) -> Tegra T114 */
2026 		.platform = "tegratab",
2027 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2028 		.model = 114,
2029 	},
2030 	{
2031 		/* "tn8" (Nvidia Shield Tablet K1) -> Tegra T124 */
2032 		.platform = "tn8",
2033 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2034 		.model = 124,
2035 	},
2036 	{
2037 		/* "roth" (Nvidia Shield Portable) -> Tegra T114 */
2038 		.platform = "roth",
2039 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2040 		.model = 114,
2041 	},
2042 	{
2043 		/* "pisces" (Xiaomi Mi 3) -> Tegra T114 */
2044 		.platform = "pisces",
2045 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2046 		.model = 114,
2047 	},
2048 	{
2049 		/* "mocha" (Xiaomi Mi Pad) -> Tegra T124 */
2050 		.platform = "mocha",
2051 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2052 		.model = 124,
2053 	},
2054 	{
2055 		/* "stingray" (Motorola XOOM) -> Tegra AP20H */
2056 		.platform = "stingray",
2057 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_ap,
2058 		.model = 20,
2059 		.suffix = 'H',
2060 	},
2061 	{
2062 		/* "Ceres" (Wiko Highway 4G) -> Tegra SL460N */
2063 		.platform = "Ceres",
2064 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_sl,
2065 		.model = 460,
2066 		.suffix = 'N',
2067 	},
2068 	{
2069 		/* "MT799" (nabi 2 Tablet) -> Tegra T30 */
2070 		.platform = "MT799",
2071 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2072 		.model = 30,
2073 	},
2074 	{
2075 		/* "t8400n" (nabi DreamTab HD8) -> Tegra T114 */
2076 		.platform = "t8400n",
2077 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2078 		.model = 114,
2079 	},
2080 	{
2081 		/* "chagall" (Fujitsu Stylistic M532) -> Tegra T30 */
2082 		.platform = "chagall",
2083 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2084 		.model = 30,
2085 	},
2086 	{
2087 		/* "ventana" (Asus Transformer TF101) -> Tegra T20 */
2088 		.platform = "ventana",
2089 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2090 		.model = 20,
2091 	},
2092 	{
2093 		/* "bobsleigh" (Fujitsu Arrows Tab F-05E) -> Tegra T33 */
2094 		.platform = "bobsleigh",
2095 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2096 		.model = 33,
2097 	},
2098 	{
2099 		/* "tegra_fjdev101" (Fujitsu Arrows X F-10D) -> Tegra AP33 */
2100 		.platform = "tegra_fjdev101",
2101 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_ap,
2102 		.model = 33,
2103 	},
2104 	{
2105 		/* "tegra_fjdev103" (Fujitsu Arrows V F-04E) -> Tegra T33 */
2106 		.platform = "tegra_fjdev103",
2107 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2108 		.model = 33,
2109 	},
2110 	{
2111 		/* "nbx03" (Sony Tablet S) -> Tegra T20 */
2112 		.platform = "nbx03",
2113 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2114 		.model = 20,
2115 	},
2116 	{
2117 		/* "txs03" (Sony Xperia Tablet S) -> Tegra T30L */
2118 		.platform = "txs03",
2119 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2120 		.model = 30,
2121 		.suffix = 'L',
2122 	},
2123 	{
2124 		/* "x3" (LG Optimus 4X HD P880) -> Tegra AP33 */
2125 		.platform = "x3",
2126 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_ap,
2127 		.model = 33,
2128 	},
2129 	{
2130 		/* "vu10" (LG Optimus Vu P895) -> Tegra AP33 */
2131 		.platform = "vu10",
2132 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_ap,
2133 		.model = 33,
2134 	},
2135 	{
2136 		/* "BIRCH" (HP Slate 7 Plus) -> Tegra T30L */
2137 		.platform = "BIRCH",
2138 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2139 		.model = 30,
2140 		.suffix = 'L',
2141 	},
2142 	{
2143 		/* "macallan" (HP Slate 8 Pro) -> Tegra T114 */
2144 		.platform = "macallan",
2145 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2146 		.model = 114,
2147 	},
2148 	{
2149 		/* "maya" (HP SlateBook 10 x2) -> Tegra T114 */
2150 		.platform = "maya",
2151 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2152 		.model = 114,
2153 	},
2154 	{
2155 		/* "antares" (Toshiba AT100) -> Tegra T20 */
2156 		.platform = "antares",
2157 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2158 		.model = 20,
2159 	},
2160 	{
2161 		/* "tostab12AL" (Toshiba AT300SE "Excite 10 SE") -> Tegra T30L */
2162 		.platform = "tostab12AL",
2163 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2164 		.model = 30,
2165 		.suffix = 'L',
2166 	},
2167 	{
2168 		/* "tostab12BL" (Toshiba AT10-A "Excite Pure") -> Tegra T30L */
2169 		.platform = "tostab12BL",
2170 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2171 		.model = 30,
2172 		.suffix = 'L',
2173 	},
2174 	{
2175 		/* "sphinx" (Toshiba AT270 "Excite 7.7") -> Tegra T30 */
2176 		.platform = "sphinx",
2177 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2178 		.model = 30,
2179 	},
2180 	{
2181 		/* "tostab11BS" (Toshiba AT570 "Regza 7.7") -> Tegra T30 */
2182 		.platform = "tostab11BS",
2183 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2184 		.model = 30,
2185 	},
2186 	{
2187 		/* "tostab12BA" (Toshiba AT10-LE-A "Excite Pro") -> Tegra T114 */
2188 		.platform = "tostab12BA",
2189 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2190 		.model = 114,
2191 	},
2192 	{
2193 		/* "vangogh" (Acer Iconia Tab A100) -> Tegra T20 */
2194 		.platform = "vangogh",
2195 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2196 		.model = 20,
2197 	},
2198 	{
2199 		/* "a110" (Acer Iconia Tab A110) -> Tegra T30L */
2200 		.platform = "a110",
2201 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2202 		.model = 30,
2203 		.suffix = 'L',
2204 	},
2205 	{
2206 		/* "picasso_e" (Acer Iconia Tab A200) -> Tegra AP20H */
2207 		.platform = "picasso_e",
2208 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_ap,
2209 		.model = 20,
2210 		.suffix = 'H',
2211 	},
2212 	{
2213 		/* "picasso_e2" (Acer Iconia Tab A210) -> Tegra T30L */
2214 		.platform = "picasso_e2",
2215 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2216 		.model = 30,
2217 		.suffix = 'L',
2218 	},
2219 	{
2220 		/* "picasso" (Acer Iconia Tab A500) -> Tegra AP20H */
2221 		.platform = "picasso",
2222 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_ap,
2223 		.model = 20,
2224 		.suffix = 'H',
2225 	},
2226 	{
2227 		/* "picasso_m" (Acer Iconia Tab A510) -> Tegra T30 */
2228 		.platform = "picasso_m",
2229 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2230 		.model = 30,
2231 	},
2232 	{
2233 		/* "picasso_mf" (Acer Iconia Tab A700) -> Tegra T30 */
2234 		.platform = "picasso_mf",
2235 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2236 		.model = 30,
2237 	},
2238 	{
2239 		/* "avalon" (Toshiba AT300 "Excite 10") -> Tegra T30L */
2240 		.platform = "avalon",
2241 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2242 		.model = 30,
2243 		.suffix = 'L',
2244 	},
2245 	{
2246 		/* "NS_14T004" (iRiver NS-14T004) -> Tegra T30L */
2247 		.platform = "NS_14T004",
2248 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2249 		.model = 30,
2250 		.suffix = 'L',
2251 	},
2252 	{
2253 		/* "WIKIPAD" (Wikipad) -> Tegra T30 */
2254 		.platform = "WIKIPAD",
2255 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2256 		.model = 30,
2257 	},
2258 	{
2259 		/* "kb" (Pegatron Q00Q) -> Tegra T114 */
2260 		.platform = "kb",
2261 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2262 		.model = 114,
2263 	},
2264 #endif /* CPUINFO_ARCH_ARM */
2265 	{
2266 		/* "foster_e" (Nvidia Shield TV, Flash) -> Tegra T210 */
2267 		.platform = "foster_e",
2268 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2269 		.model = 210,
2270 	},
2271 	{
2272 		/* "foster_e_hdd" (Nvidia Shield TV, HDD) -> Tegra T210 */
2273 		.platform = "foster_e_hdd",
2274 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2275 		.model = 210,
2276 	},
2277 	{
2278 		/* "darcy" (Nvidia Shield TV 2017) -> Tegra T210 */
2279 		.platform = "darcy",
2280 		.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2281 		.model = 210,
2282 	},
2283 };
2284 
2285 /*
2286  * Decodes chipset name from /proc/cpuinfo Hardware string.
2287  * For some chipsets, the function relies frequency and on number of cores for chipset detection.
2288  *
2289  * @param[in] platform - /proc/cpuinfo Hardware string.
2290  * @param cores - number of cores in the chipset.
2291  * @param max_cpu_freq_max - maximum of /sys/devices/system/cpu/cpu<number>/cpofreq/cpu_freq_max values.
2292  *
2293  * @returns Decoded chipset name. If chipset could not be decoded, the resulting structure would use `unknown` vendor
2294  *          and series identifiers.
2295  */
cpuinfo_arm_linux_decode_chipset_from_proc_cpuinfo_hardware(const char hardware[restrict static CPUINFO_HARDWARE_VALUE_MAX],uint32_t cores,uint32_t max_cpu_freq_max,bool is_tegra)2296 struct cpuinfo_arm_chipset cpuinfo_arm_linux_decode_chipset_from_proc_cpuinfo_hardware(
2297 	const char hardware[restrict static CPUINFO_HARDWARE_VALUE_MAX],
2298 	uint32_t cores, uint32_t max_cpu_freq_max, bool is_tegra)
2299 {
2300 	struct cpuinfo_arm_chipset chipset;
2301 	const size_t hardware_length = strnlen(hardware, CPUINFO_HARDWARE_VALUE_MAX);
2302 	const char* hardware_end = hardware + hardware_length;
2303 
2304 	if (is_tegra) {
2305 		/*
2306 		 * Nvidia Tegra-specific path: compare /proc/cpuinfo Hardware string to
2307 		 * tabulated Hardware values for popular chipsets/devices with Tegra chipsets.
2308 		 * This path is only used when ro.board.platform indicates a Tegra chipset
2309 		 * (albeit does not indicate which exactly Tegra chipset).
2310 		 */
2311 		for (size_t i = 0; i < CPUINFO_COUNT_OF(tegra_hardware_map_entries); i++) {
2312 			if (strncmp(tegra_hardware_map_entries[i].platform, hardware, hardware_length) == 0 &&
2313 					tegra_hardware_map_entries[i].platform[hardware_length] == 0)
2314 			{
2315 				cpuinfo_log_debug(
2316 					"found /proc/cpuinfo Hardware string \"%.*s\" in Nvidia Tegra chipset table",
2317 					(int) hardware_length, hardware);
2318 				/* Create chipset name from entry */
2319 				return (struct cpuinfo_arm_chipset) {
2320 					.vendor = chipset_series_vendor[tegra_hardware_map_entries[i].series],
2321 					.series = (enum cpuinfo_arm_chipset_series) tegra_hardware_map_entries[i].series,
2322 					.model = tegra_hardware_map_entries[i].model,
2323 					.suffix = {
2324 						[0] = tegra_hardware_map_entries[i].suffix,
2325 					},
2326 				};
2327 			}
2328 		}
2329 	} else {
2330 		/* Generic path: consider all other vendors */
2331 
2332 		bool word_start = true;
2333 		for (const char* pos = hardware; pos != hardware_end; pos++) {
2334 			const char c = *pos;
2335 			switch (c) {
2336 				case ' ':
2337 				case '\t':
2338 				case ',':
2339 					word_start = true;
2340 					break;
2341 				default:
2342 					if (word_start && is_ascii_alphabetic(c)) {
2343 						/* Check Qualcomm MSM/APQ signature */
2344 						if (match_msm_apq(pos, hardware_end, &chipset)) {
2345 							cpuinfo_log_debug(
2346 								"matched Qualcomm MSM/APQ signature in /proc/cpuinfo Hardware string \"%.*s\"",
2347 								(int) hardware_length, hardware);
2348 							return chipset;
2349 						}
2350 
2351 						/* Check SDMxxx (Qualcomm Snapdragon) signature */
2352 						if (match_sdm(pos, hardware_end, &chipset)) {
2353 							cpuinfo_log_debug(
2354 								"matched Qualcomm SDM signature in /proc/cpuinfo Hardware string \"%.*s\"",
2355 								(int) hardware_length, hardware);
2356 							return chipset;
2357 						}
2358 
2359 						/* Check SMxxxx (Qualcomm Snapdragon) signature */
2360 						if (match_sm(pos, hardware_end, &chipset)) {
2361 							cpuinfo_log_debug(
2362 								"matched Qualcomm SM signature in /proc/cpuinfo Hardware string \"%.*s\"",
2363 								(int) hardware_length, hardware);
2364 							return chipset;
2365 						}
2366 
2367 						/* Check MediaTek MT signature */
2368 						if (match_mt(pos, hardware_end, true, &chipset)) {
2369 							cpuinfo_log_debug(
2370 								"matched MediaTek MT signature in /proc/cpuinfo Hardware string \"%.*s\"",
2371 								(int) hardware_length, hardware);
2372 							return chipset;
2373 						}
2374 
2375 						/* Check HiSilicon Kirin signature */
2376 						if (match_kirin(pos, hardware_end, &chipset)) {
2377 							cpuinfo_log_debug(
2378 								"matched HiSilicon Kirin signature in /proc/cpuinfo Hardware string \"%.*s\"",
2379 								(int) hardware_length, hardware);
2380 							return chipset;
2381 						}
2382 
2383 						/* Check Rockchip RK signature */
2384 						if (match_rk(pos, hardware_end, &chipset)) {
2385 							cpuinfo_log_debug(
2386 								"matched Rockchip RK signature in /proc/cpuinfo Hardware string \"%.*s\"",
2387 								(int) hardware_length, hardware);
2388 							return chipset;
2389 						}
2390 
2391 						if (match_qualcomm_special(pos, hardware_end, &chipset)) {
2392 							cpuinfo_log_debug(
2393 									"matched Qualcomm signature in /proc/cpuinfo Hardware string \"%.*s\"",
2394 									(int) hardware_length, hardware);
2395 							return chipset;
2396 						}
2397 
2398 					}
2399 					word_start = false;
2400 					break;
2401 			}
2402 		}
2403 
2404 		/* Check Samsung Exynos signature */
2405 		if (match_samsung_exynos(hardware, hardware_end, &chipset)) {
2406 			cpuinfo_log_debug(
2407 				"matched Samsung Exynos signature in /proc/cpuinfo Hardware string \"%.*s\"",
2408 				(int) hardware_length, hardware);
2409 			return chipset;
2410 		}
2411 
2412 		/* Check universalXXXX (Samsung Exynos) signature */
2413 		if (match_universal(hardware, hardware_end, &chipset)) {
2414 			cpuinfo_log_debug(
2415 				"matched UNIVERSAL (Samsung Exynos) signature in /proc/cpuinfo Hardware string \"%.*s\"",
2416 				(int) hardware_length, hardware);
2417 			return chipset;
2418 		}
2419 
2420 		#if CPUINFO_ARCH_ARM
2421 			/* Match /SMDK(4410|4x12)$/ */
2422 			if (match_and_parse_smdk(hardware, hardware_end, cores, &chipset)) {
2423 				cpuinfo_log_debug(
2424 					"matched SMDK (Samsung Exynos) signature in /proc/cpuinfo Hardware string \"%.*s\"",
2425 					(int) hardware_length, hardware);
2426 				return chipset;
2427 			}
2428 		#endif
2429 
2430 		/* Check Spreadtrum SC signature */
2431 		if (match_sc(hardware, hardware_end, &chipset)) {
2432 			cpuinfo_log_debug(
2433 				"matched Spreadtrum SC signature in /proc/cpuinfo Hardware string \"%.*s\"",
2434 				(int) hardware_length, hardware);
2435 			return chipset;
2436 		}
2437 
2438 		#if CPUINFO_ARCH_ARM
2439 			/* Check Marvell PXA signature */
2440 			if (match_pxa(hardware, hardware_end, &chipset)) {
2441 				cpuinfo_log_debug(
2442 					"matched Marvell PXA signature in /proc/cpuinfo Hardware string \"%.*s\"",
2443 					(int) hardware_length, hardware);
2444 				return chipset;
2445 			}
2446 		#endif
2447 
2448 		/* Match /sun\d+i/ signature and map to Allwinner chipset name */
2449 		if (match_and_parse_sunxi(hardware, hardware_end, cores, &chipset)) {
2450 			cpuinfo_log_debug(
2451 				"matched sunxi (Allwinner Ax) signature in /proc/cpuinfo Hardware string \"%.*s\"",
2452 				(int) hardware_length, hardware);
2453 			return chipset;
2454 		}
2455 
2456 		/* Check Broadcom BCM signature */
2457 		if (match_bcm(hardware, hardware_end, &chipset)) {
2458 			cpuinfo_log_debug(
2459 				"matched Broadcom BCM signature in /proc/cpuinfo Hardware string \"%.*s\"",
2460 				(int) hardware_length, hardware);
2461 			return chipset;
2462 		}
2463 
2464 		#if CPUINFO_ARCH_ARM
2465 			/* Check Texas Instruments OMAP signature */
2466 			if (match_omap(hardware, hardware_end, &chipset)) {
2467 				cpuinfo_log_debug(
2468 					"matched Texas Instruments OMAP signature in /proc/cpuinfo Hardware string \"%.*s\"",
2469 					(int) hardware_length, hardware);
2470 				return chipset;
2471 			}
2472 
2473 			/* Check WonderMedia WMT signature and decode chipset from frequency and number of cores  */
2474 			if (match_and_parse_wmt(hardware, hardware_end, cores, max_cpu_freq_max, &chipset)) {
2475 				cpuinfo_log_debug(
2476 					"matched WonderMedia WMT signature in /proc/cpuinfo Hardware string \"%.*s\"",
2477 					(int) hardware_length, hardware);
2478 				return chipset;
2479 			}
2480 
2481 		#endif
2482 
2483 		/* Check Telechips TCC signature */
2484 		if (match_tcc(hardware, hardware_end, &chipset)) {
2485 			cpuinfo_log_debug(
2486 				"matched Telechips TCC signature in /proc/cpuinfo Hardware string \"%.*s\"",
2487 				(int) hardware_length, hardware);
2488 			return chipset;
2489 		}
2490 
2491 		/* Compare to tabulated Hardware values for popular chipsets/devices which can't be otherwise detected */
2492 		for (size_t i = 0; i < CPUINFO_COUNT_OF(special_hardware_map_entries); i++) {
2493 			if (strncmp(special_hardware_map_entries[i].platform, hardware, hardware_length) == 0 &&
2494 					special_hardware_map_entries[i].platform[hardware_length] == 0)
2495 			{
2496 				cpuinfo_log_debug(
2497 					"found /proc/cpuinfo Hardware string \"%.*s\" in special chipset table",
2498 					(int) hardware_length, hardware);
2499 				/* Create chipset name from entry */
2500 				return (struct cpuinfo_arm_chipset) {
2501 					.vendor = chipset_series_vendor[special_hardware_map_entries[i].series],
2502 					.series = (enum cpuinfo_arm_chipset_series) special_hardware_map_entries[i].series,
2503 					.model = special_hardware_map_entries[i].model,
2504 					.suffix = {
2505 						[0] = special_hardware_map_entries[i].suffix,
2506 					},
2507 				};
2508 			}
2509 		}
2510 	}
2511 
2512 	return (struct cpuinfo_arm_chipset) {
2513 		.vendor = cpuinfo_arm_chipset_vendor_unknown,
2514 		.series = cpuinfo_arm_chipset_series_unknown,
2515 	};
2516 }
2517 
2518 #ifdef __ANDROID__
2519 	static const struct special_map_entry special_board_map_entries[] = {
2520 		{
2521 			/* "hi6250" -> HiSilicon Kirin 650 */
2522 			.platform = "hi6250",
2523 			.series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2524 			.model = 650,
2525 		},
2526 		{
2527 			/* "hi6210sft" -> HiSilicon Kirin 620 */
2528 			.platform = "hi6210sft",
2529 			.series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2530 			.model = 620,
2531 		},
2532 #if CPUINFO_ARCH_ARM
2533 		{
2534 			/* "hi3630" -> HiSilicon Kirin 920 */
2535 			.platform = "hi3630",
2536 			.series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2537 			.model = 920,
2538 		},
2539 #endif /* CPUINFO_ARCH_ARM */
2540 		{
2541 			/* "hi3635" -> HiSilicon Kirin 930 */
2542 			.platform = "hi3635",
2543 			.series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2544 			.model = 930,
2545 		},
2546 		{
2547 			/* "hi3650" -> HiSilicon Kirin 950 */
2548 			.platform = "hi3650",
2549 			.series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2550 			.model = 950,
2551 		},
2552 		{
2553 			/* "hi3660" -> HiSilicon Kirin 960 */
2554 			.platform = "hi3660",
2555 			.series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2556 			.model = 960,
2557 		},
2558 #if CPUINFO_ARCH_ARM
2559 		{
2560 			/* "mp523x" -> Renesas MP5232 */
2561 			.platform = "mp523x",
2562 			.series = cpuinfo_arm_chipset_series_renesas_mp,
2563 			.model = 5232,
2564 		},
2565 #endif /* CPUINFO_ARCH_ARM */
2566 		{
2567 			/* "BEETHOVEN" (Huawei MadiaPad M3) -> HiSilicon Kirin 950 */
2568 			.platform = "BEETHOVEN",
2569 			.series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2570 			.model = 950,
2571 		},
2572 #if CPUINFO_ARCH_ARM
2573 		{
2574 			/* "hws7701u" (Huawei MediaPad 7 Youth) -> Rockchip RK3168 */
2575 			.platform = "hws7701u",
2576 			.series = cpuinfo_arm_chipset_series_rockchip_rk,
2577 			.model = 3168,
2578 		},
2579 		{
2580 			/* "g2mv" (LG G2 mini LTE) -> Nvidia Tegra SL460N */
2581 			.platform = "g2mv",
2582 			.series = cpuinfo_arm_chipset_series_nvidia_tegra_sl,
2583 			.model = 460,
2584 			.suffix = 'N',
2585 		},
2586 		{
2587 			/* "K00F" (Asus MeMO Pad 10) -> Rockchip RK3188 */
2588 			.platform = "K00F",
2589 			.series = cpuinfo_arm_chipset_series_rockchip_rk,
2590 			.model = 3188,
2591 		},
2592 		{
2593 			/* "T7H" (HP Slate 7) -> Rockchip RK3066 */
2594 			.platform = "T7H",
2595 			.series = cpuinfo_arm_chipset_series_rockchip_rk,
2596 			.model = 3066,
2597 		},
2598 		{
2599 			/* "tuna" (Samsung Galaxy Nexus) -> Texas Instruments OMAP4460 */
2600 			.platform = "tuna",
2601 			.series = cpuinfo_arm_chipset_series_texas_instruments_omap,
2602 			.model = 4460,
2603 		},
2604 		{
2605 			/* "grouper" (Asus Nexus 7 2012) -> Nvidia Tegra T30L */
2606 			.platform = "grouper",
2607 			.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2608 			.model = 30,
2609 			.suffix = 'L',
2610 		},
2611 #endif /* CPUINFO_ARCH_ARM */
2612 		{
2613 			/* "flounder" (HTC Nexus 9) -> Nvidia Tegra T132 */
2614 			.platform = "flounder",
2615 			.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2616 			.model = 132,
2617 		},
2618 		{
2619 			/* "dragon" (Google Pixel C) -> Nvidia Tegra T210 */
2620 			.platform = "dragon",
2621 			.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2622 			.model = 210,
2623 		},
2624 		{
2625 			/* "sailfish" (Google Pixel) -> Qualcomm MSM8996PRO */
2626 			.platform = "sailfish",
2627 			.series = cpuinfo_arm_chipset_series_qualcomm_msm,
2628 			.model = 8996,
2629 			.suffix = 'P',
2630 		},
2631 		{
2632 			/* "marlin" (Google Pixel XL) -> Qualcomm MSM8996PRO */
2633 			.platform = "marlin",
2634 			.series = cpuinfo_arm_chipset_series_qualcomm_msm,
2635 			.model = 8996,
2636 			.suffix = 'P',
2637 		},
2638 	};
2639 
2640 	/*
2641 	 * Decodes chipset name from ro.product.board Android system property.
2642 	 * For some chipsets, the function relies frequency and on number of cores for chipset detection.
2643 	 *
2644 	 * @param[in] platform - ro.product.board value.
2645 	 * @param cores - number of cores in the chipset.
2646 	 * @param max_cpu_freq_max - maximum of /sys/devices/system/cpu/cpu<number>/cpofreq/cpu_freq_max values.
2647 	 *
2648 	 * @returns Decoded chipset name. If chipset could not be decoded, the resulting structure would use `unknown` vendor
2649 	 *          and series identifiers.
2650 	 */
cpuinfo_arm_android_decode_chipset_from_ro_product_board(const char ro_product_board[restrict static CPUINFO_BUILD_PROP_VALUE_MAX],uint32_t cores,uint32_t max_cpu_freq_max)2651 	struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset_from_ro_product_board(
2652 		const char ro_product_board[restrict static CPUINFO_BUILD_PROP_VALUE_MAX],
2653 		uint32_t cores, uint32_t max_cpu_freq_max)
2654 	{
2655 		struct cpuinfo_arm_chipset chipset;
2656 		const char* board = ro_product_board;
2657 		const size_t board_length = strnlen(ro_product_board, CPUINFO_BUILD_PROP_VALUE_MAX);
2658 		const char* board_end = ro_product_board + board_length;
2659 
2660 		/* Check Qualcomm MSM/APQ signature */
2661 		if (match_msm_apq(board, board_end, &chipset)) {
2662 			cpuinfo_log_debug(
2663 				"matched Qualcomm MSM/APQ signature in ro.product.board string \"%.*s\"", (int) board_length, board);
2664 			return chipset;
2665 		}
2666 
2667 		/* Check universaXXXX (Samsung Exynos) signature */
2668 		if (match_universal(board, board_end, &chipset)) {
2669 			cpuinfo_log_debug(
2670 				"matched UNIVERSAL (Samsung Exynos) signature in ro.product.board string \"%.*s\"",
2671 				(int) board_length, board);
2672 			return chipset;
2673 		}
2674 
2675 		#if CPUINFO_ARCH_ARM
2676 			/* Check SMDK (Samsung Exynos) signature */
2677 			if (match_and_parse_smdk(board, board_end, cores, &chipset)) {
2678 				cpuinfo_log_debug(
2679 					"matched SMDK (Samsung Exynos) signature in ro.product.board string \"%.*s\"",
2680 					(int) board_length, board);
2681 				return chipset;
2682 			}
2683 		#endif
2684 
2685 		/* Check MediaTek MT signature */
2686 		if (match_mt(board, board_end, true, &chipset)) {
2687 			cpuinfo_log_debug(
2688 				"matched MediaTek MT signature in ro.product.board string \"%.*s\"",
2689 				(int) board_length, board);
2690 			return chipset;
2691 		}
2692 
2693 		/* Check Spreadtrum SC signature */
2694 		if (match_sc(board, board_end, &chipset)) {
2695 			cpuinfo_log_debug(
2696 				"matched Spreadtrum SC signature in ro.product.board string \"%.*s\"",
2697 				(int) board_length, board);
2698 			return chipset;
2699 		}
2700 
2701 		#if CPUINFO_ARCH_ARM
2702 			/* Check Marvell PXA signature */
2703 			if (match_pxa(board, board_end, &chipset)) {
2704 				cpuinfo_log_debug(
2705 					"matched Marvell PXA signature in ro.product.board string \"%.*s\"",
2706 					(int) board_length, board);
2707 				return chipset;
2708 			}
2709 
2710 			/* Check Leadcore LCxxxx signature */
2711 			if (match_lc(board, board_end, &chipset)) {
2712 				cpuinfo_log_debug(
2713 					"matched Leadcore LC signature in ro.product.board string \"%.*s\"",
2714 					(int) board_length, board);
2715 				return chipset;
2716 			}
2717 
2718 			/*
2719 			 * Compare to tabulated ro.product.board values for Broadcom chipsets and decode chipset from frequency and
2720 			 * number of cores.
2721 			 */
2722 			if (match_and_parse_broadcom(board, board_end, cores, max_cpu_freq_max, &chipset)) {
2723 				cpuinfo_log_debug(
2724 					"found ro.product.board string \"%.*s\" in Broadcom chipset table",
2725 					(int) board_length, board);
2726 				return chipset;
2727 			}
2728 		#endif
2729 
2730 		/* Compare to tabulated ro.product.board values for Huawei devices which don't report chipset elsewhere */
2731 		if (match_and_parse_huawei(board, board_end, &chipset)) {
2732 			cpuinfo_log_debug(
2733 				"found ro.product.board string \"%.*s\" in Huawei chipset table",
2734 				(int) board_length, board);
2735 			return chipset;
2736 		}
2737 
2738 		/* Compare to tabulated ro.product.board values for popular chipsets/devices which can't be otherwise detected */
2739 		for (size_t i = 0; i < CPUINFO_COUNT_OF(special_board_map_entries); i++) {
2740 			if (strncmp(special_board_map_entries[i].platform, board, board_length) == 0 &&
2741 					special_board_map_entries[i].platform[board_length] == 0)
2742 			{
2743 				cpuinfo_log_debug(
2744 					"found ro.product.board string \"%.*s\" in special chipset table",
2745 					(int) board_length, board);
2746 				/* Create chipset name from entry */
2747 				return (struct cpuinfo_arm_chipset) {
2748 					.vendor = chipset_series_vendor[special_board_map_entries[i].series],
2749 					.series = (enum cpuinfo_arm_chipset_series) special_board_map_entries[i].series,
2750 					.model = special_board_map_entries[i].model,
2751 					.suffix = {
2752 						[0] = special_board_map_entries[i].suffix,
2753 						/* The suffix of MSM8996PRO is truncated at the first letter, reconstruct it here. */
2754 						[1] = special_board_map_entries[i].suffix == 'P' ? 'R' : 0,
2755 						[2] = special_board_map_entries[i].suffix == 'P' ? 'O' : 0,
2756 					},
2757 				};
2758 			}
2759 		}
2760 
2761 		return (struct cpuinfo_arm_chipset) {
2762 			.vendor = cpuinfo_arm_chipset_vendor_unknown,
2763 			.series = cpuinfo_arm_chipset_series_unknown,
2764 		};
2765 	}
2766 
2767 	struct amlogic_map_entry {
2768 		char ro_board_platform[6];
2769 		uint16_t model;
2770 		uint8_t series;
2771 		char suffix[3];
2772 	};
2773 
2774 	static const struct amlogic_map_entry amlogic_map_entries[] = {
2775 #if CPUINFO_ARCH_ARM
2776 		{
2777 			/* "meson3" -> Amlogic AML8726-M */
2778 			.ro_board_platform = "meson3",
2779 			.series = cpuinfo_arm_chipset_series_amlogic_aml,
2780 			.model = 8726,
2781 			.suffix = "-M",
2782 		},
2783 		{
2784 			/* "meson6" -> Amlogic AML8726-MX */
2785 			.ro_board_platform = "meson6",
2786 			.series = cpuinfo_arm_chipset_series_amlogic_aml,
2787 			.model = 8726,
2788 			.suffix = "-MX",
2789 		},
2790 		{
2791 			/* "meson8" -> Amlogic S805 */
2792 			.ro_board_platform = "meson8",
2793 			.series = cpuinfo_arm_chipset_series_amlogic_s,
2794 			.model = 805,
2795 		},
2796 #endif /* CPUINFO_ARCH_ARM */
2797 		{
2798 			/* "gxbaby" -> Amlogic S905 */
2799 			.ro_board_platform = "gxbaby",
2800 			.series = cpuinfo_arm_chipset_series_amlogic_s,
2801 			.model = 905,
2802 		},
2803 		{
2804 			/* "gxl" -> Amlogic S905X */
2805 			.ro_board_platform = "gxl",
2806 			.series = cpuinfo_arm_chipset_series_amlogic_s,
2807 			.model = 905,
2808 			.suffix = "X",
2809 		},
2810 		{
2811 			/* "gxm" -> Amlogic S912 */
2812 			.ro_board_platform = "gxm",
2813 			.series = cpuinfo_arm_chipset_series_amlogic_s,
2814 			.model = 912,
2815 		},
2816 	};
2817 
2818 	static const struct special_map_entry special_platform_map_entries[] = {
2819 #if CPUINFO_ARCH_ARM
2820 		{
2821 			/* "hi6620oem" -> HiSilicon Kirin 910T */
2822 			.platform = "hi6620oem",
2823 			.series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2824 			.model = 910,
2825 			.suffix = 'T',
2826 		},
2827 #endif /* CPUINFO_ARCH_ARM */
2828 		{
2829 			/* "hi6250" -> HiSilicon Kirin 650 */
2830 			.platform = "hi6250",
2831 			.series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2832 			.model = 650,
2833 		},
2834 		{
2835 			/* "hi6210sft" -> HiSilicon Kirin 620 */
2836 			.platform = "hi6210sft",
2837 			.series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2838 			.model = 620,
2839 		},
2840 #if CPUINFO_ARCH_ARM
2841 		{
2842 			/* "hi3630" -> HiSilicon Kirin 920 */
2843 			.platform = "hi3630",
2844 			.series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2845 			.model = 920,
2846 		},
2847 #endif /* CPUINFO_ARCH_ARM */
2848 		{
2849 			/* "hi3635" -> HiSilicon Kirin 930 */
2850 			.platform = "hi3635",
2851 			.series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2852 			.model = 930,
2853 		},
2854 		{
2855 			/* "hi3650" -> HiSilicon Kirin 950 */
2856 			.platform = "hi3650",
2857 			.series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2858 			.model = 950,
2859 		},
2860 		{
2861 			/* "hi3660" -> HiSilicon Kirin 960 */
2862 			.platform = "hi3660",
2863 			.series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2864 			.model = 960,
2865 		},
2866 #if CPUINFO_ARCH_ARM
2867 		{
2868 			/* "k3v2oem1" -> HiSilicon K3V2 */
2869 			.platform = "k3v2oem1",
2870 			.series = cpuinfo_arm_chipset_series_hisilicon_k3v,
2871 			.model = 2,
2872 		},
2873 		{
2874 			/* "k3v200" -> HiSilicon K3V2 */
2875 			.platform = "k3v200",
2876 			.series = cpuinfo_arm_chipset_series_hisilicon_k3v,
2877 			.model = 2,
2878 		},
2879 		{
2880 			/* "montblanc" -> NovaThor U8500 */
2881 			.platform = "montblanc",
2882 			.series = cpuinfo_arm_chipset_series_novathor_u,
2883 			.model = 8500,
2884 		},
2885 #endif /* CPUINFO_ARCH_ARM */
2886 		{
2887 			/* "song" -> Pinecone Surge S1 */
2888 			.platform = "song",
2889 			.series = cpuinfo_arm_chipset_series_pinecone_surge_s,
2890 			.model = 1,
2891 		},
2892 #if CPUINFO_ARCH_ARM
2893 		{
2894 			/* "rk322x" -> RockChip RK3229 */
2895 			.platform = "rk322x",
2896 			.series = cpuinfo_arm_chipset_series_rockchip_rk,
2897 			.model = 3229,
2898 		},
2899 #endif /* CPUINFO_ARCH_ARM */
2900 		{
2901 			/* "tegra132" -> Nvidia Tegra T132 */
2902 			.platform = "tegra132",
2903 			.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2904 			.model = 132,
2905 		},
2906 		{
2907 			/* "tegra210_dragon" -> Nvidia Tegra T210 */
2908 			.platform = "tegra210_dragon",
2909 			.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2910 			.model = 210,
2911 		},
2912 #if CPUINFO_ARCH_ARM
2913 		{
2914 			/* "tegra4" -> Nvidia Tegra T114 */
2915 			.platform = "tegra4",
2916 			.series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2917 			.model = 114,
2918 		},
2919 		{
2920 			/* "s5pc110" -> Samsung Exynos 3110 */
2921 			.platform = "s5pc110",
2922 			.series = cpuinfo_arm_chipset_series_samsung_exynos,
2923 			.model = 3110,
2924 		},
2925 #endif /* CPUINFO_ARCH_ARM */
2926 	};
2927 
2928 	/*
2929 	 * Decodes chipset name from ro.board.platform Android system property.
2930 	 * For some chipsets, the function relies frequency and on number of cores for chipset detection.
2931 	 *
2932 	 * @param[in] platform - ro.board.platform value.
2933 	 * @param cores - number of cores in the chipset.
2934 	 * @param max_cpu_freq_max - maximum of /sys/devices/system/cpu/cpu<number>/cpofreq/cpu_freq_max values.
2935 	 *
2936 	 * @returns Decoded chipset name. If chipset could not be decoded, the resulting structure would use `unknown` vendor
2937 	 *          and series identifiers.
2938 	 */
cpuinfo_arm_android_decode_chipset_from_ro_board_platform(const char platform[restrict static CPUINFO_BUILD_PROP_VALUE_MAX],uint32_t cores,uint32_t max_cpu_freq_max)2939 	struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset_from_ro_board_platform(
2940 		const char platform[restrict static CPUINFO_BUILD_PROP_VALUE_MAX],
2941 		uint32_t cores, uint32_t max_cpu_freq_max)
2942 	{
2943 		struct cpuinfo_arm_chipset chipset;
2944 		const size_t platform_length = strnlen(platform, CPUINFO_BUILD_PROP_VALUE_MAX);
2945 		const char* platform_end = platform + platform_length;
2946 
2947 		/* Check Qualcomm MSM/APQ signature */
2948 		if (match_msm_apq(platform, platform_end, &chipset)) {
2949 			cpuinfo_log_debug(
2950 				"matched Qualcomm MSM/APQ signature in ro.board.platform string \"%.*s\"",
2951 				(int) platform_length, platform);
2952 			return chipset;
2953 		}
2954 
2955 		/* Check exynosXXXX (Samsung Exynos) signature */
2956 		if (match_exynos(platform, platform_end, &chipset)) {
2957 			cpuinfo_log_debug(
2958 				"matched exynosXXXX (Samsung Exynos) signature in ro.board.platform string \"%.*s\"",
2959 				(int) platform_length, platform);
2960 			return chipset;
2961 		}
2962 
2963 		/* Check MediaTek MT signature */
2964 		if (match_mt(platform, platform_end, true, &chipset)) {
2965 			cpuinfo_log_debug(
2966 				"matched MediaTek MT signature in ro.board.platform string \"%.*s\"", (int) platform_length, platform);
2967 			return chipset;
2968 		}
2969 
2970 		/* Check HiSilicon Kirin signature */
2971 		if (match_kirin(platform, platform_end, &chipset)) {
2972 			cpuinfo_log_debug(
2973 				"matched HiSilicon Kirin signature in ro.board.platform string \"%.*s\"", (int) platform_length, platform);
2974 			return chipset;
2975 		}
2976 
2977 		/* Check Spreadtrum SC signature */
2978 		if (match_sc(platform, platform_end, &chipset)) {
2979 			cpuinfo_log_debug(
2980 				"matched Spreadtrum SC signature in ro.board.platform string \"%.*s\"", (int) platform_length, platform);
2981 			return chipset;
2982 		}
2983 
2984 		/* Check Rockchip RK signature */
2985 		if (match_rk(platform, platform_end, &chipset)) {
2986 			cpuinfo_log_debug(
2987 				"matched Rockchip RK signature in ro.board.platform string \"%.*s\"", (int) platform_length, platform);
2988 			return chipset;
2989 		}
2990 
2991 		#if CPUINFO_ARCH_ARM
2992 			/* Check Leadcore LCxxxx signature */
2993 			if (match_lc(platform, platform_end, &chipset)) {
2994 				cpuinfo_log_debug(
2995 					"matched Leadcore LC signature in ro.board.platform string \"%.*s\"", (int) platform_length, platform);
2996 				return chipset;
2997 			}
2998 		#endif
2999 
3000 		/* Compare to tabulated ro.board.platform values for Huawei devices which don't report chipset elsewhere */
3001 		if (match_and_parse_huawei(platform, platform_end, &chipset)) {
3002 			cpuinfo_log_debug(
3003 				"found ro.board.platform string \"%.*s\" in Huawei chipset table",
3004 				(int) platform_length, platform);
3005 			return chipset;
3006 		}
3007 
3008 		#if CPUINFO_ARCH_ARM
3009 			/*
3010 			 * Compare to known ro.board.platform values for Broadcom devices and
3011 			 * detect chipset from frequency and number of cores
3012 			 */
3013 			if (match_and_parse_broadcom(platform, platform_end, cores, max_cpu_freq_max, &chipset)) {
3014 				cpuinfo_log_debug(
3015 					"found ro.board.platform string \"%.*s\" in Broadcom chipset table",
3016 					(int) platform_length, platform);
3017 				return chipset;
3018 			}
3019 
3020 			/*
3021 			 * Compare to ro.board.platform value ("omap4") for OMAP4xxx chipsets.
3022 			 * Upon successful match, detect OMAP4430 from frequency and number of cores.
3023 			 */
3024 			if (platform_length == 5 && cores == 2 && max_cpu_freq_max == 1008000 && memcmp(platform, "omap4", 5) == 0) {
3025 				cpuinfo_log_debug(
3026 					"matched Texas Instruments OMAP4 signature in ro.board.platform string \"%.*s\"",
3027 					(int) platform_length, platform);
3028 
3029 				return (struct cpuinfo_arm_chipset) {
3030 					.vendor = cpuinfo_arm_chipset_vendor_texas_instruments,
3031 					.series = cpuinfo_arm_chipset_series_texas_instruments_omap,
3032 					.model = 4430,
3033 				};
3034 			}
3035 		#endif
3036 
3037 		/*
3038 		 * Compare to tabulated ro.board.platform values for Amlogic chipsets/devices which can't be otherwise detected.
3039 		 * The tabulated Amlogic ro.board.platform values have not more than 6 characters.
3040 		 */
3041 		if (platform_length <= 6) {
3042 			for (size_t i = 0; i < CPUINFO_COUNT_OF(amlogic_map_entries); i++) {
3043 				if (strncmp(amlogic_map_entries[i].ro_board_platform, platform, 6) == 0) {
3044 					cpuinfo_log_debug(
3045 						"found ro.board.platform string \"%.*s\" in Amlogic chipset table",
3046 						(int) platform_length, platform);
3047 					/* Create chipset name from entry */
3048 					return (struct cpuinfo_arm_chipset) {
3049 						.vendor = cpuinfo_arm_chipset_vendor_amlogic,
3050 						.series = (enum cpuinfo_arm_chipset_series) amlogic_map_entries[i].series,
3051 						.model = amlogic_map_entries[i].model,
3052 						.suffix = {
3053 							[0] = amlogic_map_entries[i].suffix[0],
3054 							[1] = amlogic_map_entries[i].suffix[1],
3055 							[2] = amlogic_map_entries[i].suffix[2],
3056 						},
3057 					};
3058 				}
3059 			}
3060 		}
3061 
3062 		/* Compare to tabulated ro.board.platform values for popular chipsets/devices which can't be otherwise detected */
3063 		for (size_t i = 0; i < CPUINFO_COUNT_OF(special_platform_map_entries); i++) {
3064 			if (strncmp(special_platform_map_entries[i].platform, platform, platform_length) == 0 &&
3065 					special_platform_map_entries[i].platform[platform_length] == 0)
3066 			{
3067 				/* Create chipset name from entry */
3068 				cpuinfo_log_debug(
3069 					"found ro.board.platform string \"%.*s\" in special chipset table", (int) platform_length, platform);
3070 				return (struct cpuinfo_arm_chipset) {
3071 					.vendor = chipset_series_vendor[special_platform_map_entries[i].series],
3072 					.series = (enum cpuinfo_arm_chipset_series) special_platform_map_entries[i].series,
3073 					.model = special_platform_map_entries[i].model,
3074 					.suffix = {
3075 						[0] = special_platform_map_entries[i].suffix,
3076 					},
3077 				};
3078 			}
3079 		}
3080 
3081 		/* None of the ro.board.platform signatures matched, indicate unknown chipset */
3082 		return (struct cpuinfo_arm_chipset) {
3083 			.vendor = cpuinfo_arm_chipset_vendor_unknown,
3084 			.series = cpuinfo_arm_chipset_series_unknown,
3085 		};
3086 	}
3087 
3088 	/*
3089 	 * Decodes chipset name from ro.mediatek.platform Android system property.
3090 	 *
3091 	 * @param[in] platform - ro.mediatek.platform value.
3092 	 *
3093 	 * @returns Decoded chipset name. If chipset could not be decoded, the resulting structure would use `unknown`
3094 	 *          vendor and series identifiers.
3095 	 */
cpuinfo_arm_android_decode_chipset_from_ro_mediatek_platform(const char platform[restrict static CPUINFO_BUILD_PROP_VALUE_MAX])3096 	struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset_from_ro_mediatek_platform(
3097 		const char platform[restrict static CPUINFO_BUILD_PROP_VALUE_MAX])
3098 	{
3099 		struct cpuinfo_arm_chipset chipset;
3100 		const char* platform_end = platform + strnlen(platform, CPUINFO_BUILD_PROP_VALUE_MAX);
3101 
3102 		/* Check MediaTek MT signature */
3103 		if (match_mt(platform, platform_end, false, &chipset)) {
3104 			return chipset;
3105 		}
3106 
3107 		return (struct cpuinfo_arm_chipset) {
3108 			.vendor = cpuinfo_arm_chipset_vendor_unknown,
3109 			.series = cpuinfo_arm_chipset_series_unknown,
3110 		};
3111 	}
3112 
3113 
3114 	/*
3115 	 * Decodes chipset name from ro.arch Android system property.
3116 	 *
3117 	 * The ro.arch property is matched only against Samsung Exynos signature. Systems with other chipset rarely
3118 	 * configure ro.arch Android system property, and can be decoded through other properties, but some Exynos
3119 	 * chipsets are identified only in ro.arch.
3120 	 *
3121 	 * @param[in] arch - ro.arch value.
3122 	 *
3123 	 * @returns Decoded chipset name. If chipset could not be decoded, the resulting structure would use `unknown`
3124 	 *          vendor and series identifiers.
3125 	 */
cpuinfo_arm_android_decode_chipset_from_ro_arch(const char arch[restrict static CPUINFO_BUILD_PROP_VALUE_MAX])3126 	struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset_from_ro_arch(
3127 		const char arch[restrict static CPUINFO_BUILD_PROP_VALUE_MAX])
3128 	{
3129 		struct cpuinfo_arm_chipset chipset;
3130 		const char* arch_end = arch + strnlen(arch, CPUINFO_BUILD_PROP_VALUE_MAX);
3131 
3132 		/* Check Samsung exynosXXXX signature */
3133 		if (match_exynos(arch, arch_end, &chipset)) {
3134 			return chipset;
3135 		}
3136 
3137 		return (struct cpuinfo_arm_chipset) {
3138 			.vendor = cpuinfo_arm_chipset_vendor_unknown,
3139 			.series = cpuinfo_arm_chipset_series_unknown,
3140 		};
3141 	}
3142 
3143 	/*
3144 	 * Decodes chipset name from ro.chipname or ro.hardware.chipname Android system property.
3145 	 *
3146 	 * @param[in] chipname - ro.chipname or ro.hardware.chipname value.
3147 	 *
3148 	 * @returns Decoded chipset name. If chipset could not be decoded, the resulting structure would use `unknown` vendor
3149 	 *          and series identifiers.
3150 	 */
3151 
cpuinfo_arm_android_decode_chipset_from_ro_chipname(const char chipname[restrict static CPUINFO_BUILD_PROP_VALUE_MAX])3152 	struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset_from_ro_chipname(
3153 		const char chipname[restrict static CPUINFO_BUILD_PROP_VALUE_MAX])
3154 	{
3155 		struct cpuinfo_arm_chipset chipset;
3156 		const size_t chipname_length = strnlen(chipname, CPUINFO_BUILD_PROP_VALUE_MAX);
3157 		const char* chipname_end = chipname + chipname_length;
3158 
3159 		/* Check Qualcomm MSM/APQ signatures */
3160 		if (match_msm_apq(chipname, chipname_end, &chipset)) {
3161 			cpuinfo_log_debug(
3162 				"matched Qualcomm MSM/APQ signature in ro.chipname string \"%.*s\"",
3163 				(int) chipname_length, chipname);
3164 			return chipset;
3165 		}
3166 
3167 		/* Check SMxxxx (Qualcomm Snapdragon) signature */
3168 		if (match_sm(chipname, chipname_end, &chipset)) {
3169 			cpuinfo_log_debug(
3170 				"matched Qualcomm SM signature in /proc/cpuinfo Hardware string \"%.*s\"",
3171 				(int) chipname_length, chipname);
3172 			return chipset;
3173 		}
3174 
3175 		/* Check exynosXXXX (Samsung Exynos) signature */
3176 		if (match_exynos(chipname, chipname_end, &chipset)) {
3177 			cpuinfo_log_debug(
3178 				"matched exynosXXXX (Samsung Exynos) signature in ro.chipname string \"%.*s\"",
3179 				(int) chipname_length, chipname);
3180 			return chipset;
3181 		}
3182 
3183 		/* Check universalXXXX (Samsung Exynos) signature */
3184 		if (match_universal(chipname, chipname_end, &chipset)) {
3185 			cpuinfo_log_debug(
3186 				"matched UNIVERSAL (Samsung Exynos) signature in ro.chipname Hardware string \"%.*s\"",
3187 				(int) chipname_length, chipname);
3188 			return chipset;
3189 		}
3190 
3191 		/* Check MediaTek MT signature */
3192 		if (match_mt(chipname, chipname_end, true, &chipset)) {
3193 			cpuinfo_log_debug(
3194 				"matched MediaTek MT signature in ro.chipname string \"%.*s\"",
3195 				(int) chipname_length, chipname);
3196 			return chipset;
3197 		}
3198 
3199 		/* Check Spreadtrum SC signature */
3200 		if (match_sc(chipname, chipname_end, &chipset)) {
3201 			cpuinfo_log_debug(
3202 				"matched Spreadtrum SC signature in ro.chipname string \"%.*s\"",
3203 				(int) chipname_length, chipname);
3204 			return chipset;
3205 		}
3206 
3207 		#if CPUINFO_ARCH_ARM
3208 			/* Check Marvell PXA signature */
3209 			if (match_pxa(chipname, chipname_end, &chipset)) {
3210 				cpuinfo_log_debug(
3211 					"matched Marvell PXA signature in ro.chipname string \"%.*s\"",
3212 					(int) chipname_length, chipname);
3213 				return chipset;
3214 			}
3215 
3216 			/* Compare to ro.chipname value ("mp523x") for Renesas MP5232 which can't be otherwise detected */
3217 			if (chipname_length == 6 && memcmp(chipname, "mp523x", 6) == 0) {
3218 				cpuinfo_log_debug(
3219 					"matched Renesas MP5232 signature in ro.chipname string \"%.*s\"",
3220 					(int) chipname_length, chipname);
3221 
3222 				return (struct cpuinfo_arm_chipset) {
3223 					.vendor = cpuinfo_arm_chipset_vendor_renesas,
3224 					.series = cpuinfo_arm_chipset_series_renesas_mp,
3225 					.model = 5232,
3226 				};
3227 			}
3228 		#endif
3229 
3230 		return (struct cpuinfo_arm_chipset) {
3231 			.vendor = cpuinfo_arm_chipset_vendor_unknown,
3232 			.series = cpuinfo_arm_chipset_series_unknown,
3233 		};
3234 	}
3235 #endif /* __ANDROID__ */
3236 
3237 /*
3238  * Fix common bugs, typos, and renames in chipset name.
3239  *
3240  * @param[in,out] chipset - chipset name to fix.
3241  * @param cores - number of cores in the chipset.
3242  * @param max_cpu_freq_max - maximum of /sys/devices/system/cpu/cpu<number>/cpofreq/cpu_freq_max values.
3243  */
cpuinfo_arm_fixup_chipset(struct cpuinfo_arm_chipset chipset[restrict static1],uint32_t cores,uint32_t max_cpu_freq_max)3244 void cpuinfo_arm_fixup_chipset(
3245 	struct cpuinfo_arm_chipset chipset[restrict static 1], uint32_t cores, uint32_t max_cpu_freq_max)
3246 {
3247 	switch (chipset->series) {
3248 		case cpuinfo_arm_chipset_series_qualcomm_msm:
3249 			/* Check if there is suffix */
3250 			if (chipset->suffix[0] == 0) {
3251 				/* No suffix, but the model may be misreported */
3252 				switch (chipset->model) {
3253 					case 8216:
3254 						/* MSM8216 was renamed to MSM8916 */
3255 						cpuinfo_log_info("reinterpreted MSM8216 chipset as MSM8916");
3256 						chipset->model = 8916;
3257 						break;
3258 					case 8916:
3259 						/* Common bug: MSM8939 (Octa-core) reported as MSM8916 (Quad-core) */
3260 						switch (cores) {
3261 							case 4:
3262 								break;
3263 							case 8:
3264 								cpuinfo_log_info("reinterpreted MSM8916 chipset with 8 cores as MSM8939");
3265 								chipset->model = 8939;
3266 								break;
3267 							default:
3268 								cpuinfo_log_warning("system reported invalid %"PRIu32"-core MSM%"PRIu32" chipset",
3269 									cores, chipset->model);
3270 								chipset->model = 0;
3271 						}
3272 						break;
3273 					case 8937:
3274 						/* Common bug: MSM8917 (Quad-core) reported as MSM8937 (Octa-core) */
3275 						switch (cores) {
3276 							case 4:
3277 								cpuinfo_log_info("reinterpreted MSM8937 chipset with 4 cores as MSM8917");
3278 								chipset->model = 8917;
3279 								break;
3280 							case 8:
3281 								break;
3282 							default:
3283 								cpuinfo_log_warning("system reported invalid %"PRIu32"-core MSM%"PRIu32" chipset",
3284 									cores, chipset->model);
3285 								chipset->model = 0;
3286 						}
3287 						break;
3288 					case 8960:
3289 						/* Common bug: APQ8064 (Quad-core) reported as MSM8960 (Dual-core) */
3290 						switch (cores) {
3291 							case 2:
3292 								break;
3293 							case 4:
3294 								cpuinfo_log_info("reinterpreted MSM8960 chipset with 4 cores as APQ8064");
3295 								chipset->series = cpuinfo_arm_chipset_series_qualcomm_apq;
3296 								chipset->model = 8064;
3297 								break;
3298 							default:
3299 								cpuinfo_log_warning("system reported invalid %"PRIu32"-core MSM%"PRIu32" chipset",
3300 									cores, chipset->model);
3301 								chipset->model = 0;
3302 						}
3303 						break;
3304 					case 8996:
3305 						/* Common bug: MSM8994 (Octa-core) reported as MSM8996 (Quad-core) */
3306 						switch (cores) {
3307 							case 4:
3308 								break;
3309 							case 8:
3310 								cpuinfo_log_info("reinterpreted MSM8996 chipset with 8 cores as MSM8994");
3311 								chipset->model = 8994;
3312 								break;
3313 							default:
3314 								cpuinfo_log_warning("system reported invalid %"PRIu32"-core MSM%"PRIu32" chipset",
3315 									cores, chipset->model);
3316 								chipset->model = 0;
3317 						}
3318 						break;
3319 #if CPUINFO_ARCH_ARM
3320 					case 8610:
3321 						/* Common bug: MSM8612 (Quad-core) reported as MSM8610 (Dual-core) */
3322 						switch (cores) {
3323 							case 2:
3324 								break;
3325 							case 4:
3326 								cpuinfo_log_info("reinterpreted MSM8610 chipset with 4 cores as MSM8612");
3327 								chipset->model = 8612;
3328 								break;
3329 							default:
3330 								cpuinfo_log_warning("system reported invalid %"PRIu32"-core MSM%"PRIu32" chipset",
3331 									cores, chipset->model);
3332 								chipset->model = 0;
3333 						}
3334 						break;
3335 #endif /* CPUINFO_ARCH_ARM */
3336 				}
3337 			} else {
3338 				/* Suffix may need correction */
3339 				const uint32_t suffix_word = load_u32le(chipset->suffix);
3340 				if (suffix_word == UINT32_C(0x004D534D) /* "\0MSM" = reverse("MSM\0") */) {
3341 					/*
3342 					 * Common bug: model name repeated twice, e.g. "MSM8916MSM8916"
3343 					 * In this case, model matching code parses the second "MSM" as a suffix
3344 					 */
3345 					chipset->suffix[0] = 0;
3346 					chipset->suffix[1] = 0;
3347 					chipset->suffix[2] = 0;
3348 				} else {
3349 					switch (chipset->model) {
3350 						case 8976:
3351 							/* MSM8976SG -> MSM8976PRO */
3352 							if (suffix_word == UINT32_C(0x00004753) /* "\0\0GS" = reverse("SG\0\0") */ ) {
3353 								chipset->suffix[0] = 'P';
3354 								chipset->suffix[1] = 'R';
3355 								chipset->suffix[2] = 'O';
3356 							}
3357 							break;
3358 						case 8996:
3359 							/* MSM8996PRO -> MSM8996PRO-AB or MSM8996PRO-AC */
3360 							if (suffix_word == UINT32_C(0x004F5250) /* "\0ORP" = reverse("PRO\0") */ ) {
3361 								chipset->suffix[3] = '-';
3362 								chipset->suffix[4] = 'A';
3363 								chipset->suffix[5] = 'B' + (char) (max_cpu_freq_max >= 2188800);
3364 							}
3365 							break;
3366 					}
3367 				}
3368 			}
3369 			break;
3370 		case cpuinfo_arm_chipset_series_qualcomm_apq:
3371 		{
3372 			/* Suffix may need correction */
3373 			const uint32_t expected_apq = load_u32le(chipset->suffix);
3374 			if (expected_apq == UINT32_C(0x00515041) /* "\0QPA" = reverse("APQ\0") */) {
3375 				/*
3376 				 * Common bug: model name repeated twice, e.g. "APQ8016APQ8016"
3377 				 * In this case, model matching code parses the second "APQ" as a suffix
3378 				 */
3379 				chipset->suffix[0] = 0;
3380 				chipset->suffix[1] = 0;
3381 				chipset->suffix[2] = 0;
3382 			}
3383 			break;
3384 		}
3385 		case cpuinfo_arm_chipset_series_samsung_exynos:
3386 			switch (chipset->model) {
3387 #if CPUINFO_ARCH_ARM
3388 				case 4410:
3389 					/* Exynos 4410 was renamed to Exynos 4412 */
3390 					chipset->model = 4412;
3391 					break;
3392 				case 5420:
3393 					/* Common bug: Exynos 5260 (Hexa-core) reported as Exynos 5420 (Quad-core) */
3394 					switch (cores) {
3395 						case 4:
3396 							break;
3397 						case 6:
3398 							cpuinfo_log_info("reinterpreted Exynos 5420 chipset with 6 cores as Exynos 5260");
3399 							chipset->model = 5260;
3400 							break;
3401 						default:
3402 							cpuinfo_log_warning("system reported invalid %"PRIu32"-core Exynos 5420 chipset", cores);
3403 							chipset->model = 0;
3404 					}
3405 					break;
3406 #endif /* CPUINFO_ARCH_ARM */
3407 				case 7580:
3408 					/* Common bug: Exynos 7578 (Quad-core) reported as Exynos 7580 (Octa-core) */
3409 					switch (cores) {
3410 						case 4:
3411 							cpuinfo_log_info("reinterpreted Exynos 7580 chipset with 4 cores as Exynos 7578");
3412 							chipset->model = 7578;
3413 							break;
3414 						case 8:
3415 							break;
3416 						default:
3417 							cpuinfo_log_warning("system reported invalid %"PRIu32"-core Exynos 7580 chipset", cores);
3418 							chipset->model = 0;
3419 					}
3420 					break;
3421 			}
3422 			break;
3423 		case cpuinfo_arm_chipset_series_mediatek_mt:
3424 			if (chipset->model == 6752) {
3425 				/* Common bug: MT6732 (Quad-core) reported as MT6752 (Octa-core) */
3426 				switch (cores) {
3427 					case 4:
3428 						cpuinfo_log_info("reinterpreted MT6752 chipset with 4 cores as MT6732");
3429 						chipset->model = 6732;
3430 						break;
3431 					case 8:
3432 						break;
3433 					default:
3434 						cpuinfo_log_warning("system reported invalid %"PRIu32"-core MT6752 chipset", cores);
3435 						chipset->model = 0;
3436 				}
3437 			}
3438 			if (chipset->suffix[0] == 'T') {
3439 				/* Normalization: "TURBO" and "TRUBO" (apparently a typo) -> "T" */
3440 				const uint32_t suffix_word = load_u32le(chipset->suffix + 1);
3441 				switch (suffix_word) {
3442 					case UINT32_C(0x4F425255): /* "OBRU" = reverse("URBO") */
3443 					case UINT32_C(0x4F425552): /* "OBUR" = reverse("RUBO") */
3444 						if (chipset->suffix[5] == 0) {
3445 							chipset->suffix[1] = 0;
3446 							chipset->suffix[2] = 0;
3447 							chipset->suffix[3] = 0;
3448 							chipset->suffix[4] = 0;
3449 						}
3450 						break;
3451 				}
3452 			}
3453 			break;
3454 		case cpuinfo_arm_chipset_series_rockchip_rk:
3455 			if (chipset->model == 3288) {
3456 				/* Common bug: Rockchip RK3399 (Hexa-core) always reported as RK3288 (Quad-core) */
3457 				switch (cores) {
3458 					case 4:
3459 						break;
3460 					case 6:
3461 						cpuinfo_log_info("reinterpreted RK3288 chipset with 6 cores as RK3399");
3462 						chipset->model = 3399;
3463 						break;
3464 					default:
3465 						cpuinfo_log_warning("system reported invalid %"PRIu32"-core RK3288 chipset", cores);
3466 						chipset->model = 0;
3467 				}
3468 			}
3469 			break;
3470 		default:
3471 			break;
3472 	}
3473 }
3474 
3475 /* Map from ARM chipset vendor ID to its string representation */
3476 static const char* chipset_vendor_string[cpuinfo_arm_chipset_vendor_max] = {
3477 	[cpuinfo_arm_chipset_vendor_unknown]           = "Unknown",
3478 	[cpuinfo_arm_chipset_vendor_qualcomm]          = "Qualcomm",
3479 	[cpuinfo_arm_chipset_vendor_mediatek]          = "MediaTek",
3480 	[cpuinfo_arm_chipset_vendor_samsung]           = "Samsung",
3481 	[cpuinfo_arm_chipset_vendor_hisilicon]         = "HiSilicon",
3482 	[cpuinfo_arm_chipset_vendor_actions]           = "Actions",
3483 	[cpuinfo_arm_chipset_vendor_allwinner]         = "Allwinner",
3484 	[cpuinfo_arm_chipset_vendor_amlogic]           = "Amlogic",
3485 	[cpuinfo_arm_chipset_vendor_broadcom]          = "Broadcom",
3486 	[cpuinfo_arm_chipset_vendor_lg]                = "LG",
3487 	[cpuinfo_arm_chipset_vendor_leadcore]          = "Leadcore",
3488 	[cpuinfo_arm_chipset_vendor_marvell]           = "Marvell",
3489 	[cpuinfo_arm_chipset_vendor_mstar]             = "MStar",
3490 	[cpuinfo_arm_chipset_vendor_novathor]          = "NovaThor",
3491 	[cpuinfo_arm_chipset_vendor_nvidia]            = "Nvidia",
3492 	[cpuinfo_arm_chipset_vendor_pinecone]          = "Pinecone",
3493 	[cpuinfo_arm_chipset_vendor_renesas]           = "Renesas",
3494 	[cpuinfo_arm_chipset_vendor_rockchip]          = "Rockchip",
3495 	[cpuinfo_arm_chipset_vendor_spreadtrum]        = "Spreadtrum",
3496 	[cpuinfo_arm_chipset_vendor_telechips]         = "Telechips",
3497 	[cpuinfo_arm_chipset_vendor_texas_instruments] = "Texas Instruments",
3498 	[cpuinfo_arm_chipset_vendor_wondermedia]       = "WonderMedia",
3499 };
3500 
3501 /* Map from ARM chipset series ID to its string representation */
3502 static const char* chipset_series_string[cpuinfo_arm_chipset_series_max] = {
3503 	[cpuinfo_arm_chipset_series_unknown]                = NULL,
3504 	[cpuinfo_arm_chipset_series_qualcomm_qsd]           = "QSD",
3505 	[cpuinfo_arm_chipset_series_qualcomm_msm]           = "MSM",
3506 	[cpuinfo_arm_chipset_series_qualcomm_apq]           = "APQ",
3507 	[cpuinfo_arm_chipset_series_qualcomm_snapdragon]    = "Snapdragon ",
3508 	[cpuinfo_arm_chipset_series_mediatek_mt]            = "MT",
3509 	[cpuinfo_arm_chipset_series_samsung_exynos]         = "Exynos ",
3510 	[cpuinfo_arm_chipset_series_hisilicon_k3v]          = "K3V",
3511 	[cpuinfo_arm_chipset_series_hisilicon_hi]           = "Hi",
3512 	[cpuinfo_arm_chipset_series_hisilicon_kirin]        = "Kirin ",
3513 	[cpuinfo_arm_chipset_series_actions_atm]            = "ATM",
3514 	[cpuinfo_arm_chipset_series_allwinner_a]            = "A",
3515 	[cpuinfo_arm_chipset_series_amlogic_aml]            = "AML",
3516 	[cpuinfo_arm_chipset_series_amlogic_s]              = "S",
3517 	[cpuinfo_arm_chipset_series_broadcom_bcm]           = "BCM",
3518 	[cpuinfo_arm_chipset_series_lg_nuclun]              = "Nuclun ",
3519 	[cpuinfo_arm_chipset_series_leadcore_lc]            = "LC",
3520 	[cpuinfo_arm_chipset_series_marvell_pxa]            = "PXA",
3521 	[cpuinfo_arm_chipset_series_mstar_6a]               = "6A",
3522 	[cpuinfo_arm_chipset_series_novathor_u]             = "U",
3523 	[cpuinfo_arm_chipset_series_nvidia_tegra_t]         = "Tegra T",
3524 	[cpuinfo_arm_chipset_series_nvidia_tegra_ap]        = "Tegra AP",
3525 	[cpuinfo_arm_chipset_series_nvidia_tegra_sl]        = "Tegra SL",
3526 	[cpuinfo_arm_chipset_series_pinecone_surge_s]       = "Surge S",
3527 	[cpuinfo_arm_chipset_series_renesas_mp]             = "MP",
3528 	[cpuinfo_arm_chipset_series_rockchip_rk]            = "RK",
3529 	[cpuinfo_arm_chipset_series_spreadtrum_sc]          = "SC",
3530 	[cpuinfo_arm_chipset_series_telechips_tcc]          = "TCC",
3531 	[cpuinfo_arm_chipset_series_texas_instruments_omap] = "OMAP",
3532 	[cpuinfo_arm_chipset_series_wondermedia_wm]         = "WM",
3533 };
3534 
3535 /* Convert chipset name represented by cpuinfo_arm_chipset structure to a string representation */
cpuinfo_arm_chipset_to_string(const struct cpuinfo_arm_chipset chipset[restrict static1],char name[restrict static CPUINFO_ARM_CHIPSET_NAME_MAX])3536 void cpuinfo_arm_chipset_to_string(
3537 	const struct cpuinfo_arm_chipset chipset[restrict static 1],
3538 	char name[restrict static CPUINFO_ARM_CHIPSET_NAME_MAX])
3539 {
3540 	enum cpuinfo_arm_chipset_vendor vendor = chipset->vendor;
3541 	if (vendor >= cpuinfo_arm_chipset_vendor_max) {
3542 		vendor = cpuinfo_arm_chipset_vendor_unknown;
3543 	}
3544 	enum cpuinfo_arm_chipset_series series = chipset->series;
3545 	if (series >= cpuinfo_arm_chipset_series_max) {
3546 		series = cpuinfo_arm_chipset_series_unknown;
3547 	}
3548 	const char* vendor_string = chipset_vendor_string[vendor];
3549 	const char* series_string = chipset_series_string[series];
3550 	const uint32_t model = chipset->model;
3551 	if (model == 0) {
3552 		if (series == cpuinfo_arm_chipset_series_unknown) {
3553 			strncpy(name, vendor_string, CPUINFO_ARM_CHIPSET_NAME_MAX);
3554 		} else {
3555 			snprintf(name, CPUINFO_ARM_CHIPSET_NAME_MAX,
3556 				"%s %s", vendor_string, series_string);
3557 		}
3558 	} else {
3559 		const size_t suffix_length = strnlen(chipset->suffix, CPUINFO_ARM_CHIPSET_SUFFIX_MAX);
3560 		snprintf(name, CPUINFO_ARM_CHIPSET_NAME_MAX,
3561 			"%s %s%"PRIu32"%.*s", vendor_string, series_string, model, (int) suffix_length, chipset->suffix);
3562 	}
3563 }
3564 
3565 #ifdef __ANDROID__
disambiguate_qualcomm_chipset(const struct cpuinfo_arm_chipset proc_cpuinfo_hardware_chipset[restrict static1],const struct cpuinfo_arm_chipset ro_product_board_chipset[restrict static1],const struct cpuinfo_arm_chipset ro_board_platform_chipset[restrict static1],const struct cpuinfo_arm_chipset ro_chipname_chipset[restrict static1],const struct cpuinfo_arm_chipset ro_hardware_chipname_chipset[restrict static1])3566 	static inline struct cpuinfo_arm_chipset disambiguate_qualcomm_chipset(
3567 		const struct cpuinfo_arm_chipset proc_cpuinfo_hardware_chipset[restrict static 1],
3568 		const struct cpuinfo_arm_chipset ro_product_board_chipset[restrict static 1],
3569 		const struct cpuinfo_arm_chipset ro_board_platform_chipset[restrict static 1],
3570 		const struct cpuinfo_arm_chipset ro_chipname_chipset[restrict static 1],
3571 		const struct cpuinfo_arm_chipset ro_hardware_chipname_chipset[restrict static 1])
3572 	{
3573 		if (ro_hardware_chipname_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3574 			return *ro_hardware_chipname_chipset;
3575 		}
3576 		if (ro_chipname_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3577 			return *ro_chipname_chipset;
3578 		}
3579 		if (proc_cpuinfo_hardware_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3580 			return *proc_cpuinfo_hardware_chipset;
3581 		}
3582 		if (ro_product_board_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3583 			return *ro_product_board_chipset;
3584 		}
3585 		return *ro_board_platform_chipset;
3586 	}
3587 
disambiguate_mediatek_chipset(const struct cpuinfo_arm_chipset proc_cpuinfo_hardware_chipset[restrict static1],const struct cpuinfo_arm_chipset ro_product_board_chipset[restrict static1],const struct cpuinfo_arm_chipset ro_board_platform_chipset[restrict static1],const struct cpuinfo_arm_chipset ro_mediatek_platform_chipset[restrict static1],const struct cpuinfo_arm_chipset ro_chipname_chipset[restrict static1])3588 	static inline struct cpuinfo_arm_chipset disambiguate_mediatek_chipset(
3589 		const struct cpuinfo_arm_chipset proc_cpuinfo_hardware_chipset[restrict static 1],
3590 		const struct cpuinfo_arm_chipset ro_product_board_chipset[restrict static 1],
3591 		const struct cpuinfo_arm_chipset ro_board_platform_chipset[restrict static 1],
3592 		const struct cpuinfo_arm_chipset ro_mediatek_platform_chipset[restrict static 1],
3593 		const struct cpuinfo_arm_chipset ro_chipname_chipset[restrict static 1])
3594 	{
3595 		if (ro_chipname_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3596 			return *ro_chipname_chipset;
3597 		}
3598 		if (proc_cpuinfo_hardware_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3599 			return *proc_cpuinfo_hardware_chipset;
3600 		}
3601 		if (ro_product_board_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3602 			return *ro_product_board_chipset;
3603 		}
3604 		if (ro_board_platform_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3605 			return *ro_board_platform_chipset;
3606 		}
3607 		return *ro_mediatek_platform_chipset;
3608 	}
3609 
disambiguate_hisilicon_chipset(const struct cpuinfo_arm_chipset proc_cpuinfo_hardware_chipset[restrict static1],const struct cpuinfo_arm_chipset ro_product_board_chipset[restrict static1],const struct cpuinfo_arm_chipset ro_board_platform_chipset[restrict static1])3610 	static inline struct cpuinfo_arm_chipset disambiguate_hisilicon_chipset(
3611 		const struct cpuinfo_arm_chipset proc_cpuinfo_hardware_chipset[restrict static 1],
3612 		const struct cpuinfo_arm_chipset ro_product_board_chipset[restrict static 1],
3613 		const struct cpuinfo_arm_chipset ro_board_platform_chipset[restrict static 1])
3614 	{
3615 		if (proc_cpuinfo_hardware_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3616 			return *proc_cpuinfo_hardware_chipset;
3617 		}
3618 		if (ro_product_board_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3619 			return *ro_product_board_chipset;
3620 		}
3621 		return *ro_board_platform_chipset;
3622 	}
3623 
disambiguate_amlogic_chipset(const struct cpuinfo_arm_chipset proc_cpuinfo_hardware_chipset[restrict static1],const struct cpuinfo_arm_chipset ro_board_platform_chipset[restrict static1])3624 	static inline struct cpuinfo_arm_chipset disambiguate_amlogic_chipset(
3625 		const struct cpuinfo_arm_chipset proc_cpuinfo_hardware_chipset[restrict static 1],
3626 		const struct cpuinfo_arm_chipset ro_board_platform_chipset[restrict static 1])
3627 	{
3628 		if (proc_cpuinfo_hardware_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3629 			return *proc_cpuinfo_hardware_chipset;
3630 		}
3631 		return *ro_board_platform_chipset;
3632 	}
3633 
disambiguate_marvell_chipset(const struct cpuinfo_arm_chipset proc_cpuinfo_hardware_chipset[restrict static1],const struct cpuinfo_arm_chipset ro_product_board_chipset[restrict static1],const struct cpuinfo_arm_chipset ro_chipname_chipset[restrict static1])3634 	static inline struct cpuinfo_arm_chipset disambiguate_marvell_chipset(
3635 		const struct cpuinfo_arm_chipset proc_cpuinfo_hardware_chipset[restrict static 1],
3636 		const struct cpuinfo_arm_chipset ro_product_board_chipset[restrict static 1],
3637 		const struct cpuinfo_arm_chipset ro_chipname_chipset[restrict static 1])
3638 	{
3639 		if (ro_chipname_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3640 			return *ro_chipname_chipset;
3641 		}
3642 		if (ro_product_board_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3643 			return *ro_product_board_chipset;
3644 		}
3645 		return *proc_cpuinfo_hardware_chipset;
3646 	}
3647 
disambiguate_rockchip_chipset(const struct cpuinfo_arm_chipset proc_cpuinfo_hardware_chipset[restrict static1],const struct cpuinfo_arm_chipset ro_product_board_chipset[restrict static1],const struct cpuinfo_arm_chipset ro_board_platform_chipset[restrict static1])3648 	static inline struct cpuinfo_arm_chipset disambiguate_rockchip_chipset(
3649 		const struct cpuinfo_arm_chipset proc_cpuinfo_hardware_chipset[restrict static 1],
3650 		const struct cpuinfo_arm_chipset ro_product_board_chipset[restrict static 1],
3651 		const struct cpuinfo_arm_chipset ro_board_platform_chipset[restrict static 1])
3652 	{
3653 		if (ro_product_board_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3654 			return *ro_product_board_chipset;
3655 		}
3656 		if (proc_cpuinfo_hardware_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3657 			return *proc_cpuinfo_hardware_chipset;
3658 		}
3659 		return *ro_board_platform_chipset;
3660 	}
3661 
disambiguate_spreadtrum_chipset(const struct cpuinfo_arm_chipset proc_cpuinfo_hardware_chipset[restrict static1],const struct cpuinfo_arm_chipset ro_product_board_chipset[restrict static1],const struct cpuinfo_arm_chipset ro_board_platform_chipset[restrict static1],const struct cpuinfo_arm_chipset ro_chipname_chipset[restrict static1])3662 	static inline struct cpuinfo_arm_chipset disambiguate_spreadtrum_chipset(
3663 		const struct cpuinfo_arm_chipset proc_cpuinfo_hardware_chipset[restrict static 1],
3664 		const struct cpuinfo_arm_chipset ro_product_board_chipset[restrict static 1],
3665 		const struct cpuinfo_arm_chipset ro_board_platform_chipset[restrict static 1],
3666 		const struct cpuinfo_arm_chipset ro_chipname_chipset[restrict static 1])
3667 	{
3668 		if (ro_chipname_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3669 			return *ro_chipname_chipset;
3670 		}
3671 		if (ro_product_board_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3672 			return *ro_product_board_chipset;
3673 		}
3674 		if (proc_cpuinfo_hardware_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3675 			return *proc_cpuinfo_hardware_chipset;
3676 		}
3677 		return *ro_board_platform_chipset;
3678 	}
3679 
3680 	/*
3681 	 * Decodes chipset name from Android system properties:
3682 	 * - /proc/cpuinfo Hardware string
3683 	 * - ro.product.board
3684 	 * - ro.board.platform
3685 	 * - ro.mediatek.platform
3686 	 * - ro.chipname
3687 	 * For some chipsets, the function relies frequency and on number of cores for chipset detection.
3688 	 *
3689 	 * @param[in] properties - structure with the Android system properties described above.
3690 	 * @param cores - number of cores in the chipset.
3691 	 * @param max_cpu_freq_max - maximum of /sys/devices/system/cpu/cpu<number>/cpofreq/cpu_freq_max values.
3692 	 *
3693 	 * @returns Decoded chipset name. If chipset could not be decoded, the resulting structure would use `unknown` vendor
3694 	 *          and series identifiers.
3695 	 */
cpuinfo_arm_android_decode_chipset(const struct cpuinfo_android_properties properties[restrict static1],uint32_t cores,uint32_t max_cpu_freq_max)3696 	struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset(
3697 		const struct cpuinfo_android_properties properties[restrict static 1],
3698 		uint32_t cores,
3699 		uint32_t max_cpu_freq_max)
3700 	{
3701 		struct cpuinfo_arm_chipset chipset = {
3702 			.vendor = cpuinfo_arm_chipset_vendor_unknown,
3703 			.series = cpuinfo_arm_chipset_series_unknown,
3704 		};
3705 
3706 		const bool tegra_platform = is_tegra(
3707 			properties->ro_board_platform,
3708 			properties->ro_board_platform + strnlen(properties->ro_board_platform, CPUINFO_BUILD_PROP_VALUE_MAX));
3709 
3710 		struct cpuinfo_arm_chipset chipsets[cpuinfo_android_chipset_property_max] = {
3711 			[cpuinfo_android_chipset_property_proc_cpuinfo_hardware] =
3712 				cpuinfo_arm_linux_decode_chipset_from_proc_cpuinfo_hardware(
3713 					properties->proc_cpuinfo_hardware, cores, max_cpu_freq_max, tegra_platform),
3714 			[cpuinfo_android_chipset_property_ro_product_board] =
3715 				cpuinfo_arm_android_decode_chipset_from_ro_product_board(
3716 					properties->ro_product_board, cores, max_cpu_freq_max),
3717 			[cpuinfo_android_chipset_property_ro_board_platform] =
3718 				cpuinfo_arm_android_decode_chipset_from_ro_board_platform(
3719 					properties->ro_board_platform, cores, max_cpu_freq_max),
3720 			[cpuinfo_android_chipset_property_ro_mediatek_platform] =
3721 				cpuinfo_arm_android_decode_chipset_from_ro_mediatek_platform(properties->ro_mediatek_platform),
3722 			[cpuinfo_android_chipset_property_ro_arch] =
3723 				cpuinfo_arm_android_decode_chipset_from_ro_arch(properties->ro_arch),
3724 			[cpuinfo_android_chipset_property_ro_chipname] =
3725 				cpuinfo_arm_android_decode_chipset_from_ro_chipname(properties->ro_chipname),
3726 			[cpuinfo_android_chipset_property_ro_hardware_chipname] =
3727 				cpuinfo_arm_android_decode_chipset_from_ro_chipname(properties->ro_hardware_chipname),
3728 		};
3729 		enum cpuinfo_arm_chipset_vendor vendor = cpuinfo_arm_chipset_vendor_unknown;
3730 		for (size_t i = 0; i < cpuinfo_android_chipset_property_max; i++) {
3731 			const enum cpuinfo_arm_chipset_vendor decoded_vendor = chipsets[i].vendor;
3732 			if (decoded_vendor != cpuinfo_arm_chipset_vendor_unknown) {
3733 				if (vendor == cpuinfo_arm_chipset_vendor_unknown) {
3734 					vendor = decoded_vendor;
3735 				} else if (vendor != decoded_vendor) {
3736 					/* Parsing different system properties produces different chipset vendors. This situation is rare. */
3737 					cpuinfo_log_error(
3738 						"chipset detection failed: different chipset vendors reported in different system properties");
3739 					goto finish;
3740 				}
3741 			}
3742 		}
3743 		if (vendor == cpuinfo_arm_chipset_vendor_unknown) {
3744 			cpuinfo_log_warning(
3745 				"chipset detection failed: none of the system properties matched known signatures");
3746 			goto finish;
3747 		}
3748 
3749 		/* Fix common bugs in reported chipsets */
3750 		for (size_t i = 0; i < cpuinfo_android_chipset_property_max; i++) {
3751 			cpuinfo_arm_fixup_chipset(&chipsets[i], cores, max_cpu_freq_max);
3752 		}
3753 
3754 		/*
3755 		 * Propagate suffixes: consider all pairs of chipsets, if both chipsets in the pair are from the same series,
3756 		 * and one's suffix is a prefix of another's chipset suffix, use the longest suffix.
3757 		 */
3758 		for (size_t i = 0; i < cpuinfo_android_chipset_property_max; i++) {
3759 			const size_t chipset_i_suffix_length = strnlen(chipsets[i].suffix, CPUINFO_ARM_CHIPSET_SUFFIX_MAX);
3760 			for (size_t j = 0; j < i; j++) {
3761 				if (chipsets[i].series == chipsets[j].series) {
3762 					const size_t chipset_j_suffix_length = strnlen(chipsets[j].suffix, CPUINFO_ARM_CHIPSET_SUFFIX_MAX);
3763 					if (chipset_i_suffix_length != chipset_j_suffix_length) {
3764 						const size_t common_prefix_length = (chipset_i_suffix_length < chipset_j_suffix_length) ?
3765 							chipset_i_suffix_length : chipset_j_suffix_length;
3766 						if (common_prefix_length == 0 ||
3767 							memcmp(chipsets[i].suffix, chipsets[j].suffix, common_prefix_length) == 0)
3768 						{
3769 							if (chipset_i_suffix_length > chipset_j_suffix_length) {
3770 								memcpy(chipsets[j].suffix, chipsets[i].suffix, chipset_i_suffix_length);
3771 							} else {
3772 								memcpy(chipsets[i].suffix, chipsets[j].suffix, chipset_j_suffix_length);
3773 							}
3774 						}
3775 					}
3776 				}
3777 			}
3778 		}
3779 
3780 		for (size_t i = 0; i < cpuinfo_android_chipset_property_max; i++) {
3781 			if (chipsets[i].series != cpuinfo_arm_chipset_series_unknown) {
3782 				if (chipset.series == cpuinfo_arm_chipset_series_unknown) {
3783 					chipset = chipsets[i];
3784 				} else if (chipsets[i].series != chipset.series || chipsets[i].model != chipset.model ||
3785 					strncmp(chipsets[i].suffix, chipset.suffix, CPUINFO_ARM_CHIPSET_SUFFIX_MAX) != 0)
3786 				{
3787 					cpuinfo_log_info(
3788 						"different chipsets reported in different system properties; "
3789 						"vendor-specific disambiguation heuristic would be used");
3790 					switch (vendor) {
3791 						case cpuinfo_arm_chipset_vendor_qualcomm:
3792 							return disambiguate_qualcomm_chipset(
3793 								&chipsets[cpuinfo_android_chipset_property_proc_cpuinfo_hardware],
3794 								&chipsets[cpuinfo_android_chipset_property_ro_product_board],
3795 								&chipsets[cpuinfo_android_chipset_property_ro_board_platform],
3796 								&chipsets[cpuinfo_android_chipset_property_ro_chipname],
3797 								&chipsets[cpuinfo_android_chipset_property_ro_hardware_chipname]);
3798 						case cpuinfo_arm_chipset_vendor_mediatek:
3799 							return disambiguate_mediatek_chipset(
3800 								&chipsets[cpuinfo_android_chipset_property_proc_cpuinfo_hardware],
3801 								&chipsets[cpuinfo_android_chipset_property_ro_product_board],
3802 								&chipsets[cpuinfo_android_chipset_property_ro_board_platform],
3803 								&chipsets[cpuinfo_android_chipset_property_ro_mediatek_platform],
3804 								&chipsets[cpuinfo_android_chipset_property_ro_chipname]);
3805 						case cpuinfo_arm_chipset_vendor_hisilicon:
3806 							return disambiguate_hisilicon_chipset(
3807 								&chipsets[cpuinfo_android_chipset_property_proc_cpuinfo_hardware],
3808 								&chipsets[cpuinfo_android_chipset_property_ro_product_board],
3809 								&chipsets[cpuinfo_android_chipset_property_ro_board_platform]);
3810 						case cpuinfo_arm_chipset_vendor_amlogic:
3811 							return disambiguate_amlogic_chipset(
3812 								&chipsets[cpuinfo_android_chipset_property_proc_cpuinfo_hardware],
3813 								&chipsets[cpuinfo_android_chipset_property_ro_board_platform]);
3814 						case cpuinfo_arm_chipset_vendor_marvell:
3815 							return disambiguate_marvell_chipset(
3816 								&chipsets[cpuinfo_android_chipset_property_proc_cpuinfo_hardware],
3817 								&chipsets[cpuinfo_android_chipset_property_ro_product_board],
3818 								&chipsets[cpuinfo_android_chipset_property_ro_chipname]);
3819 						case cpuinfo_arm_chipset_vendor_rockchip:
3820 							return disambiguate_rockchip_chipset(
3821 								&chipsets[cpuinfo_android_chipset_property_proc_cpuinfo_hardware],
3822 								&chipsets[cpuinfo_android_chipset_property_ro_product_board],
3823 								&chipsets[cpuinfo_android_chipset_property_ro_board_platform]);
3824 						case cpuinfo_arm_chipset_vendor_spreadtrum:
3825 							return disambiguate_spreadtrum_chipset(
3826 								&chipsets[cpuinfo_android_chipset_property_proc_cpuinfo_hardware],
3827 								&chipsets[cpuinfo_android_chipset_property_ro_product_board],
3828 								&chipsets[cpuinfo_android_chipset_property_ro_board_platform],
3829 								&chipsets[cpuinfo_android_chipset_property_ro_chipname]);
3830 						default:
3831 							cpuinfo_log_error(
3832 								"chipset detection failed: "
3833 								"could not disambiguate different chipsets reported in different system properties");
3834 							/* chipset variable contains valid, but inconsistent chipset information, overwrite it */
3835 							chipset = (struct cpuinfo_arm_chipset) {
3836 								.vendor = cpuinfo_arm_chipset_vendor_unknown,
3837 								.series = cpuinfo_arm_chipset_series_unknown,
3838 							};
3839 							goto finish;
3840 					}
3841 				}
3842 			}
3843 		}
3844 
3845 	finish:
3846 		return chipset;
3847 	}
3848 #else /* !defined(__ANDROID__) */
3849 	/*
3850 	 * Fix commonly misreported Broadcom BCM models on Raspberry Pi boards.
3851 	 *
3852 	 * @param[in,out] chipset - chipset name to fix.
3853 	 * @param[in] revision - /proc/cpuinfo Revision string.
3854 	 */
cpuinfo_arm_fixup_raspberry_pi_chipset(struct cpuinfo_arm_chipset chipset[restrict static1],const char revision[restrict static CPUINFO_HARDWARE_VALUE_MAX])3855 	void cpuinfo_arm_fixup_raspberry_pi_chipset(
3856 		struct cpuinfo_arm_chipset chipset[restrict static 1],
3857 		const char revision[restrict static CPUINFO_HARDWARE_VALUE_MAX])
3858 	{
3859 		const size_t revision_length = strnlen(revision, CPUINFO_REVISION_VALUE_MAX);
3860 
3861 		/* Parse revision codes according to https://www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md */
3862 		#if CPUINFO_ARCH_ARM
3863 			if (revision_length == 4) {
3864 				/*
3865 				 * Old-style revision codes.
3866 				 * All Raspberry Pi models with old-style revision code use Broadcom BCM2835.
3867 				 */
3868 
3869 				/* BCM2835 often misreported as BCM2708 */
3870 				if (chipset->model == 2708) {
3871 					chipset->model = 2835;
3872 				}
3873 				return;
3874 			}
3875 		#endif
3876 		if ((size_t) (revision_length - 5) <= (size_t) (8 - 5) /* 5 <= length(revision) <= 8 */) {
3877 			/* New-style revision codes */
3878 
3879 			uint32_t model = 0;
3880 			switch (revision[revision_length - 4]) {
3881 				case '0':
3882 					/* BCM2835 */
3883 					model = 2835;
3884 					break;
3885 				case '1':
3886 					/* BCM2836 */
3887 					model = 2836;
3888 					break;
3889 				case '2':
3890 					/* BCM2837 */
3891 					model = 2837;
3892 					break;
3893 				case '3':
3894 					/* BCM2711 */
3895 					model = 2711;
3896 					break;
3897 			}
3898 
3899 			if (model != 0) {
3900 				chipset->model = model;
3901 				chipset->suffix[0] = 0;
3902 			}
3903 		}
3904 	}
3905 
3906 	/*
3907 	 * Decodes chipset name from /proc/cpuinfo Hardware string.
3908 	 * For some chipsets, the function relies frequency and on number of cores for chipset detection.
3909 	 *
3910 	 * @param[in] hardware - /proc/cpuinfo Hardware string.
3911 	 * @param cores - number of cores in the chipset.
3912 	 * @param max_cpu_freq_max - maximum of /sys/devices/system/cpu/cpu<number>/cpofreq/cpu_freq_max values.
3913 	 *
3914 	 * @returns Decoded chipset name. If chipset could not be decoded, the resulting structure would use `unknown` vendor
3915 	 *          and series identifiers.
3916 	 */
cpuinfo_arm_linux_decode_chipset(const char hardware[restrict static CPUINFO_HARDWARE_VALUE_MAX],const char revision[restrict static CPUINFO_REVISION_VALUE_MAX],uint32_t cores,uint32_t max_cpu_freq_max)3917 	struct cpuinfo_arm_chipset cpuinfo_arm_linux_decode_chipset(
3918 		const char hardware[restrict static CPUINFO_HARDWARE_VALUE_MAX],
3919 		const char revision[restrict static CPUINFO_REVISION_VALUE_MAX],
3920 		uint32_t cores,
3921 		uint32_t max_cpu_freq_max)
3922 	{
3923 		struct cpuinfo_arm_chipset chipset =
3924 			cpuinfo_arm_linux_decode_chipset_from_proc_cpuinfo_hardware(
3925 				hardware, cores, max_cpu_freq_max, false);
3926 		if (chipset.vendor == cpuinfo_arm_chipset_vendor_unknown) {
3927 			cpuinfo_log_warning(
3928 				"chipset detection failed: /proc/cpuinfo Hardware string did not match known signatures");
3929 		} else if (chipset.vendor == cpuinfo_arm_chipset_vendor_broadcom) {
3930 			/* Raspberry Pi kernel reports bogus chipset models; detect chipset from RPi revision */
3931 			cpuinfo_arm_fixup_raspberry_pi_chipset(&chipset, revision);
3932 		} else {
3933 			cpuinfo_arm_fixup_chipset(&chipset, cores, max_cpu_freq_max);
3934 		}
3935 		return chipset;
3936 	}
3937 
3938 #endif
3939