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