1 /* 2 * SPDX-License-Identifier: GPL-2.0-or-later 3 * Host specific cpu identification for ppc. 4 */ 5 6 #include "qemu/osdep.h" 7 #include "host/cpuinfo.h" 8 9 #ifdef CONFIG_LINUX 10 # include <asm/cputable.h> 11 # ifdef CONFIG_GETAUXVAL 12 # include <sys/auxv.h> 13 # else 14 # include "elf.h" 15 # endif 16 #endif 17 #if defined(CONFIG_ELF_AUX_INFO) 18 # include <sys/auxv.h> 19 # include <machine/cpu.h> 20 # ifndef PPC_FEATURE2_ARCH_3_1 21 # define PPC_FEATURE2_ARCH_3_1 0 22 # endif 23 # define PPC_FEATURE2_VEC_CRYPTO PPC_FEATURE2_HAS_VEC_CRYPTO 24 #endif 25 26 unsigned cpuinfo; 27 28 /* Called both as constructor and (possibly) via other constructors. */ 29 unsigned __attribute__((constructor)) cpuinfo_init(void) 30 { 31 unsigned info = cpuinfo; 32 33 if (info) { 34 return info; 35 } 36 37 info = CPUINFO_ALWAYS; 38 39 #if defined(CONFIG_LINUX) || defined(CONFIG_ELF_AUX_INFO) 40 unsigned long hwcap = qemu_getauxval(AT_HWCAP); 41 unsigned long hwcap2 = qemu_getauxval(AT_HWCAP2); 42 43 /* Version numbers are monotonic, and so imply all lower versions. */ 44 if (hwcap2 & PPC_FEATURE2_ARCH_3_1) { 45 info |= CPUINFO_V3_1 | CPUINFO_V3_0 | CPUINFO_V2_07 | CPUINFO_V2_06; 46 } else if (hwcap2 & PPC_FEATURE2_ARCH_3_00) { 47 info |= CPUINFO_V3_0 | CPUINFO_V2_07 | CPUINFO_V2_06; 48 } else if (hwcap2 & PPC_FEATURE2_ARCH_2_07) { 49 info |= CPUINFO_V2_07 | CPUINFO_V2_06; 50 } else if (hwcap & PPC_FEATURE_ARCH_2_06) { 51 info |= CPUINFO_V2_06; 52 } 53 54 if (hwcap2 & PPC_FEATURE2_ISEL) { 55 info |= CPUINFO_ISEL; 56 } 57 if (hwcap & PPC_FEATURE_HAS_ALTIVEC) { 58 info |= CPUINFO_ALTIVEC; 59 /* We only care about the portion of VSX that overlaps Altivec. */ 60 if (hwcap & PPC_FEATURE_HAS_VSX) { 61 info |= CPUINFO_VSX; 62 /* 63 * We use VSX especially for little-endian, but we should 64 * always have both anyway, since VSX came with Power7 65 * and crypto came with Power8. 66 */ 67 if (hwcap2 & PPC_FEATURE2_VEC_CRYPTO) { 68 info |= CPUINFO_CRYPTO; 69 } 70 } 71 } 72 #endif 73 74 cpuinfo = info; 75 return info; 76 } 77