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"
19*32cad1ffSPhilippe Mathieu-Daudé #include "system/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
s390x_write_elf64_prstatus(Note * note,S390CPU * cpu,int id)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 }
10587c9d801SOmar Sandoval note->contents.prstatus.pid = cpu_to_be32(id);
1069b4f38e1SEkaterina Tumanova }
1079b4f38e1SEkaterina Tumanova
s390x_write_elf64_fpregset(Note * note,S390CPU * cpu,int id)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
s390x_write_elf64_vregslo(Note * note,S390CPU * cpu,int id)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
s390x_write_elf64_vregshi(Note * note,S390CPU * cpu,int id)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
s390x_write_elf64_gscb(Note * note,S390CPU * cpu,int id)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
s390x_write_elf64_timer(Note * note,S390CPU * cpu,int id)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
s390x_write_elf64_todcmp(Note * note,S390CPU * cpu,int id)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
s390x_write_elf64_todpreg(Note * note,S390CPU * cpu,int id)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
s390x_write_elf64_ctrs(Note * note,S390CPU * cpu,int id)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
s390x_write_elf64_prefix(Note * note,S390CPU * cpu,int id)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
s390x_write_elf64_pv(Note * note,S390CPU * cpu,int id)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
s390x_write_elf64_notes(const char * note_name,WriteCoreDumpFunction f,S390CPU * cpu,int id,DumpState * s,const NoteFuncDesc * funcs)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
s390_cpu_write_elf64_note(WriteCoreDumpFunction f,CPUState * cs,int cpuid,DumpState * s)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 */
get_mem_state_size_from_len(uint64_t len)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
get_size_mem_state(DumpState * s)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
get_size_completion_data(DumpState * s)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*/
get_data_completion(DumpState * s,uint8_t * buff)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
get_mem_state(DumpState * s,uint8_t * buff)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
arch_sections_write_hdr(DumpState * s,uint8_t * buff)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 */
arch_sections_add(DumpState * s)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 */
arch_sections_write(DumpState * s,uint8_t * buff)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
arch_cleanup(DumpState * s)436d12a91e0SJanosch Frank static void arch_cleanup(DumpState *s)
437d12a91e0SJanosch Frank {
438d12a91e0SJanosch Frank g_autofree uint8_t *buff = NULL;
439d12a91e0SJanosch Frank int rc;
440d12a91e0SJanosch Frank
441d12a91e0SJanosch Frank if (!pv_dump_initialized) {
442d12a91e0SJanosch Frank return;
443d12a91e0SJanosch Frank }
444d12a91e0SJanosch Frank
445d12a91e0SJanosch Frank buff = g_malloc(kvm_s390_pv_dmp_get_size_completion_data());
446d12a91e0SJanosch Frank rc = kvm_s390_dump_completion_data(buff);
447d12a91e0SJanosch Frank if (!rc) {
448d12a91e0SJanosch Frank pv_dump_initialized = false;
449d12a91e0SJanosch Frank }
450d12a91e0SJanosch Frank }
451d12a91e0SJanosch Frank
cpu_get_dump_info(ArchDumpInfo * info,const struct GuestPhysBlockList * guest_phys_blocks)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;
467d12a91e0SJanosch Frank info->arch_cleanup_fn = *arch_cleanup;
468113d8f4eSJanosch Frank }
4699b4f38e1SEkaterina Tumanova return 0;
4709b4f38e1SEkaterina Tumanova }
4719b4f38e1SEkaterina Tumanova
cpu_get_note_size(int class,int machine,int nr_cpus)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