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 "qemu/units.h" 16 #include "cpu.h" 17 #include "s390x-internal.h" 18 #include "elf.h" 19 #include "sysemu/dump.h" 20 #include "hw/s390x/pv.h" 21 #include "kvm/kvm_s390x.h" 22 23 struct S390xUserRegsStruct { 24 uint64_t psw[2]; 25 uint64_t gprs[16]; 26 uint32_t acrs[16]; 27 } QEMU_PACKED; 28 29 typedef struct S390xUserRegsStruct S390xUserRegs; 30 31 struct S390xElfPrstatusStruct { 32 uint8_t pad1[32]; 33 uint32_t pid; 34 uint8_t pad2[76]; 35 S390xUserRegs regs; 36 uint8_t pad3[16]; 37 } QEMU_PACKED; 38 39 typedef struct S390xElfPrstatusStruct S390xElfPrstatus; 40 41 struct S390xElfFpregsetStruct { 42 uint32_t fpc; 43 uint32_t pad; 44 uint64_t fprs[16]; 45 } QEMU_PACKED; 46 47 typedef struct S390xElfFpregsetStruct S390xElfFpregset; 48 49 struct S390xElfVregsLoStruct { 50 uint64_t vregs[16]; 51 } QEMU_PACKED; 52 53 typedef struct S390xElfVregsLoStruct S390xElfVregsLo; 54 55 struct S390xElfVregsHiStruct { 56 uint64_t vregs[16][2]; 57 } QEMU_PACKED; 58 59 typedef struct S390xElfVregsHiStruct S390xElfVregsHi; 60 61 struct S390xElfGSCBStruct { 62 uint64_t gsregs[4]; 63 } QEMU_PACKED; 64 65 typedef struct S390xElfGSCBStruct S390xElfGSCB; 66 67 typedef struct noteStruct { 68 Elf64_Nhdr hdr; 69 char name[8]; 70 union { 71 S390xElfPrstatus prstatus; 72 S390xElfFpregset fpregset; 73 S390xElfVregsLo vregslo; 74 S390xElfVregsHi vregshi; 75 S390xElfGSCB gscb; 76 uint32_t prefix; 77 uint64_t timer; 78 uint64_t todcmp; 79 uint32_t todpreg; 80 uint64_t ctrs[16]; 81 uint8_t dynamic[1]; /* 82 * Would be a flexible array member, if 83 * that was legal inside a union. Real 84 * size comes from PV info interface. 85 */ 86 } contents; 87 } QEMU_PACKED Note; 88 89 static bool pv_dump_initialized; 90 91 static void s390x_write_elf64_prstatus(Note *note, S390CPU *cpu, int id) 92 { 93 int i; 94 S390xUserRegs *regs; 95 96 note->hdr.n_type = cpu_to_be32(NT_PRSTATUS); 97 98 regs = &(note->contents.prstatus.regs); 99 regs->psw[0] = cpu_to_be64(cpu->env.psw.mask); 100 regs->psw[1] = cpu_to_be64(cpu->env.psw.addr); 101 for (i = 0; i <= 15; i++) { 102 regs->acrs[i] = cpu_to_be32(cpu->env.aregs[i]); 103 regs->gprs[i] = cpu_to_be64(cpu->env.regs[i]); 104 } 105 note->contents.prstatus.pid = id; 106 } 107 108 static void s390x_write_elf64_fpregset(Note *note, S390CPU *cpu, int id) 109 { 110 int i; 111 CPUS390XState *cs = &cpu->env; 112 113 note->hdr.n_type = cpu_to_be32(NT_FPREGSET); 114 note->contents.fpregset.fpc = cpu_to_be32(cpu->env.fpc); 115 for (i = 0; i <= 15; i++) { 116 note->contents.fpregset.fprs[i] = cpu_to_be64(*get_freg(cs, i)); 117 } 118 } 119 120 static void s390x_write_elf64_vregslo(Note *note, S390CPU *cpu, int id) 121 { 122 int i; 123 124 note->hdr.n_type = cpu_to_be32(NT_S390_VXRS_LOW); 125 for (i = 0; i <= 15; i++) { 126 note->contents.vregslo.vregs[i] = cpu_to_be64(cpu->env.vregs[i][1]); 127 } 128 } 129 130 static void s390x_write_elf64_vregshi(Note *note, S390CPU *cpu, int id) 131 { 132 int i; 133 S390xElfVregsHi *temp_vregshi; 134 135 temp_vregshi = ¬e->contents.vregshi; 136 137 note->hdr.n_type = cpu_to_be32(NT_S390_VXRS_HIGH); 138 for (i = 0; i <= 15; i++) { 139 temp_vregshi->vregs[i][0] = cpu_to_be64(cpu->env.vregs[i + 16][0]); 140 temp_vregshi->vregs[i][1] = cpu_to_be64(cpu->env.vregs[i + 16][1]); 141 } 142 } 143 144 static void s390x_write_elf64_gscb(Note *note, S390CPU *cpu, int id) 145 { 146 int i; 147 148 note->hdr.n_type = cpu_to_be32(NT_S390_GS_CB); 149 for (i = 0; i < 4; i++) { 150 note->contents.gscb.gsregs[i] = cpu_to_be64(cpu->env.gscb[i]); 151 } 152 } 153 154 static void s390x_write_elf64_timer(Note *note, S390CPU *cpu, int id) 155 { 156 note->hdr.n_type = cpu_to_be32(NT_S390_TIMER); 157 note->contents.timer = cpu_to_be64((uint64_t)(cpu->env.cputm)); 158 } 159 160 static void s390x_write_elf64_todcmp(Note *note, S390CPU *cpu, int id) 161 { 162 note->hdr.n_type = cpu_to_be32(NT_S390_TODCMP); 163 note->contents.todcmp = cpu_to_be64((uint64_t)(cpu->env.ckc)); 164 } 165 166 static void s390x_write_elf64_todpreg(Note *note, S390CPU *cpu, int id) 167 { 168 note->hdr.n_type = cpu_to_be32(NT_S390_TODPREG); 169 note->contents.todpreg = cpu_to_be32((uint32_t)(cpu->env.todpr)); 170 } 171 172 static void s390x_write_elf64_ctrs(Note *note, S390CPU *cpu, int id) 173 { 174 int i; 175 176 note->hdr.n_type = cpu_to_be32(NT_S390_CTRS); 177 178 for (i = 0; i <= 15; i++) { 179 note->contents.ctrs[i] = cpu_to_be64(cpu->env.cregs[i]); 180 } 181 } 182 183 static void s390x_write_elf64_prefix(Note *note, S390CPU *cpu, int id) 184 { 185 note->hdr.n_type = cpu_to_be32(NT_S390_PREFIX); 186 note->contents.prefix = cpu_to_be32((uint32_t)(cpu->env.psa)); 187 } 188 189 static void s390x_write_elf64_pv(Note *note, S390CPU *cpu, int id) 190 { 191 note->hdr.n_type = cpu_to_be32(NT_S390_PV_CPU_DATA); 192 if (!pv_dump_initialized) { 193 return; 194 } 195 kvm_s390_dump_cpu(cpu, ¬e->contents.dynamic); 196 } 197 198 typedef struct NoteFuncDescStruct { 199 int contents_size; 200 uint64_t (*note_size_func)(void); /* NULL for non-dynamic sized contents */ 201 void (*note_contents_func)(Note *note, S390CPU *cpu, int id); 202 bool pvonly; 203 } NoteFuncDesc; 204 205 static const NoteFuncDesc note_core[] = { 206 {sizeof_field(Note, contents.prstatus), NULL, s390x_write_elf64_prstatus, false}, 207 {sizeof_field(Note, contents.fpregset), NULL, s390x_write_elf64_fpregset, false}, 208 { 0, NULL, NULL, false} 209 }; 210 211 static const NoteFuncDesc note_linux[] = { 212 {sizeof_field(Note, contents.prefix), NULL, s390x_write_elf64_prefix, false}, 213 {sizeof_field(Note, contents.ctrs), NULL, s390x_write_elf64_ctrs, false}, 214 {sizeof_field(Note, contents.timer), NULL, s390x_write_elf64_timer, false}, 215 {sizeof_field(Note, contents.todcmp), NULL, s390x_write_elf64_todcmp, false}, 216 {sizeof_field(Note, contents.todpreg), NULL, s390x_write_elf64_todpreg, false}, 217 {sizeof_field(Note, contents.vregslo), NULL, s390x_write_elf64_vregslo, false}, 218 {sizeof_field(Note, contents.vregshi), NULL, s390x_write_elf64_vregshi, false}, 219 {sizeof_field(Note, contents.gscb), NULL, s390x_write_elf64_gscb, false}, 220 {0, kvm_s390_pv_dmp_get_size_cpu, s390x_write_elf64_pv, true}, 221 { 0, NULL, NULL, false} 222 }; 223 224 static int s390x_write_elf64_notes(const char *note_name, 225 WriteCoreDumpFunction f, 226 S390CPU *cpu, int id, 227 DumpState *s, 228 const NoteFuncDesc *funcs) 229 { 230 Note note, *notep; 231 const NoteFuncDesc *nf; 232 int note_size, content_size; 233 int ret = -1; 234 235 assert(strlen(note_name) < sizeof(note.name)); 236 237 for (nf = funcs; nf->note_contents_func; nf++) { 238 notep = ¬e; 239 if (nf->pvonly && !s390_is_pv()) { 240 continue; 241 } 242 243 content_size = nf->note_size_func ? nf->note_size_func() : nf->contents_size; 244 note_size = sizeof(note) - sizeof(notep->contents) + content_size; 245 246 /* Notes with dynamic sizes need to allocate a note */ 247 if (nf->note_size_func) { 248 notep = g_malloc(note_size); 249 } 250 251 memset(notep, 0, sizeof(note)); 252 253 /* Setup note header data */ 254 notep->hdr.n_descsz = cpu_to_be32(content_size); 255 notep->hdr.n_namesz = cpu_to_be32(strlen(note_name) + 1); 256 g_strlcpy(notep->name, note_name, sizeof(notep->name)); 257 258 /* Get contents and write them out */ 259 (*nf->note_contents_func)(notep, cpu, id); 260 ret = f(notep, note_size, s); 261 262 if (nf->note_size_func) { 263 g_free(notep); 264 } 265 266 if (ret < 0) { 267 return -1; 268 } 269 270 } 271 272 return 0; 273 } 274 275 276 int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, 277 int cpuid, DumpState *s) 278 { 279 S390CPU *cpu = S390_CPU(cs); 280 int r; 281 282 r = s390x_write_elf64_notes("CORE", f, cpu, cpuid, s, note_core); 283 if (r) { 284 return r; 285 } 286 return s390x_write_elf64_notes("LINUX", f, cpu, cpuid, s, note_linux); 287 } 288 289 /* PV dump section size functions */ 290 static uint64_t get_mem_state_size_from_len(uint64_t len) 291 { 292 return (len / (MiB)) * kvm_s390_pv_dmp_get_size_mem_state(); 293 } 294 295 static uint64_t get_size_mem_state(DumpState *s) 296 { 297 return get_mem_state_size_from_len(s->total_size); 298 } 299 300 static uint64_t get_size_completion_data(DumpState *s) 301 { 302 return kvm_s390_pv_dmp_get_size_completion_data(); 303 } 304 305 /* PV dump section data functions*/ 306 static int get_data_completion(DumpState *s, uint8_t *buff) 307 { 308 int rc; 309 310 if (!pv_dump_initialized) { 311 return 0; 312 } 313 rc = kvm_s390_dump_completion_data(buff); 314 if (!rc) { 315 pv_dump_initialized = false; 316 } 317 return rc; 318 } 319 320 static int get_mem_state(DumpState *s, uint8_t *buff) 321 { 322 int64_t memblock_size, memblock_start; 323 GuestPhysBlock *block; 324 uint64_t off; 325 int rc; 326 327 QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) { 328 memblock_start = dump_filtered_memblock_start(block, s->filter_area_begin, 329 s->filter_area_length); 330 if (memblock_start == -1) { 331 continue; 332 } 333 334 memblock_size = dump_filtered_memblock_size(block, s->filter_area_begin, 335 s->filter_area_length); 336 337 off = get_mem_state_size_from_len(block->target_start); 338 339 rc = kvm_s390_dump_mem_state(block->target_start, 340 get_mem_state_size_from_len(memblock_size), 341 buff + off); 342 if (rc) { 343 return rc; 344 } 345 } 346 347 return 0; 348 } 349 350 static struct sections { 351 uint64_t (*sections_size_func)(DumpState *s); 352 int (*sections_contents_func)(DumpState *s, uint8_t *buff); 353 char sctn_str[12]; 354 } sections[] = { 355 { get_size_mem_state, get_mem_state, "pv_mem_meta"}, 356 { get_size_completion_data, get_data_completion, "pv_compl"}, 357 {NULL , NULL, ""} 358 }; 359 360 static uint64_t arch_sections_write_hdr(DumpState *s, uint8_t *buff) 361 { 362 Elf64_Shdr *shdr = (void *)buff; 363 struct sections *sctn = sections; 364 uint64_t off = s->section_offset; 365 366 if (!pv_dump_initialized) { 367 return 0; 368 } 369 370 for (; sctn->sections_size_func; off += shdr->sh_size, sctn++, shdr++) { 371 memset(shdr, 0, sizeof(*shdr)); 372 shdr->sh_type = SHT_PROGBITS; 373 shdr->sh_offset = off; 374 shdr->sh_size = sctn->sections_size_func(s); 375 shdr->sh_name = s->string_table_buf->len; 376 g_array_append_vals(s->string_table_buf, sctn->sctn_str, sizeof(sctn->sctn_str)); 377 } 378 379 return (uintptr_t)shdr - (uintptr_t)buff; 380 } 381 382 383 /* Add arch specific number of sections and their respective sizes */ 384 static void arch_sections_add(DumpState *s) 385 { 386 struct sections *sctn = sections; 387 388 /* 389 * We only do a PV dump if we are running a PV guest, KVM supports 390 * the dump API and we got valid dump length information. 391 */ 392 if (!s390_is_pv() || !kvm_s390_get_protected_dump() || 393 !kvm_s390_pv_info_basic_valid()) { 394 return; 395 } 396 397 /* 398 * Start the UV dump process by doing the initialize dump call via 399 * KVM as the proxy. 400 */ 401 if (!kvm_s390_dump_init()) { 402 pv_dump_initialized = true; 403 } else { 404 /* 405 * Dump init failed, maybe the guest owner disabled dumping. 406 * We'll continue the non-PV dump process since this is no 407 * reason to crash qemu. 408 */ 409 return; 410 } 411 412 for (; sctn->sections_size_func; sctn++) { 413 s->shdr_num += 1; 414 s->elf_section_data_size += sctn->sections_size_func(s); 415 } 416 } 417 418 /* 419 * After the PV dump has been initialized, the CPU data has been 420 * fetched and memory has been dumped, we need to grab the tweak data 421 * and the completion data. 422 */ 423 static int arch_sections_write(DumpState *s, uint8_t *buff) 424 { 425 struct sections *sctn = sections; 426 int rc; 427 428 if (!pv_dump_initialized) { 429 return -EINVAL; 430 } 431 432 for (; sctn->sections_size_func; sctn++) { 433 rc = sctn->sections_contents_func(s, buff); 434 buff += sctn->sections_size_func(s); 435 if (rc) { 436 return rc; 437 } 438 } 439 return 0; 440 } 441 442 int cpu_get_dump_info(ArchDumpInfo *info, 443 const struct GuestPhysBlockList *guest_phys_blocks) 444 { 445 info->d_machine = EM_S390; 446 info->d_endian = ELFDATA2MSB; 447 info->d_class = ELFCLASS64; 448 /* 449 * This is evaluated for each dump so we can freely switch 450 * between PV and non-PV. 451 */ 452 if (s390_is_pv() && kvm_s390_get_protected_dump() && 453 kvm_s390_pv_info_basic_valid()) { 454 info->arch_sections_add_fn = *arch_sections_add; 455 info->arch_sections_write_hdr_fn = *arch_sections_write_hdr; 456 info->arch_sections_write_fn = *arch_sections_write; 457 } else { 458 info->arch_sections_add_fn = NULL; 459 info->arch_sections_write_hdr_fn = NULL; 460 info->arch_sections_write_fn = NULL; 461 } 462 return 0; 463 } 464 465 ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) 466 { 467 int name_size = 8; /* "LINUX" or "CORE" + pad */ 468 size_t elf_note_size = 0; 469 int note_head_size, content_size; 470 const NoteFuncDesc *nf; 471 472 assert(class == ELFCLASS64); 473 assert(machine == EM_S390); 474 475 note_head_size = sizeof(Elf64_Nhdr); 476 477 for (nf = note_core; nf->note_contents_func; nf++) { 478 elf_note_size = elf_note_size + note_head_size + name_size + nf->contents_size; 479 } 480 for (nf = note_linux; nf->note_contents_func; nf++) { 481 if (nf->pvonly && !s390_is_pv()) { 482 continue; 483 } 484 content_size = nf->contents_size ? nf->contents_size : nf->note_size_func(); 485 elf_note_size = elf_note_size + note_head_size + name_size + 486 content_size; 487 } 488 489 return (elf_note_size) * nr_cpus; 490 } 491