diff options
-rw-r--r-- | arch/s390/kernel/crash_dump.c | 81 |
1 files changed, 54 insertions, 27 deletions
diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c index d8f355657171..0c9a897a1fb5 100644 --- a/arch/s390/kernel/crash_dump.c +++ b/arch/s390/kernel/crash_dump.c | |||
@@ -64,6 +64,11 @@ static ssize_t copy_page_real(void *buf, void *src, size_t csize) | |||
64 | } | 64 | } |
65 | 65 | ||
66 | /* | 66 | /* |
67 | * Pointer to ELF header in new kernel | ||
68 | */ | ||
69 | static void *elfcorehdr_newmem; | ||
70 | |||
71 | /* | ||
67 | * Copy one page from "oldmem" | 72 | * Copy one page from "oldmem" |
68 | * | 73 | * |
69 | * For the kdump reserved memory this functions performs a swap operation: | 74 | * For the kdump reserved memory this functions performs a swap operation: |
@@ -368,14 +373,6 @@ static int get_mem_chunk_cnt(void) | |||
368 | } | 373 | } |
369 | 374 | ||
370 | /* | 375 | /* |
371 | * Relocate pointer in order to allow vmcore code access the data | ||
372 | */ | ||
373 | static inline unsigned long relocate(unsigned long addr) | ||
374 | { | ||
375 | return OLDMEM_BASE + addr; | ||
376 | } | ||
377 | |||
378 | /* | ||
379 | * Initialize ELF loads (new kernel) | 376 | * Initialize ELF loads (new kernel) |
380 | */ | 377 | */ |
381 | static int loads_init(Elf64_Phdr *phdr, u64 loads_offset) | 378 | static int loads_init(Elf64_Phdr *phdr, u64 loads_offset) |
@@ -426,7 +423,7 @@ static void *notes_init(Elf64_Phdr *phdr, void *ptr, u64 notes_offset) | |||
426 | ptr = nt_vmcoreinfo(ptr); | 423 | ptr = nt_vmcoreinfo(ptr); |
427 | memset(phdr, 0, sizeof(*phdr)); | 424 | memset(phdr, 0, sizeof(*phdr)); |
428 | phdr->p_type = PT_NOTE; | 425 | phdr->p_type = PT_NOTE; |
429 | phdr->p_offset = relocate(notes_offset); | 426 | phdr->p_offset = notes_offset; |
430 | phdr->p_filesz = (unsigned long) PTR_SUB(ptr, ptr_start); | 427 | phdr->p_filesz = (unsigned long) PTR_SUB(ptr, ptr_start); |
431 | phdr->p_memsz = phdr->p_filesz; | 428 | phdr->p_memsz = phdr->p_filesz; |
432 | return ptr; | 429 | return ptr; |
@@ -435,7 +432,7 @@ static void *notes_init(Elf64_Phdr *phdr, void *ptr, u64 notes_offset) | |||
435 | /* | 432 | /* |
436 | * Create ELF core header (new kernel) | 433 | * Create ELF core header (new kernel) |
437 | */ | 434 | */ |
438 | static void s390_elf_corehdr_create(char **elfcorebuf, size_t *elfcorebuf_sz) | 435 | int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size) |
439 | { | 436 | { |
440 | Elf64_Phdr *phdr_notes, *phdr_loads; | 437 | Elf64_Phdr *phdr_notes, *phdr_loads; |
441 | int mem_chunk_cnt; | 438 | int mem_chunk_cnt; |
@@ -443,6 +440,11 @@ static void s390_elf_corehdr_create(char **elfcorebuf, size_t *elfcorebuf_sz) | |||
443 | u32 alloc_size; | 440 | u32 alloc_size; |
444 | u64 hdr_off; | 441 | u64 hdr_off; |
445 | 442 | ||
443 | if (!OLDMEM_BASE) | ||
444 | return 0; | ||
445 | /* If elfcorehdr= has been passed via cmdline, we use that one */ | ||
446 | if (elfcorehdr_addr != ELFCORE_ADDR_MAX) | ||
447 | return 0; | ||
446 | mem_chunk_cnt = get_mem_chunk_cnt(); | 448 | mem_chunk_cnt = get_mem_chunk_cnt(); |
447 | 449 | ||
448 | alloc_size = 0x1000 + get_cpu_cnt() * 0x300 + | 450 | alloc_size = 0x1000 + get_cpu_cnt() * 0x300 + |
@@ -460,27 +462,52 @@ static void s390_elf_corehdr_create(char **elfcorebuf, size_t *elfcorebuf_sz) | |||
460 | ptr = notes_init(phdr_notes, ptr, ((unsigned long) hdr) + hdr_off); | 462 | ptr = notes_init(phdr_notes, ptr, ((unsigned long) hdr) + hdr_off); |
461 | /* Init loads */ | 463 | /* Init loads */ |
462 | hdr_off = PTR_DIFF(ptr, hdr); | 464 | hdr_off = PTR_DIFF(ptr, hdr); |
463 | loads_init(phdr_loads, ((unsigned long) hdr) + hdr_off); | 465 | loads_init(phdr_loads, hdr_off); |
464 | *elfcorebuf_sz = hdr_off; | 466 | *addr = (unsigned long long) hdr; |
465 | *elfcorebuf = (void *) relocate((unsigned long) hdr); | 467 | elfcorehdr_newmem = hdr; |
466 | BUG_ON(*elfcorebuf_sz > alloc_size); | 468 | *size = (unsigned long long) hdr_off; |
469 | BUG_ON(elfcorehdr_size > alloc_size); | ||
470 | return 0; | ||
467 | } | 471 | } |
468 | 472 | ||
469 | /* | 473 | /* |
470 | * Create kdump ELF core header in new kernel, if it has not been passed via | 474 | * Free ELF core header (new kernel) |
471 | * the "elfcorehdr" kernel parameter | ||
472 | */ | 475 | */ |
473 | static int setup_kdump_elfcorehdr(void) | 476 | void elfcorehdr_free(unsigned long long addr) |
474 | { | 477 | { |
475 | size_t elfcorebuf_sz; | 478 | if (!elfcorehdr_newmem) |
476 | char *elfcorebuf; | 479 | return; |
477 | 480 | kfree((void *)(unsigned long)addr); | |
478 | if (!OLDMEM_BASE || is_kdump_kernel()) | 481 | } |
479 | return -EINVAL; | 482 | |
480 | s390_elf_corehdr_create(&elfcorebuf, &elfcorebuf_sz); | 483 | /* |
481 | elfcorehdr_addr = (unsigned long long) elfcorebuf; | 484 | * Read from ELF header |
482 | elfcorehdr_size = elfcorebuf_sz; | 485 | */ |
483 | return 0; | 486 | ssize_t elfcorehdr_read(char *buf, size_t count, u64 *ppos) |
487 | { | ||
488 | void *src = (void *)(unsigned long)*ppos; | ||
489 | |||
490 | src = elfcorehdr_newmem ? src : src - OLDMEM_BASE; | ||
491 | memcpy(buf, src, count); | ||
492 | *ppos += count; | ||
493 | return count; | ||
484 | } | 494 | } |
485 | 495 | ||
486 | subsys_initcall(setup_kdump_elfcorehdr); | 496 | /* |
497 | * Read from ELF notes data | ||
498 | */ | ||
499 | ssize_t elfcorehdr_read_notes(char *buf, size_t count, u64 *ppos) | ||
500 | { | ||
501 | void *src = (void *)(unsigned long)*ppos; | ||
502 | int rc; | ||
503 | |||
504 | if (elfcorehdr_newmem) { | ||
505 | memcpy(buf, src, count); | ||
506 | } else { | ||
507 | rc = copy_from_oldmem(buf, src, count); | ||
508 | if (rc) | ||
509 | return rc; | ||
510 | } | ||
511 | *ppos += count; | ||
512 | return count; | ||
513 | } | ||