| 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
| 2 | |
| 3 | #include "qemu/osdep.h" |
| 4 | #include "qemu.h" |
| 5 | #include "exec/page-protection.h" |
| 6 | #include "loader.h" |
| 7 | #include "user-internals.h" |
| 8 | #include "target_elf.h" |
| 9 | #include "target/arm/cpu-features.h" |
| 10 | #include "target_elf.h" |
| 11 | #include "elf.h" |
| 12 | |
| 13 | |
| 14 | const char *get_elf_cpu_model(uint32_t eflags) |
| 15 | { |
| 16 | return "any"; |
| 17 | } |
| 18 | |
| 19 | enum |
| 20 | { |
| 21 | ARM_HWCAP_ARM_SWP = 1 << 0, |
| 22 | ARM_HWCAP_ARM_HALF = 1 << 1, |
| 23 | ARM_HWCAP_ARM_THUMB = 1 << 2, |
| 24 | ARM_HWCAP_ARM_26BIT = 1 << 3, |
| 25 | ARM_HWCAP_ARM_FAST_MULT = 1 << 4, |
| 26 | ARM_HWCAP_ARM_FPA = 1 << 5, |
| 27 | ARM_HWCAP_ARM_VFP = 1 << 6, |
| 28 | ARM_HWCAP_ARM_EDSP = 1 << 7, |
| 29 | ARM_HWCAP_ARM_JAVA = 1 << 8, |
| 30 | ARM_HWCAP_ARM_IWMMXT = 1 << 9, |
| 31 | ARM_HWCAP_ARM_CRUNCH = 1 << 10, |
| 32 | ARM_HWCAP_ARM_THUMBEE = 1 << 11, |
| 33 | ARM_HWCAP_ARM_NEON = 1 << 12, |
| 34 | ARM_HWCAP_ARM_VFPv3 = 1 << 13, |
| 35 | ARM_HWCAP_ARM_VFPv3D16 = 1 << 14, |
| 36 | ARM_HWCAP_ARM_TLS = 1 << 15, |
| 37 | ARM_HWCAP_ARM_VFPv4 = 1 << 16, |
| 38 | ARM_HWCAP_ARM_IDIVA = 1 << 17, |
| 39 | ARM_HWCAP_ARM_IDIVT = 1 << 18, |
| 40 | ARM_HWCAP_ARM_VFPD32 = 1 << 19, |
| 41 | ARM_HWCAP_ARM_LPAE = 1 << 20, |
| 42 | ARM_HWCAP_ARM_EVTSTRM = 1 << 21, |
| 43 | ARM_HWCAP_ARM_FPHP = 1 << 22, |
| 44 | ARM_HWCAP_ARM_ASIMDHP = 1 << 23, |
| 45 | ARM_HWCAP_ARM_ASIMDDP = 1 << 24, |
| 46 | ARM_HWCAP_ARM_ASIMDFHM = 1 << 25, |
| 47 | ARM_HWCAP_ARM_ASIMDBF16 = 1 << 26, |
| 48 | ARM_HWCAP_ARM_I8MM = 1 << 27, |
| 49 | }; |
| 50 | |
| 51 | enum { |
| 52 | ARM_HWCAP2_ARM_AES = 1 << 0, |
| 53 | ARM_HWCAP2_ARM_PMULL = 1 << 1, |
| 54 | ARM_HWCAP2_ARM_SHA1 = 1 << 2, |
| 55 | ARM_HWCAP2_ARM_SHA2 = 1 << 3, |
| 56 | ARM_HWCAP2_ARM_CRC32 = 1 << 4, |
| 57 | ARM_HWCAP2_ARM_SB = 1 << 5, |
| 58 | ARM_HWCAP2_ARM_SSBS = 1 << 6, |
| 59 | }; |
| 60 | |
| 61 | abi_ulong get_elf_hwcap(CPUState *cs) |
| 62 | { |
| 63 | ARMCPU *cpu = ARM_CPU(cs); |
| 64 | abi_ulong hwcaps = 0; |
| 65 | |
| 66 | hwcaps |= ARM_HWCAP_ARM_SWP; |
| 67 | hwcaps |= ARM_HWCAP_ARM_HALF; |
| 68 | hwcaps |= ARM_HWCAP_ARM_THUMB; |
| 69 | hwcaps |= ARM_HWCAP_ARM_FAST_MULT; |
| 70 | |
| 71 | /* probe for the extra features */ |
| 72 | #define GET_FEATURE(feat, hwcap) \ |
| 73 | do { if (arm_feature(&cpu->env, feat)) { hwcaps |= hwcap; } } while (0) |
| 74 | |
| 75 | #define GET_FEATURE_ID(feat, hwcap) \ |
| 76 | do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0) |
| 77 | |
| 78 | /* EDSP is in v5TE and above, but all our v5 CPUs are v5TE */ |
| 79 | GET_FEATURE(ARM_FEATURE_V5, ARM_HWCAP_ARM_EDSP); |
| 80 | GET_FEATURE(ARM_FEATURE_THUMB2EE, ARM_HWCAP_ARM_THUMBEE); |
| 81 | GET_FEATURE(ARM_FEATURE_NEON, ARM_HWCAP_ARM_NEON); |
| 82 | GET_FEATURE(ARM_FEATURE_V6K, ARM_HWCAP_ARM_TLS); |
| 83 | GET_FEATURE(ARM_FEATURE_LPAE, ARM_HWCAP_ARM_LPAE); |
| 84 | GET_FEATURE_ID(aa32_arm_div, ARM_HWCAP_ARM_IDIVA); |
| 85 | GET_FEATURE_ID(aa32_thumb_div, ARM_HWCAP_ARM_IDIVT); |
| 86 | GET_FEATURE_ID(aa32_vfp, ARM_HWCAP_ARM_VFP); |
| 87 | |
| 88 | if (cpu_isar_feature(aa32_fpsp_v3, cpu) || |
| 89 | cpu_isar_feature(aa32_fpdp_v3, cpu)) { |
| 90 | hwcaps |= ARM_HWCAP_ARM_VFPv3; |
| 91 | if (cpu_isar_feature(aa32_simd_r32, cpu)) { |
| 92 | hwcaps |= ARM_HWCAP_ARM_VFPD32; |
| 93 | } else { |
| 94 | hwcaps |= ARM_HWCAP_ARM_VFPv3D16; |
| 95 | } |
| 96 | } |
| 97 | GET_FEATURE_ID(aa32_simdfmac, ARM_HWCAP_ARM_VFPv4); |
| 98 | /* |
| 99 | * MVFR1.FPHP and .SIMDHP must be in sync, and QEMU uses the same |
| 100 | * isar_feature function for both. The kernel reports them as two hwcaps. |
| 101 | */ |
| 102 | GET_FEATURE_ID(aa32_fp16_arith, ARM_HWCAP_ARM_FPHP); |
| 103 | GET_FEATURE_ID(aa32_fp16_arith, ARM_HWCAP_ARM_ASIMDHP); |
| 104 | GET_FEATURE_ID(aa32_dp, ARM_HWCAP_ARM_ASIMDDP); |
| 105 | GET_FEATURE_ID(aa32_fhm, ARM_HWCAP_ARM_ASIMDFHM); |
| 106 | GET_FEATURE_ID(aa32_bf16, ARM_HWCAP_ARM_ASIMDBF16); |
| 107 | GET_FEATURE_ID(aa32_i8mm, ARM_HWCAP_ARM_I8MM); |
| 108 | |
| 109 | return hwcaps; |
| 110 | } |
| 111 | |
| 112 | abi_ulong get_elf_hwcap2(CPUState *cs) |
| 113 | { |
| 114 | ARMCPU *cpu = ARM_CPU(cs); |
| 115 | abi_ulong hwcaps = 0; |
| 116 | |
| 117 | GET_FEATURE_ID(aa32_aes, ARM_HWCAP2_ARM_AES); |
| 118 | GET_FEATURE_ID(aa32_pmull, ARM_HWCAP2_ARM_PMULL); |
| 119 | GET_FEATURE_ID(aa32_sha1, ARM_HWCAP2_ARM_SHA1); |
| 120 | GET_FEATURE_ID(aa32_sha2, ARM_HWCAP2_ARM_SHA2); |
| 121 | GET_FEATURE_ID(aa32_crc32, ARM_HWCAP2_ARM_CRC32); |
| 122 | GET_FEATURE_ID(aa32_sb, ARM_HWCAP2_ARM_SB); |
| 123 | GET_FEATURE_ID(aa32_ssbs, ARM_HWCAP2_ARM_SSBS); |
| 124 | return hwcaps; |
| 125 | } |
| 126 | |
| 127 | const char *elf_hwcap_str(uint32_t bit) |
| 128 | { |
| 129 | static const char *hwcap_str[] = { |
| 130 | [__builtin_ctz(ARM_HWCAP_ARM_SWP )] = "swp", |
| 131 | [__builtin_ctz(ARM_HWCAP_ARM_HALF )] = "half", |
| 132 | [__builtin_ctz(ARM_HWCAP_ARM_THUMB )] = "thumb", |
| 133 | [__builtin_ctz(ARM_HWCAP_ARM_26BIT )] = "26bit", |
| 134 | [__builtin_ctz(ARM_HWCAP_ARM_FAST_MULT)] = "fast_mult", |
| 135 | [__builtin_ctz(ARM_HWCAP_ARM_FPA )] = "fpa", |
| 136 | [__builtin_ctz(ARM_HWCAP_ARM_VFP )] = "vfp", |
| 137 | [__builtin_ctz(ARM_HWCAP_ARM_EDSP )] = "edsp", |
| 138 | [__builtin_ctz(ARM_HWCAP_ARM_JAVA )] = "java", |
| 139 | [__builtin_ctz(ARM_HWCAP_ARM_IWMMXT )] = "iwmmxt", |
| 140 | [__builtin_ctz(ARM_HWCAP_ARM_CRUNCH )] = "crunch", |
| 141 | [__builtin_ctz(ARM_HWCAP_ARM_THUMBEE )] = "thumbee", |
| 142 | [__builtin_ctz(ARM_HWCAP_ARM_NEON )] = "neon", |
| 143 | [__builtin_ctz(ARM_HWCAP_ARM_VFPv3 )] = "vfpv3", |
| 144 | [__builtin_ctz(ARM_HWCAP_ARM_VFPv3D16 )] = "vfpv3d16", |
| 145 | [__builtin_ctz(ARM_HWCAP_ARM_TLS )] = "tls", |
| 146 | [__builtin_ctz(ARM_HWCAP_ARM_VFPv4 )] = "vfpv4", |
| 147 | [__builtin_ctz(ARM_HWCAP_ARM_IDIVA )] = "idiva", |
| 148 | [__builtin_ctz(ARM_HWCAP_ARM_IDIVT )] = "idivt", |
| 149 | [__builtin_ctz(ARM_HWCAP_ARM_VFPD32 )] = "vfpd32", |
| 150 | [__builtin_ctz(ARM_HWCAP_ARM_LPAE )] = "lpae", |
| 151 | [__builtin_ctz(ARM_HWCAP_ARM_EVTSTRM )] = "evtstrm", |
| 152 | [__builtin_ctz(ARM_HWCAP_ARM_FPHP )] = "fphp", |
| 153 | [__builtin_ctz(ARM_HWCAP_ARM_ASIMDHP )] = "asimdhp", |
| 154 | [__builtin_ctz(ARM_HWCAP_ARM_ASIMDDP )] = "asimddp", |
| 155 | [__builtin_ctz(ARM_HWCAP_ARM_ASIMDFHM )] = "asimdfhm", |
| 156 | [__builtin_ctz(ARM_HWCAP_ARM_ASIMDBF16)] = "asimdbf16", |
| 157 | [__builtin_ctz(ARM_HWCAP_ARM_I8MM )] = "i8mm", |
| 158 | }; |
| 159 | |
| 160 | return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL; |
| 161 | } |
| 162 | |
| 163 | const char *elf_hwcap2_str(uint32_t bit) |
| 164 | { |
| 165 | static const char *hwcap_str[] = { |
| 166 | [__builtin_ctz(ARM_HWCAP2_ARM_AES )] = "aes", |
| 167 | [__builtin_ctz(ARM_HWCAP2_ARM_PMULL)] = "pmull", |
| 168 | [__builtin_ctz(ARM_HWCAP2_ARM_SHA1 )] = "sha1", |
| 169 | [__builtin_ctz(ARM_HWCAP2_ARM_SHA2 )] = "sha2", |
| 170 | [__builtin_ctz(ARM_HWCAP2_ARM_CRC32)] = "crc32", |
| 171 | [__builtin_ctz(ARM_HWCAP2_ARM_SB )] = "sb", |
| 172 | [__builtin_ctz(ARM_HWCAP2_ARM_SSBS )] = "ssbs", |
| 173 | }; |
| 174 | |
| 175 | return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL; |
| 176 | } |
| 177 | |
| 178 | const char *get_elf_platform(CPUState *cs) |
| 179 | { |
| 180 | CPUARMState *env = cpu_env(cs); |
| 181 | |
| 182 | #if TARGET_BIG_ENDIAN |
| 183 | # define END "b" |
| 184 | #else |
| 185 | # define END "l" |
| 186 | #endif |
| 187 | |
| 188 | if (arm_feature(env, ARM_FEATURE_V8)) { |
| 189 | return "v8" END; |
| 190 | } else if (arm_feature(env, ARM_FEATURE_V7)) { |
| 191 | if (arm_feature(env, ARM_FEATURE_M)) { |
| 192 | return "v7m" END; |
| 193 | } else { |
| 194 | return "v7" END; |
| 195 | } |
| 196 | } else if (arm_feature(env, ARM_FEATURE_V6)) { |
| 197 | return "v6" END; |
| 198 | } else if (arm_feature(env, ARM_FEATURE_V5)) { |
| 199 | return "v5" END; |
| 200 | } else { |
| 201 | return "v4" END; |
| 202 | } |
| 203 | |
| 204 | #undef END |
| 205 | } |
| 206 | |
| 207 | bool init_guest_commpage(void) |
| 208 | { |
| 209 | ARMCPU *cpu = ARM_CPU(thread_cpu); |
| 210 | int host_page_size = qemu_real_host_page_size(); |
| 211 | abi_ptr commpage; |
| 212 | void *want; |
| 213 | void *addr; |
| 214 | |
| 215 | /* |
| 216 | * M-profile allocates maximum of 2GB address space, so can never |
| 217 | * allocate the commpage. Skip it. |
| 218 | */ |
| 219 | if (arm_feature(&cpu->env, ARM_FEATURE_M)) { |
| 220 | return true; |
| 221 | } |
| 222 | |
| 223 | commpage = COMMPAGE & -host_page_size; |
| 224 | want = g2h_untagged(commpage); |
| 225 | addr = mmap(want, host_page_size, PROT_READ | PROT_WRITE, |
| 226 | MAP_ANONYMOUS | MAP_PRIVATE | |
| 227 | (commpage < reserved_va ? MAP_FIXED : MAP_FIXED_NOREPLACE), |
| 228 | -1, 0); |
| 229 | |
| 230 | if (addr == MAP_FAILED) { |
| 231 | perror("Allocating guest commpage"); |
| 232 | exit(EXIT_FAILURE); |
| 233 | } |
| 234 | if (addr != want) { |
| 235 | return false; |
| 236 | } |
| 237 | |
| 238 | /* Set kernel helper versions; rest of page is 0. */ |
| 239 | __put_user(5, (uint32_t *)g2h_untagged(0xffff0ffcu)); |
| 240 | |
| 241 | if (mprotect(addr, host_page_size, PROT_READ)) { |
| 242 | perror("Protecting guest commpage"); |
| 243 | exit(EXIT_FAILURE); |
| 244 | } |
| 245 | |
| 246 | page_set_flags(commpage, commpage | (host_page_size - 1), |
| 247 | PAGE_READ | PAGE_EXEC | PAGE_VALID, PAGE_VALID); |
| 248 | return true; |
| 249 | } |
| 250 | |
| 251 | void elf_core_copy_regs(target_elf_gregset_t *r, const CPUARMState *env) |
| 252 | { |
| 253 | for (int i = 0; i < 16; ++i) { |
| 254 | r->pt.regs[i] = tswapal(env->regs[i]); |
| 255 | } |
| 256 | r->pt.cpsr = tswapal(cpsr_read((CPUARMState *)env)); |
| 257 | r->pt.orig_r0 = tswapal(env->regs[0]); /* FIXME */ |
| 258 | } |
| 259 | |
| 260 | #if TARGET_BIG_ENDIAN |
| 261 | # include "vdso-be8.c.inc" |
| 262 | # include "vdso-be32.c.inc" |
| 263 | #else |
| 264 | # include "vdso-le.c.inc" |
| 265 | #endif |
| 266 | |
| 267 | const VdsoImageInfo *get_vdso_image_info(uint32_t elf_flags) |
| 268 | { |
| 269 | #if TARGET_BIG_ENDIAN |
| 270 | return (EF_ARM_EABI_VERSION(elf_flags) >= EF_ARM_EABI_VER4 |
| 271 | && (elf_flags & EF_ARM_BE8) |
| 272 | ? &vdso_be8_image_info |
| 273 | : &vdso_be32_image_info); |
| 274 | #else |
| 275 | return &vdso_image_info; |
| 276 | #endif |
| 277 | } |