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