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 "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 = ¬e->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 | for (nf = funcs; nf->note_contents_func; nf++) { |
216 | memset(¬e, 0, sizeof(note)); |
217 | note.hdr.n_namesz = cpu_to_be32(strlen(note_name) + 1); |
218 | note.hdr.n_descsz = cpu_to_be32(nf->contents_size); |
219 | strncpy(note.name, note_name, sizeof(note.name)); |
220 | (*nf->note_contents_func)(¬e, cpu, id); |
221 | |
222 | note_size = sizeof(note) - sizeof(note.contents) + nf->contents_size; |
223 | ret = f(¬e, note_size, opaque); |
224 | |
225 | if (ret < 0) { |
226 | return -1; |
227 | } |
228 | |
229 | } |
230 | |
231 | return 0; |
232 | } |
233 | |
234 | |
235 | int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, |
236 | int cpuid, void *opaque) |
237 | { |
238 | S390CPU *cpu = S390_CPU(cs); |
239 | int r; |
240 | |
241 | r = s390x_write_elf64_notes("CORE" , f, cpu, cpuid, opaque, note_core); |
242 | if (r) { |
243 | return r; |
244 | } |
245 | return s390x_write_elf64_notes("LINUX" , f, cpu, cpuid, opaque, note_linux); |
246 | } |
247 | |
248 | int cpu_get_dump_info(ArchDumpInfo *info, |
249 | const struct GuestPhysBlockList *guest_phys_blocks) |
250 | { |
251 | info->d_machine = EM_S390; |
252 | info->d_endian = ELFDATA2MSB; |
253 | info->d_class = ELFCLASS64; |
254 | |
255 | return 0; |
256 | } |
257 | |
258 | ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) |
259 | { |
260 | int name_size = 8; /* "LINUX" or "CORE" + pad */ |
261 | size_t elf_note_size = 0; |
262 | int note_head_size; |
263 | const NoteFuncDesc *nf; |
264 | |
265 | assert(class == ELFCLASS64); |
266 | assert(machine == EM_S390); |
267 | |
268 | note_head_size = sizeof(Elf64_Nhdr); |
269 | |
270 | for (nf = note_core; nf->note_contents_func; nf++) { |
271 | elf_note_size = elf_note_size + note_head_size + name_size + |
272 | nf->contents_size; |
273 | } |
274 | for (nf = note_linux; nf->note_contents_func; nf++) { |
275 | elf_note_size = elf_note_size + note_head_size + name_size + |
276 | nf->contents_size; |
277 | } |
278 | |
279 | return (elf_note_size) * nr_cpus; |
280 | } |
281 | |