1 /* 2 * writing ELF notes for ppc{64,} arch 3 * 4 * 5 * Copyright IBM, Corp. 2013 6 * 7 * Authors: 8 * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> 9 * 10 * This work is licensed under the terms of the GNU GPL, version 2. See 11 * the COPYING file in the top-level directory. 12 * 13 */ 14 15 #include "qemu/osdep.h" 16 #include "cpu.h" 17 #include "elf.h" 18 #include "exec/cpu-all.h" 19 #include "sysemu/dump.h" 20 #include "sysemu/kvm.h" 21 22 #ifdef TARGET_PPC64 23 #define ELFCLASS ELFCLASS64 24 #define cpu_to_dump_reg cpu_to_dump64 25 typedef uint64_t reg_t; 26 typedef Elf64_Nhdr Elf_Nhdr; 27 #else 28 #define ELFCLASS ELFCLASS32 29 #define cpu_to_dump_reg cpu_to_dump32 30 typedef uint32_t reg_t; 31 typedef Elf32_Nhdr Elf_Nhdr; 32 #endif /* TARGET_PPC64 */ 33 34 struct PPCUserRegStruct { 35 reg_t gpr[32]; 36 reg_t nip; 37 reg_t msr; 38 reg_t orig_gpr3; 39 reg_t ctr; 40 reg_t link; 41 reg_t xer; 42 reg_t ccr; 43 reg_t softe; 44 reg_t trap; 45 reg_t dar; 46 reg_t dsisr; 47 reg_t result; 48 } QEMU_PACKED; 49 50 struct PPCElfPrstatus { 51 char pad1[112]; 52 struct PPCUserRegStruct pr_reg; 53 char pad2[40]; 54 } QEMU_PACKED; 55 56 57 struct PPCElfFpregset { 58 uint64_t fpr[32]; 59 reg_t fpscr; 60 } QEMU_PACKED; 61 62 63 struct PPCElfVmxregset { 64 ppc_avr_t avr[32]; 65 ppc_avr_t vscr; 66 union { 67 ppc_avr_t unused; 68 uint32_t value; 69 } vrsave; 70 } QEMU_PACKED; 71 72 struct PPCElfVsxregset { 73 uint64_t vsr[32]; 74 } QEMU_PACKED; 75 76 struct PPCElfSperegset { 77 uint32_t evr[32]; 78 uint64_t spe_acc; 79 uint32_t spe_fscr; 80 } QEMU_PACKED; 81 82 typedef struct noteStruct { 83 Elf_Nhdr hdr; 84 char name[5]; 85 char pad3[3]; 86 union { 87 struct PPCElfPrstatus prstatus; 88 struct PPCElfFpregset fpregset; 89 struct PPCElfVmxregset vmxregset; 90 struct PPCElfVsxregset vsxregset; 91 struct PPCElfSperegset speregset; 92 } contents; 93 } QEMU_PACKED Note; 94 95 typedef struct NoteFuncArg { 96 Note note; 97 DumpState *state; 98 } NoteFuncArg; 99 100 static void ppc_write_elf_prstatus(NoteFuncArg *arg, PowerPCCPU *cpu) 101 { 102 int i; 103 reg_t cr; 104 struct PPCElfPrstatus *prstatus; 105 struct PPCUserRegStruct *reg; 106 Note *note = &arg->note; 107 DumpState *s = arg->state; 108 109 note->hdr.n_type = cpu_to_dump32(s, NT_PRSTATUS); 110 111 prstatus = ¬e->contents.prstatus; 112 memset(prstatus, 0, sizeof(*prstatus)); 113 reg = &prstatus->pr_reg; 114 115 for (i = 0; i < 32; i++) { 116 reg->gpr[i] = cpu_to_dump_reg(s, cpu->env.gpr[i]); 117 } 118 reg->nip = cpu_to_dump_reg(s, cpu->env.nip); 119 reg->msr = cpu_to_dump_reg(s, cpu->env.msr); 120 reg->ctr = cpu_to_dump_reg(s, cpu->env.ctr); 121 reg->link = cpu_to_dump_reg(s, cpu->env.lr); 122 reg->xer = cpu_to_dump_reg(s, cpu_read_xer(&cpu->env)); 123 124 cr = 0; 125 for (i = 0; i < 8; i++) { 126 cr |= (cpu->env.crf[i] & 15) << (4 * (7 - i)); 127 } 128 reg->ccr = cpu_to_dump_reg(s, cr); 129 } 130 131 static void ppc_write_elf_fpregset(NoteFuncArg *arg, PowerPCCPU *cpu) 132 { 133 int i; 134 struct PPCElfFpregset *fpregset; 135 Note *note = &arg->note; 136 DumpState *s = arg->state; 137 138 note->hdr.n_type = cpu_to_dump32(s, NT_PRFPREG); 139 140 fpregset = ¬e->contents.fpregset; 141 memset(fpregset, 0, sizeof(*fpregset)); 142 143 for (i = 0; i < 32; i++) { 144 fpregset->fpr[i] = cpu_to_dump64(s, cpu->env.fpr[i]); 145 } 146 fpregset->fpscr = cpu_to_dump_reg(s, cpu->env.fpscr); 147 } 148 149 static void ppc_write_elf_vmxregset(NoteFuncArg *arg, PowerPCCPU *cpu) 150 { 151 int i; 152 struct PPCElfVmxregset *vmxregset; 153 Note *note = &arg->note; 154 DumpState *s = arg->state; 155 156 note->hdr.n_type = cpu_to_dump32(s, NT_PPC_VMX); 157 vmxregset = ¬e->contents.vmxregset; 158 memset(vmxregset, 0, sizeof(*vmxregset)); 159 160 for (i = 0; i < 32; i++) { 161 bool needs_byteswap; 162 163 #ifdef HOST_WORDS_BIGENDIAN 164 needs_byteswap = s->dump_info.d_endian == ELFDATA2LSB; 165 #else 166 needs_byteswap = s->dump_info.d_endian == ELFDATA2MSB; 167 #endif 168 169 if (needs_byteswap) { 170 vmxregset->avr[i].u64[0] = bswap64(cpu->env.avr[i].u64[1]); 171 vmxregset->avr[i].u64[1] = bswap64(cpu->env.avr[i].u64[0]); 172 } else { 173 vmxregset->avr[i].u64[0] = cpu->env.avr[i].u64[0]; 174 vmxregset->avr[i].u64[1] = cpu->env.avr[i].u64[1]; 175 } 176 } 177 vmxregset->vscr.u32[3] = cpu_to_dump32(s, cpu->env.vscr); 178 } 179 180 static void ppc_write_elf_vsxregset(NoteFuncArg *arg, PowerPCCPU *cpu) 181 { 182 int i; 183 struct PPCElfVsxregset *vsxregset; 184 Note *note = &arg->note; 185 DumpState *s = arg->state; 186 187 note->hdr.n_type = cpu_to_dump32(s, NT_PPC_VSX); 188 vsxregset = ¬e->contents.vsxregset; 189 memset(vsxregset, 0, sizeof(*vsxregset)); 190 191 for (i = 0; i < 32; i++) { 192 vsxregset->vsr[i] = cpu_to_dump64(s, cpu->env.vsr[i]); 193 } 194 } 195 196 static void ppc_write_elf_speregset(NoteFuncArg *arg, PowerPCCPU *cpu) 197 { 198 struct PPCElfSperegset *speregset; 199 Note *note = &arg->note; 200 DumpState *s = arg->state; 201 202 note->hdr.n_type = cpu_to_dump32(s, NT_PPC_SPE); 203 speregset = ¬e->contents.speregset; 204 memset(speregset, 0, sizeof(*speregset)); 205 206 speregset->spe_acc = cpu_to_dump64(s, cpu->env.spe_acc); 207 speregset->spe_fscr = cpu_to_dump32(s, cpu->env.spe_fscr); 208 } 209 210 static const struct NoteFuncDescStruct { 211 int contents_size; 212 void (*note_contents_func)(NoteFuncArg *arg, PowerPCCPU *cpu); 213 } note_func[] = { 214 {sizeof(((Note *)0)->contents.prstatus), ppc_write_elf_prstatus}, 215 {sizeof(((Note *)0)->contents.fpregset), ppc_write_elf_fpregset}, 216 {sizeof(((Note *)0)->contents.vmxregset), ppc_write_elf_vmxregset}, 217 {sizeof(((Note *)0)->contents.vsxregset), ppc_write_elf_vsxregset}, 218 {sizeof(((Note *)0)->contents.speregset), ppc_write_elf_speregset}, 219 { 0, NULL} 220 }; 221 222 typedef struct NoteFuncDescStruct NoteFuncDesc; 223 224 int cpu_get_dump_info(ArchDumpInfo *info, 225 const struct GuestPhysBlockList *guest_phys_blocks) 226 { 227 PowerPCCPU *cpu = POWERPC_CPU(first_cpu); 228 PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 229 230 info->d_machine = PPC_ELF_MACHINE; 231 info->d_class = ELFCLASS; 232 233 if ((*pcc->interrupts_big_endian)(cpu)) { 234 info->d_endian = ELFDATA2MSB; 235 } else { 236 info->d_endian = ELFDATA2LSB; 237 } 238 /* 64KB is the max page size for pseries kernel */ 239 if (strncmp(object_get_typename(qdev_get_machine()), 240 "pseries-", 8) == 0) { 241 info->page_size = (1U << 16); 242 } 243 244 return 0; 245 } 246 247 ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) 248 { 249 int name_size = 8; /* "CORE" or "QEMU" rounded */ 250 size_t elf_note_size = 0; 251 int note_head_size; 252 const NoteFuncDesc *nf; 253 254 note_head_size = sizeof(Elf_Nhdr); 255 for (nf = note_func; nf->note_contents_func; nf++) { 256 elf_note_size = elf_note_size + note_head_size + name_size + 257 nf->contents_size; 258 } 259 260 return (elf_note_size) * nr_cpus; 261 } 262 263 static int ppc_write_all_elf_notes(const char *note_name, 264 WriteCoreDumpFunction f, 265 PowerPCCPU *cpu, int id, 266 void *opaque) 267 { 268 NoteFuncArg arg = { .state = opaque }; 269 int ret = -1; 270 int note_size; 271 const NoteFuncDesc *nf; 272 273 for (nf = note_func; nf->note_contents_func; nf++) { 274 arg.note.hdr.n_namesz = cpu_to_dump32(opaque, sizeof(arg.note.name)); 275 arg.note.hdr.n_descsz = cpu_to_dump32(opaque, nf->contents_size); 276 strncpy(arg.note.name, note_name, sizeof(arg.note.name)); 277 278 (*nf->note_contents_func)(&arg, cpu); 279 280 note_size = 281 sizeof(arg.note) - sizeof(arg.note.contents) + nf->contents_size; 282 ret = f(&arg.note, note_size, opaque); 283 if (ret < 0) { 284 return -1; 285 } 286 } 287 return 0; 288 } 289 290 int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, 291 int cpuid, void *opaque) 292 { 293 PowerPCCPU *cpu = POWERPC_CPU(cs); 294 return ppc_write_all_elf_notes("CORE", f, cpu, cpuid, opaque); 295 } 296 297 int ppc32_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, 298 int cpuid, void *opaque) 299 { 300 PowerPCCPU *cpu = POWERPC_CPU(cs); 301 return ppc_write_all_elf_notes("CORE", f, cpu, cpuid, opaque); 302 } 303