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