qemu/target/ppc/arch_dump.c
<<
>>
Prefs
   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 "sysemu/dump.h"
  19#include "sysemu/kvm.h"
  20#include "exec/helper-proto.h"
  21
  22#ifdef TARGET_PPC64
  23#define ELFCLASS ELFCLASS64
  24#define cpu_to_dump_reg cpu_to_dump64
  25typedef uint64_t reg_t;
  26typedef Elf64_Nhdr Elf_Nhdr;
  27#else
  28#define ELFCLASS ELFCLASS32
  29#define cpu_to_dump_reg cpu_to_dump32
  30typedef uint32_t reg_t;
  31typedef Elf32_Nhdr Elf_Nhdr;
  32#endif /* TARGET_PPC64 */
  33
  34struct 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
  50struct PPCElfPrstatus {
  51    char pad1[112];
  52    struct PPCUserRegStruct pr_reg;
  53    char pad2[40];
  54} QEMU_PACKED;
  55
  56
  57struct PPCElfFpregset {
  58    uint64_t fpr[32];
  59    reg_t fpscr;
  60}  QEMU_PACKED;
  61
  62
  63struct 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
  72struct PPCElfVsxregset {
  73    uint64_t vsr[32];
  74}  QEMU_PACKED;
  75
  76struct PPCElfSperegset {
  77    uint32_t evr[32];
  78    uint64_t spe_acc;
  79    uint32_t spe_fscr;
  80}  QEMU_PACKED;
  81
  82typedef 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
  95typedef struct NoteFuncArg {
  96    Note note;
  97    DumpState *state;
  98} NoteFuncArg;
  99
 100static 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 = &note->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
 131static 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 = &note->contents.fpregset;
 141    memset(fpregset, 0, sizeof(*fpregset));
 142
 143    for (i = 0; i < 32; i++) {
 144        uint64_t *fpr = cpu_fpr_ptr(&cpu->env, i);
 145        fpregset->fpr[i] = cpu_to_dump64(s, *fpr);
 146    }
 147    fpregset->fpscr = cpu_to_dump_reg(s, cpu->env.fpscr);
 148}
 149
 150static void ppc_write_elf_vmxregset(NoteFuncArg *arg, PowerPCCPU *cpu)
 151{
 152    int i;
 153    struct PPCElfVmxregset *vmxregset;
 154    Note *note = &arg->note;
 155    DumpState *s = arg->state;
 156
 157    note->hdr.n_type = cpu_to_dump32(s, NT_PPC_VMX);
 158    vmxregset = &note->contents.vmxregset;
 159    memset(vmxregset, 0, sizeof(*vmxregset));
 160
 161    for (i = 0; i < 32; i++) {
 162        bool needs_byteswap;
 163        ppc_avr_t *avr = cpu_avr_ptr(&cpu->env, i);
 164
 165#ifdef HOST_WORDS_BIGENDIAN
 166        needs_byteswap = s->dump_info.d_endian == ELFDATA2LSB;
 167#else
 168        needs_byteswap = s->dump_info.d_endian == ELFDATA2MSB;
 169#endif
 170
 171        if (needs_byteswap) {
 172            vmxregset->avr[i].u64[0] = bswap64(avr->u64[1]);
 173            vmxregset->avr[i].u64[1] = bswap64(avr->u64[0]);
 174        } else {
 175            vmxregset->avr[i].u64[0] = avr->u64[0];
 176            vmxregset->avr[i].u64[1] = avr->u64[1];
 177        }
 178    }
 179    vmxregset->vscr.u32[3] = cpu_to_dump32(s, helper_mfvscr(&cpu->env));
 180}
 181
 182static void ppc_write_elf_vsxregset(NoteFuncArg *arg, PowerPCCPU *cpu)
 183{
 184    int i;
 185    struct PPCElfVsxregset *vsxregset;
 186    Note *note = &arg->note;
 187    DumpState *s = arg->state;
 188
 189    note->hdr.n_type = cpu_to_dump32(s, NT_PPC_VSX);
 190    vsxregset = &note->contents.vsxregset;
 191    memset(vsxregset, 0, sizeof(*vsxregset));
 192
 193    for (i = 0; i < 32; i++) {
 194        uint64_t *vsrl = cpu_vsrl_ptr(&cpu->env, i);
 195        vsxregset->vsr[i] = cpu_to_dump64(s, *vsrl);
 196    }
 197}
 198
 199static void ppc_write_elf_speregset(NoteFuncArg *arg, PowerPCCPU *cpu)
 200{
 201    struct PPCElfSperegset *speregset;
 202    Note *note = &arg->note;
 203    DumpState *s = arg->state;
 204
 205    note->hdr.n_type = cpu_to_dump32(s, NT_PPC_SPE);
 206    speregset = &note->contents.speregset;
 207    memset(speregset, 0, sizeof(*speregset));
 208
 209    speregset->spe_acc = cpu_to_dump64(s, cpu->env.spe_acc);
 210    speregset->spe_fscr = cpu_to_dump32(s, cpu->env.spe_fscr);
 211}
 212
 213static const struct NoteFuncDescStruct {
 214    int contents_size;
 215    void (*note_contents_func)(NoteFuncArg *arg, PowerPCCPU *cpu);
 216} note_func[] = {
 217    {sizeof_field(Note, contents.prstatus),  ppc_write_elf_prstatus},
 218    {sizeof_field(Note, contents.fpregset),  ppc_write_elf_fpregset},
 219    {sizeof_field(Note, contents.vmxregset), ppc_write_elf_vmxregset},
 220    {sizeof_field(Note, contents.vsxregset), ppc_write_elf_vsxregset},
 221    {sizeof_field(Note, contents.speregset), ppc_write_elf_speregset},
 222    { 0, NULL}
 223};
 224
 225typedef struct NoteFuncDescStruct NoteFuncDesc;
 226
 227int cpu_get_dump_info(ArchDumpInfo *info,
 228                      const struct GuestPhysBlockList *guest_phys_blocks)
 229{
 230    PowerPCCPU *cpu;
 231    PowerPCCPUClass *pcc;
 232
 233    if (first_cpu == NULL) {
 234        return -1;
 235    }
 236
 237    cpu = POWERPC_CPU(first_cpu);
 238    pcc = POWERPC_CPU_GET_CLASS(cpu);
 239
 240    info->d_machine = PPC_ELF_MACHINE;
 241    info->d_class = ELFCLASS;
 242
 243    if ((*pcc->interrupts_big_endian)(cpu)) {
 244        info->d_endian = ELFDATA2MSB;
 245    } else {
 246        info->d_endian = ELFDATA2LSB;
 247    }
 248    /* 64KB is the max page size for pseries kernel */
 249    if (strncmp(object_get_typename(qdev_get_machine()),
 250                "pseries-", 8) == 0) {
 251        info->page_size = (1U << 16);
 252    }
 253
 254    return 0;
 255}
 256
 257ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
 258{
 259    int name_size = 8; /* "CORE" or "QEMU" rounded */
 260    size_t elf_note_size = 0;
 261    int note_head_size;
 262    const NoteFuncDesc *nf;
 263
 264    note_head_size = sizeof(Elf_Nhdr);
 265    for (nf = note_func; nf->note_contents_func; nf++) {
 266        elf_note_size = elf_note_size + note_head_size + name_size +
 267            nf->contents_size;
 268    }
 269
 270    return (elf_note_size) * nr_cpus;
 271}
 272
 273static int ppc_write_all_elf_notes(const char *note_name,
 274                                   WriteCoreDumpFunction f,
 275                                   PowerPCCPU *cpu, int id,
 276                                   void *opaque)
 277{
 278    NoteFuncArg arg = { .state = opaque };
 279    int ret = -1;
 280    int note_size;
 281    const NoteFuncDesc *nf;
 282
 283    for (nf = note_func; nf->note_contents_func; nf++) {
 284        arg.note.hdr.n_namesz = cpu_to_dump32(opaque, sizeof(arg.note.name));
 285        arg.note.hdr.n_descsz = cpu_to_dump32(opaque, nf->contents_size);
 286        strncpy(arg.note.name, note_name, sizeof(arg.note.name));
 287
 288        (*nf->note_contents_func)(&arg, cpu);
 289
 290        note_size =
 291            sizeof(arg.note) - sizeof(arg.note.contents) + nf->contents_size;
 292        ret = f(&arg.note, note_size, opaque);
 293        if (ret < 0) {
 294            return -1;
 295        }
 296    }
 297    return 0;
 298}
 299
 300int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
 301                               int cpuid, void *opaque)
 302{
 303    PowerPCCPU *cpu = POWERPC_CPU(cs);
 304    return ppc_write_all_elf_notes("CORE", f, cpu, cpuid, opaque);
 305}
 306
 307int ppc32_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
 308                               int cpuid, void *opaque)
 309{
 310    PowerPCCPU *cpu = POWERPC_CPU(cs);
 311    return ppc_write_all_elf_notes("CORE", f, cpu, cpuid, opaque);
 312}
 313