xref: /openbmc/qemu/target/s390x/arch_dump.c (revision 30b6852c)
1 /*
2  * writing ELF notes for s390x arch
3  *
4  *
5  * Copyright IBM Corp. 2012, 2013
6  *
7  *     Ekaterina Tumanova <tumanova@linux.vnet.ibm.com>
8  *
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.
11  *
12  */
13 
14 #include "qemu/osdep.h"
15 #include "cpu.h"
16 #include "s390x-internal.h"
17 #include "elf.h"
18 #include "sysemu/dump.h"
19 
20 
21 struct S390xUserRegsStruct {
22     uint64_t psw[2];
23     uint64_t gprs[16];
24     uint32_t acrs[16];
25 } QEMU_PACKED;
26 
27 typedef struct S390xUserRegsStruct S390xUserRegs;
28 
29 struct S390xElfPrstatusStruct {
30     uint8_t pad1[32];
31     uint32_t pid;
32     uint8_t pad2[76];
33     S390xUserRegs regs;
34     uint8_t pad3[16];
35 } QEMU_PACKED;
36 
37 typedef struct S390xElfPrstatusStruct S390xElfPrstatus;
38 
39 struct S390xElfFpregsetStruct {
40     uint32_t fpc;
41     uint32_t pad;
42     uint64_t fprs[16];
43 } QEMU_PACKED;
44 
45 typedef struct S390xElfFpregsetStruct S390xElfFpregset;
46 
47 struct S390xElfVregsLoStruct {
48     uint64_t vregs[16];
49 } QEMU_PACKED;
50 
51 typedef struct S390xElfVregsLoStruct S390xElfVregsLo;
52 
53 struct S390xElfVregsHiStruct {
54     uint64_t vregs[16][2];
55 } QEMU_PACKED;
56 
57 typedef struct S390xElfVregsHiStruct S390xElfVregsHi;
58 
59 struct S390xElfGSCBStruct {
60     uint64_t gsregs[4];
61 } QEMU_PACKED;
62 
63 typedef struct S390xElfGSCBStruct S390xElfGSCB;
64 
65 typedef struct noteStruct {
66     Elf64_Nhdr hdr;
67     char name[8];
68     union {
69         S390xElfPrstatus prstatus;
70         S390xElfFpregset fpregset;
71         S390xElfVregsLo vregslo;
72         S390xElfVregsHi vregshi;
73         S390xElfGSCB gscb;
74         uint32_t prefix;
75         uint64_t timer;
76         uint64_t todcmp;
77         uint32_t todpreg;
78         uint64_t ctrs[16];
79     } contents;
80 } QEMU_PACKED Note;
81 
82 static void s390x_write_elf64_prstatus(Note *note, S390CPU *cpu, int id)
83 {
84     int i;
85     S390xUserRegs *regs;
86 
87     note->hdr.n_type = cpu_to_be32(NT_PRSTATUS);
88 
89     regs = &(note->contents.prstatus.regs);
90     regs->psw[0] = cpu_to_be64(cpu->env.psw.mask);
91     regs->psw[1] = cpu_to_be64(cpu->env.psw.addr);
92     for (i = 0; i <= 15; i++) {
93         regs->acrs[i] = cpu_to_be32(cpu->env.aregs[i]);
94         regs->gprs[i] = cpu_to_be64(cpu->env.regs[i]);
95     }
96     note->contents.prstatus.pid = id;
97 }
98 
99 static void s390x_write_elf64_fpregset(Note *note, S390CPU *cpu, int id)
100 {
101     int i;
102     CPUS390XState *cs = &cpu->env;
103 
104     note->hdr.n_type = cpu_to_be32(NT_FPREGSET);
105     note->contents.fpregset.fpc = cpu_to_be32(cpu->env.fpc);
106     for (i = 0; i <= 15; i++) {
107         note->contents.fpregset.fprs[i] = cpu_to_be64(*get_freg(cs, i));
108     }
109 }
110 
111 static void s390x_write_elf64_vregslo(Note *note, S390CPU *cpu,  int id)
112 {
113     int i;
114 
115     note->hdr.n_type = cpu_to_be32(NT_S390_VXRS_LOW);
116     for (i = 0; i <= 15; i++) {
117         note->contents.vregslo.vregs[i] = cpu_to_be64(cpu->env.vregs[i][1]);
118     }
119 }
120 
121 static void s390x_write_elf64_vregshi(Note *note, S390CPU *cpu, int id)
122 {
123     int i;
124     S390xElfVregsHi *temp_vregshi;
125 
126     temp_vregshi = &note->contents.vregshi;
127 
128     note->hdr.n_type = cpu_to_be32(NT_S390_VXRS_HIGH);
129     for (i = 0; i <= 15; i++) {
130         temp_vregshi->vregs[i][0] = cpu_to_be64(cpu->env.vregs[i + 16][0]);
131         temp_vregshi->vregs[i][1] = cpu_to_be64(cpu->env.vregs[i + 16][1]);
132     }
133 }
134 
135 static void s390x_write_elf64_gscb(Note *note, S390CPU *cpu, int id)
136 {
137     int i;
138 
139     note->hdr.n_type = cpu_to_be32(NT_S390_GS_CB);
140     for (i = 0; i < 4; i++) {
141         note->contents.gscb.gsregs[i] = cpu_to_be64(cpu->env.gscb[i]);
142     }
143 }
144 
145 static void s390x_write_elf64_timer(Note *note, S390CPU *cpu, int id)
146 {
147     note->hdr.n_type = cpu_to_be32(NT_S390_TIMER);
148     note->contents.timer = cpu_to_be64((uint64_t)(cpu->env.cputm));
149 }
150 
151 static void s390x_write_elf64_todcmp(Note *note, S390CPU *cpu, int id)
152 {
153     note->hdr.n_type = cpu_to_be32(NT_S390_TODCMP);
154     note->contents.todcmp = cpu_to_be64((uint64_t)(cpu->env.ckc));
155 }
156 
157 static void s390x_write_elf64_todpreg(Note *note, S390CPU *cpu, int id)
158 {
159     note->hdr.n_type = cpu_to_be32(NT_S390_TODPREG);
160     note->contents.todpreg = cpu_to_be32((uint32_t)(cpu->env.todpr));
161 }
162 
163 static void s390x_write_elf64_ctrs(Note *note, S390CPU *cpu, int id)
164 {
165     int i;
166 
167     note->hdr.n_type = cpu_to_be32(NT_S390_CTRS);
168 
169     for (i = 0; i <= 15; i++) {
170         note->contents.ctrs[i] = cpu_to_be64(cpu->env.cregs[i]);
171     }
172 }
173 
174 static void s390x_write_elf64_prefix(Note *note, S390CPU *cpu, int id)
175 {
176     note->hdr.n_type = cpu_to_be32(NT_S390_PREFIX);
177     note->contents.prefix = cpu_to_be32((uint32_t)(cpu->env.psa));
178 }
179 
180 
181 typedef struct NoteFuncDescStruct {
182     int contents_size;
183     void (*note_contents_func)(Note *note, S390CPU *cpu, int id);
184 } NoteFuncDesc;
185 
186 static const NoteFuncDesc note_core[] = {
187     {sizeof_field(Note, contents.prstatus), s390x_write_elf64_prstatus},
188     {sizeof_field(Note, contents.fpregset), s390x_write_elf64_fpregset},
189     { 0, NULL}
190 };
191 
192 static const NoteFuncDesc note_linux[] = {
193     {sizeof_field(Note, contents.prefix),   s390x_write_elf64_prefix},
194     {sizeof_field(Note, contents.ctrs),     s390x_write_elf64_ctrs},
195     {sizeof_field(Note, contents.timer),    s390x_write_elf64_timer},
196     {sizeof_field(Note, contents.todcmp),   s390x_write_elf64_todcmp},
197     {sizeof_field(Note, contents.todpreg),  s390x_write_elf64_todpreg},
198     {sizeof_field(Note, contents.vregslo),  s390x_write_elf64_vregslo},
199     {sizeof_field(Note, contents.vregshi),  s390x_write_elf64_vregshi},
200     {sizeof_field(Note, contents.gscb),     s390x_write_elf64_gscb},
201     { 0, NULL}
202 };
203 
204 static int s390x_write_elf64_notes(const char *note_name,
205                                        WriteCoreDumpFunction f,
206                                        S390CPU *cpu, int id,
207                                        void *opaque,
208                                        const NoteFuncDesc *funcs)
209 {
210     Note note;
211     const NoteFuncDesc *nf;
212     int note_size;
213     int ret = -1;
214 
215     assert(strlen(note_name) < sizeof(note.name));
216 
217     for (nf = funcs; nf->note_contents_func; nf++) {
218         memset(&note, 0, sizeof(note));
219         note.hdr.n_namesz = cpu_to_be32(strlen(note_name) + 1);
220         note.hdr.n_descsz = cpu_to_be32(nf->contents_size);
221         g_strlcpy(note.name, note_name, sizeof(note.name));
222         (*nf->note_contents_func)(&note, cpu, id);
223 
224         note_size = sizeof(note) - sizeof(note.contents) + nf->contents_size;
225         ret = f(&note, note_size, opaque);
226 
227         if (ret < 0) {
228             return -1;
229         }
230 
231     }
232 
233     return 0;
234 }
235 
236 
237 int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
238                               int cpuid, void *opaque)
239 {
240     S390CPU *cpu = S390_CPU(cs);
241     int r;
242 
243     r = s390x_write_elf64_notes("CORE", f, cpu, cpuid, opaque, note_core);
244     if (r) {
245         return r;
246     }
247     return s390x_write_elf64_notes("LINUX", f, cpu, cpuid, opaque, note_linux);
248 }
249 
250 int cpu_get_dump_info(ArchDumpInfo *info,
251                       const struct GuestPhysBlockList *guest_phys_blocks)
252 {
253     info->d_machine = EM_S390;
254     info->d_endian = ELFDATA2MSB;
255     info->d_class = ELFCLASS64;
256 
257     return 0;
258 }
259 
260 ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
261 {
262     int name_size = 8; /* "LINUX" or "CORE" + pad */
263     size_t elf_note_size = 0;
264     int note_head_size;
265     const NoteFuncDesc *nf;
266 
267     assert(class == ELFCLASS64);
268     assert(machine == EM_S390);
269 
270     note_head_size = sizeof(Elf64_Nhdr);
271 
272     for (nf = note_core; nf->note_contents_func; nf++) {
273         elf_note_size = elf_note_size + note_head_size + name_size +
274                         nf->contents_size;
275     }
276     for (nf = note_linux; nf->note_contents_func; nf++) {
277         elf_note_size = elf_note_size + note_head_size + name_size +
278                         nf->contents_size;
279     }
280 
281     return (elf_note_size) * nr_cpus;
282 }
283