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