| 1 | /* |
| 2 | * Arm specific proc functions for linux-user |
| 3 | * |
| 4 | * SPDX-License-Identifier: GPL-2.0-or-later |
| 5 | */ |
| 6 | #ifndef ARM_TARGET_PROC_H |
| 7 | #define ARM_TARGET_PROC_H |
| 8 | |
| 9 | #include "target/arm/cpu-features.h" /* for MIDR_EL1 field definitions */ |
| 10 | |
| 11 | static int open_cpuinfo(CPUArchState *cpu_env, int fd) |
| 12 | { |
| 13 | ARMCPU *cpu = env_archcpu(cpu_env); |
| 14 | int arch, midr_rev, midr_part, midr_var, midr_impl; |
| 15 | target_ulong elf_hwcap = get_elf_hwcap(env_cpu(cpu_env)); |
| 16 | target_ulong elf_hwcap2 = get_elf_hwcap2(env_cpu(cpu_env)); |
| 17 | const char *elf_name; |
| 18 | int num_cpus, len_part, len_var; |
| 19 | |
| 20 | #if TARGET_BIG_ENDIAN |
| 21 | # define END_SUFFIX "b" |
| 22 | #else |
| 23 | # define END_SUFFIX "l" |
| 24 | #endif |
| 25 | |
| 26 | arch = 8; |
| 27 | elf_name = "v8" END_SUFFIX; |
| 28 | midr_rev = FIELD_EX32(cpu->midr, MIDR_EL1, REVISION); |
| 29 | midr_part = FIELD_EX32(cpu->midr, MIDR_EL1, PARTNUM); |
| 30 | midr_var = FIELD_EX32(cpu->midr, MIDR_EL1, VARIANT); |
| 31 | midr_impl = FIELD_EX32(cpu->midr, MIDR_EL1, IMPLEMENTER); |
| 32 | len_part = 3; |
| 33 | len_var = 1; |
| 34 | |
| 35 | #ifndef TARGET_AARCH64 |
| 36 | /* For simplicity, treat ARMv8 as an arm64 kernel with CONFIG_COMPAT. */ |
| 37 | if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) { |
| 38 | if (arm_feature(&cpu->env, ARM_FEATURE_V7)) { |
| 39 | arch = 7; |
| 40 | midr_var = (cpu->midr >> 16) & 0x7f; |
| 41 | len_var = 2; |
| 42 | if (arm_feature(&cpu->env, ARM_FEATURE_M)) { |
| 43 | elf_name = "armv7m" END_SUFFIX; |
| 44 | } else { |
| 45 | elf_name = "armv7" END_SUFFIX; |
| 46 | } |
| 47 | } else { |
| 48 | midr_part = cpu->midr >> 4; |
| 49 | len_part = 7; |
| 50 | if (arm_feature(&cpu->env, ARM_FEATURE_V6)) { |
| 51 | arch = 6; |
| 52 | elf_name = "armv6" END_SUFFIX; |
| 53 | } else if (arm_feature(&cpu->env, ARM_FEATURE_V5)) { |
| 54 | arch = 5; |
| 55 | elf_name = "armv5t" END_SUFFIX; |
| 56 | } else { |
| 57 | arch = 4; |
| 58 | elf_name = "armv4" END_SUFFIX; |
| 59 | } |
| 60 | } |
| 61 | } |
| 62 | #endif |
| 63 | |
| 64 | #undef END_SUFFIX |
| 65 | |
| 66 | num_cpus = sysconf(_SC_NPROCESSORS_ONLN); |
| 67 | for (int i = 0; i < num_cpus; i++) { |
| 68 | dprintf(fd, |
| 69 | "processor\t: %d\n" |
| 70 | "model name\t: ARMv%d Processor rev %d (%s)\n" |
| 71 | "BogoMIPS\t: 100.00\n" |
| 72 | "Features\t:", |
| 73 | i, arch, midr_rev, elf_name); |
| 74 | |
| 75 | for (target_ulong j = elf_hwcap; j ; j &= j - 1) { |
| 76 | dprintf(fd, " %s", elf_hwcap_str(ctz64(j))); |
| 77 | } |
| 78 | for (target_ulong j = elf_hwcap2; j ; j &= j - 1) { |
| 79 | dprintf(fd, " %s", elf_hwcap2_str(ctz64(j))); |
| 80 | } |
| 81 | |
| 82 | dprintf(fd, "\n" |
| 83 | "CPU implementer\t: 0x%02x\n" |
| 84 | "CPU architecture: %d\n" |
| 85 | "CPU variant\t: 0x%0*x\n", |
| 86 | midr_impl, arch, len_var, midr_var); |
| 87 | if (arch >= 7) { |
| 88 | dprintf(fd, "CPU part\t: 0x%0*x\n", len_part, midr_part); |
| 89 | } |
| 90 | dprintf(fd, "CPU revision\t: %d\n\n", midr_rev); |
| 91 | } |
| 92 | |
| 93 | if (arch < 8) { |
| 94 | dprintf(fd, "Hardware\t: QEMU v%s %s\n", QEMU_VERSION, |
| 95 | cpu->dtb_compatible ? : ""); |
| 96 | dprintf(fd, "Revision\t: 0000\n"); |
| 97 | dprintf(fd, "Serial\t\t: 0000000000000000\n"); |
| 98 | } |
| 99 | return 0; |
| 100 | } |
| 101 | #define HAVE_ARCH_PROC_CPUINFO |
| 102 | |
| 103 | #endif /* ARM_TARGET_PROC_H */ |