2 * writing ELF notes for ppc{64,} arch
5 * Copyright IBM, Corp. 2013
8 * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
10 * This work is licensed under the terms of the GNU GPL, version 2. See
11 * the COPYING file in the top-level directory.
15 #include "qemu/osdep.h"
18 #include "sysemu/dump.h"
19 #include "sysemu/kvm.h"
22 #define ELFCLASS ELFCLASS64
23 #define cpu_to_dump_reg cpu_to_dump64
24 typedef uint64_t reg_t
;
25 typedef Elf64_Nhdr Elf_Nhdr
;
27 #define ELFCLASS ELFCLASS32
28 #define cpu_to_dump_reg cpu_to_dump32
29 typedef uint32_t reg_t
;
30 typedef Elf32_Nhdr Elf_Nhdr
;
31 #endif /* TARGET_PPC64 */
33 struct PPCUserRegStruct
{
49 struct PPCElfPrstatus
{
50 char pad1
[32]; /* 32 == offsetof(struct elf_prstatus, pr_pid) */
52 char pad2
[76]; /* 76 == offsetof(struct elf_prstatus, pr_reg) -
53 offsetof(struct elf_prstatus, pr_ppid) */
54 struct PPCUserRegStruct pr_reg
;
55 char pad3
[40]; /* 40 == sizeof(struct elf_prstatus) -
56 offsetof(struct elf_prstatus, pr_reg) -
57 sizeof(struct user_pt_regs) */
61 struct PPCElfFpregset
{
67 struct PPCElfVmxregset
{
76 struct PPCElfVsxregset
{
80 struct PPCElfSperegset
{
86 typedef struct noteStruct
{
91 struct PPCElfPrstatus prstatus
;
92 struct PPCElfFpregset fpregset
;
93 struct PPCElfVmxregset vmxregset
;
94 struct PPCElfVsxregset vsxregset
;
95 struct PPCElfSperegset speregset
;
99 typedef struct NoteFuncArg
{
104 static void ppc_write_elf_prstatus(NoteFuncArg
*arg
, PowerPCCPU
*cpu
, int id
)
108 struct PPCElfPrstatus
*prstatus
;
109 struct PPCUserRegStruct
*reg
;
110 Note
*note
= &arg
->note
;
111 DumpState
*s
= arg
->state
;
113 note
->hdr
.n_type
= cpu_to_dump32(s
, NT_PRSTATUS
);
115 prstatus
= ¬e
->contents
.prstatus
;
116 memset(prstatus
, 0, sizeof(*prstatus
));
117 prstatus
->pid
= cpu_to_dump32(s
, id
);
118 reg
= &prstatus
->pr_reg
;
120 for (i
= 0; i
< 32; i
++) {
121 reg
->gpr
[i
] = cpu_to_dump_reg(s
, cpu
->env
.gpr
[i
]);
123 reg
->nip
= cpu_to_dump_reg(s
, cpu
->env
.nip
);
124 reg
->msr
= cpu_to_dump_reg(s
, cpu
->env
.msr
);
125 reg
->ctr
= cpu_to_dump_reg(s
, cpu
->env
.ctr
);
126 reg
->link
= cpu_to_dump_reg(s
, cpu
->env
.lr
);
127 reg
->xer
= cpu_to_dump_reg(s
, cpu_read_xer(&cpu
->env
));
130 for (i
= 0; i
< 8; i
++) {
131 cr
|= (cpu
->env
.crf
[i
] & 15) << (4 * (7 - i
));
133 reg
->ccr
= cpu_to_dump_reg(s
, cr
);
136 static void ppc_write_elf_fpregset(NoteFuncArg
*arg
, PowerPCCPU
*cpu
, int id
)
139 struct PPCElfFpregset
*fpregset
;
140 Note
*note
= &arg
->note
;
141 DumpState
*s
= arg
->state
;
143 note
->hdr
.n_type
= cpu_to_dump32(s
, NT_PRFPREG
);
145 fpregset
= ¬e
->contents
.fpregset
;
146 memset(fpregset
, 0, sizeof(*fpregset
));
148 for (i
= 0; i
< 32; i
++) {
149 uint64_t *fpr
= cpu_fpr_ptr(&cpu
->env
, i
);
150 fpregset
->fpr
[i
] = cpu_to_dump64(s
, *fpr
);
152 fpregset
->fpscr
= cpu_to_dump_reg(s
, cpu
->env
.fpscr
);
155 static void ppc_write_elf_vmxregset(NoteFuncArg
*arg
, PowerPCCPU
*cpu
, int id
)
158 struct PPCElfVmxregset
*vmxregset
;
159 Note
*note
= &arg
->note
;
160 DumpState
*s
= arg
->state
;
162 note
->hdr
.n_type
= cpu_to_dump32(s
, NT_PPC_VMX
);
163 vmxregset
= ¬e
->contents
.vmxregset
;
164 memset(vmxregset
, 0, sizeof(*vmxregset
));
166 for (i
= 0; i
< 32; i
++) {
168 ppc_avr_t
*avr
= cpu_avr_ptr(&cpu
->env
, i
);
171 needs_byteswap
= s
->dump_info
.d_endian
== ELFDATA2LSB
;
173 needs_byteswap
= s
->dump_info
.d_endian
== ELFDATA2MSB
;
176 if (needs_byteswap
) {
177 vmxregset
->avr
[i
].u64
[0] = bswap64(avr
->u64
[1]);
178 vmxregset
->avr
[i
].u64
[1] = bswap64(avr
->u64
[0]);
180 vmxregset
->avr
[i
].u64
[0] = avr
->u64
[0];
181 vmxregset
->avr
[i
].u64
[1] = avr
->u64
[1];
184 vmxregset
->vscr
.u32
[3] = cpu_to_dump32(s
, ppc_get_vscr(&cpu
->env
));
187 static void ppc_write_elf_vsxregset(NoteFuncArg
*arg
, PowerPCCPU
*cpu
, int id
)
190 struct PPCElfVsxregset
*vsxregset
;
191 Note
*note
= &arg
->note
;
192 DumpState
*s
= arg
->state
;
194 note
->hdr
.n_type
= cpu_to_dump32(s
, NT_PPC_VSX
);
195 vsxregset
= ¬e
->contents
.vsxregset
;
196 memset(vsxregset
, 0, sizeof(*vsxregset
));
198 for (i
= 0; i
< 32; i
++) {
199 uint64_t *vsrl
= cpu_vsrl_ptr(&cpu
->env
, i
);
200 vsxregset
->vsr
[i
] = cpu_to_dump64(s
, *vsrl
);
204 static void ppc_write_elf_speregset(NoteFuncArg
*arg
, PowerPCCPU
*cpu
, int id
)
206 struct PPCElfSperegset
*speregset
;
207 Note
*note
= &arg
->note
;
208 DumpState
*s
= arg
->state
;
210 note
->hdr
.n_type
= cpu_to_dump32(s
, NT_PPC_SPE
);
211 speregset
= ¬e
->contents
.speregset
;
212 memset(speregset
, 0, sizeof(*speregset
));
214 speregset
->spe_acc
= cpu_to_dump64(s
, cpu
->env
.spe_acc
);
215 speregset
->spe_fscr
= cpu_to_dump32(s
, cpu
->env
.spe_fscr
);
218 static const struct NoteFuncDescStruct
{
220 void (*note_contents_func
)(NoteFuncArg
*arg
, PowerPCCPU
*cpu
, int id
);
222 {sizeof_field(Note
, contents
.prstatus
), ppc_write_elf_prstatus
},
223 {sizeof_field(Note
, contents
.fpregset
), ppc_write_elf_fpregset
},
224 {sizeof_field(Note
, contents
.vmxregset
), ppc_write_elf_vmxregset
},
225 {sizeof_field(Note
, contents
.vsxregset
), ppc_write_elf_vsxregset
},
226 {sizeof_field(Note
, contents
.speregset
), ppc_write_elf_speregset
},
230 typedef struct NoteFuncDescStruct NoteFuncDesc
;
232 int cpu_get_dump_info(ArchDumpInfo
*info
,
233 const struct GuestPhysBlockList
*guest_phys_blocks
)
237 if (first_cpu
== NULL
) {
241 cpu
= POWERPC_CPU(first_cpu
);
243 info
->d_machine
= PPC_ELF_MACHINE
;
244 info
->d_class
= ELFCLASS
;
246 if (ppc_interrupts_little_endian(cpu
, !!(cpu
->env
.msr_mask
& MSR_HVB
))) {
247 info
->d_endian
= ELFDATA2LSB
;
249 info
->d_endian
= ELFDATA2MSB
;
251 /* 64KB is the max page size for pseries kernel */
252 if (strncmp(object_get_typename(qdev_get_machine()),
253 "pseries-", 8) == 0) {
254 info
->page_size
= (1U << 16);
260 ssize_t
cpu_get_note_size(int class, int machine
, int nr_cpus
)
262 int name_size
= 8; /* "CORE" or "QEMU" rounded */
263 size_t elf_note_size
= 0;
265 const NoteFuncDesc
*nf
;
267 note_head_size
= sizeof(Elf_Nhdr
);
268 for (nf
= note_func
; nf
->note_contents_func
; nf
++) {
269 elf_note_size
= elf_note_size
+ note_head_size
+ name_size
+
273 return (elf_note_size
) * nr_cpus
;
276 static int ppc_write_all_elf_notes(const char *note_name
,
277 WriteCoreDumpFunction f
,
278 PowerPCCPU
*cpu
, int id
,
281 NoteFuncArg arg
= { .state
= s
};
284 const NoteFuncDesc
*nf
;
286 for (nf
= note_func
; nf
->note_contents_func
; nf
++) {
287 arg
.note
.hdr
.n_namesz
= cpu_to_dump32(s
, sizeof(arg
.note
.name
));
288 arg
.note
.hdr
.n_descsz
= cpu_to_dump32(s
, nf
->contents_size
);
289 strncpy(arg
.note
.name
, note_name
, sizeof(arg
.note
.name
));
291 (*nf
->note_contents_func
)(&arg
, cpu
, id
);
294 sizeof(arg
.note
) - sizeof(arg
.note
.contents
) + nf
->contents_size
;
295 ret
= f(&arg
.note
, note_size
, s
);
303 int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f
, CPUState
*cs
,
304 int cpuid
, DumpState
*s
)
306 PowerPCCPU
*cpu
= POWERPC_CPU(cs
);
307 return ppc_write_all_elf_notes("CORE", f
, cpu
, cpuid
, s
);
310 int ppc32_cpu_write_elf32_note(WriteCoreDumpFunction f
, CPUState
*cs
,
311 int cpuid
, DumpState
*s
)
313 PowerPCCPU
*cpu
= POWERPC_CPU(cs
);
314 return ppc_write_all_elf_notes("CORE", f
, cpu
, cpuid
, s
);