1 /* Support for writing ELF notes for ARM architectures 2 * 3 * Copyright (C) 2015 Red Hat Inc. 4 * 5 * Author: Andrew Jones <drjones@redhat.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 #include "qemu/osdep.h" 22 #include "cpu.h" 23 #include "elf.h" 24 #include "sysemu/dump.h" 25 26 /* struct user_pt_regs from arch/arm64/include/uapi/asm/ptrace.h */ 27 struct aarch64_user_regs { 28 uint64_t regs[31]; 29 uint64_t sp; 30 uint64_t pc; 31 uint64_t pstate; 32 } QEMU_PACKED; 33 34 QEMU_BUILD_BUG_ON(sizeof(struct aarch64_user_regs) != 272); 35 36 /* struct elf_prstatus from include/uapi/linux/elfcore.h */ 37 struct aarch64_elf_prstatus { 38 char pad1[32]; /* 32 == offsetof(struct elf_prstatus, pr_pid) */ 39 uint32_t pr_pid; 40 char pad2[76]; /* 76 == offsetof(struct elf_prstatus, pr_reg) - 41 offsetof(struct elf_prstatus, pr_ppid) */ 42 struct aarch64_user_regs pr_reg; 43 uint32_t pr_fpvalid; 44 char pad3[4]; 45 } QEMU_PACKED; 46 47 QEMU_BUILD_BUG_ON(sizeof(struct aarch64_elf_prstatus) != 392); 48 49 /* struct user_fpsimd_state from arch/arm64/include/uapi/asm/ptrace.h 50 * 51 * While the vregs member of user_fpsimd_state is of type __uint128_t, 52 * QEMU uses an array of uint64_t, where the high half of the 128-bit 53 * value is always in the 2n+1'th index. Thus we also break the 128- 54 * bit values into two halves in this reproduction of user_fpsimd_state. 55 */ 56 struct aarch64_user_vfp_state { 57 uint64_t vregs[64]; 58 uint32_t fpsr; 59 uint32_t fpcr; 60 char pad[8]; 61 } QEMU_PACKED; 62 63 QEMU_BUILD_BUG_ON(sizeof(struct aarch64_user_vfp_state) != 528); 64 65 struct aarch64_note { 66 Elf64_Nhdr hdr; 67 char name[8]; /* align_up(sizeof("CORE"), 4) */ 68 union { 69 struct aarch64_elf_prstatus prstatus; 70 struct aarch64_user_vfp_state vfp; 71 }; 72 } QEMU_PACKED; 73 74 #define AARCH64_NOTE_HEADER_SIZE offsetof(struct aarch64_note, prstatus) 75 #define AARCH64_PRSTATUS_NOTE_SIZE \ 76 (AARCH64_NOTE_HEADER_SIZE + sizeof(struct aarch64_elf_prstatus)) 77 #define AARCH64_PRFPREG_NOTE_SIZE \ 78 (AARCH64_NOTE_HEADER_SIZE + sizeof(struct aarch64_user_vfp_state)) 79 80 static void aarch64_note_init(struct aarch64_note *note, DumpState *s, 81 const char *name, Elf64_Word namesz, 82 Elf64_Word type, Elf64_Word descsz) 83 { 84 memset(note, 0, sizeof(*note)); 85 86 note->hdr.n_namesz = cpu_to_dump32(s, namesz); 87 note->hdr.n_descsz = cpu_to_dump32(s, descsz); 88 note->hdr.n_type = cpu_to_dump32(s, type); 89 90 memcpy(note->name, name, namesz); 91 } 92 93 static int aarch64_write_elf64_prfpreg(WriteCoreDumpFunction f, 94 CPUARMState *env, int cpuid, 95 DumpState *s) 96 { 97 struct aarch64_note note; 98 int ret, i; 99 100 aarch64_note_init(¬e, s, "CORE", 5, NT_PRFPREG, sizeof(note.vfp)); 101 102 for (i = 0; i < 64; ++i) { 103 note.vfp.vregs[i] = cpu_to_dump64(s, float64_val(env->vfp.regs[i])); 104 } 105 106 if (s->dump_info.d_endian == ELFDATA2MSB) { 107 /* For AArch64 we must always swap the vfp.regs's 2n and 2n+1 108 * entries when generating BE notes, because even big endian 109 * hosts use 2n+1 for the high half. 110 */ 111 for (i = 0; i < 32; ++i) { 112 uint64_t tmp = note.vfp.vregs[2*i]; 113 note.vfp.vregs[2*i] = note.vfp.vregs[2*i+1]; 114 note.vfp.vregs[2*i+1] = tmp; 115 } 116 } 117 118 note.vfp.fpsr = cpu_to_dump32(s, vfp_get_fpsr(env)); 119 note.vfp.fpcr = cpu_to_dump32(s, vfp_get_fpcr(env)); 120 121 ret = f(¬e, AARCH64_PRFPREG_NOTE_SIZE, s); 122 if (ret < 0) { 123 return -1; 124 } 125 126 return 0; 127 } 128 129 int arm_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, 130 int cpuid, void *opaque) 131 { 132 struct aarch64_note note; 133 CPUARMState *env = &ARM_CPU(cs)->env; 134 DumpState *s = opaque; 135 uint64_t pstate, sp; 136 int ret, i; 137 138 aarch64_note_init(¬e, s, "CORE", 5, NT_PRSTATUS, sizeof(note.prstatus)); 139 140 note.prstatus.pr_pid = cpu_to_dump32(s, cpuid); 141 note.prstatus.pr_fpvalid = cpu_to_dump32(s, 1); 142 143 if (!is_a64(env)) { 144 aarch64_sync_32_to_64(env); 145 pstate = cpsr_read(env); 146 sp = 0; 147 } else { 148 pstate = pstate_read(env); 149 sp = env->xregs[31]; 150 } 151 152 for (i = 0; i < 31; ++i) { 153 note.prstatus.pr_reg.regs[i] = cpu_to_dump64(s, env->xregs[i]); 154 } 155 note.prstatus.pr_reg.sp = cpu_to_dump64(s, sp); 156 note.prstatus.pr_reg.pc = cpu_to_dump64(s, env->pc); 157 note.prstatus.pr_reg.pstate = cpu_to_dump64(s, pstate); 158 159 ret = f(¬e, AARCH64_PRSTATUS_NOTE_SIZE, s); 160 if (ret < 0) { 161 return -1; 162 } 163 164 return aarch64_write_elf64_prfpreg(f, env, cpuid, s); 165 } 166 167 /* struct pt_regs from arch/arm/include/asm/ptrace.h */ 168 struct arm_user_regs { 169 uint32_t regs[17]; 170 char pad[4]; 171 } QEMU_PACKED; 172 173 QEMU_BUILD_BUG_ON(sizeof(struct arm_user_regs) != 72); 174 175 /* struct elf_prstatus from include/uapi/linux/elfcore.h */ 176 struct arm_elf_prstatus { 177 char pad1[24]; /* 24 == offsetof(struct elf_prstatus, pr_pid) */ 178 uint32_t pr_pid; 179 char pad2[44]; /* 44 == offsetof(struct elf_prstatus, pr_reg) - 180 offsetof(struct elf_prstatus, pr_ppid) */ 181 struct arm_user_regs pr_reg; 182 uint32_t pr_fpvalid; 183 } QEMU_PACKED arm_elf_prstatus; 184 185 QEMU_BUILD_BUG_ON(sizeof(struct arm_elf_prstatus) != 148); 186 187 /* struct user_vfp from arch/arm/include/asm/user.h */ 188 struct arm_user_vfp_state { 189 uint64_t vregs[32]; 190 uint32_t fpscr; 191 } QEMU_PACKED; 192 193 QEMU_BUILD_BUG_ON(sizeof(struct arm_user_vfp_state) != 260); 194 195 struct arm_note { 196 Elf32_Nhdr hdr; 197 char name[8]; /* align_up(sizeof("LINUX"), 4) */ 198 union { 199 struct arm_elf_prstatus prstatus; 200 struct arm_user_vfp_state vfp; 201 }; 202 } QEMU_PACKED; 203 204 #define ARM_NOTE_HEADER_SIZE offsetof(struct arm_note, prstatus) 205 #define ARM_PRSTATUS_NOTE_SIZE \ 206 (ARM_NOTE_HEADER_SIZE + sizeof(struct arm_elf_prstatus)) 207 #define ARM_VFP_NOTE_SIZE \ 208 (ARM_NOTE_HEADER_SIZE + sizeof(struct arm_user_vfp_state)) 209 210 static void arm_note_init(struct arm_note *note, DumpState *s, 211 const char *name, Elf32_Word namesz, 212 Elf32_Word type, Elf32_Word descsz) 213 { 214 memset(note, 0, sizeof(*note)); 215 216 note->hdr.n_namesz = cpu_to_dump32(s, namesz); 217 note->hdr.n_descsz = cpu_to_dump32(s, descsz); 218 note->hdr.n_type = cpu_to_dump32(s, type); 219 220 memcpy(note->name, name, namesz); 221 } 222 223 static int arm_write_elf32_vfp(WriteCoreDumpFunction f, CPUARMState *env, 224 int cpuid, DumpState *s) 225 { 226 struct arm_note note; 227 int ret, i; 228 229 arm_note_init(¬e, s, "LINUX", 6, NT_ARM_VFP, sizeof(note.vfp)); 230 231 for (i = 0; i < 32; ++i) { 232 note.vfp.vregs[i] = cpu_to_dump64(s, float64_val(env->vfp.regs[i])); 233 } 234 235 note.vfp.fpscr = cpu_to_dump32(s, vfp_get_fpscr(env)); 236 237 ret = f(¬e, ARM_VFP_NOTE_SIZE, s); 238 if (ret < 0) { 239 return -1; 240 } 241 242 return 0; 243 } 244 245 int arm_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, 246 int cpuid, void *opaque) 247 { 248 struct arm_note note; 249 CPUARMState *env = &ARM_CPU(cs)->env; 250 DumpState *s = opaque; 251 int ret, i, fpvalid = !!arm_feature(env, ARM_FEATURE_VFP); 252 253 arm_note_init(¬e, s, "CORE", 5, NT_PRSTATUS, sizeof(note.prstatus)); 254 255 note.prstatus.pr_pid = cpu_to_dump32(s, cpuid); 256 note.prstatus.pr_fpvalid = cpu_to_dump32(s, fpvalid); 257 258 for (i = 0; i < 16; ++i) { 259 note.prstatus.pr_reg.regs[i] = cpu_to_dump32(s, env->regs[i]); 260 } 261 note.prstatus.pr_reg.regs[16] = cpu_to_dump32(s, cpsr_read(env)); 262 263 ret = f(¬e, ARM_PRSTATUS_NOTE_SIZE, s); 264 if (ret < 0) { 265 return -1; 266 } else if (fpvalid) { 267 return arm_write_elf32_vfp(f, env, cpuid, s); 268 } 269 270 return 0; 271 } 272 273 int cpu_get_dump_info(ArchDumpInfo *info, 274 const GuestPhysBlockList *guest_phys_blocks) 275 { 276 ARMCPU *cpu; 277 CPUARMState *env; 278 GuestPhysBlock *block; 279 hwaddr lowest_addr = ULLONG_MAX; 280 281 if (first_cpu == NULL) { 282 return -1; 283 } 284 285 cpu = ARM_CPU(first_cpu); 286 env = &cpu->env; 287 288 /* Take a best guess at the phys_base. If we get it wrong then crash 289 * will need '--machdep phys_offset=<phys-offset>' added to its command 290 * line, which isn't any worse than assuming we can use zero, but being 291 * wrong. This is the same algorithm the crash utility uses when 292 * attempting to guess as it loads non-dumpfile formatted files. 293 */ 294 QTAILQ_FOREACH(block, &guest_phys_blocks->head, next) { 295 if (block->target_start < lowest_addr) { 296 lowest_addr = block->target_start; 297 } 298 } 299 300 if (arm_feature(env, ARM_FEATURE_AARCH64)) { 301 info->d_machine = EM_AARCH64; 302 info->d_class = ELFCLASS64; 303 info->page_size = (1 << 16); /* aarch64 max pagesize */ 304 if (lowest_addr != ULLONG_MAX) { 305 info->phys_base = lowest_addr; 306 } 307 } else { 308 info->d_machine = EM_ARM; 309 info->d_class = ELFCLASS32; 310 info->page_size = (1 << 12); 311 if (lowest_addr < UINT_MAX) { 312 info->phys_base = lowest_addr; 313 } 314 } 315 316 /* We assume the relevant endianness is that of EL1; this is right 317 * for kernels, but might give the wrong answer if you're trying to 318 * dump a hypervisor that happens to be running an opposite-endian 319 * kernel. 320 */ 321 info->d_endian = (env->cp15.sctlr_el[1] & SCTLR_EE) != 0 322 ? ELFDATA2MSB : ELFDATA2LSB; 323 324 return 0; 325 } 326 327 ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) 328 { 329 ARMCPU *cpu = ARM_CPU(first_cpu); 330 CPUARMState *env = &cpu->env; 331 size_t note_size; 332 333 if (class == ELFCLASS64) { 334 note_size = AARCH64_PRSTATUS_NOTE_SIZE; 335 note_size += AARCH64_PRFPREG_NOTE_SIZE; 336 } else { 337 note_size = ARM_PRSTATUS_NOTE_SIZE; 338 if (arm_feature(env, ARM_FEATURE_VFP)) { 339 note_size += ARM_VFP_NOTE_SIZE; 340 } 341 } 342 343 return note_size * nr_cpus; 344 } 345