64 #include "cpu-features.h"
73 #include <sys/system_properties.h>
75 #include <winpr/wtypes.h>
76 #include <winpr/debug.h>
78 static pthread_once_t g_once;
80 static AndroidCpuFamily g_cpuFamily;
81 static uint64_t g_cpuFeatures;
82 static int g_cpuCount;
85 static uint32_t g_cpuIdArm;
88 static const int android_cpufeatures_debug = 0;
93 if (android_cpufeatures_debug) \
95 printf(__VA_ARGS__); \
101 static __inline__
void x86_cpuid(
int func,
int values[4])
106 __asm__ __volatile__(
"push %%ebx\n"
110 :
"=a"(a),
"=r"(b),
"=c"(c),
"=d"(d)
117 #elif defined(__x86_64__)
118 static __inline__
void x86_cpuid(
int func,
int values[4])
123 __asm__ __volatile__(
"push %%rbx\n"
127 :
"=a"(a),
"=r"(b),
"=c"(c),
"=d"(d)
140 static int get_file_size(
const char* pathname)
144 fd = open(pathname, O_RDONLY);
148 char ebuffer[256] = { 0 };
149 D(
"Can't open %s: %s\n", pathname, winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
155 int ret = read(fd, buffer,
sizeof buffer);
159 char ebuffer[256] = { 0 };
163 D(
"Error while reading %s: %s\n", pathname,
164 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
183 static int read_file(
const char* pathname,
char* buffer,
size_t buffsize)
186 fd = open(pathname, O_RDONLY);
190 char ebuffer[256] = { 0 };
191 D(
"Could not open %s: %s\n", pathname, winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
197 while (count < (
int)buffsize)
199 int ret = read(fd, buffer + count, buffsize - count);
203 char ebuffer[256] = { 0 };
207 D(
"Error while reading from %s: %s\n", pathname,
208 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
233 static char* extract_cpuinfo_field(
const char* buffer,
int buflen,
const char* field)
235 int fieldlen = strlen(field);
236 const char* bufend = buffer + buflen;
245 p = memmem(p, bufend - p, field, fieldlen);
250 if (p == buffer || p[-1] ==
'\n')
258 p = memchr(p,
':', bufend - p);
260 if (p == NULL || p[1] !=
' ')
265 q = memchr(p,
'\n', bufend - p);
272 result = malloc(len + 1);
277 memcpy(result, p, len);
286 static int has_list_item(
const char* list,
const char* item)
288 const char* p = list;
289 int itemlen = strlen(item);
299 while (*p ==
' ' || *p ==
'\t')
305 while (*q && *q !=
' ' && *q !=
'\t')
308 if (itemlen == q - p && !memcmp(p, item, itemlen))
329 static const char* parse_number(
const char* input,
const char* limit,
int base,
int* result)
331 const char* p = input;
338 if ((
unsigned)d >= 10U)
342 if ((
unsigned)d >= 6U)
345 if ((
unsigned)d >= 6U)
354 val = val * base + d;
365 static const char* parse_decimal(
const char* input,
const char* limit,
int* result)
367 return parse_number(input, limit, 10, result);
371 static const char* parse_hexadecimal(
const char* input,
const char* limit,
int* result)
373 return parse_number(input, limit, 16, result);
388 static __inline__
void cpulist_init(CpuList* list)
393 static __inline__
void cpulist_and(CpuList* list1, CpuList* list2)
395 list1->mask &= list2->mask;
398 static __inline__
void cpulist_set(CpuList* list,
int index)
400 if ((
unsigned)index < 32)
402 list->mask |= (uint32_t)(1U << index);
406 static __inline__
int cpulist_count(CpuList* list)
408 return __builtin_popcount(list->mask);
421 static void cpulist_parse(CpuList* list,
const char* line,
int line_len)
423 const char* p = line;
424 const char* end = p + line_len;
430 while (p < end && *p !=
'\n')
435 q = memchr(p,
',', end - p);
443 p = parse_decimal(p, q, &start_value);
448 end_value = start_value;
453 if (p < q && *p ==
'-')
455 p = parse_decimal(p + 1, q, &end_value);
462 for (
int val = start_value; val <= end_value; val++)
464 cpulist_set(list, val);
478 static void cpulist_read_from(CpuList* list,
const char* filename)
483 filelen = read_file(filename, file,
sizeof file);
487 char ebuffer[256] = { 0 };
488 D(
"Could not read %s: %s\n", filename, winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
492 cpulist_parse(list, file, filelen);
494 #if defined(__aarch64__)
496 #define HWCAP_FP (1 << 0)
497 #define HWCAP_ASIMD (1 << 1)
498 #define HWCAP_AES (1 << 3)
499 #define HWCAP_PMULL (1 << 4)
500 #define HWCAP_SHA1 (1 << 5)
501 #define HWCAP_SHA2 (1 << 6)
502 #define HWCAP_CRC32 (1 << 7)
508 #define HWCAP_VFP (1 << 6)
509 #define HWCAP_IWMMXT (1 << 9)
510 #define HWCAP_NEON (1 << 12)
511 #define HWCAP_VFPv3 (1 << 13)
512 #define HWCAP_VFPv3D16 (1 << 14)
513 #define HWCAP_VFPv4 (1 << 16)
514 #define HWCAP_IDIVA (1 << 17)
515 #define HWCAP_IDIVT (1 << 18)
518 #define HWCAP2_AES (1 << 0)
519 #define HWCAP2_PMULL (1 << 1)
520 #define HWCAP2_SHA1 (1 << 2)
521 #define HWCAP2_SHA2 (1 << 3)
522 #define HWCAP2_CRC32 (1 << 4)
527 #define HWCAP_SET_FOR_ARMV8 \
528 (HWCAP_VFP | HWCAP_NEON | HWCAP_VFPv3 | HWCAP_VFPv4 | HWCAP_IDIVA | HWCAP_IDIVT)
531 #if defined(__mips__)
533 #define HWCAP_MIPS_R6 (1 << 0)
534 #define HWCAP_MIPS_MSA (1 << 1)
537 #if defined(__arm__) || defined(__aarch64__) || defined(__mips__)
556 static uint32_t get_elf_hwcap_from_getauxval(
int hwcap_type)
558 typedef unsigned long getauxval_func_t(
unsigned long);
560 void* libc_handle = dlopen(
"libc.so", RTLD_NOW);
564 D(
"Could not dlopen() C library: %s\n", dlerror());
569 getauxval_func_t* func = (getauxval_func_t*)dlsym(libc_handle,
"getauxval");
573 D(
"Could not find getauxval() in C library\n");
578 ret = (uint32_t)(*func)(hwcap_type);
581 dlclose(libc_handle);
591 static uint32_t get_elf_hwcap_from_proc_self_auxv(
void)
593 const char filepath[] =
"/proc/self/auxv";
594 int fd = TEMP_FAILURE_RETRY(open(filepath, O_RDONLY));
598 char ebuffer[256] = { 0 };
599 D(
"Could not open %s: %s\n", filepath, winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
613 int ret = TEMP_FAILURE_RETRY(read(fd, (
char*)&entry,
sizeof entry));
617 char ebuffer[256] = { 0 };
618 D(
"Error while reading %s: %s\n", filepath,
619 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
624 if (ret == 0 || (entry.tag == 0 && entry.value == 0))
627 if (entry.tag == AT_HWCAP)
629 result = entry.value;
643 static uint32_t get_elf_hwcap_from_proc_cpuinfo(
const char* cpuinfo,
int cpuinfo_len)
646 long architecture = 0;
647 char* cpuArch = extract_cpuinfo_field(cpuinfo, cpuinfo_len,
"CPU architecture");
651 architecture = strtol(cpuArch, NULL, 10);
654 if (architecture >= 8L)
660 D(
"Faking 32-bit ARM HWCaps on ARMv%ld CPU\n", architecture);
661 return HWCAP_SET_FOR_ARMV8;
665 char* cpuFeatures = extract_cpuinfo_field(cpuinfo, cpuinfo_len,
"Features");
667 if (cpuFeatures != NULL)
669 D(
"Found cpuFeatures = '%s'\n", cpuFeatures);
671 if (has_list_item(cpuFeatures,
"vfp"))
674 if (has_list_item(cpuFeatures,
"vfpv3"))
675 hwcaps |= HWCAP_VFPv3;
677 if (has_list_item(cpuFeatures,
"vfpv3d16"))
678 hwcaps |= HWCAP_VFPv3D16;
680 if (has_list_item(cpuFeatures,
"vfpv4"))
681 hwcaps |= HWCAP_VFPv4;
683 if (has_list_item(cpuFeatures,
"neon"))
684 hwcaps |= HWCAP_NEON;
686 if (has_list_item(cpuFeatures,
"idiva"))
687 hwcaps |= HWCAP_IDIVA;
689 if (has_list_item(cpuFeatures,
"idivt"))
690 hwcaps |= HWCAP_IDIVT;
692 if (has_list_item(cpuFeatures,
"idiv"))
693 hwcaps |= HWCAP_IDIVA | HWCAP_IDIVT;
695 if (has_list_item(cpuFeatures,
"iwmmxt"))
696 hwcaps |= HWCAP_IWMMXT;
711 static int get_cpu_count(
void)
713 CpuList cpus_present[1];
714 CpuList cpus_possible[1];
715 cpulist_read_from(cpus_present,
"/sys/devices/system/cpu/present");
716 cpulist_read_from(cpus_possible,
"/sys/devices/system/cpu/possible");
720 cpulist_and(cpus_present, cpus_possible);
721 return cpulist_count(cpus_present);
724 static void android_cpuInitFamily(
void)
727 g_cpuFamily = ANDROID_CPU_FAMILY_ARM;
728 #elif defined(__i386__)
729 g_cpuFamily = ANDROID_CPU_FAMILY_X86;
730 #elif defined(__mips64)
732 g_cpuFamily = ANDROID_CPU_FAMILY_MIPS64;
733 #elif defined(__mips__)
734 g_cpuFamily = ANDROID_CPU_FAMILY_MIPS;
735 #elif defined(__aarch64__)
736 g_cpuFamily = ANDROID_CPU_FAMILY_ARM64;
737 #elif defined(__x86_64__)
738 g_cpuFamily = ANDROID_CPU_FAMILY_X86_64;
740 g_cpuFamily = ANDROID_CPU_FAMILY_UNKNOWN;
744 static void android_cpuInit(
void)
746 char* cpuinfo = NULL;
748 android_cpuInitFamily();
752 cpuinfo_len = get_file_size(
"/proc/cpuinfo");
756 D(
"cpuinfo_len cannot be computed!");
760 cpuinfo = malloc(cpuinfo_len);
764 D(
"cpuinfo buffer could not be allocated");
768 cpuinfo_len = read_file(
"/proc/cpuinfo", cpuinfo, cpuinfo_len);
769 D(
"cpuinfo_len is (%d):\n%.*s\n", cpuinfo_len, cpuinfo_len >= 0 ? cpuinfo_len : 0, cpuinfo);
778 g_cpuCount = get_cpu_count();
785 D(
"found cpuCount = %d\n", g_cpuCount);
796 char* cpuArch = extract_cpuinfo_field(cpuinfo, cpuinfo_len,
"CPU architecture");
803 D(
"found cpuArch = '%s'\n", cpuArch);
805 archNumber = strtol(cpuArch, &end, 10);
808 if (end > cpuArch && archNumber >= 7)
825 char* cpuProc = extract_cpuinfo_field(cpuinfo, cpuinfo_len,
"Processor");
829 D(
"found cpuProc = '%s'\n", cpuProc);
831 if (has_list_item(cpuProc,
"(v6l)"))
833 D(
"CPU processor and architecture mismatch!!\n");
843 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_ARMv7;
849 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_LDREX_STREX;
857 hwcaps = get_elf_hwcap_from_getauxval(AT_HWCAP);
861 D(
"Parsing /proc/self/auxv to extract ELF hwcaps!\n");
862 hwcaps = get_elf_hwcap_from_proc_self_auxv();
870 D(
"Parsing /proc/cpuinfo to extract ELF hwcaps!\n");
871 hwcaps = get_elf_hwcap_from_proc_cpuinfo(cpuinfo, cpuinfo_len);
876 int has_vfp = (hwcaps & HWCAP_VFP);
877 int has_vfpv3 = (hwcaps & HWCAP_VFPv3);
878 int has_vfpv3d16 = (hwcaps & HWCAP_VFPv3D16);
879 int has_vfpv4 = (hwcaps & HWCAP_VFPv4);
880 int has_neon = (hwcaps & HWCAP_NEON);
881 int has_idiva = (hwcaps & HWCAP_IDIVA);
882 int has_idivt = (hwcaps & HWCAP_IDIVT);
883 int has_iwmmxt = (hwcaps & HWCAP_IWMMXT);
890 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3 | ANDROID_CPU_ARM_FEATURE_VFP_FP16 |
891 ANDROID_CPU_ARM_FEATURE_VFP_FMA;
898 if (has_vfpv3 || has_vfpv3d16)
899 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3;
905 if (g_cpuFeatures & ANDROID_CPU_ARM_FEATURE_ARMv7)
906 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3;
908 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv2;
914 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3 | ANDROID_CPU_ARM_FEATURE_NEON |
915 ANDROID_CPU_ARM_FEATURE_VFP_D32;
918 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON_FMA;
922 if (g_cpuFeatures & ANDROID_CPU_ARM_FEATURE_VFPv3)
923 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv2 | ANDROID_CPU_ARM_FEATURE_ARMv7;
926 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_IDIV_ARM;
929 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2;
932 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_iWMMXt;
936 uint32_t hwcaps2 = 0;
937 hwcaps2 = get_elf_hwcap_from_getauxval(AT_HWCAP2);
941 int has_aes = (hwcaps2 & HWCAP2_AES);
942 int has_pmull = (hwcaps2 & HWCAP2_PMULL);
943 int has_sha1 = (hwcaps2 & HWCAP2_SHA1);
944 int has_sha2 = (hwcaps2 & HWCAP2_SHA2);
945 int has_crc32 = (hwcaps2 & HWCAP2_CRC32);
948 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_AES;
951 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_PMULL;
954 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_SHA1;
957 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_SHA2;
960 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_CRC32;
966 static const struct CpuIdEntry
972 } cpu_id_entries[] = {
973 {
"CPU implementer",
'x', 24, 8 },
974 {
"CPU variant",
'x', 20, 4 },
975 {
"CPU part",
'x', 4, 12 },
976 {
"CPU revision",
'd', 0, 4 },
978 D(
"Parsing /proc/cpuinfo to recover CPUID\n");
980 for (
size_t i = 0; i <
sizeof(cpu_id_entries) /
sizeof(cpu_id_entries[0]); ++i)
982 const struct CpuIdEntry* entry = &cpu_id_entries[i];
983 char* value = extract_cpuinfo_field(cpuinfo, cpuinfo_len, entry->field);
988 D(
"field=%s value='%s'\n", entry->field, value);
989 char* value_end = value + strlen(value);
991 const char* start = value;
994 if (value[0] ==
'0' && (value[1] ==
'x' || value[1] ==
'X'))
997 p = parse_hexadecimal(start, value_end, &val);
999 else if (entry->format ==
'x')
1000 p = parse_hexadecimal(value, value_end, &val);
1002 p = parse_decimal(value, value_end, &val);
1004 if (p > (
const char*)start)
1006 val &= ((1 << entry->bit_length) - 1);
1007 val <<= entry->bit_lshift;
1008 g_cpuIdArm |= (uint32_t)val;
1016 static const struct CpuFix
1023 { 0x510006f2, ANDROID_CPU_ARM_FEATURE_IDIV_ARM | ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2 },
1024 { 0x510006f3, ANDROID_CPU_ARM_FEATURE_IDIV_ARM | ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2 },
1027 for (
size_t n = 0; n <
sizeof(cpu_fixes) /
sizeof(cpu_fixes[0]); ++n)
1029 const struct CpuFix* entry = &cpu_fixes[n];
1031 if (g_cpuIdArm == entry->cpuid)
1032 g_cpuFeatures |= entry->or_flags;
1040 char* hardware = extract_cpuinfo_field(cpuinfo, cpuinfo_len,
"Hardware");
1044 if (!strcmp(hardware,
"Goldfish") && g_cpuIdArm == 0x4100c080 &&
1045 (g_cpuFamily & ANDROID_CPU_ARM_FEATURE_ARMv7) != 0)
1047 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_IDIV_ARM;
1057 uint32_t hwcaps = 0;
1058 hwcaps = get_elf_hwcap_from_getauxval(AT_HWCAP);
1062 int has_fp = (hwcaps & HWCAP_FP);
1063 int has_asimd = (hwcaps & HWCAP_ASIMD);
1064 int has_aes = (hwcaps & HWCAP_AES);
1065 int has_pmull = (hwcaps & HWCAP_PMULL);
1066 int has_sha1 = (hwcaps & HWCAP_SHA1);
1067 int has_sha2 = (hwcaps & HWCAP_SHA2);
1068 int has_crc32 = (hwcaps & HWCAP_CRC32);
1072 D(
"ERROR: Floating-point unit missing, but is required by Android on AArch64 "
1078 D(
"ERROR: ASIMD unit missing, but is required by Android on AArch64 CPUs\n");
1082 g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_FP;
1085 g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_ASIMD;
1088 g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_AES;
1091 g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_PMULL;
1094 g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_SHA1;
1097 g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_SHA2;
1100 g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_CRC32;
1104 #if defined(__i386__) || defined(__x86_64__)
1107 #define VENDOR_INTEL_b 0x756e6547
1108 #define VENDOR_INTEL_c 0x6c65746e
1109 #define VENDOR_INTEL_d 0x49656e69
1112 (regs[1] == VENDOR_INTEL_b && regs[2] == VENDOR_INTEL_c && regs[3] == VENDOR_INTEL_d);
1115 if ((regs[2] & (1 << 9)) != 0)
1117 g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSSE3;
1120 if ((regs[2] & (1 << 23)) != 0)
1122 g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_POPCNT;
1125 if ((regs[2] & (1 << 19)) != 0)
1127 g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSE4_1;
1130 if ((regs[2] & (1 << 20)) != 0)
1132 g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSE4_2;
1135 if (vendorIsIntel && (regs[2] & (1 << 22)) != 0)
1137 g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_MOVBE;
1140 if ((regs[2] & (1 << 25)) != 0)
1142 g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AES_NI;
1145 if ((regs[2] & (1 << 28)) != 0)
1147 g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AVX;
1150 if ((regs[2] & (1 << 30)) != 0)
1152 g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_RDRAND;
1157 if ((regs[1] & (1 << 5)) != 0)
1159 g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AVX2;
1162 if ((regs[1] & (1 << 29)) != 0)
1164 g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SHA_NI;
1168 #if defined(__mips__)
1172 uint32_t hwcaps = 0;
1173 hwcaps = get_elf_hwcap_from_getauxval(AT_HWCAP);
1177 int has_r6 = (hwcaps & HWCAP_MIPS_R6);
1178 int has_msa = (hwcaps & HWCAP_MIPS_MSA);
1181 g_cpuFeatures |= ANDROID_CPU_MIPS_FEATURE_R6;
1184 g_cpuFeatures |= ANDROID_CPU_MIPS_FEATURE_MSA;
1191 AndroidCpuFamily android_getCpuFamily(
void)
1193 pthread_once(&g_once, android_cpuInit);
1197 uint64_t android_getCpuFeatures(
void)
1199 pthread_once(&g_once, android_cpuInit);
1200 return g_cpuFeatures;
1203 int android_getCpuCount(
void)
1205 pthread_once(&g_once, android_cpuInit);
1209 static void android_cpuInitDummy(
void)
1214 int android_setCpu(
int cpu_count, uint64_t cpu_features)
1220 android_cpuInitFamily();
1221 g_cpuCount = (cpu_count <= 0 ? 1 : cpu_count);
1222 g_cpuFeatures = cpu_features;
1223 pthread_once(&g_once, android_cpuInitDummy);
1228 uint32_t android_getCpuIdArm(
void)
1230 pthread_once(&g_once, android_cpuInit);
1234 int android_setCpuArm(
int cpu_count, uint64_t cpu_features, uint32_t cpu_id)
1236 if (!android_setCpu(cpu_count, cpu_features))
1239 g_cpuIdArm = cpu_id;