qemu

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

arch_dump.c (14053B)


      1 /*
      2  * writing ELF notes for s390x arch
      3  *
      4  *
      5  * Copyright IBM Corp. 2012, 2013
      6  *
      7  *     Ekaterina Tumanova <tumanova@linux.vnet.ibm.com>
      8  *
      9  * This work is licensed under the terms of the GNU GPL, version 2 or later.
     10  * See the COPYING file in the top-level directory.
     11  *
     12  */
     13 
     14 #include "qemu/osdep.h"
     15 #include "qemu/units.h"
     16 #include "cpu.h"
     17 #include "s390x-internal.h"
     18 #include "elf.h"
     19 #include "sysemu/dump.h"
     20 #include "hw/s390x/pv.h"
     21 #include "kvm/kvm_s390x.h"
     22 
     23 struct S390xUserRegsStruct {
     24     uint64_t psw[2];
     25     uint64_t gprs[16];
     26     uint32_t acrs[16];
     27 } QEMU_PACKED;
     28 
     29 typedef struct S390xUserRegsStruct S390xUserRegs;
     30 
     31 struct S390xElfPrstatusStruct {
     32     uint8_t pad1[32];
     33     uint32_t pid;
     34     uint8_t pad2[76];
     35     S390xUserRegs regs;
     36     uint8_t pad3[16];
     37 } QEMU_PACKED;
     38 
     39 typedef struct S390xElfPrstatusStruct S390xElfPrstatus;
     40 
     41 struct S390xElfFpregsetStruct {
     42     uint32_t fpc;
     43     uint32_t pad;
     44     uint64_t fprs[16];
     45 } QEMU_PACKED;
     46 
     47 typedef struct S390xElfFpregsetStruct S390xElfFpregset;
     48 
     49 struct S390xElfVregsLoStruct {
     50     uint64_t vregs[16];
     51 } QEMU_PACKED;
     52 
     53 typedef struct S390xElfVregsLoStruct S390xElfVregsLo;
     54 
     55 struct S390xElfVregsHiStruct {
     56     uint64_t vregs[16][2];
     57 } QEMU_PACKED;
     58 
     59 typedef struct S390xElfVregsHiStruct S390xElfVregsHi;
     60 
     61 struct S390xElfGSCBStruct {
     62     uint64_t gsregs[4];
     63 } QEMU_PACKED;
     64 
     65 typedef struct S390xElfGSCBStruct S390xElfGSCB;
     66 
     67 typedef struct noteStruct {
     68     Elf64_Nhdr hdr;
     69     char name[8];
     70     union {
     71         S390xElfPrstatus prstatus;
     72         S390xElfFpregset fpregset;
     73         S390xElfVregsLo vregslo;
     74         S390xElfVregsHi vregshi;
     75         S390xElfGSCB gscb;
     76         uint32_t prefix;
     77         uint64_t timer;
     78         uint64_t todcmp;
     79         uint32_t todpreg;
     80         uint64_t ctrs[16];
     81         uint8_t dynamic[1];  /*
     82                               * Would be a flexible array member, if
     83                               * that was legal inside a union. Real
     84                               * size comes from PV info interface.
     85                               */
     86     } contents;
     87 } QEMU_PACKED Note;
     88 
     89 static bool pv_dump_initialized;
     90 
     91 static void s390x_write_elf64_prstatus(Note *note, S390CPU *cpu, int id)
     92 {
     93     int i;
     94     S390xUserRegs *regs;
     95 
     96     note->hdr.n_type = cpu_to_be32(NT_PRSTATUS);
     97 
     98     regs = &(note->contents.prstatus.regs);
     99     regs->psw[0] = cpu_to_be64(cpu->env.psw.mask);
    100     regs->psw[1] = cpu_to_be64(cpu->env.psw.addr);
    101     for (i = 0; i <= 15; i++) {
    102         regs->acrs[i] = cpu_to_be32(cpu->env.aregs[i]);
    103         regs->gprs[i] = cpu_to_be64(cpu->env.regs[i]);
    104     }
    105     note->contents.prstatus.pid = id;
    106 }
    107 
    108 static void s390x_write_elf64_fpregset(Note *note, S390CPU *cpu, int id)
    109 {
    110     int i;
    111     CPUS390XState *cs = &cpu->env;
    112 
    113     note->hdr.n_type = cpu_to_be32(NT_FPREGSET);
    114     note->contents.fpregset.fpc = cpu_to_be32(cpu->env.fpc);
    115     for (i = 0; i <= 15; i++) {
    116         note->contents.fpregset.fprs[i] = cpu_to_be64(*get_freg(cs, i));
    117     }
    118 }
    119 
    120 static void s390x_write_elf64_vregslo(Note *note, S390CPU *cpu,  int id)
    121 {
    122     int i;
    123 
    124     note->hdr.n_type = cpu_to_be32(NT_S390_VXRS_LOW);
    125     for (i = 0; i <= 15; i++) {
    126         note->contents.vregslo.vregs[i] = cpu_to_be64(cpu->env.vregs[i][1]);
    127     }
    128 }
    129 
    130 static void s390x_write_elf64_vregshi(Note *note, S390CPU *cpu, int id)
    131 {
    132     int i;
    133     S390xElfVregsHi *temp_vregshi;
    134 
    135     temp_vregshi = &note->contents.vregshi;
    136 
    137     note->hdr.n_type = cpu_to_be32(NT_S390_VXRS_HIGH);
    138     for (i = 0; i <= 15; i++) {
    139         temp_vregshi->vregs[i][0] = cpu_to_be64(cpu->env.vregs[i + 16][0]);
    140         temp_vregshi->vregs[i][1] = cpu_to_be64(cpu->env.vregs[i + 16][1]);
    141     }
    142 }
    143 
    144 static void s390x_write_elf64_gscb(Note *note, S390CPU *cpu, int id)
    145 {
    146     int i;
    147 
    148     note->hdr.n_type = cpu_to_be32(NT_S390_GS_CB);
    149     for (i = 0; i < 4; i++) {
    150         note->contents.gscb.gsregs[i] = cpu_to_be64(cpu->env.gscb[i]);
    151     }
    152 }
    153 
    154 static void s390x_write_elf64_timer(Note *note, S390CPU *cpu, int id)
    155 {
    156     note->hdr.n_type = cpu_to_be32(NT_S390_TIMER);
    157     note->contents.timer = cpu_to_be64((uint64_t)(cpu->env.cputm));
    158 }
    159 
    160 static void s390x_write_elf64_todcmp(Note *note, S390CPU *cpu, int id)
    161 {
    162     note->hdr.n_type = cpu_to_be32(NT_S390_TODCMP);
    163     note->contents.todcmp = cpu_to_be64((uint64_t)(cpu->env.ckc));
    164 }
    165 
    166 static void s390x_write_elf64_todpreg(Note *note, S390CPU *cpu, int id)
    167 {
    168     note->hdr.n_type = cpu_to_be32(NT_S390_TODPREG);
    169     note->contents.todpreg = cpu_to_be32((uint32_t)(cpu->env.todpr));
    170 }
    171 
    172 static void s390x_write_elf64_ctrs(Note *note, S390CPU *cpu, int id)
    173 {
    174     int i;
    175 
    176     note->hdr.n_type = cpu_to_be32(NT_S390_CTRS);
    177 
    178     for (i = 0; i <= 15; i++) {
    179         note->contents.ctrs[i] = cpu_to_be64(cpu->env.cregs[i]);
    180     }
    181 }
    182 
    183 static void s390x_write_elf64_prefix(Note *note, S390CPU *cpu, int id)
    184 {
    185     note->hdr.n_type = cpu_to_be32(NT_S390_PREFIX);
    186     note->contents.prefix = cpu_to_be32((uint32_t)(cpu->env.psa));
    187 }
    188 
    189 static void s390x_write_elf64_pv(Note *note, S390CPU *cpu, int id)
    190 {
    191     note->hdr.n_type = cpu_to_be32(NT_S390_PV_CPU_DATA);
    192     if (!pv_dump_initialized) {
    193         return;
    194     }
    195     kvm_s390_dump_cpu(cpu, &note->contents.dynamic);
    196 }
    197 
    198 typedef struct NoteFuncDescStruct {
    199     int contents_size;
    200     uint64_t (*note_size_func)(void); /* NULL for non-dynamic sized contents */
    201     void (*note_contents_func)(Note *note, S390CPU *cpu, int id);
    202     bool pvonly;
    203 } NoteFuncDesc;
    204 
    205 static const NoteFuncDesc note_core[] = {
    206     {sizeof_field(Note, contents.prstatus), NULL, s390x_write_elf64_prstatus, false},
    207     {sizeof_field(Note, contents.fpregset), NULL, s390x_write_elf64_fpregset, false},
    208     { 0, NULL, NULL, false}
    209 };
    210 
    211 static const NoteFuncDesc note_linux[] = {
    212     {sizeof_field(Note, contents.prefix),   NULL, s390x_write_elf64_prefix,  false},
    213     {sizeof_field(Note, contents.ctrs),     NULL, s390x_write_elf64_ctrs,    false},
    214     {sizeof_field(Note, contents.timer),    NULL, s390x_write_elf64_timer,   false},
    215     {sizeof_field(Note, contents.todcmp),   NULL, s390x_write_elf64_todcmp,  false},
    216     {sizeof_field(Note, contents.todpreg),  NULL, s390x_write_elf64_todpreg, false},
    217     {sizeof_field(Note, contents.vregslo),  NULL, s390x_write_elf64_vregslo, false},
    218     {sizeof_field(Note, contents.vregshi),  NULL, s390x_write_elf64_vregshi, false},
    219     {sizeof_field(Note, contents.gscb),     NULL, s390x_write_elf64_gscb,    false},
    220     {0, kvm_s390_pv_dmp_get_size_cpu,       s390x_write_elf64_pv, true},
    221     { 0, NULL, NULL, false}
    222 };
    223 
    224 static int s390x_write_elf64_notes(const char *note_name,
    225                                        WriteCoreDumpFunction f,
    226                                        S390CPU *cpu, int id,
    227                                        DumpState *s,
    228                                        const NoteFuncDesc *funcs)
    229 {
    230     Note note, *notep;
    231     const NoteFuncDesc *nf;
    232     int note_size, content_size;
    233     int ret = -1;
    234 
    235     assert(strlen(note_name) < sizeof(note.name));
    236 
    237     for (nf = funcs; nf->note_contents_func; nf++) {
    238         notep = &note;
    239         if (nf->pvonly && !s390_is_pv()) {
    240             continue;
    241         }
    242 
    243         content_size = nf->note_size_func ? nf->note_size_func() : nf->contents_size;
    244         note_size = sizeof(note) - sizeof(notep->contents) + content_size;
    245 
    246         /* Notes with dynamic sizes need to allocate a note */
    247         if (nf->note_size_func) {
    248             notep = g_malloc(note_size);
    249         }
    250 
    251         memset(notep, 0, sizeof(note));
    252 
    253         /* Setup note header data */
    254         notep->hdr.n_descsz = cpu_to_be32(content_size);
    255         notep->hdr.n_namesz = cpu_to_be32(strlen(note_name) + 1);
    256         g_strlcpy(notep->name, note_name, sizeof(notep->name));
    257 
    258         /* Get contents and write them out */
    259         (*nf->note_contents_func)(notep, cpu, id);
    260         ret = f(notep, note_size, s);
    261 
    262         if (nf->note_size_func) {
    263             g_free(notep);
    264         }
    265 
    266         if (ret < 0) {
    267             return -1;
    268         }
    269 
    270     }
    271 
    272     return 0;
    273 }
    274 
    275 
    276 int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
    277                               int cpuid, DumpState *s)
    278 {
    279     S390CPU *cpu = S390_CPU(cs);
    280     int r;
    281 
    282     r = s390x_write_elf64_notes("CORE", f, cpu, cpuid, s, note_core);
    283     if (r) {
    284         return r;
    285     }
    286     return s390x_write_elf64_notes("LINUX", f, cpu, cpuid, s, note_linux);
    287 }
    288 
    289 /* PV dump section size functions */
    290 static uint64_t get_mem_state_size_from_len(uint64_t len)
    291 {
    292     return (len / (MiB)) * kvm_s390_pv_dmp_get_size_mem_state();
    293 }
    294 
    295 static uint64_t get_size_mem_state(DumpState *s)
    296 {
    297     return get_mem_state_size_from_len(s->total_size);
    298 }
    299 
    300 static uint64_t get_size_completion_data(DumpState *s)
    301 {
    302     return kvm_s390_pv_dmp_get_size_completion_data();
    303 }
    304 
    305 /* PV dump section data functions*/
    306 static int get_data_completion(DumpState *s, uint8_t *buff)
    307 {
    308     int rc;
    309 
    310     if (!pv_dump_initialized) {
    311         return 0;
    312     }
    313     rc = kvm_s390_dump_completion_data(buff);
    314     if (!rc) {
    315             pv_dump_initialized = false;
    316     }
    317     return rc;
    318 }
    319 
    320 static int get_mem_state(DumpState *s, uint8_t *buff)
    321 {
    322     int64_t memblock_size, memblock_start;
    323     GuestPhysBlock *block;
    324     uint64_t off;
    325     int rc;
    326 
    327     QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) {
    328         memblock_start = dump_filtered_memblock_start(block, s->filter_area_begin,
    329                                                       s->filter_area_length);
    330         if (memblock_start == -1) {
    331             continue;
    332         }
    333 
    334         memblock_size = dump_filtered_memblock_size(block, s->filter_area_begin,
    335                                                     s->filter_area_length);
    336 
    337         off = get_mem_state_size_from_len(block->target_start);
    338 
    339         rc = kvm_s390_dump_mem_state(block->target_start,
    340                                      get_mem_state_size_from_len(memblock_size),
    341                                      buff + off);
    342         if (rc) {
    343             return rc;
    344         }
    345     }
    346 
    347     return 0;
    348 }
    349 
    350 static struct sections {
    351     uint64_t (*sections_size_func)(DumpState *s);
    352     int (*sections_contents_func)(DumpState *s, uint8_t *buff);
    353     char sctn_str[12];
    354 } sections[] = {
    355     { get_size_mem_state, get_mem_state, "pv_mem_meta"},
    356     { get_size_completion_data, get_data_completion, "pv_compl"},
    357     {NULL , NULL, ""}
    358 };
    359 
    360 static uint64_t arch_sections_write_hdr(DumpState *s, uint8_t *buff)
    361 {
    362     Elf64_Shdr *shdr = (void *)buff;
    363     struct sections *sctn = sections;
    364     uint64_t off = s->section_offset;
    365 
    366     if (!pv_dump_initialized) {
    367         return 0;
    368     }
    369 
    370     for (; sctn->sections_size_func; off += shdr->sh_size, sctn++, shdr++) {
    371         memset(shdr, 0, sizeof(*shdr));
    372         shdr->sh_type = SHT_PROGBITS;
    373         shdr->sh_offset = off;
    374         shdr->sh_size = sctn->sections_size_func(s);
    375         shdr->sh_name = s->string_table_buf->len;
    376         g_array_append_vals(s->string_table_buf, sctn->sctn_str, sizeof(sctn->sctn_str));
    377     }
    378 
    379     return (uintptr_t)shdr - (uintptr_t)buff;
    380 }
    381 
    382 
    383 /* Add arch specific number of sections and their respective sizes */
    384 static void arch_sections_add(DumpState *s)
    385 {
    386     struct sections *sctn = sections;
    387 
    388     /*
    389      * We only do a PV dump if we are running a PV guest, KVM supports
    390      * the dump API and we got valid dump length information.
    391      */
    392     if (!s390_is_pv() || !kvm_s390_get_protected_dump() ||
    393         !kvm_s390_pv_info_basic_valid()) {
    394         return;
    395     }
    396 
    397     /*
    398      * Start the UV dump process by doing the initialize dump call via
    399      * KVM as the proxy.
    400      */
    401     if (!kvm_s390_dump_init()) {
    402         pv_dump_initialized = true;
    403     } else {
    404         /*
    405          * Dump init failed, maybe the guest owner disabled dumping.
    406          * We'll continue the non-PV dump process since this is no
    407          * reason to crash qemu.
    408          */
    409         return;
    410     }
    411 
    412     for (; sctn->sections_size_func; sctn++) {
    413         s->shdr_num += 1;
    414         s->elf_section_data_size += sctn->sections_size_func(s);
    415     }
    416 }
    417 
    418 /*
    419  * After the PV dump has been initialized, the CPU data has been
    420  * fetched and memory has been dumped, we need to grab the tweak data
    421  * and the completion data.
    422  */
    423 static int arch_sections_write(DumpState *s, uint8_t *buff)
    424 {
    425     struct sections *sctn = sections;
    426     int rc;
    427 
    428     if (!pv_dump_initialized) {
    429         return -EINVAL;
    430     }
    431 
    432     for (; sctn->sections_size_func; sctn++) {
    433         rc = sctn->sections_contents_func(s, buff);
    434         buff += sctn->sections_size_func(s);
    435         if (rc) {
    436             return rc;
    437         }
    438     }
    439     return 0;
    440 }
    441 
    442 int cpu_get_dump_info(ArchDumpInfo *info,
    443                       const struct GuestPhysBlockList *guest_phys_blocks)
    444 {
    445     info->d_machine = EM_S390;
    446     info->d_endian = ELFDATA2MSB;
    447     info->d_class = ELFCLASS64;
    448     /*
    449      * This is evaluated for each dump so we can freely switch
    450      * between PV and non-PV.
    451      */
    452     if (s390_is_pv() && kvm_s390_get_protected_dump() &&
    453         kvm_s390_pv_info_basic_valid()) {
    454         info->arch_sections_add_fn = *arch_sections_add;
    455         info->arch_sections_write_hdr_fn = *arch_sections_write_hdr;
    456         info->arch_sections_write_fn = *arch_sections_write;
    457     } else {
    458         info->arch_sections_add_fn = NULL;
    459         info->arch_sections_write_hdr_fn = NULL;
    460         info->arch_sections_write_fn = NULL;
    461     }
    462     return 0;
    463 }
    464 
    465 ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
    466 {
    467     int name_size = 8; /* "LINUX" or "CORE" + pad */
    468     size_t elf_note_size = 0;
    469     int note_head_size, content_size;
    470     const NoteFuncDesc *nf;
    471 
    472     assert(class == ELFCLASS64);
    473     assert(machine == EM_S390);
    474 
    475     note_head_size = sizeof(Elf64_Nhdr);
    476 
    477     for (nf = note_core; nf->note_contents_func; nf++) {
    478         elf_note_size = elf_note_size + note_head_size + name_size + nf->contents_size;
    479     }
    480     for (nf = note_linux; nf->note_contents_func; nf++) {
    481         if (nf->pvonly && !s390_is_pv()) {
    482             continue;
    483         }
    484         content_size = nf->contents_size ? nf->contents_size : nf->note_size_func();
    485         elf_note_size = elf_note_size + note_head_size + name_size +
    486                         content_size;
    487     }
    488 
    489     return (elf_note_size) * nr_cpus;
    490 }