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 assert(strlen(note_name) < sizeof(note.name)); 216 217 for (nf = funcs; nf->note_contents_func; nf++) { 218 memset(¬e, 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)(¬e, cpu, id); 223 224 note_size = sizeof(note) - sizeof(note.contents) + nf->contents_size; 225 ret = f(¬e, 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