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 = ¬e->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, ¬e->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