| 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 | } |