aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/crash_dump.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/kernel/crash_dump.c')
-rw-r--r--arch/s390/kernel/crash_dump.c81
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 */
69static 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 */
373static 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 */
381static int loads_init(Elf64_Phdr *phdr, u64 loads_offset) 378static 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 */
438static void s390_elf_corehdr_create(char **elfcorebuf, size_t *elfcorebuf_sz) 435int 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 */
473static int setup_kdump_elfcorehdr(void) 476void 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; 486ssize_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
486subsys_initcall(setup_kdump_elfcorehdr); 496/*
497 * Read from ELF notes data
498 */
499ssize_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}