|
@@ -123,6 +123,36 @@ static ssize_t read_from_oldmem(char *buf, size_t count,
|
|
|
return read;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Architectures may override this function to allocate ELF header in 2nd kernel
|
|
|
+ */
|
|
|
+int __weak elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size)
|
|
|
+{
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Architectures may override this function to free header
|
|
|
+ */
|
|
|
+void __weak elfcorehdr_free(unsigned long long addr)
|
|
|
+{}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Architectures may override this function to read from ELF header
|
|
|
+ */
|
|
|
+ssize_t __weak elfcorehdr_read(char *buf, size_t count, u64 *ppos)
|
|
|
+{
|
|
|
+ return read_from_oldmem(buf, count, ppos, 0);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Architectures may override this function to read from notes sections
|
|
|
+ */
|
|
|
+ssize_t __weak elfcorehdr_read_notes(char *buf, size_t count, u64 *ppos)
|
|
|
+{
|
|
|
+ return read_from_oldmem(buf, count, ppos, 0);
|
|
|
+}
|
|
|
+
|
|
|
/* Read from the ELF header and then the crash dump. On error, negative value is
|
|
|
* returned otherwise number of bytes read are returned.
|
|
|
*/
|
|
@@ -357,7 +387,7 @@ static int __init update_note_header_size_elf64(const Elf64_Ehdr *ehdr_ptr)
|
|
|
notes_section = kmalloc(max_sz, GFP_KERNEL);
|
|
|
if (!notes_section)
|
|
|
return -ENOMEM;
|
|
|
- rc = read_from_oldmem(notes_section, max_sz, &offset, 0);
|
|
|
+ rc = elfcorehdr_read_notes(notes_section, max_sz, &offset);
|
|
|
if (rc < 0) {
|
|
|
kfree(notes_section);
|
|
|
return rc;
|
|
@@ -444,7 +474,8 @@ static int __init copy_notes_elf64(const Elf64_Ehdr *ehdr_ptr, char *notes_buf)
|
|
|
if (phdr_ptr->p_type != PT_NOTE)
|
|
|
continue;
|
|
|
offset = phdr_ptr->p_offset;
|
|
|
- rc = read_from_oldmem(notes_buf, phdr_ptr->p_memsz, &offset, 0);
|
|
|
+ rc = elfcorehdr_read_notes(notes_buf, phdr_ptr->p_memsz,
|
|
|
+ &offset);
|
|
|
if (rc < 0)
|
|
|
return rc;
|
|
|
notes_buf += phdr_ptr->p_memsz;
|
|
@@ -536,7 +567,7 @@ static int __init update_note_header_size_elf32(const Elf32_Ehdr *ehdr_ptr)
|
|
|
notes_section = kmalloc(max_sz, GFP_KERNEL);
|
|
|
if (!notes_section)
|
|
|
return -ENOMEM;
|
|
|
- rc = read_from_oldmem(notes_section, max_sz, &offset, 0);
|
|
|
+ rc = elfcorehdr_read_notes(notes_section, max_sz, &offset);
|
|
|
if (rc < 0) {
|
|
|
kfree(notes_section);
|
|
|
return rc;
|
|
@@ -623,7 +654,8 @@ static int __init copy_notes_elf32(const Elf32_Ehdr *ehdr_ptr, char *notes_buf)
|
|
|
if (phdr_ptr->p_type != PT_NOTE)
|
|
|
continue;
|
|
|
offset = phdr_ptr->p_offset;
|
|
|
- rc = read_from_oldmem(notes_buf, phdr_ptr->p_memsz, &offset, 0);
|
|
|
+ rc = elfcorehdr_read_notes(notes_buf, phdr_ptr->p_memsz,
|
|
|
+ &offset);
|
|
|
if (rc < 0)
|
|
|
return rc;
|
|
|
notes_buf += phdr_ptr->p_memsz;
|
|
@@ -810,7 +842,7 @@ static int __init parse_crash_elf64_headers(void)
|
|
|
addr = elfcorehdr_addr;
|
|
|
|
|
|
/* Read Elf header */
|
|
|
- rc = read_from_oldmem((char*)&ehdr, sizeof(Elf64_Ehdr), &addr, 0);
|
|
|
+ rc = elfcorehdr_read((char *)&ehdr, sizeof(Elf64_Ehdr), &addr);
|
|
|
if (rc < 0)
|
|
|
return rc;
|
|
|
|
|
@@ -837,7 +869,7 @@ static int __init parse_crash_elf64_headers(void)
|
|
|
if (!elfcorebuf)
|
|
|
return -ENOMEM;
|
|
|
addr = elfcorehdr_addr;
|
|
|
- rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz_orig, &addr, 0);
|
|
|
+ rc = elfcorehdr_read(elfcorebuf, elfcorebuf_sz_orig, &addr);
|
|
|
if (rc < 0)
|
|
|
goto fail;
|
|
|
|
|
@@ -866,7 +898,7 @@ static int __init parse_crash_elf32_headers(void)
|
|
|
addr = elfcorehdr_addr;
|
|
|
|
|
|
/* Read Elf header */
|
|
|
- rc = read_from_oldmem((char*)&ehdr, sizeof(Elf32_Ehdr), &addr, 0);
|
|
|
+ rc = elfcorehdr_read((char *)&ehdr, sizeof(Elf32_Ehdr), &addr);
|
|
|
if (rc < 0)
|
|
|
return rc;
|
|
|
|
|
@@ -892,7 +924,7 @@ static int __init parse_crash_elf32_headers(void)
|
|
|
if (!elfcorebuf)
|
|
|
return -ENOMEM;
|
|
|
addr = elfcorehdr_addr;
|
|
|
- rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz_orig, &addr, 0);
|
|
|
+ rc = elfcorehdr_read(elfcorebuf, elfcorebuf_sz_orig, &addr);
|
|
|
if (rc < 0)
|
|
|
goto fail;
|
|
|
|
|
@@ -919,7 +951,7 @@ static int __init parse_crash_elf_headers(void)
|
|
|
int rc=0;
|
|
|
|
|
|
addr = elfcorehdr_addr;
|
|
|
- rc = read_from_oldmem(e_ident, EI_NIDENT, &addr, 0);
|
|
|
+ rc = elfcorehdr_read(e_ident, EI_NIDENT, &addr);
|
|
|
if (rc < 0)
|
|
|
return rc;
|
|
|
if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) {
|
|
@@ -952,7 +984,14 @@ static int __init vmcore_init(void)
|
|
|
{
|
|
|
int rc = 0;
|
|
|
|
|
|
- /* If elfcorehdr= has been passed in cmdline, then capture the dump.*/
|
|
|
+ /* Allow architectures to allocate ELF header in 2nd kernel */
|
|
|
+ rc = elfcorehdr_alloc(&elfcorehdr_addr, &elfcorehdr_size);
|
|
|
+ if (rc)
|
|
|
+ return rc;
|
|
|
+ /*
|
|
|
+ * If elfcorehdr= has been passed in cmdline or created in 2nd kernel,
|
|
|
+ * then capture the dump.
|
|
|
+ */
|
|
|
if (!(is_vmcore_usable()))
|
|
|
return rc;
|
|
|
rc = parse_crash_elf_headers();
|
|
@@ -960,6 +999,8 @@ static int __init vmcore_init(void)
|
|
|
pr_warn("Kdump: vmcore not initialized\n");
|
|
|
return rc;
|
|
|
}
|
|
|
+ elfcorehdr_free(elfcorehdr_addr);
|
|
|
+ elfcorehdr_addr = ELFCORE_ADDR_ERR;
|
|
|
|
|
|
proc_vmcore = proc_create("vmcore", S_IRUSR, NULL, &proc_vmcore_operations);
|
|
|
if (proc_vmcore)
|