|
@@ -63,6 +63,11 @@ static ssize_t copy_page_real(void *buf, void *src, size_t csize)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Pointer to ELF header in new kernel
|
|
|
+ */
|
|
|
+static void *elfcorehdr_newmem;
|
|
|
+
|
|
|
/*
|
|
|
* Copy one page from "oldmem"
|
|
|
*
|
|
@@ -367,14 +372,6 @@ static int get_mem_chunk_cnt(void)
|
|
|
return cnt;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * Relocate pointer in order to allow vmcore code access the data
|
|
|
- */
|
|
|
-static inline unsigned long relocate(unsigned long addr)
|
|
|
-{
|
|
|
- return OLDMEM_BASE + addr;
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* Initialize ELF loads (new kernel)
|
|
|
*/
|
|
@@ -426,7 +423,7 @@ static void *notes_init(Elf64_Phdr *phdr, void *ptr, u64 notes_offset)
|
|
|
ptr = nt_vmcoreinfo(ptr);
|
|
|
memset(phdr, 0, sizeof(*phdr));
|
|
|
phdr->p_type = PT_NOTE;
|
|
|
- phdr->p_offset = relocate(notes_offset);
|
|
|
+ phdr->p_offset = notes_offset;
|
|
|
phdr->p_filesz = (unsigned long) PTR_SUB(ptr, ptr_start);
|
|
|
phdr->p_memsz = phdr->p_filesz;
|
|
|
return ptr;
|
|
@@ -435,7 +432,7 @@ static void *notes_init(Elf64_Phdr *phdr, void *ptr, u64 notes_offset)
|
|
|
/*
|
|
|
* Create ELF core header (new kernel)
|
|
|
*/
|
|
|
-static void s390_elf_corehdr_create(char **elfcorebuf, size_t *elfcorebuf_sz)
|
|
|
+int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size)
|
|
|
{
|
|
|
Elf64_Phdr *phdr_notes, *phdr_loads;
|
|
|
int mem_chunk_cnt;
|
|
@@ -443,6 +440,11 @@ static void s390_elf_corehdr_create(char **elfcorebuf, size_t *elfcorebuf_sz)
|
|
|
u32 alloc_size;
|
|
|
u64 hdr_off;
|
|
|
|
|
|
+ if (!OLDMEM_BASE)
|
|
|
+ return 0;
|
|
|
+ /* If elfcorehdr= has been passed via cmdline, we use that one */
|
|
|
+ if (elfcorehdr_addr != ELFCORE_ADDR_MAX)
|
|
|
+ return 0;
|
|
|
mem_chunk_cnt = get_mem_chunk_cnt();
|
|
|
|
|
|
alloc_size = 0x1000 + get_cpu_cnt() * 0x300 +
|
|
@@ -460,27 +462,52 @@ static void s390_elf_corehdr_create(char **elfcorebuf, size_t *elfcorebuf_sz)
|
|
|
ptr = notes_init(phdr_notes, ptr, ((unsigned long) hdr) + hdr_off);
|
|
|
/* Init loads */
|
|
|
hdr_off = PTR_DIFF(ptr, hdr);
|
|
|
- loads_init(phdr_loads, ((unsigned long) hdr) + hdr_off);
|
|
|
- *elfcorebuf_sz = hdr_off;
|
|
|
- *elfcorebuf = (void *) relocate((unsigned long) hdr);
|
|
|
- BUG_ON(*elfcorebuf_sz > alloc_size);
|
|
|
+ loads_init(phdr_loads, hdr_off);
|
|
|
+ *addr = (unsigned long long) hdr;
|
|
|
+ elfcorehdr_newmem = hdr;
|
|
|
+ *size = (unsigned long long) hdr_off;
|
|
|
+ BUG_ON(elfcorehdr_size > alloc_size);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * Create kdump ELF core header in new kernel, if it has not been passed via
|
|
|
- * the "elfcorehdr" kernel parameter
|
|
|
+ * Free ELF core header (new kernel)
|
|
|
*/
|
|
|
-static int setup_kdump_elfcorehdr(void)
|
|
|
+void elfcorehdr_free(unsigned long long addr)
|
|
|
{
|
|
|
- size_t elfcorebuf_sz;
|
|
|
- char *elfcorebuf;
|
|
|
-
|
|
|
- if (!OLDMEM_BASE || is_kdump_kernel())
|
|
|
- return -EINVAL;
|
|
|
- s390_elf_corehdr_create(&elfcorebuf, &elfcorebuf_sz);
|
|
|
- elfcorehdr_addr = (unsigned long long) elfcorebuf;
|
|
|
- elfcorehdr_size = elfcorebuf_sz;
|
|
|
- return 0;
|
|
|
+ if (!elfcorehdr_newmem)
|
|
|
+ return;
|
|
|
+ kfree((void *)(unsigned long)addr);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Read from ELF header
|
|
|
+ */
|
|
|
+ssize_t elfcorehdr_read(char *buf, size_t count, u64 *ppos)
|
|
|
+{
|
|
|
+ void *src = (void *)(unsigned long)*ppos;
|
|
|
+
|
|
|
+ src = elfcorehdr_newmem ? src : src - OLDMEM_BASE;
|
|
|
+ memcpy(buf, src, count);
|
|
|
+ *ppos += count;
|
|
|
+ return count;
|
|
|
}
|
|
|
|
|
|
-subsys_initcall(setup_kdump_elfcorehdr);
|
|
|
+/*
|
|
|
+ * Read from ELF notes data
|
|
|
+ */
|
|
|
+ssize_t elfcorehdr_read_notes(char *buf, size_t count, u64 *ppos)
|
|
|
+{
|
|
|
+ void *src = (void *)(unsigned long)*ppos;
|
|
|
+ int rc;
|
|
|
+
|
|
|
+ if (elfcorehdr_newmem) {
|
|
|
+ memcpy(buf, src, count);
|
|
|
+ } else {
|
|
|
+ rc = copy_from_oldmem(buf, src, count);
|
|
|
+ if (rc)
|
|
|
+ return rc;
|
|
|
+ }
|
|
|
+ *ppos += count;
|
|
|
+ return count;
|
|
|
+}
|