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" 164e58b838SDavid Hildenbrand #include "internal.h" 179b4f38e1SEkaterina Tumanova #include "elf.h" 189b4f38e1SEkaterina Tumanova #include "sysemu/dump.h" 199b4f38e1SEkaterina Tumanova 209b4f38e1SEkaterina Tumanova 219b4f38e1SEkaterina Tumanova struct S390xUserRegsStruct { 229b4f38e1SEkaterina Tumanova uint64_t psw[2]; 239b4f38e1SEkaterina Tumanova uint64_t gprs[16]; 249b4f38e1SEkaterina Tumanova uint32_t acrs[16]; 259b4f38e1SEkaterina Tumanova } QEMU_PACKED; 269b4f38e1SEkaterina Tumanova 279b4f38e1SEkaterina Tumanova typedef struct S390xUserRegsStruct S390xUserRegs; 289b4f38e1SEkaterina Tumanova 299b4f38e1SEkaterina Tumanova struct S390xElfPrstatusStruct { 309b4f38e1SEkaterina Tumanova uint8_t pad1[32]; 319b4f38e1SEkaterina Tumanova uint32_t pid; 329b4f38e1SEkaterina Tumanova uint8_t pad2[76]; 339b4f38e1SEkaterina Tumanova S390xUserRegs regs; 349b4f38e1SEkaterina Tumanova uint8_t pad3[16]; 359b4f38e1SEkaterina Tumanova } QEMU_PACKED; 369b4f38e1SEkaterina Tumanova 379b4f38e1SEkaterina Tumanova typedef struct S390xElfPrstatusStruct S390xElfPrstatus; 389b4f38e1SEkaterina Tumanova 399b4f38e1SEkaterina Tumanova struct S390xElfFpregsetStruct { 409b4f38e1SEkaterina Tumanova uint32_t fpc; 419b4f38e1SEkaterina Tumanova uint32_t pad; 429b4f38e1SEkaterina Tumanova uint64_t fprs[16]; 439b4f38e1SEkaterina Tumanova } QEMU_PACKED; 449b4f38e1SEkaterina Tumanova 459b4f38e1SEkaterina Tumanova typedef struct S390xElfFpregsetStruct S390xElfFpregset; 469b4f38e1SEkaterina Tumanova 473ceeb293SEric Farman struct S390xElfVregsLoStruct { 483ceeb293SEric Farman uint64_t vregs[16]; 493ceeb293SEric Farman } QEMU_PACKED; 503ceeb293SEric Farman 513ceeb293SEric Farman typedef struct S390xElfVregsLoStruct S390xElfVregsLo; 523ceeb293SEric Farman 533ceeb293SEric Farman struct S390xElfVregsHiStruct { 543ceeb293SEric Farman uint64_t vregs[16][2]; 553ceeb293SEric Farman } QEMU_PACKED; 563ceeb293SEric Farman 573ceeb293SEric Farman typedef struct S390xElfVregsHiStruct S390xElfVregsHi; 583ceeb293SEric Farman 5921a10690SChristian Borntraeger struct S390xElfGSCBStruct { 6021a10690SChristian Borntraeger uint64_t gsregs[4]; 6121a10690SChristian Borntraeger } QEMU_PACKED; 6221a10690SChristian Borntraeger 6321a10690SChristian Borntraeger typedef struct S390xElfGSCBStruct S390xElfGSCB; 6421a10690SChristian Borntraeger 659b4f38e1SEkaterina Tumanova typedef struct noteStruct { 669b4f38e1SEkaterina Tumanova Elf64_Nhdr hdr; 675f706fdcSChristian Borntraeger char name[8]; 689b4f38e1SEkaterina Tumanova union { 699b4f38e1SEkaterina Tumanova S390xElfPrstatus prstatus; 709b4f38e1SEkaterina Tumanova S390xElfFpregset fpregset; 713ceeb293SEric Farman S390xElfVregsLo vregslo; 723ceeb293SEric Farman S390xElfVregsHi vregshi; 7321a10690SChristian Borntraeger S390xElfGSCB gscb; 749b4f38e1SEkaterina Tumanova uint32_t prefix; 759b4f38e1SEkaterina Tumanova uint64_t timer; 769b4f38e1SEkaterina Tumanova uint64_t todcmp; 779b4f38e1SEkaterina Tumanova uint32_t todpreg; 789b4f38e1SEkaterina Tumanova uint64_t ctrs[16]; 799b4f38e1SEkaterina Tumanova } contents; 809b4f38e1SEkaterina Tumanova } QEMU_PACKED Note; 819b4f38e1SEkaterina Tumanova 82f738f296SChristian Borntraeger static void s390x_write_elf64_prstatus(Note *note, S390CPU *cpu, int id) 839b4f38e1SEkaterina Tumanova { 849b4f38e1SEkaterina Tumanova int i; 859b4f38e1SEkaterina Tumanova S390xUserRegs *regs; 869b4f38e1SEkaterina Tumanova 879b4f38e1SEkaterina Tumanova note->hdr.n_type = cpu_to_be32(NT_PRSTATUS); 889b4f38e1SEkaterina Tumanova 899b4f38e1SEkaterina Tumanova regs = &(note->contents.prstatus.regs); 909b4f38e1SEkaterina Tumanova regs->psw[0] = cpu_to_be64(cpu->env.psw.mask); 919b4f38e1SEkaterina Tumanova regs->psw[1] = cpu_to_be64(cpu->env.psw.addr); 929b4f38e1SEkaterina Tumanova for (i = 0; i <= 15; i++) { 939b4f38e1SEkaterina Tumanova regs->acrs[i] = cpu_to_be32(cpu->env.aregs[i]); 949b4f38e1SEkaterina Tumanova regs->gprs[i] = cpu_to_be64(cpu->env.regs[i]); 959b4f38e1SEkaterina Tumanova } 96f738f296SChristian Borntraeger note->contents.prstatus.pid = id; 979b4f38e1SEkaterina Tumanova } 989b4f38e1SEkaterina Tumanova 99f738f296SChristian Borntraeger static void s390x_write_elf64_fpregset(Note *note, S390CPU *cpu, int id) 1009b4f38e1SEkaterina Tumanova { 1019b4f38e1SEkaterina Tumanova int i; 102c498d8e3SEric Farman CPUS390XState *cs = &cpu->env; 1039b4f38e1SEkaterina Tumanova 1049b4f38e1SEkaterina Tumanova note->hdr.n_type = cpu_to_be32(NT_FPREGSET); 1059b4f38e1SEkaterina Tumanova note->contents.fpregset.fpc = cpu_to_be32(cpu->env.fpc); 1069b4f38e1SEkaterina Tumanova for (i = 0; i <= 15; i++) { 1074f83d7d2SDavid Hildenbrand note->contents.fpregset.fprs[i] = cpu_to_be64(*get_freg(cs, i)); 1089b4f38e1SEkaterina Tumanova } 1099b4f38e1SEkaterina Tumanova } 1109b4f38e1SEkaterina Tumanova 111f738f296SChristian Borntraeger static void s390x_write_elf64_vregslo(Note *note, S390CPU *cpu, int id) 1123ceeb293SEric Farman { 1133ceeb293SEric Farman int i; 1143ceeb293SEric Farman 1153ceeb293SEric Farman note->hdr.n_type = cpu_to_be32(NT_S390_VXRS_LOW); 1163ceeb293SEric Farman for (i = 0; i <= 15; i++) { 1174f83d7d2SDavid Hildenbrand note->contents.vregslo.vregs[i] = cpu_to_be64(cpu->env.vregs[i][1]); 1183ceeb293SEric Farman } 1193ceeb293SEric Farman } 1203ceeb293SEric Farman 121f738f296SChristian Borntraeger static void s390x_write_elf64_vregshi(Note *note, S390CPU *cpu, int id) 1223ceeb293SEric Farman { 1233ceeb293SEric Farman int i; 1243ceeb293SEric Farman S390xElfVregsHi *temp_vregshi; 1253ceeb293SEric Farman 1263ceeb293SEric Farman temp_vregshi = ¬e->contents.vregshi; 1273ceeb293SEric Farman 1283ceeb293SEric Farman note->hdr.n_type = cpu_to_be32(NT_S390_VXRS_HIGH); 1293ceeb293SEric Farman for (i = 0; i <= 15; i++) { 1304f83d7d2SDavid Hildenbrand temp_vregshi->vregs[i][0] = cpu_to_be64(cpu->env.vregs[i + 16][0]); 1314f83d7d2SDavid Hildenbrand temp_vregshi->vregs[i][1] = cpu_to_be64(cpu->env.vregs[i + 16][1]); 1323ceeb293SEric Farman } 1333ceeb293SEric Farman } 1349b4f38e1SEkaterina Tumanova 13521a10690SChristian Borntraeger static void s390x_write_elf64_gscb(Note *note, S390CPU *cpu, int id) 13621a10690SChristian Borntraeger { 13721a10690SChristian Borntraeger int i; 13821a10690SChristian Borntraeger 13921a10690SChristian Borntraeger note->hdr.n_type = cpu_to_be32(NT_S390_GS_CB); 14021a10690SChristian Borntraeger for (i = 0; i < 4; i++) { 14121a10690SChristian Borntraeger note->contents.gscb.gsregs[i] = cpu_to_be64(cpu->env.gscb[i]); 14221a10690SChristian Borntraeger } 14321a10690SChristian Borntraeger } 14421a10690SChristian Borntraeger 145f738f296SChristian Borntraeger static void s390x_write_elf64_timer(Note *note, S390CPU *cpu, int id) 1469b4f38e1SEkaterina Tumanova { 1479b4f38e1SEkaterina Tumanova note->hdr.n_type = cpu_to_be32(NT_S390_TIMER); 1489b4f38e1SEkaterina Tumanova note->contents.timer = cpu_to_be64((uint64_t)(cpu->env.cputm)); 1499b4f38e1SEkaterina Tumanova } 1509b4f38e1SEkaterina Tumanova 151f738f296SChristian Borntraeger static void s390x_write_elf64_todcmp(Note *note, S390CPU *cpu, int id) 1529b4f38e1SEkaterina Tumanova { 1539b4f38e1SEkaterina Tumanova note->hdr.n_type = cpu_to_be32(NT_S390_TODCMP); 1549b4f38e1SEkaterina Tumanova note->contents.todcmp = cpu_to_be64((uint64_t)(cpu->env.ckc)); 1559b4f38e1SEkaterina Tumanova } 1569b4f38e1SEkaterina Tumanova 157f738f296SChristian Borntraeger static void s390x_write_elf64_todpreg(Note *note, S390CPU *cpu, int id) 1589b4f38e1SEkaterina Tumanova { 1599b4f38e1SEkaterina Tumanova note->hdr.n_type = cpu_to_be32(NT_S390_TODPREG); 1609b4f38e1SEkaterina Tumanova note->contents.todpreg = cpu_to_be32((uint32_t)(cpu->env.todpr)); 1619b4f38e1SEkaterina Tumanova } 1629b4f38e1SEkaterina Tumanova 163f738f296SChristian Borntraeger static void s390x_write_elf64_ctrs(Note *note, S390CPU *cpu, int id) 1649b4f38e1SEkaterina Tumanova { 1659b4f38e1SEkaterina Tumanova int i; 1669b4f38e1SEkaterina Tumanova 1679b4f38e1SEkaterina Tumanova note->hdr.n_type = cpu_to_be32(NT_S390_CTRS); 1689b4f38e1SEkaterina Tumanova 1699b4f38e1SEkaterina Tumanova for (i = 0; i <= 15; i++) { 1709b4f38e1SEkaterina Tumanova note->contents.ctrs[i] = cpu_to_be64(cpu->env.cregs[i]); 1719b4f38e1SEkaterina Tumanova } 1729b4f38e1SEkaterina Tumanova } 1739b4f38e1SEkaterina Tumanova 174f738f296SChristian Borntraeger static void s390x_write_elf64_prefix(Note *note, S390CPU *cpu, int id) 1759b4f38e1SEkaterina Tumanova { 1769b4f38e1SEkaterina Tumanova note->hdr.n_type = cpu_to_be32(NT_S390_PREFIX); 1779b4f38e1SEkaterina Tumanova note->contents.prefix = cpu_to_be32((uint32_t)(cpu->env.psa)); 1789b4f38e1SEkaterina Tumanova } 1799b4f38e1SEkaterina Tumanova 1809b4f38e1SEkaterina Tumanova 1815f706fdcSChristian Borntraeger typedef struct NoteFuncDescStruct { 1829b4f38e1SEkaterina Tumanova int contents_size; 183f738f296SChristian Borntraeger void (*note_contents_func)(Note *note, S390CPU *cpu, int id); 1845f706fdcSChristian Borntraeger } NoteFuncDesc; 1855f706fdcSChristian Borntraeger 1865f706fdcSChristian Borntraeger static const NoteFuncDesc note_core[] = { 187f18793b0SStefan Hajnoczi {sizeof_field(Note, contents.prstatus), s390x_write_elf64_prstatus}, 188f18793b0SStefan Hajnoczi {sizeof_field(Note, contents.fpregset), s390x_write_elf64_fpregset}, 1895f706fdcSChristian Borntraeger { 0, NULL} 1905f706fdcSChristian Borntraeger }; 1915f706fdcSChristian Borntraeger 1925f706fdcSChristian Borntraeger static const NoteFuncDesc note_linux[] = { 193f18793b0SStefan Hajnoczi {sizeof_field(Note, contents.prefix), s390x_write_elf64_prefix}, 194f18793b0SStefan Hajnoczi {sizeof_field(Note, contents.ctrs), s390x_write_elf64_ctrs}, 195f18793b0SStefan Hajnoczi {sizeof_field(Note, contents.timer), s390x_write_elf64_timer}, 196f18793b0SStefan Hajnoczi {sizeof_field(Note, contents.todcmp), s390x_write_elf64_todcmp}, 197f18793b0SStefan Hajnoczi {sizeof_field(Note, contents.todpreg), s390x_write_elf64_todpreg}, 198f18793b0SStefan Hajnoczi {sizeof_field(Note, contents.vregslo), s390x_write_elf64_vregslo}, 199f18793b0SStefan Hajnoczi {sizeof_field(Note, contents.vregshi), s390x_write_elf64_vregshi}, 200f18793b0SStefan Hajnoczi {sizeof_field(Note, contents.gscb), s390x_write_elf64_gscb}, 2019b4f38e1SEkaterina Tumanova { 0, NULL} 2029b4f38e1SEkaterina Tumanova }; 2039b4f38e1SEkaterina Tumanova 2045f706fdcSChristian Borntraeger static int s390x_write_elf64_notes(const char *note_name, 2059b4f38e1SEkaterina Tumanova WriteCoreDumpFunction f, 2069b4f38e1SEkaterina Tumanova S390CPU *cpu, int id, 2075f706fdcSChristian Borntraeger void *opaque, 2085f706fdcSChristian Borntraeger const NoteFuncDesc *funcs) 2099b4f38e1SEkaterina Tumanova { 2109b4f38e1SEkaterina Tumanova Note note; 211ecb4e01eSStefan Weil const NoteFuncDesc *nf; 2129b4f38e1SEkaterina Tumanova int note_size; 2139b4f38e1SEkaterina Tumanova int ret = -1; 2149b4f38e1SEkaterina Tumanova 215*ea1b90b4SThomas Huth assert(strlen(note_name) < sizeof(note.name)); 216*ea1b90b4SThomas Huth 2175f706fdcSChristian Borntraeger for (nf = funcs; nf->note_contents_func; nf++) { 218abd137a1SChristian Borntraeger memset(¬e, 0, sizeof(note)); 2195f706fdcSChristian Borntraeger note.hdr.n_namesz = cpu_to_be32(strlen(note_name) + 1); 2209b4f38e1SEkaterina Tumanova note.hdr.n_descsz = cpu_to_be32(nf->contents_size); 221*ea1b90b4SThomas Huth g_strlcpy(note.name, note_name, sizeof(note.name)); 222f738f296SChristian Borntraeger (*nf->note_contents_func)(¬e, cpu, id); 2239b4f38e1SEkaterina Tumanova 2249b4f38e1SEkaterina Tumanova note_size = sizeof(note) - sizeof(note.contents) + nf->contents_size; 2259b4f38e1SEkaterina Tumanova ret = f(¬e, note_size, opaque); 2269b4f38e1SEkaterina Tumanova 2279b4f38e1SEkaterina Tumanova if (ret < 0) { 2289b4f38e1SEkaterina Tumanova return -1; 2299b4f38e1SEkaterina Tumanova } 2309b4f38e1SEkaterina Tumanova 2319b4f38e1SEkaterina Tumanova } 2329b4f38e1SEkaterina Tumanova 2339b4f38e1SEkaterina Tumanova return 0; 2349b4f38e1SEkaterina Tumanova } 2359b4f38e1SEkaterina Tumanova 2369b4f38e1SEkaterina Tumanova 2379b4f38e1SEkaterina Tumanova int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, 2389b4f38e1SEkaterina Tumanova int cpuid, void *opaque) 2399b4f38e1SEkaterina Tumanova { 2409b4f38e1SEkaterina Tumanova S390CPU *cpu = S390_CPU(cs); 2415f706fdcSChristian Borntraeger int r; 2425f706fdcSChristian Borntraeger 2435f706fdcSChristian Borntraeger r = s390x_write_elf64_notes("CORE", f, cpu, cpuid, opaque, note_core); 2445f706fdcSChristian Borntraeger if (r) { 2455f706fdcSChristian Borntraeger return r; 2465f706fdcSChristian Borntraeger } 2475f706fdcSChristian Borntraeger return s390x_write_elf64_notes("LINUX", f, cpu, cpuid, opaque, note_linux); 2489b4f38e1SEkaterina Tumanova } 2499b4f38e1SEkaterina Tumanova 25056c4bfb3SLaszlo Ersek int cpu_get_dump_info(ArchDumpInfo *info, 25156c4bfb3SLaszlo Ersek const struct GuestPhysBlockList *guest_phys_blocks) 2529b4f38e1SEkaterina Tumanova { 2539b4f38e1SEkaterina Tumanova info->d_machine = EM_S390; 2549b4f38e1SEkaterina Tumanova info->d_endian = ELFDATA2MSB; 2559b4f38e1SEkaterina Tumanova info->d_class = ELFCLASS64; 2569b4f38e1SEkaterina Tumanova 2579b4f38e1SEkaterina Tumanova return 0; 2589b4f38e1SEkaterina Tumanova } 2599b4f38e1SEkaterina Tumanova 2609b4f38e1SEkaterina Tumanova ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) 2619b4f38e1SEkaterina Tumanova { 2625f706fdcSChristian Borntraeger int name_size = 8; /* "LINUX" or "CORE" + pad */ 2639b4f38e1SEkaterina Tumanova size_t elf_note_size = 0; 2649b4f38e1SEkaterina Tumanova int note_head_size; 265ecb4e01eSStefan Weil const NoteFuncDesc *nf; 2669b4f38e1SEkaterina Tumanova 2679b4f38e1SEkaterina Tumanova assert(class == ELFCLASS64); 2689b4f38e1SEkaterina Tumanova assert(machine == EM_S390); 2699b4f38e1SEkaterina Tumanova 2709b4f38e1SEkaterina Tumanova note_head_size = sizeof(Elf64_Nhdr); 2719b4f38e1SEkaterina Tumanova 2725f706fdcSChristian Borntraeger for (nf = note_core; nf->note_contents_func; nf++) { 2735f706fdcSChristian Borntraeger elf_note_size = elf_note_size + note_head_size + name_size + 2745f706fdcSChristian Borntraeger nf->contents_size; 2755f706fdcSChristian Borntraeger } 2765f706fdcSChristian Borntraeger for (nf = note_linux; nf->note_contents_func; nf++) { 2779b4f38e1SEkaterina Tumanova elf_note_size = elf_note_size + note_head_size + name_size + 2789b4f38e1SEkaterina Tumanova nf->contents_size; 2799b4f38e1SEkaterina Tumanova } 2809b4f38e1SEkaterina Tumanova 2819b4f38e1SEkaterina Tumanova return (elf_note_size) * nr_cpus; 2829b4f38e1SEkaterina Tumanova } 283