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 "exec/cpu-all.h"
19 #include "sysemu/dump.h"
20 #include "sysemu/kvm.h"
23 #define ELFCLASS ELFCLASS64
24 #define cpu_to_dump_reg cpu_to_dump64
25 typedef uint64_t reg_t
;
26 typedef Elf64_Nhdr Elf_Nhdr
;
28 #define ELFCLASS ELFCLASS32
29 #define cpu_to_dump_reg cpu_to_dump32
30 typedef uint32_t reg_t
;
31 typedef Elf32_Nhdr Elf_Nhdr
;
32 #endif /* TARGET_PPC64 */
34 struct PPCUserRegStruct
{
50 struct PPCElfPrstatus
{
52 struct PPCUserRegStruct pr_reg
;
57 struct PPCElfFpregset
{
63 struct PPCElfVmxregset
{
72 struct PPCElfVsxregset
{
76 struct PPCElfSperegset
{
82 typedef struct noteStruct
{
87 struct PPCElfPrstatus prstatus
;
88 struct PPCElfFpregset fpregset
;
89 struct PPCElfVmxregset vmxregset
;
90 struct PPCElfVsxregset vsxregset
;
91 struct PPCElfSperegset speregset
;
95 typedef struct NoteFuncArg
{
100 static void ppc_write_elf_prstatus(NoteFuncArg
*arg
, PowerPCCPU
*cpu
)
104 struct PPCElfPrstatus
*prstatus
;
105 struct PPCUserRegStruct
*reg
;
106 Note
*note
= &arg
->note
;
107 DumpState
*s
= arg
->state
;
109 note
->hdr
.n_type
= cpu_to_dump32(s
, NT_PRSTATUS
);
111 prstatus
= ¬e
->contents
.prstatus
;
112 memset(prstatus
, 0, sizeof(*prstatus
));
113 reg
= &prstatus
->pr_reg
;
115 for (i
= 0; i
< 32; i
++) {
116 reg
->gpr
[i
] = cpu_to_dump_reg(s
, cpu
->env
.gpr
[i
]);
118 reg
->nip
= cpu_to_dump_reg(s
, cpu
->env
.nip
);
119 reg
->msr
= cpu_to_dump_reg(s
, cpu
->env
.msr
);
120 reg
->ctr
= cpu_to_dump_reg(s
, cpu
->env
.ctr
);
121 reg
->link
= cpu_to_dump_reg(s
, cpu
->env
.lr
);
122 reg
->xer
= cpu_to_dump_reg(s
, cpu_read_xer(&cpu
->env
));
125 for (i
= 0; i
< 8; i
++) {
126 cr
|= (cpu
->env
.crf
[i
] & 15) << (4 * (7 - i
));
128 reg
->ccr
= cpu_to_dump_reg(s
, cr
);
131 static void ppc_write_elf_fpregset(NoteFuncArg
*arg
, PowerPCCPU
*cpu
)
134 struct PPCElfFpregset
*fpregset
;
135 Note
*note
= &arg
->note
;
136 DumpState
*s
= arg
->state
;
138 note
->hdr
.n_type
= cpu_to_dump32(s
, NT_PRFPREG
);
140 fpregset
= ¬e
->contents
.fpregset
;
141 memset(fpregset
, 0, sizeof(*fpregset
));
143 for (i
= 0; i
< 32; i
++) {
144 fpregset
->fpr
[i
] = cpu_to_dump64(s
, cpu
->env
.fpr
[i
]);
146 fpregset
->fpscr
= cpu_to_dump_reg(s
, cpu
->env
.fpscr
);
149 static void ppc_write_elf_vmxregset(NoteFuncArg
*arg
, PowerPCCPU
*cpu
)
152 struct PPCElfVmxregset
*vmxregset
;
153 Note
*note
= &arg
->note
;
154 DumpState
*s
= arg
->state
;
156 note
->hdr
.n_type
= cpu_to_dump32(s
, NT_PPC_VMX
);
157 vmxregset
= ¬e
->contents
.vmxregset
;
158 memset(vmxregset
, 0, sizeof(*vmxregset
));
160 for (i
= 0; i
< 32; i
++) {
163 #ifdef HOST_WORDS_BIGENDIAN
164 needs_byteswap
= s
->dump_info
.d_endian
== ELFDATA2LSB
;
166 needs_byteswap
= s
->dump_info
.d_endian
== ELFDATA2MSB
;
169 if (needs_byteswap
) {
170 vmxregset
->avr
[i
].u64
[0] = bswap64(cpu
->env
.avr
[i
].u64
[1]);
171 vmxregset
->avr
[i
].u64
[1] = bswap64(cpu
->env
.avr
[i
].u64
[0]);
173 vmxregset
->avr
[i
].u64
[0] = cpu
->env
.avr
[i
].u64
[0];
174 vmxregset
->avr
[i
].u64
[1] = cpu
->env
.avr
[i
].u64
[1];
177 vmxregset
->vscr
.u32
[3] = cpu_to_dump32(s
, cpu
->env
.vscr
);
180 static void ppc_write_elf_vsxregset(NoteFuncArg
*arg
, PowerPCCPU
*cpu
)
183 struct PPCElfVsxregset
*vsxregset
;
184 Note
*note
= &arg
->note
;
185 DumpState
*s
= arg
->state
;
187 note
->hdr
.n_type
= cpu_to_dump32(s
, NT_PPC_VSX
);
188 vsxregset
= ¬e
->contents
.vsxregset
;
189 memset(vsxregset
, 0, sizeof(*vsxregset
));
191 for (i
= 0; i
< 32; i
++) {
192 vsxregset
->vsr
[i
] = cpu_to_dump64(s
, cpu
->env
.vsr
[i
]);
196 static void ppc_write_elf_speregset(NoteFuncArg
*arg
, PowerPCCPU
*cpu
)
198 struct PPCElfSperegset
*speregset
;
199 Note
*note
= &arg
->note
;
200 DumpState
*s
= arg
->state
;
202 note
->hdr
.n_type
= cpu_to_dump32(s
, NT_PPC_SPE
);
203 speregset
= ¬e
->contents
.speregset
;
204 memset(speregset
, 0, sizeof(*speregset
));
206 speregset
->spe_acc
= cpu_to_dump64(s
, cpu
->env
.spe_acc
);
207 speregset
->spe_fscr
= cpu_to_dump32(s
, cpu
->env
.spe_fscr
);
210 static const struct NoteFuncDescStruct
{
212 void (*note_contents_func
)(NoteFuncArg
*arg
, PowerPCCPU
*cpu
);
214 {sizeof(((Note
*)0)->contents
.prstatus
), ppc_write_elf_prstatus
},
215 {sizeof(((Note
*)0)->contents
.fpregset
), ppc_write_elf_fpregset
},
216 {sizeof(((Note
*)0)->contents
.vmxregset
), ppc_write_elf_vmxregset
},
217 {sizeof(((Note
*)0)->contents
.vsxregset
), ppc_write_elf_vsxregset
},
218 {sizeof(((Note
*)0)->contents
.speregset
), ppc_write_elf_speregset
},
222 typedef struct NoteFuncDescStruct NoteFuncDesc
;
224 int cpu_get_dump_info(ArchDumpInfo
*info
,
225 const struct GuestPhysBlockList
*guest_phys_blocks
)
227 PowerPCCPU
*cpu
= POWERPC_CPU(first_cpu
);
228 PowerPCCPUClass
*pcc
= POWERPC_CPU_GET_CLASS(cpu
);
230 info
->d_machine
= PPC_ELF_MACHINE
;
231 info
->d_class
= ELFCLASS
;
233 if ((*pcc
->interrupts_big_endian
)(cpu
)) {
234 info
->d_endian
= ELFDATA2MSB
;
236 info
->d_endian
= ELFDATA2LSB
;
238 /* 64KB is the max page size for pseries kernel */
239 if (strncmp(object_get_typename(qdev_get_machine()),
240 "pseries-", 8) == 0) {
241 info
->page_size
= (1U << 16);
247 ssize_t
cpu_get_note_size(int class, int machine
, int nr_cpus
)
249 int name_size
= 8; /* "CORE" or "QEMU" rounded */
250 size_t elf_note_size
= 0;
252 const NoteFuncDesc
*nf
;
254 note_head_size
= sizeof(Elf_Nhdr
);
255 for (nf
= note_func
; nf
->note_contents_func
; nf
++) {
256 elf_note_size
= elf_note_size
+ note_head_size
+ name_size
+
260 return (elf_note_size
) * nr_cpus
;
263 static int ppc_write_all_elf_notes(const char *note_name
,
264 WriteCoreDumpFunction f
,
265 PowerPCCPU
*cpu
, int id
,
268 NoteFuncArg arg
= { .state
= opaque
};
271 const NoteFuncDesc
*nf
;
273 for (nf
= note_func
; nf
->note_contents_func
; nf
++) {
274 arg
.note
.hdr
.n_namesz
= cpu_to_dump32(opaque
, sizeof(arg
.note
.name
));
275 arg
.note
.hdr
.n_descsz
= cpu_to_dump32(opaque
, nf
->contents_size
);
276 strncpy(arg
.note
.name
, note_name
, sizeof(arg
.note
.name
));
278 (*nf
->note_contents_func
)(&arg
, cpu
);
281 sizeof(arg
.note
) - sizeof(arg
.note
.contents
) + nf
->contents_size
;
282 ret
= f(&arg
.note
, note_size
, opaque
);
290 int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f
, CPUState
*cs
,
291 int cpuid
, void *opaque
)
293 PowerPCCPU
*cpu
= POWERPC_CPU(cs
);
294 return ppc_write_all_elf_notes("CORE", f
, cpu
, cpuid
, opaque
);
297 int ppc32_cpu_write_elf32_note(WriteCoreDumpFunction f
, CPUState
*cs
,
298 int cpuid
, void *opaque
)
300 PowerPCCPU
*cpu
= POWERPC_CPU(cs
);
301 return ppc_write_all_elf_notes("CORE", f
, cpu
, cpuid
, opaque
);