19b4f38e1SEkaterina Tumanova /* 29b4f38e1SEkaterina Tumanova * writing ELF notes for s390x arch 39b4f38e1SEkaterina Tumanova * 49b4f38e1SEkaterina Tumanova * 59b4f38e1SEkaterina Tumanova * Copyright IBM Corp. 2012, 2013 69b4f38e1SEkaterina Tumanova * 79b4f38e1SEkaterina Tumanova * Ekaterina Tumanova <tumanova@linux.vnet.ibm.com> 89b4f38e1SEkaterina Tumanova * 99b4f38e1SEkaterina Tumanova * This work is licensed under the terms of the GNU GPL, version 2 or later. 109b4f38e1SEkaterina Tumanova * See the COPYING file in the top-level directory. 119b4f38e1SEkaterina Tumanova * 129b4f38e1SEkaterina Tumanova */ 139b4f38e1SEkaterina Tumanova 149615495aSPeter Maydell #include "qemu/osdep.h" 159b4f38e1SEkaterina Tumanova #include "cpu.h" 169b4f38e1SEkaterina Tumanova #include "elf.h" 179b4f38e1SEkaterina Tumanova #include "exec/cpu-all.h" 189b4f38e1SEkaterina Tumanova #include "sysemu/dump.h" 199b4f38e1SEkaterina Tumanova #include "sysemu/kvm.h" 209b4f38e1SEkaterina Tumanova 219b4f38e1SEkaterina Tumanova 229b4f38e1SEkaterina Tumanova struct S390xUserRegsStruct { 239b4f38e1SEkaterina Tumanova uint64_t psw[2]; 249b4f38e1SEkaterina Tumanova uint64_t gprs[16]; 259b4f38e1SEkaterina Tumanova uint32_t acrs[16]; 269b4f38e1SEkaterina Tumanova } QEMU_PACKED; 279b4f38e1SEkaterina Tumanova 289b4f38e1SEkaterina Tumanova typedef struct S390xUserRegsStruct S390xUserRegs; 299b4f38e1SEkaterina Tumanova 309b4f38e1SEkaterina Tumanova struct S390xElfPrstatusStruct { 319b4f38e1SEkaterina Tumanova uint8_t pad1[32]; 329b4f38e1SEkaterina Tumanova uint32_t pid; 339b4f38e1SEkaterina Tumanova uint8_t pad2[76]; 349b4f38e1SEkaterina Tumanova S390xUserRegs regs; 359b4f38e1SEkaterina Tumanova uint8_t pad3[16]; 369b4f38e1SEkaterina Tumanova } QEMU_PACKED; 379b4f38e1SEkaterina Tumanova 389b4f38e1SEkaterina Tumanova typedef struct S390xElfPrstatusStruct S390xElfPrstatus; 399b4f38e1SEkaterina Tumanova 409b4f38e1SEkaterina Tumanova struct S390xElfFpregsetStruct { 419b4f38e1SEkaterina Tumanova uint32_t fpc; 429b4f38e1SEkaterina Tumanova uint32_t pad; 439b4f38e1SEkaterina Tumanova uint64_t fprs[16]; 449b4f38e1SEkaterina Tumanova } QEMU_PACKED; 459b4f38e1SEkaterina Tumanova 469b4f38e1SEkaterina Tumanova typedef struct S390xElfFpregsetStruct S390xElfFpregset; 479b4f38e1SEkaterina Tumanova 483ceeb293SEric Farman struct S390xElfVregsLoStruct { 493ceeb293SEric Farman uint64_t vregs[16]; 503ceeb293SEric Farman } QEMU_PACKED; 513ceeb293SEric Farman 523ceeb293SEric Farman typedef struct S390xElfVregsLoStruct S390xElfVregsLo; 533ceeb293SEric Farman 543ceeb293SEric Farman struct S390xElfVregsHiStruct { 553ceeb293SEric Farman uint64_t vregs[16][2]; 563ceeb293SEric Farman } QEMU_PACKED; 573ceeb293SEric Farman 583ceeb293SEric Farman typedef struct S390xElfVregsHiStruct S390xElfVregsHi; 593ceeb293SEric Farman 60*21a10690SChristian Borntraeger struct S390xElfGSCBStruct { 61*21a10690SChristian Borntraeger uint64_t gsregs[4]; 62*21a10690SChristian Borntraeger } QEMU_PACKED; 63*21a10690SChristian Borntraeger 64*21a10690SChristian Borntraeger typedef struct S390xElfGSCBStruct S390xElfGSCB; 65*21a10690SChristian Borntraeger 669b4f38e1SEkaterina Tumanova typedef struct noteStruct { 679b4f38e1SEkaterina Tumanova Elf64_Nhdr hdr; 685f706fdcSChristian Borntraeger char name[8]; 699b4f38e1SEkaterina Tumanova union { 709b4f38e1SEkaterina Tumanova S390xElfPrstatus prstatus; 719b4f38e1SEkaterina Tumanova S390xElfFpregset fpregset; 723ceeb293SEric Farman S390xElfVregsLo vregslo; 733ceeb293SEric Farman S390xElfVregsHi vregshi; 74*21a10690SChristian Borntraeger S390xElfGSCB gscb; 759b4f38e1SEkaterina Tumanova uint32_t prefix; 769b4f38e1SEkaterina Tumanova uint64_t timer; 779b4f38e1SEkaterina Tumanova uint64_t todcmp; 789b4f38e1SEkaterina Tumanova uint32_t todpreg; 799b4f38e1SEkaterina Tumanova uint64_t ctrs[16]; 809b4f38e1SEkaterina Tumanova } contents; 819b4f38e1SEkaterina Tumanova } QEMU_PACKED Note; 829b4f38e1SEkaterina Tumanova 83f738f296SChristian Borntraeger static void s390x_write_elf64_prstatus(Note *note, S390CPU *cpu, int id) 849b4f38e1SEkaterina Tumanova { 859b4f38e1SEkaterina Tumanova int i; 869b4f38e1SEkaterina Tumanova S390xUserRegs *regs; 879b4f38e1SEkaterina Tumanova 889b4f38e1SEkaterina Tumanova note->hdr.n_type = cpu_to_be32(NT_PRSTATUS); 899b4f38e1SEkaterina Tumanova 909b4f38e1SEkaterina Tumanova regs = &(note->contents.prstatus.regs); 919b4f38e1SEkaterina Tumanova regs->psw[0] = cpu_to_be64(cpu->env.psw.mask); 929b4f38e1SEkaterina Tumanova regs->psw[1] = cpu_to_be64(cpu->env.psw.addr); 939b4f38e1SEkaterina Tumanova for (i = 0; i <= 15; i++) { 949b4f38e1SEkaterina Tumanova regs->acrs[i] = cpu_to_be32(cpu->env.aregs[i]); 959b4f38e1SEkaterina Tumanova regs->gprs[i] = cpu_to_be64(cpu->env.regs[i]); 969b4f38e1SEkaterina Tumanova } 97f738f296SChristian Borntraeger note->contents.prstatus.pid = id; 989b4f38e1SEkaterina Tumanova } 999b4f38e1SEkaterina Tumanova 100f738f296SChristian Borntraeger static void s390x_write_elf64_fpregset(Note *note, S390CPU *cpu, int id) 1019b4f38e1SEkaterina Tumanova { 1029b4f38e1SEkaterina Tumanova int i; 103c498d8e3SEric Farman CPUS390XState *cs = &cpu->env; 1049b4f38e1SEkaterina Tumanova 1059b4f38e1SEkaterina Tumanova note->hdr.n_type = cpu_to_be32(NT_FPREGSET); 1069b4f38e1SEkaterina Tumanova note->contents.fpregset.fpc = cpu_to_be32(cpu->env.fpc); 1079b4f38e1SEkaterina Tumanova for (i = 0; i <= 15; i++) { 108c498d8e3SEric Farman note->contents.fpregset.fprs[i] = cpu_to_be64(get_freg(cs, i)->ll); 1099b4f38e1SEkaterina Tumanova } 1109b4f38e1SEkaterina Tumanova } 1119b4f38e1SEkaterina Tumanova 112f738f296SChristian Borntraeger static void s390x_write_elf64_vregslo(Note *note, S390CPU *cpu, int id) 1133ceeb293SEric Farman { 1143ceeb293SEric Farman int i; 1153ceeb293SEric Farman 1163ceeb293SEric Farman note->hdr.n_type = cpu_to_be32(NT_S390_VXRS_LOW); 1173ceeb293SEric Farman for (i = 0; i <= 15; i++) { 1183ceeb293SEric Farman note->contents.vregslo.vregs[i] = cpu_to_be64(cpu->env.vregs[i][1].ll); 1193ceeb293SEric Farman } 1203ceeb293SEric Farman } 1213ceeb293SEric Farman 122f738f296SChristian Borntraeger static void s390x_write_elf64_vregshi(Note *note, S390CPU *cpu, int id) 1233ceeb293SEric Farman { 1243ceeb293SEric Farman int i; 1253ceeb293SEric Farman S390xElfVregsHi *temp_vregshi; 1263ceeb293SEric Farman 1273ceeb293SEric Farman temp_vregshi = ¬e->contents.vregshi; 1283ceeb293SEric Farman 1293ceeb293SEric Farman note->hdr.n_type = cpu_to_be32(NT_S390_VXRS_HIGH); 1303ceeb293SEric Farman for (i = 0; i <= 15; i++) { 1313ceeb293SEric Farman temp_vregshi->vregs[i][0] = cpu_to_be64(cpu->env.vregs[i + 16][0].ll); 1323ceeb293SEric Farman temp_vregshi->vregs[i][1] = cpu_to_be64(cpu->env.vregs[i + 16][1].ll); 1333ceeb293SEric Farman } 1343ceeb293SEric Farman } 1359b4f38e1SEkaterina Tumanova 136*21a10690SChristian Borntraeger static void s390x_write_elf64_gscb(Note *note, S390CPU *cpu, int id) 137*21a10690SChristian Borntraeger { 138*21a10690SChristian Borntraeger int i; 139*21a10690SChristian Borntraeger 140*21a10690SChristian Borntraeger note->hdr.n_type = cpu_to_be32(NT_S390_GS_CB); 141*21a10690SChristian Borntraeger for (i = 0; i < 4; i++) { 142*21a10690SChristian Borntraeger note->contents.gscb.gsregs[i] = cpu_to_be64(cpu->env.gscb[i]); 143*21a10690SChristian Borntraeger } 144*21a10690SChristian Borntraeger } 145*21a10690SChristian Borntraeger 146f738f296SChristian Borntraeger static void s390x_write_elf64_timer(Note *note, S390CPU *cpu, int id) 1479b4f38e1SEkaterina Tumanova { 1489b4f38e1SEkaterina Tumanova note->hdr.n_type = cpu_to_be32(NT_S390_TIMER); 1499b4f38e1SEkaterina Tumanova note->contents.timer = cpu_to_be64((uint64_t)(cpu->env.cputm)); 1509b4f38e1SEkaterina Tumanova } 1519b4f38e1SEkaterina Tumanova 152f738f296SChristian Borntraeger static void s390x_write_elf64_todcmp(Note *note, S390CPU *cpu, int id) 1539b4f38e1SEkaterina Tumanova { 1549b4f38e1SEkaterina Tumanova note->hdr.n_type = cpu_to_be32(NT_S390_TODCMP); 1559b4f38e1SEkaterina Tumanova note->contents.todcmp = cpu_to_be64((uint64_t)(cpu->env.ckc)); 1569b4f38e1SEkaterina Tumanova } 1579b4f38e1SEkaterina Tumanova 158f738f296SChristian Borntraeger static void s390x_write_elf64_todpreg(Note *note, S390CPU *cpu, int id) 1599b4f38e1SEkaterina Tumanova { 1609b4f38e1SEkaterina Tumanova note->hdr.n_type = cpu_to_be32(NT_S390_TODPREG); 1619b4f38e1SEkaterina Tumanova note->contents.todpreg = cpu_to_be32((uint32_t)(cpu->env.todpr)); 1629b4f38e1SEkaterina Tumanova } 1639b4f38e1SEkaterina Tumanova 164f738f296SChristian Borntraeger static void s390x_write_elf64_ctrs(Note *note, S390CPU *cpu, int id) 1659b4f38e1SEkaterina Tumanova { 1669b4f38e1SEkaterina Tumanova int i; 1679b4f38e1SEkaterina Tumanova 1689b4f38e1SEkaterina Tumanova note->hdr.n_type = cpu_to_be32(NT_S390_CTRS); 1699b4f38e1SEkaterina Tumanova 1709b4f38e1SEkaterina Tumanova for (i = 0; i <= 15; i++) { 1719b4f38e1SEkaterina Tumanova note->contents.ctrs[i] = cpu_to_be64(cpu->env.cregs[i]); 1729b4f38e1SEkaterina Tumanova } 1739b4f38e1SEkaterina Tumanova } 1749b4f38e1SEkaterina Tumanova 175f738f296SChristian Borntraeger static void s390x_write_elf64_prefix(Note *note, S390CPU *cpu, int id) 1769b4f38e1SEkaterina Tumanova { 1779b4f38e1SEkaterina Tumanova note->hdr.n_type = cpu_to_be32(NT_S390_PREFIX); 1789b4f38e1SEkaterina Tumanova note->contents.prefix = cpu_to_be32((uint32_t)(cpu->env.psa)); 1799b4f38e1SEkaterina Tumanova } 1809b4f38e1SEkaterina Tumanova 1819b4f38e1SEkaterina Tumanova 1825f706fdcSChristian Borntraeger typedef struct NoteFuncDescStruct { 1839b4f38e1SEkaterina Tumanova int contents_size; 184f738f296SChristian Borntraeger void (*note_contents_func)(Note *note, S390CPU *cpu, int id); 1855f706fdcSChristian Borntraeger } NoteFuncDesc; 1865f706fdcSChristian Borntraeger 1875f706fdcSChristian Borntraeger static const NoteFuncDesc note_core[] = { 1889b4f38e1SEkaterina Tumanova {sizeof(((Note *)0)->contents.prstatus), s390x_write_elf64_prstatus}, 1899b4f38e1SEkaterina Tumanova {sizeof(((Note *)0)->contents.fpregset), s390x_write_elf64_fpregset}, 1905f706fdcSChristian Borntraeger { 0, NULL} 1915f706fdcSChristian Borntraeger }; 1925f706fdcSChristian Borntraeger 1935f706fdcSChristian Borntraeger static const NoteFuncDesc note_linux[] = { 1945f706fdcSChristian Borntraeger {sizeof(((Note *)0)->contents.prefix), s390x_write_elf64_prefix}, 1959b4f38e1SEkaterina Tumanova {sizeof(((Note *)0)->contents.ctrs), s390x_write_elf64_ctrs}, 1969b4f38e1SEkaterina Tumanova {sizeof(((Note *)0)->contents.timer), s390x_write_elf64_timer}, 1979b4f38e1SEkaterina Tumanova {sizeof(((Note *)0)->contents.todcmp), s390x_write_elf64_todcmp}, 1989b4f38e1SEkaterina Tumanova {sizeof(((Note *)0)->contents.todpreg), s390x_write_elf64_todpreg}, 1993ceeb293SEric Farman {sizeof(((Note *)0)->contents.vregslo), s390x_write_elf64_vregslo}, 2003ceeb293SEric Farman {sizeof(((Note *)0)->contents.vregshi), s390x_write_elf64_vregshi}, 201*21a10690SChristian Borntraeger {sizeof(((Note *)0)->contents.gscb), s390x_write_elf64_gscb}, 2029b4f38e1SEkaterina Tumanova { 0, NULL} 2039b4f38e1SEkaterina Tumanova }; 2049b4f38e1SEkaterina Tumanova 2055f706fdcSChristian Borntraeger static int s390x_write_elf64_notes(const char *note_name, 2069b4f38e1SEkaterina Tumanova WriteCoreDumpFunction f, 2079b4f38e1SEkaterina Tumanova S390CPU *cpu, int id, 2085f706fdcSChristian Borntraeger void *opaque, 2095f706fdcSChristian Borntraeger const NoteFuncDesc *funcs) 2109b4f38e1SEkaterina Tumanova { 2119b4f38e1SEkaterina Tumanova Note note; 212ecb4e01eSStefan Weil const NoteFuncDesc *nf; 2139b4f38e1SEkaterina Tumanova int note_size; 2149b4f38e1SEkaterina Tumanova int ret = -1; 2159b4f38e1SEkaterina Tumanova 2165f706fdcSChristian Borntraeger for (nf = funcs; nf->note_contents_func; nf++) { 217abd137a1SChristian Borntraeger memset(¬e, 0, sizeof(note)); 2185f706fdcSChristian Borntraeger note.hdr.n_namesz = cpu_to_be32(strlen(note_name) + 1); 2199b4f38e1SEkaterina Tumanova note.hdr.n_descsz = cpu_to_be32(nf->contents_size); 2209b4f38e1SEkaterina Tumanova strncpy(note.name, note_name, sizeof(note.name)); 221f738f296SChristian Borntraeger (*nf->note_contents_func)(¬e, cpu, id); 2229b4f38e1SEkaterina Tumanova 2239b4f38e1SEkaterina Tumanova note_size = sizeof(note) - sizeof(note.contents) + nf->contents_size; 2249b4f38e1SEkaterina Tumanova ret = f(¬e, note_size, opaque); 2259b4f38e1SEkaterina Tumanova 2269b4f38e1SEkaterina Tumanova if (ret < 0) { 2279b4f38e1SEkaterina Tumanova return -1; 2289b4f38e1SEkaterina Tumanova } 2299b4f38e1SEkaterina Tumanova 2309b4f38e1SEkaterina Tumanova } 2319b4f38e1SEkaterina Tumanova 2329b4f38e1SEkaterina Tumanova return 0; 2339b4f38e1SEkaterina Tumanova } 2349b4f38e1SEkaterina Tumanova 2359b4f38e1SEkaterina Tumanova 2369b4f38e1SEkaterina Tumanova int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, 2379b4f38e1SEkaterina Tumanova int cpuid, void *opaque) 2389b4f38e1SEkaterina Tumanova { 2399b4f38e1SEkaterina Tumanova S390CPU *cpu = S390_CPU(cs); 2405f706fdcSChristian Borntraeger int r; 2415f706fdcSChristian Borntraeger 2425f706fdcSChristian Borntraeger r = s390x_write_elf64_notes("CORE", f, cpu, cpuid, opaque, note_core); 2435f706fdcSChristian Borntraeger if (r) { 2445f706fdcSChristian Borntraeger return r; 2455f706fdcSChristian Borntraeger } 2465f706fdcSChristian Borntraeger return s390x_write_elf64_notes("LINUX", f, cpu, cpuid, opaque, note_linux); 2479b4f38e1SEkaterina Tumanova } 2489b4f38e1SEkaterina Tumanova 24956c4bfb3SLaszlo Ersek int cpu_get_dump_info(ArchDumpInfo *info, 25056c4bfb3SLaszlo Ersek const struct GuestPhysBlockList *guest_phys_blocks) 2519b4f38e1SEkaterina Tumanova { 2529b4f38e1SEkaterina Tumanova info->d_machine = EM_S390; 2539b4f38e1SEkaterina Tumanova info->d_endian = ELFDATA2MSB; 2549b4f38e1SEkaterina Tumanova info->d_class = ELFCLASS64; 2559b4f38e1SEkaterina Tumanova 2569b4f38e1SEkaterina Tumanova return 0; 2579b4f38e1SEkaterina Tumanova } 2589b4f38e1SEkaterina Tumanova 2599b4f38e1SEkaterina Tumanova ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) 2609b4f38e1SEkaterina Tumanova { 2615f706fdcSChristian Borntraeger int name_size = 8; /* "LINUX" or "CORE" + pad */ 2629b4f38e1SEkaterina Tumanova size_t elf_note_size = 0; 2639b4f38e1SEkaterina Tumanova int note_head_size; 264ecb4e01eSStefan Weil const NoteFuncDesc *nf; 2659b4f38e1SEkaterina Tumanova 2669b4f38e1SEkaterina Tumanova assert(class == ELFCLASS64); 2679b4f38e1SEkaterina Tumanova assert(machine == EM_S390); 2689b4f38e1SEkaterina Tumanova 2699b4f38e1SEkaterina Tumanova note_head_size = sizeof(Elf64_Nhdr); 2709b4f38e1SEkaterina Tumanova 2715f706fdcSChristian Borntraeger for (nf = note_core; nf->note_contents_func; nf++) { 2725f706fdcSChristian Borntraeger elf_note_size = elf_note_size + note_head_size + name_size + 2735f706fdcSChristian Borntraeger nf->contents_size; 2745f706fdcSChristian Borntraeger } 2755f706fdcSChristian Borntraeger for (nf = note_linux; nf->note_contents_func; nf++) { 2769b4f38e1SEkaterina Tumanova elf_note_size = elf_note_size + note_head_size + name_size + 2779b4f38e1SEkaterina Tumanova nf->contents_size; 2789b4f38e1SEkaterina Tumanova } 2799b4f38e1SEkaterina Tumanova 2809b4f38e1SEkaterina Tumanova return (elf_note_size) * nr_cpus; 2819b4f38e1SEkaterina Tumanova } 282