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 21unsigned cpuinfo; 22 23#ifdef CONFIG_DARWIN 24static 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. */ 45unsigned __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 info |= (hwcap & HWCAP_AES ? CPUINFO_AES: 0); 60#endif 61#ifdef CONFIG_DARWIN 62 info |= sysctl_for_bool("hw.optional.arm.FEAT_LSE") * CPUINFO_LSE; 63 info |= sysctl_for_bool("hw.optional.arm.FEAT_LSE2") * CPUINFO_LSE2; 64 info |= sysctl_for_bool("hw.optional.arm.FEAT_AES") * CPUINFO_AES; 65#endif 66 67 cpuinfo = info; 68 return info; 69} 70