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