qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

arch_dump.c (8203B)


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