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" 15113d8f4eSJanosch Frank #include "qemu/units.h" 169b4f38e1SEkaterina Tumanova #include "cpu.h" 17b6b47223SCho, Yu-Chen #include "s390x-internal.h" 189b4f38e1SEkaterina Tumanova #include "elf.h" 199b4f38e1SEkaterina Tumanova #include "sysemu/dump.h" 20113d8f4eSJanosch Frank #include "kvm/kvm_s390x.h" 21f5f9c6eaSPhilippe Mathieu-Daudé #include "target/s390x/kvm/pv.h" 229b4f38e1SEkaterina Tumanova 239b4f38e1SEkaterina Tumanova struct S390xUserRegsStruct { 249b4f38e1SEkaterina Tumanova uint64_t psw[2]; 259b4f38e1SEkaterina Tumanova uint64_t gprs[16]; 269b4f38e1SEkaterina Tumanova uint32_t acrs[16]; 279b4f38e1SEkaterina Tumanova } QEMU_PACKED; 289b4f38e1SEkaterina Tumanova 299b4f38e1SEkaterina Tumanova typedef struct S390xUserRegsStruct S390xUserRegs; 309b4f38e1SEkaterina Tumanova 319b4f38e1SEkaterina Tumanova struct S390xElfPrstatusStruct { 329b4f38e1SEkaterina Tumanova uint8_t pad1[32]; 339b4f38e1SEkaterina Tumanova uint32_t pid; 349b4f38e1SEkaterina Tumanova uint8_t pad2[76]; 359b4f38e1SEkaterina Tumanova S390xUserRegs regs; 369b4f38e1SEkaterina Tumanova uint8_t pad3[16]; 379b4f38e1SEkaterina Tumanova } QEMU_PACKED; 389b4f38e1SEkaterina Tumanova 399b4f38e1SEkaterina Tumanova typedef struct S390xElfPrstatusStruct S390xElfPrstatus; 409b4f38e1SEkaterina Tumanova 419b4f38e1SEkaterina Tumanova struct S390xElfFpregsetStruct { 429b4f38e1SEkaterina Tumanova uint32_t fpc; 439b4f38e1SEkaterina Tumanova uint32_t pad; 449b4f38e1SEkaterina Tumanova uint64_t fprs[16]; 459b4f38e1SEkaterina Tumanova } QEMU_PACKED; 469b4f38e1SEkaterina Tumanova 479b4f38e1SEkaterina Tumanova typedef struct S390xElfFpregsetStruct S390xElfFpregset; 489b4f38e1SEkaterina Tumanova 493ceeb293SEric Farman struct S390xElfVregsLoStruct { 503ceeb293SEric Farman uint64_t vregs[16]; 513ceeb293SEric Farman } QEMU_PACKED; 523ceeb293SEric Farman 533ceeb293SEric Farman typedef struct S390xElfVregsLoStruct S390xElfVregsLo; 543ceeb293SEric Farman 553ceeb293SEric Farman struct S390xElfVregsHiStruct { 563ceeb293SEric Farman uint64_t vregs[16][2]; 573ceeb293SEric Farman } QEMU_PACKED; 583ceeb293SEric Farman 593ceeb293SEric Farman typedef struct S390xElfVregsHiStruct S390xElfVregsHi; 603ceeb293SEric Farman 6121a10690SChristian Borntraeger struct S390xElfGSCBStruct { 6221a10690SChristian Borntraeger uint64_t gsregs[4]; 6321a10690SChristian Borntraeger } QEMU_PACKED; 6421a10690SChristian Borntraeger 6521a10690SChristian Borntraeger typedef struct S390xElfGSCBStruct S390xElfGSCB; 6621a10690SChristian Borntraeger 679b4f38e1SEkaterina Tumanova typedef struct noteStruct { 689b4f38e1SEkaterina Tumanova Elf64_Nhdr hdr; 695f706fdcSChristian Borntraeger char name[8]; 709b4f38e1SEkaterina Tumanova union { 719b4f38e1SEkaterina Tumanova S390xElfPrstatus prstatus; 729b4f38e1SEkaterina Tumanova S390xElfFpregset fpregset; 733ceeb293SEric Farman S390xElfVregsLo vregslo; 743ceeb293SEric Farman S390xElfVregsHi vregshi; 7521a10690SChristian Borntraeger S390xElfGSCB gscb; 769b4f38e1SEkaterina Tumanova uint32_t prefix; 779b4f38e1SEkaterina Tumanova uint64_t timer; 789b4f38e1SEkaterina Tumanova uint64_t todcmp; 799b4f38e1SEkaterina Tumanova uint32_t todpreg; 809b4f38e1SEkaterina Tumanova uint64_t ctrs[16]; 81113d8f4eSJanosch Frank uint8_t dynamic[1]; /* 82113d8f4eSJanosch Frank * Would be a flexible array member, if 83113d8f4eSJanosch Frank * that was legal inside a union. Real 84113d8f4eSJanosch Frank * size comes from PV info interface. 85113d8f4eSJanosch Frank */ 869b4f38e1SEkaterina Tumanova } contents; 879b4f38e1SEkaterina Tumanova } QEMU_PACKED Note; 889b4f38e1SEkaterina Tumanova 89113d8f4eSJanosch Frank static bool pv_dump_initialized; 90113d8f4eSJanosch Frank 91f738f296SChristian Borntraeger static void s390x_write_elf64_prstatus(Note *note, S390CPU *cpu, int id) 929b4f38e1SEkaterina Tumanova { 939b4f38e1SEkaterina Tumanova int i; 949b4f38e1SEkaterina Tumanova S390xUserRegs *regs; 959b4f38e1SEkaterina Tumanova 969b4f38e1SEkaterina Tumanova note->hdr.n_type = cpu_to_be32(NT_PRSTATUS); 979b4f38e1SEkaterina Tumanova 989b4f38e1SEkaterina Tumanova regs = &(note->contents.prstatus.regs); 999b4f38e1SEkaterina Tumanova regs->psw[0] = cpu_to_be64(cpu->env.psw.mask); 1009b4f38e1SEkaterina Tumanova regs->psw[1] = cpu_to_be64(cpu->env.psw.addr); 1019b4f38e1SEkaterina Tumanova for (i = 0; i <= 15; i++) { 1029b4f38e1SEkaterina Tumanova regs->acrs[i] = cpu_to_be32(cpu->env.aregs[i]); 1039b4f38e1SEkaterina Tumanova regs->gprs[i] = cpu_to_be64(cpu->env.regs[i]); 1049b4f38e1SEkaterina Tumanova } 105f738f296SChristian Borntraeger note->contents.prstatus.pid = id; 1069b4f38e1SEkaterina Tumanova } 1079b4f38e1SEkaterina Tumanova 108f738f296SChristian Borntraeger static void s390x_write_elf64_fpregset(Note *note, S390CPU *cpu, int id) 1099b4f38e1SEkaterina Tumanova { 1109b4f38e1SEkaterina Tumanova int i; 111c498d8e3SEric Farman CPUS390XState *cs = &cpu->env; 1129b4f38e1SEkaterina Tumanova 1139b4f38e1SEkaterina Tumanova note->hdr.n_type = cpu_to_be32(NT_FPREGSET); 1149b4f38e1SEkaterina Tumanova note->contents.fpregset.fpc = cpu_to_be32(cpu->env.fpc); 1159b4f38e1SEkaterina Tumanova for (i = 0; i <= 15; i++) { 1164f83d7d2SDavid Hildenbrand note->contents.fpregset.fprs[i] = cpu_to_be64(*get_freg(cs, i)); 1179b4f38e1SEkaterina Tumanova } 1189b4f38e1SEkaterina Tumanova } 1199b4f38e1SEkaterina Tumanova 120f738f296SChristian Borntraeger static void s390x_write_elf64_vregslo(Note *note, S390CPU *cpu, int id) 1213ceeb293SEric Farman { 1223ceeb293SEric Farman int i; 1233ceeb293SEric Farman 1243ceeb293SEric Farman note->hdr.n_type = cpu_to_be32(NT_S390_VXRS_LOW); 1253ceeb293SEric Farman for (i = 0; i <= 15; i++) { 1264f83d7d2SDavid Hildenbrand note->contents.vregslo.vregs[i] = cpu_to_be64(cpu->env.vregs[i][1]); 1273ceeb293SEric Farman } 1283ceeb293SEric Farman } 1293ceeb293SEric Farman 130f738f296SChristian Borntraeger static void s390x_write_elf64_vregshi(Note *note, S390CPU *cpu, int id) 1313ceeb293SEric Farman { 1323ceeb293SEric Farman int i; 1333ceeb293SEric Farman S390xElfVregsHi *temp_vregshi; 1343ceeb293SEric Farman 1353ceeb293SEric Farman temp_vregshi = ¬e->contents.vregshi; 1363ceeb293SEric Farman 1373ceeb293SEric Farman note->hdr.n_type = cpu_to_be32(NT_S390_VXRS_HIGH); 1383ceeb293SEric Farman for (i = 0; i <= 15; i++) { 1394f83d7d2SDavid Hildenbrand temp_vregshi->vregs[i][0] = cpu_to_be64(cpu->env.vregs[i + 16][0]); 1404f83d7d2SDavid Hildenbrand temp_vregshi->vregs[i][1] = cpu_to_be64(cpu->env.vregs[i + 16][1]); 1413ceeb293SEric Farman } 1423ceeb293SEric Farman } 1439b4f38e1SEkaterina Tumanova 14421a10690SChristian Borntraeger static void s390x_write_elf64_gscb(Note *note, S390CPU *cpu, int id) 14521a10690SChristian Borntraeger { 14621a10690SChristian Borntraeger int i; 14721a10690SChristian Borntraeger 14821a10690SChristian Borntraeger note->hdr.n_type = cpu_to_be32(NT_S390_GS_CB); 14921a10690SChristian Borntraeger for (i = 0; i < 4; i++) { 15021a10690SChristian Borntraeger note->contents.gscb.gsregs[i] = cpu_to_be64(cpu->env.gscb[i]); 15121a10690SChristian Borntraeger } 15221a10690SChristian Borntraeger } 15321a10690SChristian Borntraeger 154f738f296SChristian Borntraeger static void s390x_write_elf64_timer(Note *note, S390CPU *cpu, int id) 1559b4f38e1SEkaterina Tumanova { 1569b4f38e1SEkaterina Tumanova note->hdr.n_type = cpu_to_be32(NT_S390_TIMER); 1579b4f38e1SEkaterina Tumanova note->contents.timer = cpu_to_be64((uint64_t)(cpu->env.cputm)); 1589b4f38e1SEkaterina Tumanova } 1599b4f38e1SEkaterina Tumanova 160f738f296SChristian Borntraeger static void s390x_write_elf64_todcmp(Note *note, S390CPU *cpu, int id) 1619b4f38e1SEkaterina Tumanova { 1629b4f38e1SEkaterina Tumanova note->hdr.n_type = cpu_to_be32(NT_S390_TODCMP); 1639b4f38e1SEkaterina Tumanova note->contents.todcmp = cpu_to_be64((uint64_t)(cpu->env.ckc)); 1649b4f38e1SEkaterina Tumanova } 1659b4f38e1SEkaterina Tumanova 166f738f296SChristian Borntraeger static void s390x_write_elf64_todpreg(Note *note, S390CPU *cpu, int id) 1679b4f38e1SEkaterina Tumanova { 1689b4f38e1SEkaterina Tumanova note->hdr.n_type = cpu_to_be32(NT_S390_TODPREG); 1699b4f38e1SEkaterina Tumanova note->contents.todpreg = cpu_to_be32((uint32_t)(cpu->env.todpr)); 1709b4f38e1SEkaterina Tumanova } 1719b4f38e1SEkaterina Tumanova 172f738f296SChristian Borntraeger static void s390x_write_elf64_ctrs(Note *note, S390CPU *cpu, int id) 1739b4f38e1SEkaterina Tumanova { 1749b4f38e1SEkaterina Tumanova int i; 1759b4f38e1SEkaterina Tumanova 1769b4f38e1SEkaterina Tumanova note->hdr.n_type = cpu_to_be32(NT_S390_CTRS); 1779b4f38e1SEkaterina Tumanova 1789b4f38e1SEkaterina Tumanova for (i = 0; i <= 15; i++) { 1799b4f38e1SEkaterina Tumanova note->contents.ctrs[i] = cpu_to_be64(cpu->env.cregs[i]); 1809b4f38e1SEkaterina Tumanova } 1819b4f38e1SEkaterina Tumanova } 1829b4f38e1SEkaterina Tumanova 183f738f296SChristian Borntraeger static void s390x_write_elf64_prefix(Note *note, S390CPU *cpu, int id) 1849b4f38e1SEkaterina Tumanova { 1859b4f38e1SEkaterina Tumanova note->hdr.n_type = cpu_to_be32(NT_S390_PREFIX); 1869b4f38e1SEkaterina Tumanova note->contents.prefix = cpu_to_be32((uint32_t)(cpu->env.psa)); 1879b4f38e1SEkaterina Tumanova } 1889b4f38e1SEkaterina Tumanova 189113d8f4eSJanosch Frank static void s390x_write_elf64_pv(Note *note, S390CPU *cpu, int id) 190113d8f4eSJanosch Frank { 191113d8f4eSJanosch Frank note->hdr.n_type = cpu_to_be32(NT_S390_PV_CPU_DATA); 192113d8f4eSJanosch Frank if (!pv_dump_initialized) { 193113d8f4eSJanosch Frank return; 194113d8f4eSJanosch Frank } 195113d8f4eSJanosch Frank kvm_s390_dump_cpu(cpu, ¬e->contents.dynamic); 196113d8f4eSJanosch Frank } 1979b4f38e1SEkaterina Tumanova 1985f706fdcSChristian Borntraeger typedef struct NoteFuncDescStruct { 1999b4f38e1SEkaterina Tumanova int contents_size; 200113d8f4eSJanosch Frank uint64_t (*note_size_func)(void); /* NULL for non-dynamic sized contents */ 201f738f296SChristian Borntraeger void (*note_contents_func)(Note *note, S390CPU *cpu, int id); 202113d8f4eSJanosch Frank bool pvonly; 2035f706fdcSChristian Borntraeger } NoteFuncDesc; 2045f706fdcSChristian Borntraeger 2055f706fdcSChristian Borntraeger static const NoteFuncDesc note_core[] = { 206113d8f4eSJanosch Frank {sizeof_field(Note, contents.prstatus), NULL, s390x_write_elf64_prstatus, false}, 207113d8f4eSJanosch Frank {sizeof_field(Note, contents.fpregset), NULL, s390x_write_elf64_fpregset, false}, 208113d8f4eSJanosch Frank { 0, NULL, NULL, false} 2095f706fdcSChristian Borntraeger }; 2105f706fdcSChristian Borntraeger 2115f706fdcSChristian Borntraeger static const NoteFuncDesc note_linux[] = { 212113d8f4eSJanosch Frank {sizeof_field(Note, contents.prefix), NULL, s390x_write_elf64_prefix, false}, 213113d8f4eSJanosch Frank {sizeof_field(Note, contents.ctrs), NULL, s390x_write_elf64_ctrs, false}, 214113d8f4eSJanosch Frank {sizeof_field(Note, contents.timer), NULL, s390x_write_elf64_timer, false}, 215113d8f4eSJanosch Frank {sizeof_field(Note, contents.todcmp), NULL, s390x_write_elf64_todcmp, false}, 216113d8f4eSJanosch Frank {sizeof_field(Note, contents.todpreg), NULL, s390x_write_elf64_todpreg, false}, 217113d8f4eSJanosch Frank {sizeof_field(Note, contents.vregslo), NULL, s390x_write_elf64_vregslo, false}, 218113d8f4eSJanosch Frank {sizeof_field(Note, contents.vregshi), NULL, s390x_write_elf64_vregshi, false}, 219113d8f4eSJanosch Frank {sizeof_field(Note, contents.gscb), NULL, s390x_write_elf64_gscb, false}, 220113d8f4eSJanosch Frank {0, kvm_s390_pv_dmp_get_size_cpu, s390x_write_elf64_pv, true}, 221113d8f4eSJanosch Frank { 0, NULL, NULL, false} 2229b4f38e1SEkaterina Tumanova }; 2239b4f38e1SEkaterina Tumanova 2245f706fdcSChristian Borntraeger static int s390x_write_elf64_notes(const char *note_name, 2259b4f38e1SEkaterina Tumanova WriteCoreDumpFunction f, 2269b4f38e1SEkaterina Tumanova S390CPU *cpu, int id, 2271af0006aSJanosch Frank DumpState *s, 2285f706fdcSChristian Borntraeger const NoteFuncDesc *funcs) 2299b4f38e1SEkaterina Tumanova { 2304376a770SThomas Huth g_autofree Note *notep = NULL; 231ecb4e01eSStefan Weil const NoteFuncDesc *nf; 2324376a770SThomas Huth int note_size, prev_size = 0, content_size; 2339b4f38e1SEkaterina Tumanova int ret = -1; 2349b4f38e1SEkaterina Tumanova 2354376a770SThomas Huth assert(strlen(note_name) < sizeof(notep->name)); 236ea1b90b4SThomas Huth 2375f706fdcSChristian Borntraeger for (nf = funcs; nf->note_contents_func; nf++) { 238113d8f4eSJanosch Frank if (nf->pvonly && !s390_is_pv()) { 239113d8f4eSJanosch Frank continue; 240113d8f4eSJanosch Frank } 2419b4f38e1SEkaterina Tumanova 242113d8f4eSJanosch Frank content_size = nf->note_size_func ? nf->note_size_func() : nf->contents_size; 2434376a770SThomas Huth note_size = sizeof(Note) - sizeof(notep->contents) + content_size; 244113d8f4eSJanosch Frank 2454376a770SThomas Huth if (prev_size < note_size) { 2464376a770SThomas Huth g_free(notep); 247113d8f4eSJanosch Frank notep = g_malloc(note_size); 2484376a770SThomas Huth prev_size = note_size; 249113d8f4eSJanosch Frank } 250113d8f4eSJanosch Frank 251eb600261SThomas Huth memset(notep, 0, note_size); 252113d8f4eSJanosch Frank 253113d8f4eSJanosch Frank /* Setup note header data */ 254113d8f4eSJanosch Frank notep->hdr.n_descsz = cpu_to_be32(content_size); 255113d8f4eSJanosch Frank notep->hdr.n_namesz = cpu_to_be32(strlen(note_name) + 1); 256113d8f4eSJanosch Frank g_strlcpy(notep->name, note_name, sizeof(notep->name)); 257113d8f4eSJanosch Frank 258113d8f4eSJanosch Frank /* Get contents and write them out */ 259113d8f4eSJanosch Frank (*nf->note_contents_func)(notep, cpu, id); 260113d8f4eSJanosch Frank ret = f(notep, note_size, s); 2619b4f38e1SEkaterina Tumanova if (ret < 0) { 2629b4f38e1SEkaterina Tumanova return -1; 2639b4f38e1SEkaterina Tumanova } 2649b4f38e1SEkaterina Tumanova } 2659b4f38e1SEkaterina Tumanova 2669b4f38e1SEkaterina Tumanova return 0; 2679b4f38e1SEkaterina Tumanova } 2689b4f38e1SEkaterina Tumanova 2699b4f38e1SEkaterina Tumanova 2709b4f38e1SEkaterina Tumanova int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, 2711af0006aSJanosch Frank int cpuid, DumpState *s) 2729b4f38e1SEkaterina Tumanova { 2739b4f38e1SEkaterina Tumanova S390CPU *cpu = S390_CPU(cs); 2745f706fdcSChristian Borntraeger int r; 2755f706fdcSChristian Borntraeger 2761af0006aSJanosch Frank r = s390x_write_elf64_notes("CORE", f, cpu, cpuid, s, note_core); 2775f706fdcSChristian Borntraeger if (r) { 2785f706fdcSChristian Borntraeger return r; 2795f706fdcSChristian Borntraeger } 2801af0006aSJanosch Frank return s390x_write_elf64_notes("LINUX", f, cpu, cpuid, s, note_linux); 2819b4f38e1SEkaterina Tumanova } 2829b4f38e1SEkaterina Tumanova 283113d8f4eSJanosch Frank /* PV dump section size functions */ 284113d8f4eSJanosch Frank static uint64_t get_mem_state_size_from_len(uint64_t len) 285113d8f4eSJanosch Frank { 286113d8f4eSJanosch Frank return (len / (MiB)) * kvm_s390_pv_dmp_get_size_mem_state(); 287113d8f4eSJanosch Frank } 288113d8f4eSJanosch Frank 289113d8f4eSJanosch Frank static uint64_t get_size_mem_state(DumpState *s) 290113d8f4eSJanosch Frank { 291113d8f4eSJanosch Frank return get_mem_state_size_from_len(s->total_size); 292113d8f4eSJanosch Frank } 293113d8f4eSJanosch Frank 294113d8f4eSJanosch Frank static uint64_t get_size_completion_data(DumpState *s) 295113d8f4eSJanosch Frank { 296113d8f4eSJanosch Frank return kvm_s390_pv_dmp_get_size_completion_data(); 297113d8f4eSJanosch Frank } 298113d8f4eSJanosch Frank 299113d8f4eSJanosch Frank /* PV dump section data functions*/ 300113d8f4eSJanosch Frank static int get_data_completion(DumpState *s, uint8_t *buff) 301113d8f4eSJanosch Frank { 302113d8f4eSJanosch Frank int rc; 303113d8f4eSJanosch Frank 304113d8f4eSJanosch Frank if (!pv_dump_initialized) { 305113d8f4eSJanosch Frank return 0; 306113d8f4eSJanosch Frank } 307113d8f4eSJanosch Frank rc = kvm_s390_dump_completion_data(buff); 308113d8f4eSJanosch Frank if (!rc) { 309113d8f4eSJanosch Frank pv_dump_initialized = false; 310113d8f4eSJanosch Frank } 311113d8f4eSJanosch Frank return rc; 312113d8f4eSJanosch Frank } 313113d8f4eSJanosch Frank 314113d8f4eSJanosch Frank static int get_mem_state(DumpState *s, uint8_t *buff) 315113d8f4eSJanosch Frank { 316113d8f4eSJanosch Frank int64_t memblock_size, memblock_start; 317113d8f4eSJanosch Frank GuestPhysBlock *block; 318113d8f4eSJanosch Frank uint64_t off; 319113d8f4eSJanosch Frank int rc; 320113d8f4eSJanosch Frank 321113d8f4eSJanosch Frank QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) { 322113d8f4eSJanosch Frank memblock_start = dump_filtered_memblock_start(block, s->filter_area_begin, 323113d8f4eSJanosch Frank s->filter_area_length); 324113d8f4eSJanosch Frank if (memblock_start == -1) { 325113d8f4eSJanosch Frank continue; 326113d8f4eSJanosch Frank } 327113d8f4eSJanosch Frank 328113d8f4eSJanosch Frank memblock_size = dump_filtered_memblock_size(block, s->filter_area_begin, 329113d8f4eSJanosch Frank s->filter_area_length); 330113d8f4eSJanosch Frank 331113d8f4eSJanosch Frank off = get_mem_state_size_from_len(block->target_start); 332113d8f4eSJanosch Frank 333113d8f4eSJanosch Frank rc = kvm_s390_dump_mem_state(block->target_start, 334113d8f4eSJanosch Frank get_mem_state_size_from_len(memblock_size), 335113d8f4eSJanosch Frank buff + off); 336113d8f4eSJanosch Frank if (rc) { 337113d8f4eSJanosch Frank return rc; 338113d8f4eSJanosch Frank } 339113d8f4eSJanosch Frank } 340113d8f4eSJanosch Frank 341113d8f4eSJanosch Frank return 0; 342113d8f4eSJanosch Frank } 343113d8f4eSJanosch Frank 344113d8f4eSJanosch Frank static struct sections { 345113d8f4eSJanosch Frank uint64_t (*sections_size_func)(DumpState *s); 346113d8f4eSJanosch Frank int (*sections_contents_func)(DumpState *s, uint8_t *buff); 347113d8f4eSJanosch Frank char sctn_str[12]; 348113d8f4eSJanosch Frank } sections[] = { 349113d8f4eSJanosch Frank { get_size_mem_state, get_mem_state, "pv_mem_meta"}, 350113d8f4eSJanosch Frank { get_size_completion_data, get_data_completion, "pv_compl"}, 351113d8f4eSJanosch Frank {NULL , NULL, ""} 352113d8f4eSJanosch Frank }; 353113d8f4eSJanosch Frank 354113d8f4eSJanosch Frank static uint64_t arch_sections_write_hdr(DumpState *s, uint8_t *buff) 355113d8f4eSJanosch Frank { 356113d8f4eSJanosch Frank Elf64_Shdr *shdr = (void *)buff; 357113d8f4eSJanosch Frank struct sections *sctn = sections; 358113d8f4eSJanosch Frank uint64_t off = s->section_offset; 359113d8f4eSJanosch Frank 360113d8f4eSJanosch Frank if (!pv_dump_initialized) { 361113d8f4eSJanosch Frank return 0; 362113d8f4eSJanosch Frank } 363113d8f4eSJanosch Frank 364113d8f4eSJanosch Frank for (; sctn->sections_size_func; off += shdr->sh_size, sctn++, shdr++) { 365113d8f4eSJanosch Frank memset(shdr, 0, sizeof(*shdr)); 366113d8f4eSJanosch Frank shdr->sh_type = SHT_PROGBITS; 367113d8f4eSJanosch Frank shdr->sh_offset = off; 368113d8f4eSJanosch Frank shdr->sh_size = sctn->sections_size_func(s); 369113d8f4eSJanosch Frank shdr->sh_name = s->string_table_buf->len; 370113d8f4eSJanosch Frank g_array_append_vals(s->string_table_buf, sctn->sctn_str, sizeof(sctn->sctn_str)); 371113d8f4eSJanosch Frank } 372113d8f4eSJanosch Frank 373113d8f4eSJanosch Frank return (uintptr_t)shdr - (uintptr_t)buff; 374113d8f4eSJanosch Frank } 375113d8f4eSJanosch Frank 376113d8f4eSJanosch Frank 377113d8f4eSJanosch Frank /* Add arch specific number of sections and their respective sizes */ 378113d8f4eSJanosch Frank static void arch_sections_add(DumpState *s) 379113d8f4eSJanosch Frank { 380113d8f4eSJanosch Frank struct sections *sctn = sections; 381113d8f4eSJanosch Frank 382113d8f4eSJanosch Frank /* 383113d8f4eSJanosch Frank * We only do a PV dump if we are running a PV guest, KVM supports 384113d8f4eSJanosch Frank * the dump API and we got valid dump length information. 385113d8f4eSJanosch Frank */ 386113d8f4eSJanosch Frank if (!s390_is_pv() || !kvm_s390_get_protected_dump() || 387113d8f4eSJanosch Frank !kvm_s390_pv_info_basic_valid()) { 388113d8f4eSJanosch Frank return; 389113d8f4eSJanosch Frank } 390113d8f4eSJanosch Frank 391113d8f4eSJanosch Frank /* 392113d8f4eSJanosch Frank * Start the UV dump process by doing the initialize dump call via 393113d8f4eSJanosch Frank * KVM as the proxy. 394113d8f4eSJanosch Frank */ 395113d8f4eSJanosch Frank if (!kvm_s390_dump_init()) { 396113d8f4eSJanosch Frank pv_dump_initialized = true; 397113d8f4eSJanosch Frank } else { 398113d8f4eSJanosch Frank /* 399113d8f4eSJanosch Frank * Dump init failed, maybe the guest owner disabled dumping. 400113d8f4eSJanosch Frank * We'll continue the non-PV dump process since this is no 401113d8f4eSJanosch Frank * reason to crash qemu. 402113d8f4eSJanosch Frank */ 403113d8f4eSJanosch Frank return; 404113d8f4eSJanosch Frank } 405113d8f4eSJanosch Frank 406113d8f4eSJanosch Frank for (; sctn->sections_size_func; sctn++) { 407113d8f4eSJanosch Frank s->shdr_num += 1; 408113d8f4eSJanosch Frank s->elf_section_data_size += sctn->sections_size_func(s); 409113d8f4eSJanosch Frank } 410113d8f4eSJanosch Frank } 411113d8f4eSJanosch Frank 412113d8f4eSJanosch Frank /* 413113d8f4eSJanosch Frank * After the PV dump has been initialized, the CPU data has been 414113d8f4eSJanosch Frank * fetched and memory has been dumped, we need to grab the tweak data 415113d8f4eSJanosch Frank * and the completion data. 416113d8f4eSJanosch Frank */ 417113d8f4eSJanosch Frank static int arch_sections_write(DumpState *s, uint8_t *buff) 418113d8f4eSJanosch Frank { 419113d8f4eSJanosch Frank struct sections *sctn = sections; 420113d8f4eSJanosch Frank int rc; 421113d8f4eSJanosch Frank 422113d8f4eSJanosch Frank if (!pv_dump_initialized) { 423113d8f4eSJanosch Frank return -EINVAL; 424113d8f4eSJanosch Frank } 425113d8f4eSJanosch Frank 426113d8f4eSJanosch Frank for (; sctn->sections_size_func; sctn++) { 427113d8f4eSJanosch Frank rc = sctn->sections_contents_func(s, buff); 428113d8f4eSJanosch Frank buff += sctn->sections_size_func(s); 429113d8f4eSJanosch Frank if (rc) { 430113d8f4eSJanosch Frank return rc; 431113d8f4eSJanosch Frank } 432113d8f4eSJanosch Frank } 433113d8f4eSJanosch Frank return 0; 434113d8f4eSJanosch Frank } 435113d8f4eSJanosch Frank 436*d12a91e0SJanosch Frank static void arch_cleanup(DumpState *s) 437*d12a91e0SJanosch Frank { 438*d12a91e0SJanosch Frank g_autofree uint8_t *buff = NULL; 439*d12a91e0SJanosch Frank int rc; 440*d12a91e0SJanosch Frank 441*d12a91e0SJanosch Frank if (!pv_dump_initialized) { 442*d12a91e0SJanosch Frank return; 443*d12a91e0SJanosch Frank } 444*d12a91e0SJanosch Frank 445*d12a91e0SJanosch Frank buff = g_malloc(kvm_s390_pv_dmp_get_size_completion_data()); 446*d12a91e0SJanosch Frank rc = kvm_s390_dump_completion_data(buff); 447*d12a91e0SJanosch Frank if (!rc) { 448*d12a91e0SJanosch Frank pv_dump_initialized = false; 449*d12a91e0SJanosch Frank } 450*d12a91e0SJanosch Frank } 451*d12a91e0SJanosch Frank 45256c4bfb3SLaszlo Ersek int cpu_get_dump_info(ArchDumpInfo *info, 45356c4bfb3SLaszlo Ersek const struct GuestPhysBlockList *guest_phys_blocks) 4549b4f38e1SEkaterina Tumanova { 4559b4f38e1SEkaterina Tumanova info->d_machine = EM_S390; 4569b4f38e1SEkaterina Tumanova info->d_endian = ELFDATA2MSB; 4579b4f38e1SEkaterina Tumanova info->d_class = ELFCLASS64; 458113d8f4eSJanosch Frank /* 459113d8f4eSJanosch Frank * This is evaluated for each dump so we can freely switch 460113d8f4eSJanosch Frank * between PV and non-PV. 461113d8f4eSJanosch Frank */ 462113d8f4eSJanosch Frank if (s390_is_pv() && kvm_s390_get_protected_dump() && 463113d8f4eSJanosch Frank kvm_s390_pv_info_basic_valid()) { 464113d8f4eSJanosch Frank info->arch_sections_add_fn = *arch_sections_add; 465113d8f4eSJanosch Frank info->arch_sections_write_hdr_fn = *arch_sections_write_hdr; 466113d8f4eSJanosch Frank info->arch_sections_write_fn = *arch_sections_write; 467*d12a91e0SJanosch Frank info->arch_cleanup_fn = *arch_cleanup; 468113d8f4eSJanosch Frank } 4699b4f38e1SEkaterina Tumanova return 0; 4709b4f38e1SEkaterina Tumanova } 4719b4f38e1SEkaterina Tumanova 4729b4f38e1SEkaterina Tumanova ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) 4739b4f38e1SEkaterina Tumanova { 4745f706fdcSChristian Borntraeger int name_size = 8; /* "LINUX" or "CORE" + pad */ 4759b4f38e1SEkaterina Tumanova size_t elf_note_size = 0; 476113d8f4eSJanosch Frank int note_head_size, content_size; 477ecb4e01eSStefan Weil const NoteFuncDesc *nf; 4789b4f38e1SEkaterina Tumanova 4799b4f38e1SEkaterina Tumanova assert(class == ELFCLASS64); 4809b4f38e1SEkaterina Tumanova assert(machine == EM_S390); 4819b4f38e1SEkaterina Tumanova 4829b4f38e1SEkaterina Tumanova note_head_size = sizeof(Elf64_Nhdr); 4839b4f38e1SEkaterina Tumanova 4845f706fdcSChristian Borntraeger for (nf = note_core; nf->note_contents_func; nf++) { 485113d8f4eSJanosch Frank elf_note_size = elf_note_size + note_head_size + name_size + nf->contents_size; 4865f706fdcSChristian Borntraeger } 4875f706fdcSChristian Borntraeger for (nf = note_linux; nf->note_contents_func; nf++) { 488113d8f4eSJanosch Frank if (nf->pvonly && !s390_is_pv()) { 489113d8f4eSJanosch Frank continue; 490113d8f4eSJanosch Frank } 491113d8f4eSJanosch Frank content_size = nf->contents_size ? nf->contents_size : nf->note_size_func(); 4929b4f38e1SEkaterina Tumanova elf_note_size = elf_note_size + note_head_size + name_size + 493113d8f4eSJanosch Frank content_size; 4949b4f38e1SEkaterina Tumanova } 4959b4f38e1SEkaterina Tumanova 4969b4f38e1SEkaterina Tumanova return (elf_note_size) * nr_cpus; 4979b4f38e1SEkaterina Tumanova } 498