1 /* 2 * writing ELF notes for ppc64 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 struct PPC64UserRegStruct { 23 uint64_t gpr[32]; 24 uint64_t nip; 25 uint64_t msr; 26 uint64_t orig_gpr3; 27 uint64_t ctr; 28 uint64_t link; 29 uint64_t xer; 30 uint64_t ccr; 31 uint64_t softe; 32 uint64_t trap; 33 uint64_t dar; 34 uint64_t dsisr; 35 uint64_t result; 36 } QEMU_PACKED; 37 38 struct PPC64ElfPrstatus { 39 char pad1[112]; 40 struct PPC64UserRegStruct pr_reg; 41 uint64_t pad2[4]; 42 } QEMU_PACKED; 43 44 45 struct PPC64ElfFpregset { 46 uint64_t fpr[32]; 47 uint64_t fpscr; 48 } QEMU_PACKED; 49 50 51 struct PPC64ElfVmxregset { 52 ppc_avr_t avr[32]; 53 ppc_avr_t vscr; 54 union { 55 ppc_avr_t unused; 56 uint32_t value; 57 } vrsave; 58 } QEMU_PACKED; 59 60 struct PPC64ElfVsxregset { 61 uint64_t vsr[32]; 62 } QEMU_PACKED; 63 64 struct PPC64ElfSperegset { 65 uint32_t evr[32]; 66 uint64_t spe_acc; 67 uint32_t spe_fscr; 68 } QEMU_PACKED; 69 70 typedef struct noteStruct { 71 Elf64_Nhdr hdr; 72 char name[5]; 73 char pad3[3]; 74 union { 75 struct PPC64ElfPrstatus prstatus; 76 struct PPC64ElfFpregset fpregset; 77 struct PPC64ElfVmxregset vmxregset; 78 struct PPC64ElfVsxregset vsxregset; 79 struct PPC64ElfSperegset speregset; 80 } contents; 81 } QEMU_PACKED Note; 82 83 typedef struct NoteFuncArg { 84 Note note; 85 DumpState *state; 86 } NoteFuncArg; 87 88 static void ppc64_write_elf64_prstatus(NoteFuncArg *arg, PowerPCCPU *cpu) 89 { 90 int i; 91 uint64_t cr; 92 struct PPC64ElfPrstatus *prstatus; 93 struct PPC64UserRegStruct *reg; 94 Note *note = &arg->note; 95 DumpState *s = arg->state; 96 97 note->hdr.n_type = cpu_to_dump32(s, NT_PRSTATUS); 98 99 prstatus = ¬e->contents.prstatus; 100 memset(prstatus, 0, sizeof(*prstatus)); 101 reg = &prstatus->pr_reg; 102 103 for (i = 0; i < 32; i++) { 104 reg->gpr[i] = cpu_to_dump64(s, cpu->env.gpr[i]); 105 } 106 reg->nip = cpu_to_dump64(s, cpu->env.nip); 107 reg->msr = cpu_to_dump64(s, cpu->env.msr); 108 reg->ctr = cpu_to_dump64(s, cpu->env.ctr); 109 reg->link = cpu_to_dump64(s, cpu->env.lr); 110 reg->xer = cpu_to_dump64(s, cpu_read_xer(&cpu->env)); 111 112 cr = 0; 113 for (i = 0; i < 8; i++) { 114 cr |= (cpu->env.crf[i] & 15) << (4 * (7 - i)); 115 } 116 reg->ccr = cpu_to_dump64(s, cr); 117 } 118 119 static void ppc64_write_elf64_fpregset(NoteFuncArg *arg, PowerPCCPU *cpu) 120 { 121 int i; 122 struct PPC64ElfFpregset *fpregset; 123 Note *note = &arg->note; 124 DumpState *s = arg->state; 125 126 note->hdr.n_type = cpu_to_dump32(s, NT_PRFPREG); 127 128 fpregset = ¬e->contents.fpregset; 129 memset(fpregset, 0, sizeof(*fpregset)); 130 131 for (i = 0; i < 32; i++) { 132 fpregset->fpr[i] = cpu_to_dump64(s, cpu->env.fpr[i]); 133 } 134 fpregset->fpscr = cpu_to_dump64(s, cpu->env.fpscr); 135 } 136 137 static void ppc64_write_elf64_vmxregset(NoteFuncArg *arg, PowerPCCPU *cpu) 138 { 139 int i; 140 struct PPC64ElfVmxregset *vmxregset; 141 Note *note = &arg->note; 142 DumpState *s = arg->state; 143 144 note->hdr.n_type = cpu_to_dump32(s, NT_PPC_VMX); 145 vmxregset = ¬e->contents.vmxregset; 146 memset(vmxregset, 0, sizeof(*vmxregset)); 147 148 for (i = 0; i < 32; i++) { 149 bool needs_byteswap; 150 151 #ifdef HOST_WORDS_BIGENDIAN 152 needs_byteswap = s->dump_info.d_endian == ELFDATA2LSB; 153 #else 154 needs_byteswap = s->dump_info.d_endian == ELFDATA2MSB; 155 #endif 156 157 if (needs_byteswap) { 158 vmxregset->avr[i].u64[0] = bswap64(cpu->env.avr[i].u64[1]); 159 vmxregset->avr[i].u64[1] = bswap64(cpu->env.avr[i].u64[0]); 160 } else { 161 vmxregset->avr[i].u64[0] = cpu->env.avr[i].u64[0]; 162 vmxregset->avr[i].u64[1] = cpu->env.avr[i].u64[1]; 163 } 164 } 165 vmxregset->vscr.u32[3] = cpu_to_dump32(s, cpu->env.vscr); 166 } 167 static void ppc64_write_elf64_vsxregset(NoteFuncArg *arg, PowerPCCPU *cpu) 168 { 169 int i; 170 struct PPC64ElfVsxregset *vsxregset; 171 Note *note = &arg->note; 172 DumpState *s = arg->state; 173 174 note->hdr.n_type = cpu_to_dump32(s, NT_PPC_VSX); 175 vsxregset = ¬e->contents.vsxregset; 176 memset(vsxregset, 0, sizeof(*vsxregset)); 177 178 for (i = 0; i < 32; i++) { 179 vsxregset->vsr[i] = cpu_to_dump64(s, cpu->env.vsr[i]); 180 } 181 } 182 static void ppc64_write_elf64_speregset(NoteFuncArg *arg, PowerPCCPU *cpu) 183 { 184 struct PPC64ElfSperegset *speregset; 185 Note *note = &arg->note; 186 DumpState *s = arg->state; 187 188 note->hdr.n_type = cpu_to_dump32(s, NT_PPC_SPE); 189 speregset = ¬e->contents.speregset; 190 memset(speregset, 0, sizeof(*speregset)); 191 192 speregset->spe_acc = cpu_to_dump64(s, cpu->env.spe_acc); 193 speregset->spe_fscr = cpu_to_dump32(s, cpu->env.spe_fscr); 194 } 195 196 static const struct NoteFuncDescStruct { 197 int contents_size; 198 void (*note_contents_func)(NoteFuncArg *arg, PowerPCCPU *cpu); 199 } note_func[] = { 200 {sizeof(((Note *)0)->contents.prstatus), ppc64_write_elf64_prstatus}, 201 {sizeof(((Note *)0)->contents.fpregset), ppc64_write_elf64_fpregset}, 202 {sizeof(((Note *)0)->contents.vmxregset), ppc64_write_elf64_vmxregset}, 203 {sizeof(((Note *)0)->contents.vsxregset), ppc64_write_elf64_vsxregset}, 204 {sizeof(((Note *)0)->contents.speregset), ppc64_write_elf64_speregset}, 205 { 0, NULL} 206 }; 207 208 typedef struct NoteFuncDescStruct NoteFuncDesc; 209 210 int cpu_get_dump_info(ArchDumpInfo *info, 211 const struct GuestPhysBlockList *guest_phys_blocks) 212 { 213 PowerPCCPU *cpu = POWERPC_CPU(first_cpu); 214 PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 215 216 info->d_machine = EM_PPC64; 217 info->d_class = ELFCLASS64; 218 if ((*pcc->interrupts_big_endian)(cpu)) { 219 info->d_endian = ELFDATA2MSB; 220 } else { 221 info->d_endian = ELFDATA2LSB; 222 } 223 /* 64KB is the max page size for pseries kernel */ 224 if (strncmp(object_get_typename(qdev_get_machine()), 225 "pseries-", 8) == 0) { 226 info->page_size = (1U << 16); 227 } 228 229 return 0; 230 } 231 232 ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) 233 { 234 int name_size = 8; /* "CORE" or "QEMU" rounded */ 235 size_t elf_note_size = 0; 236 int note_head_size; 237 const NoteFuncDesc *nf; 238 239 if (class != ELFCLASS64) { 240 return -1; 241 } 242 assert(machine == EM_PPC64); 243 244 note_head_size = sizeof(Elf64_Nhdr); 245 246 for (nf = note_func; nf->note_contents_func; nf++) { 247 elf_note_size = elf_note_size + note_head_size + name_size + 248 nf->contents_size; 249 } 250 251 return (elf_note_size) * nr_cpus; 252 } 253 254 static int ppc64_write_all_elf64_notes(const char *note_name, 255 WriteCoreDumpFunction f, 256 PowerPCCPU *cpu, int id, 257 void *opaque) 258 { 259 NoteFuncArg arg = { .state = opaque }; 260 int ret = -1; 261 int note_size; 262 const NoteFuncDesc *nf; 263 264 for (nf = note_func; nf->note_contents_func; nf++) { 265 arg.note.hdr.n_namesz = cpu_to_dump32(opaque, sizeof(arg.note.name)); 266 arg.note.hdr.n_descsz = cpu_to_dump32(opaque, nf->contents_size); 267 strncpy(arg.note.name, note_name, sizeof(arg.note.name)); 268 269 (*nf->note_contents_func)(&arg, cpu); 270 271 note_size = 272 sizeof(arg.note) - sizeof(arg.note.contents) + nf->contents_size; 273 ret = f(&arg.note, note_size, opaque); 274 if (ret < 0) { 275 return -1; 276 } 277 } 278 return 0; 279 } 280 281 int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, 282 int cpuid, void *opaque) 283 { 284 PowerPCCPU *cpu = POWERPC_CPU(cs); 285 return ppc64_write_all_elf64_notes("CORE", f, cpu, cpuid, opaque); 286 } 287