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