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