2 * writing ELF notes for s390x arch
5 * Copyright IBM Corp. 2012, 2013
7 * Ekaterina Tumanova <tumanova@linux.vnet.ibm.com>
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
14 #include "qemu/osdep.h"
15 #include "qemu/units.h"
17 #include "s390x-internal.h"
19 #include "sysemu/dump.h"
20 #include "hw/s390x/pv.h"
21 #include "kvm/kvm_s390x.h"
23 struct S390xUserRegsStruct
{
29 typedef struct S390xUserRegsStruct S390xUserRegs
;
31 struct S390xElfPrstatusStruct
{
39 typedef struct S390xElfPrstatusStruct S390xElfPrstatus
;
41 struct S390xElfFpregsetStruct
{
47 typedef struct S390xElfFpregsetStruct S390xElfFpregset
;
49 struct S390xElfVregsLoStruct
{
53 typedef struct S390xElfVregsLoStruct S390xElfVregsLo
;
55 struct S390xElfVregsHiStruct
{
56 uint64_t vregs
[16][2];
59 typedef struct S390xElfVregsHiStruct S390xElfVregsHi
;
61 struct S390xElfGSCBStruct
{
65 typedef struct S390xElfGSCBStruct S390xElfGSCB
;
67 typedef struct noteStruct
{
71 S390xElfPrstatus prstatus
;
72 S390xElfFpregset fpregset
;
73 S390xElfVregsLo vregslo
;
74 S390xElfVregsHi vregshi
;
81 uint8_t dynamic
[1]; /*
82 * Would be a flexible array member, if
83 * that was legal inside a union. Real
84 * size comes from PV info interface.
89 static bool pv_dump_initialized
;
91 static void s390x_write_elf64_prstatus(Note
*note
, S390CPU
*cpu
, int id
)
96 note
->hdr
.n_type
= cpu_to_be32(NT_PRSTATUS
);
98 regs
= &(note
->contents
.prstatus
.regs
);
99 regs
->psw
[0] = cpu_to_be64(cpu
->env
.psw
.mask
);
100 regs
->psw
[1] = cpu_to_be64(cpu
->env
.psw
.addr
);
101 for (i
= 0; i
<= 15; i
++) {
102 regs
->acrs
[i
] = cpu_to_be32(cpu
->env
.aregs
[i
]);
103 regs
->gprs
[i
] = cpu_to_be64(cpu
->env
.regs
[i
]);
105 note
->contents
.prstatus
.pid
= id
;
108 static void s390x_write_elf64_fpregset(Note
*note
, S390CPU
*cpu
, int id
)
111 CPUS390XState
*cs
= &cpu
->env
;
113 note
->hdr
.n_type
= cpu_to_be32(NT_FPREGSET
);
114 note
->contents
.fpregset
.fpc
= cpu_to_be32(cpu
->env
.fpc
);
115 for (i
= 0; i
<= 15; i
++) {
116 note
->contents
.fpregset
.fprs
[i
] = cpu_to_be64(*get_freg(cs
, i
));
120 static void s390x_write_elf64_vregslo(Note
*note
, S390CPU
*cpu
, int id
)
124 note
->hdr
.n_type
= cpu_to_be32(NT_S390_VXRS_LOW
);
125 for (i
= 0; i
<= 15; i
++) {
126 note
->contents
.vregslo
.vregs
[i
] = cpu_to_be64(cpu
->env
.vregs
[i
][1]);
130 static void s390x_write_elf64_vregshi(Note
*note
, S390CPU
*cpu
, int id
)
133 S390xElfVregsHi
*temp_vregshi
;
135 temp_vregshi
= ¬e
->contents
.vregshi
;
137 note
->hdr
.n_type
= cpu_to_be32(NT_S390_VXRS_HIGH
);
138 for (i
= 0; i
<= 15; i
++) {
139 temp_vregshi
->vregs
[i
][0] = cpu_to_be64(cpu
->env
.vregs
[i
+ 16][0]);
140 temp_vregshi
->vregs
[i
][1] = cpu_to_be64(cpu
->env
.vregs
[i
+ 16][1]);
144 static void s390x_write_elf64_gscb(Note
*note
, S390CPU
*cpu
, int id
)
148 note
->hdr
.n_type
= cpu_to_be32(NT_S390_GS_CB
);
149 for (i
= 0; i
< 4; i
++) {
150 note
->contents
.gscb
.gsregs
[i
] = cpu_to_be64(cpu
->env
.gscb
[i
]);
154 static void s390x_write_elf64_timer(Note
*note
, S390CPU
*cpu
, int id
)
156 note
->hdr
.n_type
= cpu_to_be32(NT_S390_TIMER
);
157 note
->contents
.timer
= cpu_to_be64((uint64_t)(cpu
->env
.cputm
));
160 static void s390x_write_elf64_todcmp(Note
*note
, S390CPU
*cpu
, int id
)
162 note
->hdr
.n_type
= cpu_to_be32(NT_S390_TODCMP
);
163 note
->contents
.todcmp
= cpu_to_be64((uint64_t)(cpu
->env
.ckc
));
166 static void s390x_write_elf64_todpreg(Note
*note
, S390CPU
*cpu
, int id
)
168 note
->hdr
.n_type
= cpu_to_be32(NT_S390_TODPREG
);
169 note
->contents
.todpreg
= cpu_to_be32((uint32_t)(cpu
->env
.todpr
));
172 static void s390x_write_elf64_ctrs(Note
*note
, S390CPU
*cpu
, int id
)
176 note
->hdr
.n_type
= cpu_to_be32(NT_S390_CTRS
);
178 for (i
= 0; i
<= 15; i
++) {
179 note
->contents
.ctrs
[i
] = cpu_to_be64(cpu
->env
.cregs
[i
]);
183 static void s390x_write_elf64_prefix(Note
*note
, S390CPU
*cpu
, int id
)
185 note
->hdr
.n_type
= cpu_to_be32(NT_S390_PREFIX
);
186 note
->contents
.prefix
= cpu_to_be32((uint32_t)(cpu
->env
.psa
));
189 static void s390x_write_elf64_pv(Note
*note
, S390CPU
*cpu
, int id
)
191 note
->hdr
.n_type
= cpu_to_be32(NT_S390_PV_CPU_DATA
);
192 if (!pv_dump_initialized
) {
195 kvm_s390_dump_cpu(cpu
, ¬e
->contents
.dynamic
);
198 typedef struct NoteFuncDescStruct
{
200 uint64_t (*note_size_func
)(void); /* NULL for non-dynamic sized contents */
201 void (*note_contents_func
)(Note
*note
, S390CPU
*cpu
, int id
);
205 static const NoteFuncDesc note_core
[] = {
206 {sizeof_field(Note
, contents
.prstatus
), NULL
, s390x_write_elf64_prstatus
, false},
207 {sizeof_field(Note
, contents
.fpregset
), NULL
, s390x_write_elf64_fpregset
, false},
208 { 0, NULL
, NULL
, false}
211 static const NoteFuncDesc note_linux
[] = {
212 {sizeof_field(Note
, contents
.prefix
), NULL
, s390x_write_elf64_prefix
, false},
213 {sizeof_field(Note
, contents
.ctrs
), NULL
, s390x_write_elf64_ctrs
, false},
214 {sizeof_field(Note
, contents
.timer
), NULL
, s390x_write_elf64_timer
, false},
215 {sizeof_field(Note
, contents
.todcmp
), NULL
, s390x_write_elf64_todcmp
, false},
216 {sizeof_field(Note
, contents
.todpreg
), NULL
, s390x_write_elf64_todpreg
, false},
217 {sizeof_field(Note
, contents
.vregslo
), NULL
, s390x_write_elf64_vregslo
, false},
218 {sizeof_field(Note
, contents
.vregshi
), NULL
, s390x_write_elf64_vregshi
, false},
219 {sizeof_field(Note
, contents
.gscb
), NULL
, s390x_write_elf64_gscb
, false},
220 {0, kvm_s390_pv_dmp_get_size_cpu
, s390x_write_elf64_pv
, true},
221 { 0, NULL
, NULL
, false}
224 static int s390x_write_elf64_notes(const char *note_name
,
225 WriteCoreDumpFunction f
,
226 S390CPU
*cpu
, int id
,
228 const NoteFuncDesc
*funcs
)
231 const NoteFuncDesc
*nf
;
232 int note_size
, content_size
;
235 assert(strlen(note_name
) < sizeof(note
.name
));
237 for (nf
= funcs
; nf
->note_contents_func
; nf
++) {
239 if (nf
->pvonly
&& !s390_is_pv()) {
243 content_size
= nf
->note_size_func
? nf
->note_size_func() : nf
->contents_size
;
244 note_size
= sizeof(note
) - sizeof(notep
->contents
) + content_size
;
246 /* Notes with dynamic sizes need to allocate a note */
247 if (nf
->note_size_func
) {
248 notep
= g_malloc(note_size
);
251 memset(notep
, 0, sizeof(note
));
253 /* Setup note header data */
254 notep
->hdr
.n_descsz
= cpu_to_be32(content_size
);
255 notep
->hdr
.n_namesz
= cpu_to_be32(strlen(note_name
) + 1);
256 g_strlcpy(notep
->name
, note_name
, sizeof(notep
->name
));
258 /* Get contents and write them out */
259 (*nf
->note_contents_func
)(notep
, cpu
, id
);
260 ret
= f(notep
, note_size
, s
);
262 if (nf
->note_size_func
) {
276 int s390_cpu_write_elf64_note(WriteCoreDumpFunction f
, CPUState
*cs
,
277 int cpuid
, DumpState
*s
)
279 S390CPU
*cpu
= S390_CPU(cs
);
282 r
= s390x_write_elf64_notes("CORE", f
, cpu
, cpuid
, s
, note_core
);
286 return s390x_write_elf64_notes("LINUX", f
, cpu
, cpuid
, s
, note_linux
);
289 /* PV dump section size functions */
290 static uint64_t get_mem_state_size_from_len(uint64_t len
)
292 return (len
/ (MiB
)) * kvm_s390_pv_dmp_get_size_mem_state();
295 static uint64_t get_size_mem_state(DumpState
*s
)
297 return get_mem_state_size_from_len(s
->total_size
);
300 static uint64_t get_size_completion_data(DumpState
*s
)
302 return kvm_s390_pv_dmp_get_size_completion_data();
305 /* PV dump section data functions*/
306 static int get_data_completion(DumpState
*s
, uint8_t *buff
)
310 if (!pv_dump_initialized
) {
313 rc
= kvm_s390_dump_completion_data(buff
);
315 pv_dump_initialized
= false;
320 static int get_mem_state(DumpState
*s
, uint8_t *buff
)
322 int64_t memblock_size
, memblock_start
;
323 GuestPhysBlock
*block
;
327 QTAILQ_FOREACH(block
, &s
->guest_phys_blocks
.head
, next
) {
328 memblock_start
= dump_filtered_memblock_start(block
, s
->filter_area_begin
,
329 s
->filter_area_length
);
330 if (memblock_start
== -1) {
334 memblock_size
= dump_filtered_memblock_size(block
, s
->filter_area_begin
,
335 s
->filter_area_length
);
337 off
= get_mem_state_size_from_len(block
->target_start
);
339 rc
= kvm_s390_dump_mem_state(block
->target_start
,
340 get_mem_state_size_from_len(memblock_size
),
350 static struct sections
{
351 uint64_t (*sections_size_func
)(DumpState
*s
);
352 int (*sections_contents_func
)(DumpState
*s
, uint8_t *buff
);
355 { get_size_mem_state
, get_mem_state
, "pv_mem_meta"},
356 { get_size_completion_data
, get_data_completion
, "pv_compl"},
360 static uint64_t arch_sections_write_hdr(DumpState
*s
, uint8_t *buff
)
362 Elf64_Shdr
*shdr
= (void *)buff
;
363 struct sections
*sctn
= sections
;
364 uint64_t off
= s
->section_offset
;
366 if (!pv_dump_initialized
) {
370 for (; sctn
->sections_size_func
; off
+= shdr
->sh_size
, sctn
++, shdr
++) {
371 memset(shdr
, 0, sizeof(*shdr
));
372 shdr
->sh_type
= SHT_PROGBITS
;
373 shdr
->sh_offset
= off
;
374 shdr
->sh_size
= sctn
->sections_size_func(s
);
375 shdr
->sh_name
= s
->string_table_buf
->len
;
376 g_array_append_vals(s
->string_table_buf
, sctn
->sctn_str
, sizeof(sctn
->sctn_str
));
379 return (uintptr_t)shdr
- (uintptr_t)buff
;
383 /* Add arch specific number of sections and their respective sizes */
384 static void arch_sections_add(DumpState
*s
)
386 struct sections
*sctn
= sections
;
389 * We only do a PV dump if we are running a PV guest, KVM supports
390 * the dump API and we got valid dump length information.
392 if (!s390_is_pv() || !kvm_s390_get_protected_dump() ||
393 !kvm_s390_pv_info_basic_valid()) {
398 * Start the UV dump process by doing the initialize dump call via
401 if (!kvm_s390_dump_init()) {
402 pv_dump_initialized
= true;
405 * Dump init failed, maybe the guest owner disabled dumping.
406 * We'll continue the non-PV dump process since this is no
407 * reason to crash qemu.
412 for (; sctn
->sections_size_func
; sctn
++) {
414 s
->elf_section_data_size
+= sctn
->sections_size_func(s
);
419 * After the PV dump has been initialized, the CPU data has been
420 * fetched and memory has been dumped, we need to grab the tweak data
421 * and the completion data.
423 static int arch_sections_write(DumpState
*s
, uint8_t *buff
)
425 struct sections
*sctn
= sections
;
428 if (!pv_dump_initialized
) {
432 for (; sctn
->sections_size_func
; sctn
++) {
433 rc
= sctn
->sections_contents_func(s
, buff
);
434 buff
+= sctn
->sections_size_func(s
);
442 int cpu_get_dump_info(ArchDumpInfo
*info
,
443 const struct GuestPhysBlockList
*guest_phys_blocks
)
445 info
->d_machine
= EM_S390
;
446 info
->d_endian
= ELFDATA2MSB
;
447 info
->d_class
= ELFCLASS64
;
449 * This is evaluated for each dump so we can freely switch
450 * between PV and non-PV.
452 if (s390_is_pv() && kvm_s390_get_protected_dump() &&
453 kvm_s390_pv_info_basic_valid()) {
454 info
->arch_sections_add_fn
= *arch_sections_add
;
455 info
->arch_sections_write_hdr_fn
= *arch_sections_write_hdr
;
456 info
->arch_sections_write_fn
= *arch_sections_write
;
458 info
->arch_sections_add_fn
= NULL
;
459 info
->arch_sections_write_hdr_fn
= NULL
;
460 info
->arch_sections_write_fn
= NULL
;
465 ssize_t
cpu_get_note_size(int class, int machine
, int nr_cpus
)
467 int name_size
= 8; /* "LINUX" or "CORE" + pad */
468 size_t elf_note_size
= 0;
469 int note_head_size
, content_size
;
470 const NoteFuncDesc
*nf
;
472 assert(class == ELFCLASS64
);
473 assert(machine
== EM_S390
);
475 note_head_size
= sizeof(Elf64_Nhdr
);
477 for (nf
= note_core
; nf
->note_contents_func
; nf
++) {
478 elf_note_size
= elf_note_size
+ note_head_size
+ name_size
+ nf
->contents_size
;
480 for (nf
= note_linux
; nf
->note_contents_func
; nf
++) {
481 if (nf
->pvonly
&& !s390_is_pv()) {
484 content_size
= nf
->contents_size
? nf
->contents_size
: nf
->note_size_func();
485 elf_note_size
= elf_note_size
+ note_head_size
+ name_size
+
489 return (elf_note_size
) * nr_cpus
;