xref: /qemu/target/s390x/arch_dump.c (revision 87c9d801)
1fcf5ef2aSThomas Huth /*
2fcf5ef2aSThomas Huth  * writing ELF notes for s390x arch
3fcf5ef2aSThomas Huth  *
4fcf5ef2aSThomas Huth  *
5fcf5ef2aSThomas Huth  * Copyright IBM Corp. 2012, 2013
6fcf5ef2aSThomas Huth  *
7fcf5ef2aSThomas Huth  *     Ekaterina Tumanova <tumanova@linux.vnet.ibm.com>
8fcf5ef2aSThomas Huth  *
9fcf5ef2aSThomas Huth  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10fcf5ef2aSThomas Huth  * See the COPYING file in the top-level directory.
11fcf5ef2aSThomas Huth  *
12fcf5ef2aSThomas Huth  */
13fcf5ef2aSThomas Huth 
14fcf5ef2aSThomas Huth #include "qemu/osdep.h"
15113d8f4eSJanosch Frank #include "qemu/units.h"
16fcf5ef2aSThomas Huth #include "cpu.h"
17b6b47223SCho, Yu-Chen #include "s390x-internal.h"
18fcf5ef2aSThomas Huth #include "elf.h"
19fcf5ef2aSThomas Huth #include "sysemu/dump.h"
20113d8f4eSJanosch Frank #include "kvm/kvm_s390x.h"
21f5f9c6eaSPhilippe Mathieu-Daudé #include "target/s390x/kvm/pv.h"
22fcf5ef2aSThomas Huth 
23fcf5ef2aSThomas Huth struct S390xUserRegsStruct {
24fcf5ef2aSThomas Huth     uint64_t psw[2];
25fcf5ef2aSThomas Huth     uint64_t gprs[16];
26fcf5ef2aSThomas Huth     uint32_t acrs[16];
27fcf5ef2aSThomas Huth } QEMU_PACKED;
28fcf5ef2aSThomas Huth 
29fcf5ef2aSThomas Huth typedef struct S390xUserRegsStruct S390xUserRegs;
30fcf5ef2aSThomas Huth 
31fcf5ef2aSThomas Huth struct S390xElfPrstatusStruct {
32fcf5ef2aSThomas Huth     uint8_t pad1[32];
33fcf5ef2aSThomas Huth     uint32_t pid;
34fcf5ef2aSThomas Huth     uint8_t pad2[76];
35fcf5ef2aSThomas Huth     S390xUserRegs regs;
36fcf5ef2aSThomas Huth     uint8_t pad3[16];
37fcf5ef2aSThomas Huth } QEMU_PACKED;
38fcf5ef2aSThomas Huth 
39fcf5ef2aSThomas Huth typedef struct S390xElfPrstatusStruct S390xElfPrstatus;
40fcf5ef2aSThomas Huth 
41fcf5ef2aSThomas Huth struct S390xElfFpregsetStruct {
42fcf5ef2aSThomas Huth     uint32_t fpc;
43fcf5ef2aSThomas Huth     uint32_t pad;
44fcf5ef2aSThomas Huth     uint64_t fprs[16];
45fcf5ef2aSThomas Huth } QEMU_PACKED;
46fcf5ef2aSThomas Huth 
47fcf5ef2aSThomas Huth typedef struct S390xElfFpregsetStruct S390xElfFpregset;
48fcf5ef2aSThomas Huth 
49fcf5ef2aSThomas Huth struct S390xElfVregsLoStruct {
50fcf5ef2aSThomas Huth     uint64_t vregs[16];
51fcf5ef2aSThomas Huth } QEMU_PACKED;
52fcf5ef2aSThomas Huth 
53fcf5ef2aSThomas Huth typedef struct S390xElfVregsLoStruct S390xElfVregsLo;
54fcf5ef2aSThomas Huth 
55fcf5ef2aSThomas Huth struct S390xElfVregsHiStruct {
56fcf5ef2aSThomas Huth     uint64_t vregs[16][2];
57fcf5ef2aSThomas Huth } QEMU_PACKED;
58fcf5ef2aSThomas Huth 
59fcf5ef2aSThomas Huth typedef struct S390xElfVregsHiStruct S390xElfVregsHi;
60fcf5ef2aSThomas Huth 
6121a10690SChristian Borntraeger struct S390xElfGSCBStruct {
6221a10690SChristian Borntraeger     uint64_t gsregs[4];
6321a10690SChristian Borntraeger } QEMU_PACKED;
6421a10690SChristian Borntraeger 
6521a10690SChristian Borntraeger typedef struct S390xElfGSCBStruct S390xElfGSCB;
6621a10690SChristian Borntraeger 
67fcf5ef2aSThomas Huth typedef struct noteStruct {
68fcf5ef2aSThomas Huth     Elf64_Nhdr hdr;
695f706fdcSChristian Borntraeger     char name[8];
70fcf5ef2aSThomas Huth     union {
71fcf5ef2aSThomas Huth         S390xElfPrstatus prstatus;
72fcf5ef2aSThomas Huth         S390xElfFpregset fpregset;
73fcf5ef2aSThomas Huth         S390xElfVregsLo vregslo;
74fcf5ef2aSThomas Huth         S390xElfVregsHi vregshi;
7521a10690SChristian Borntraeger         S390xElfGSCB gscb;
76fcf5ef2aSThomas Huth         uint32_t prefix;
77fcf5ef2aSThomas Huth         uint64_t timer;
78fcf5ef2aSThomas Huth         uint64_t todcmp;
79fcf5ef2aSThomas Huth         uint32_t todpreg;
80fcf5ef2aSThomas Huth         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                               */
86fcf5ef2aSThomas Huth     } contents;
87fcf5ef2aSThomas Huth } QEMU_PACKED Note;
88fcf5ef2aSThomas Huth 
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)
92fcf5ef2aSThomas Huth {
93fcf5ef2aSThomas Huth     int i;
94fcf5ef2aSThomas Huth     S390xUserRegs *regs;
95fcf5ef2aSThomas Huth 
96fcf5ef2aSThomas Huth     note->hdr.n_type = cpu_to_be32(NT_PRSTATUS);
97fcf5ef2aSThomas Huth 
98fcf5ef2aSThomas Huth     regs = &(note->contents.prstatus.regs);
99fcf5ef2aSThomas Huth     regs->psw[0] = cpu_to_be64(cpu->env.psw.mask);
100fcf5ef2aSThomas Huth     regs->psw[1] = cpu_to_be64(cpu->env.psw.addr);
101fcf5ef2aSThomas Huth     for (i = 0; i <= 15; i++) {
102fcf5ef2aSThomas Huth         regs->acrs[i] = cpu_to_be32(cpu->env.aregs[i]);
103fcf5ef2aSThomas Huth         regs->gprs[i] = cpu_to_be64(cpu->env.regs[i]);
104fcf5ef2aSThomas Huth     }
105*87c9d801SOmar Sandoval     note->contents.prstatus.pid = cpu_to_be32(id);
106fcf5ef2aSThomas Huth }
107fcf5ef2aSThomas Huth 
s390x_write_elf64_fpregset(Note * note,S390CPU * cpu,int id)108f738f296SChristian Borntraeger static void s390x_write_elf64_fpregset(Note *note, S390CPU *cpu, int id)
109fcf5ef2aSThomas Huth {
110fcf5ef2aSThomas Huth     int i;
111fcf5ef2aSThomas Huth     CPUS390XState *cs = &cpu->env;
112fcf5ef2aSThomas Huth 
113fcf5ef2aSThomas Huth     note->hdr.n_type = cpu_to_be32(NT_FPREGSET);
114fcf5ef2aSThomas Huth     note->contents.fpregset.fpc = cpu_to_be32(cpu->env.fpc);
115fcf5ef2aSThomas Huth     for (i = 0; i <= 15; i++) {
1164f83d7d2SDavid Hildenbrand         note->contents.fpregset.fprs[i] = cpu_to_be64(*get_freg(cs, i));
117fcf5ef2aSThomas Huth     }
118fcf5ef2aSThomas Huth }
119fcf5ef2aSThomas Huth 
s390x_write_elf64_vregslo(Note * note,S390CPU * cpu,int id)120f738f296SChristian Borntraeger static void s390x_write_elf64_vregslo(Note *note, S390CPU *cpu,  int id)
121fcf5ef2aSThomas Huth {
122fcf5ef2aSThomas Huth     int i;
123fcf5ef2aSThomas Huth 
124fcf5ef2aSThomas Huth     note->hdr.n_type = cpu_to_be32(NT_S390_VXRS_LOW);
125fcf5ef2aSThomas Huth     for (i = 0; i <= 15; i++) {
1264f83d7d2SDavid Hildenbrand         note->contents.vregslo.vregs[i] = cpu_to_be64(cpu->env.vregs[i][1]);
127fcf5ef2aSThomas Huth     }
128fcf5ef2aSThomas Huth }
129fcf5ef2aSThomas Huth 
s390x_write_elf64_vregshi(Note * note,S390CPU * cpu,int id)130f738f296SChristian Borntraeger static void s390x_write_elf64_vregshi(Note *note, S390CPU *cpu, int id)
131fcf5ef2aSThomas Huth {
132fcf5ef2aSThomas Huth     int i;
133fcf5ef2aSThomas Huth     S390xElfVregsHi *temp_vregshi;
134fcf5ef2aSThomas Huth 
135fcf5ef2aSThomas Huth     temp_vregshi = &note->contents.vregshi;
136fcf5ef2aSThomas Huth 
137fcf5ef2aSThomas Huth     note->hdr.n_type = cpu_to_be32(NT_S390_VXRS_HIGH);
138fcf5ef2aSThomas Huth     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]);
141fcf5ef2aSThomas Huth     }
142fcf5ef2aSThomas Huth }
143fcf5ef2aSThomas Huth 
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)
155fcf5ef2aSThomas Huth {
156fcf5ef2aSThomas Huth     note->hdr.n_type = cpu_to_be32(NT_S390_TIMER);
157fcf5ef2aSThomas Huth     note->contents.timer = cpu_to_be64((uint64_t)(cpu->env.cputm));
158fcf5ef2aSThomas Huth }
159fcf5ef2aSThomas Huth 
s390x_write_elf64_todcmp(Note * note,S390CPU * cpu,int id)160f738f296SChristian Borntraeger static void s390x_write_elf64_todcmp(Note *note, S390CPU *cpu, int id)
161fcf5ef2aSThomas Huth {
162fcf5ef2aSThomas Huth     note->hdr.n_type = cpu_to_be32(NT_S390_TODCMP);
163fcf5ef2aSThomas Huth     note->contents.todcmp = cpu_to_be64((uint64_t)(cpu->env.ckc));
164fcf5ef2aSThomas Huth }
165fcf5ef2aSThomas Huth 
s390x_write_elf64_todpreg(Note * note,S390CPU * cpu,int id)166f738f296SChristian Borntraeger static void s390x_write_elf64_todpreg(Note *note, S390CPU *cpu, int id)
167fcf5ef2aSThomas Huth {
168fcf5ef2aSThomas Huth     note->hdr.n_type = cpu_to_be32(NT_S390_TODPREG);
169fcf5ef2aSThomas Huth     note->contents.todpreg = cpu_to_be32((uint32_t)(cpu->env.todpr));
170fcf5ef2aSThomas Huth }
171fcf5ef2aSThomas Huth 
s390x_write_elf64_ctrs(Note * note,S390CPU * cpu,int id)172f738f296SChristian Borntraeger static void s390x_write_elf64_ctrs(Note *note, S390CPU *cpu, int id)
173fcf5ef2aSThomas Huth {
174fcf5ef2aSThomas Huth     int i;
175fcf5ef2aSThomas Huth 
176fcf5ef2aSThomas Huth     note->hdr.n_type = cpu_to_be32(NT_S390_CTRS);
177fcf5ef2aSThomas Huth 
178fcf5ef2aSThomas Huth     for (i = 0; i <= 15; i++) {
179fcf5ef2aSThomas Huth         note->contents.ctrs[i] = cpu_to_be64(cpu->env.cregs[i]);
180fcf5ef2aSThomas Huth     }
181fcf5ef2aSThomas Huth }
182fcf5ef2aSThomas Huth 
s390x_write_elf64_prefix(Note * note,S390CPU * cpu,int id)183f738f296SChristian Borntraeger static void s390x_write_elf64_prefix(Note *note, S390CPU *cpu, int id)
184fcf5ef2aSThomas Huth {
185fcf5ef2aSThomas Huth     note->hdr.n_type = cpu_to_be32(NT_S390_PREFIX);
186fcf5ef2aSThomas Huth     note->contents.prefix = cpu_to_be32((uint32_t)(cpu->env.psa));
187fcf5ef2aSThomas Huth }
188fcf5ef2aSThomas Huth 
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, &note->contents.dynamic);
196113d8f4eSJanosch Frank }
197fcf5ef2aSThomas Huth 
1985f706fdcSChristian Borntraeger typedef struct NoteFuncDescStruct {
199fcf5ef2aSThomas Huth     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}
222fcf5ef2aSThomas Huth };
223fcf5ef2aSThomas Huth 
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,
225fcf5ef2aSThomas Huth                                        WriteCoreDumpFunction f,
226fcf5ef2aSThomas Huth                                        S390CPU *cpu, int id,
2271af0006aSJanosch Frank                                        DumpState *s,
2285f706fdcSChristian Borntraeger                                        const NoteFuncDesc *funcs)
229fcf5ef2aSThomas Huth {
2304376a770SThomas Huth     g_autofree Note *notep = NULL;
231fcf5ef2aSThomas Huth     const NoteFuncDesc *nf;
2324376a770SThomas Huth     int note_size, prev_size = 0, content_size;
233fcf5ef2aSThomas Huth     int ret = -1;
234fcf5ef2aSThomas Huth 
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         }
241fcf5ef2aSThomas Huth 
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);
261fcf5ef2aSThomas Huth         if (ret < 0) {
262fcf5ef2aSThomas Huth             return -1;
263fcf5ef2aSThomas Huth         }
264fcf5ef2aSThomas Huth     }
265fcf5ef2aSThomas Huth 
266fcf5ef2aSThomas Huth     return 0;
267fcf5ef2aSThomas Huth }
268fcf5ef2aSThomas Huth 
269fcf5ef2aSThomas Huth 
s390_cpu_write_elf64_note(WriteCoreDumpFunction f,CPUState * cs,int cpuid,DumpState * s)270fcf5ef2aSThomas Huth int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
2711af0006aSJanosch Frank                               int cpuid, DumpState *s)
272fcf5ef2aSThomas Huth {
273fcf5ef2aSThomas Huth     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);
281fcf5ef2aSThomas Huth }
282fcf5ef2aSThomas Huth 
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)452fcf5ef2aSThomas Huth int cpu_get_dump_info(ArchDumpInfo *info,
453fcf5ef2aSThomas Huth                       const struct GuestPhysBlockList *guest_phys_blocks)
454fcf5ef2aSThomas Huth {
455fcf5ef2aSThomas Huth     info->d_machine = EM_S390;
456fcf5ef2aSThomas Huth     info->d_endian = ELFDATA2MSB;
457fcf5ef2aSThomas Huth     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     }
469fcf5ef2aSThomas Huth     return 0;
470fcf5ef2aSThomas Huth }
471fcf5ef2aSThomas Huth 
cpu_get_note_size(int class,int machine,int nr_cpus)472fcf5ef2aSThomas Huth ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
473fcf5ef2aSThomas Huth {
4745f706fdcSChristian Borntraeger     int name_size = 8; /* "LINUX" or "CORE" + pad */
475fcf5ef2aSThomas Huth     size_t elf_note_size = 0;
476113d8f4eSJanosch Frank     int note_head_size, content_size;
477fcf5ef2aSThomas Huth     const NoteFuncDesc *nf;
478fcf5ef2aSThomas Huth 
479fcf5ef2aSThomas Huth     assert(class == ELFCLASS64);
480fcf5ef2aSThomas Huth     assert(machine == EM_S390);
481fcf5ef2aSThomas Huth 
482fcf5ef2aSThomas Huth     note_head_size = sizeof(Elf64_Nhdr);
483fcf5ef2aSThomas Huth 
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();
492fcf5ef2aSThomas Huth         elf_note_size = elf_note_size + note_head_size + name_size +
493113d8f4eSJanosch Frank                         content_size;
494fcf5ef2aSThomas Huth     }
495fcf5ef2aSThomas Huth 
496fcf5ef2aSThomas Huth     return (elf_note_size) * nr_cpus;
497fcf5ef2aSThomas Huth }
498