1 /* 2 * SPDX-License-Identifier: GPL-2.0-or-later 3 * Host specific cpu indentification for AArch64. 4 */ 5 6 #include "qemu/osdep.h" 7 #include "host/cpuinfo.h" 8 9 #ifdef CONFIG_LINUX 10 # ifdef CONFIG_GETAUXVAL 11 # include <sys/auxv.h> 12 # else 13 # include <asm/hwcap.h> 14 # include "elf.h" 15 # endif 16 #endif 17 #ifdef CONFIG_DARWIN 18 # include <sys/sysctl.h> 19 #endif 20 21 unsigned cpuinfo; 22 23 #ifdef CONFIG_DARWIN 24 static bool sysctl_for_bool(const char *name) 25 { 26 int val = 0; 27 size_t len = sizeof(val); 28 29 if (sysctlbyname(name, &val, &len, NULL, 0) == 0) { 30 return val != 0; 31 } 32 33 /* 34 * We might in the future ask for properties not present in older kernels, 35 * but we're only asking about static properties, all of which should be 36 * 'int'. So we shouln't see ENOMEM (val too small), or any of the other 37 * more exotic errors. 38 */ 39 assert(errno == ENOENT); 40 return false; 41 } 42 #endif 43 44 /* Called both as constructor and (possibly) via other constructors. */ 45 unsigned __attribute__((constructor)) cpuinfo_init(void) 46 { 47 unsigned info = cpuinfo; 48 49 if (info) { 50 return info; 51 } 52 53 info = CPUINFO_ALWAYS; 54 55 #ifdef CONFIG_LINUX 56 unsigned long hwcap = qemu_getauxval(AT_HWCAP); 57 info |= (hwcap & HWCAP_ATOMICS ? CPUINFO_LSE : 0); 58 info |= (hwcap & HWCAP_USCAT ? CPUINFO_LSE2 : 0); 59 #endif 60 #ifdef CONFIG_DARWIN 61 info |= sysctl_for_bool("hw.optional.arm.FEAT_LSE") * CPUINFO_LSE; 62 info |= sysctl_for_bool("hw.optional.arm.FEAT_LSE2") * CPUINFO_LSE2; 63 #endif 64 65 cpuinfo = info; 66 return info; 67 } 68