|
@@ -306,6 +306,15 @@ static void *kzalloc_panic(int len)
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
+static const char *nt_name(Elf64_Word type)
|
|
|
+{
|
|
|
+ const char *name = "LINUX";
|
|
|
+
|
|
|
+ if (type == NT_PRPSINFO || type == NT_PRSTATUS || type == NT_PRFPREG)
|
|
|
+ name = KEXEC_CORE_NOTE_NAME;
|
|
|
+ return name;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Initialize ELF note
|
|
|
*/
|
|
@@ -332,11 +341,26 @@ static void *nt_init_name(void *buf, Elf64_Word type, void *desc, int d_len,
|
|
|
|
|
|
static inline void *nt_init(void *buf, Elf64_Word type, void *desc, int d_len)
|
|
|
{
|
|
|
- const char *note_name = "LINUX";
|
|
|
+ return nt_init_name(buf, type, desc, d_len, nt_name(type));
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Calculate the size of ELF note
|
|
|
+ */
|
|
|
+static size_t nt_size_name(int d_len, const char *name)
|
|
|
+{
|
|
|
+ size_t size;
|
|
|
|
|
|
- if (type == NT_PRPSINFO || type == NT_PRSTATUS || type == NT_PRFPREG)
|
|
|
- note_name = KEXEC_CORE_NOTE_NAME;
|
|
|
- return nt_init_name(buf, type, desc, d_len, note_name);
|
|
|
+ size = sizeof(Elf64_Nhdr);
|
|
|
+ size += roundup(strlen(name) + 1, 4);
|
|
|
+ size += roundup(d_len, 4);
|
|
|
+
|
|
|
+ return size;
|
|
|
+}
|
|
|
+
|
|
|
+static inline size_t nt_size(Elf64_Word type, int d_len)
|
|
|
+{
|
|
|
+ return nt_size_name(d_len, nt_name(type));
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -374,6 +398,29 @@ static void *fill_cpu_elf_notes(void *ptr, int cpu, struct save_area *sa)
|
|
|
return ptr;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Calculate size of ELF notes per cpu
|
|
|
+ */
|
|
|
+static size_t get_cpu_elf_notes_size(void)
|
|
|
+{
|
|
|
+ struct save_area *sa = NULL;
|
|
|
+ size_t size;
|
|
|
+
|
|
|
+ size = nt_size(NT_PRSTATUS, sizeof(struct elf_prstatus));
|
|
|
+ size += nt_size(NT_PRFPREG, sizeof(elf_fpregset_t));
|
|
|
+ size += nt_size(NT_S390_TIMER, sizeof(sa->timer));
|
|
|
+ size += nt_size(NT_S390_TODCMP, sizeof(sa->todcmp));
|
|
|
+ size += nt_size(NT_S390_TODPREG, sizeof(sa->todpreg));
|
|
|
+ size += nt_size(NT_S390_CTRS, sizeof(sa->ctrs));
|
|
|
+ size += nt_size(NT_S390_PREFIX, sizeof(sa->prefix));
|
|
|
+ if (MACHINE_HAS_VX) {
|
|
|
+ size += nt_size(NT_S390_VXRS_HIGH, sizeof(sa->vxrs_high));
|
|
|
+ size += nt_size(NT_S390_VXRS_LOW, sizeof(sa->vxrs_low));
|
|
|
+ }
|
|
|
+
|
|
|
+ return size;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Initialize prpsinfo note (new kernel)
|
|
|
*/
|
|
@@ -429,6 +476,30 @@ static void *nt_vmcoreinfo(void *ptr)
|
|
|
return nt_init_name(ptr, 0, vmcoreinfo, size, "VMCOREINFO");
|
|
|
}
|
|
|
|
|
|
+static size_t nt_vmcoreinfo_size(void)
|
|
|
+{
|
|
|
+ const char *name = "VMCOREINFO";
|
|
|
+ char nt_name[11];
|
|
|
+ Elf64_Nhdr note;
|
|
|
+ void *addr;
|
|
|
+
|
|
|
+ if (copy_oldmem_kernel(&addr, &S390_lowcore.vmcore_info, sizeof(addr)))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (copy_oldmem_kernel(¬e, addr, sizeof(note)))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ memset(nt_name, 0, sizeof(nt_name));
|
|
|
+ if (copy_oldmem_kernel(nt_name, addr + sizeof(note),
|
|
|
+ sizeof(nt_name) - 1))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (strcmp(nt_name, name) != 0)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ return nt_size_name(note.n_descsz, name);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Initialize final note (needed for /proc/vmcore code)
|
|
|
*/
|
|
@@ -539,6 +610,27 @@ static void *notes_init(Elf64_Phdr *phdr, void *ptr, u64 notes_offset)
|
|
|
return ptr;
|
|
|
}
|
|
|
|
|
|
+static size_t get_elfcorehdr_size(int mem_chunk_cnt)
|
|
|
+{
|
|
|
+ size_t size;
|
|
|
+
|
|
|
+ size = sizeof(Elf64_Ehdr);
|
|
|
+ /* PT_NOTES */
|
|
|
+ size += sizeof(Elf64_Phdr);
|
|
|
+ /* nt_prpsinfo */
|
|
|
+ size += nt_size(NT_PRPSINFO, sizeof(struct elf_prpsinfo));
|
|
|
+ /* regsets */
|
|
|
+ size += get_cpu_cnt() * get_cpu_elf_notes_size();
|
|
|
+ /* nt_vmcoreinfo */
|
|
|
+ size += nt_vmcoreinfo_size();
|
|
|
+ /* nt_final */
|
|
|
+ size += sizeof(Elf64_Nhdr);
|
|
|
+ /* PT_LOADS */
|
|
|
+ size += mem_chunk_cnt * sizeof(Elf64_Phdr);
|
|
|
+
|
|
|
+ return size;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Create ELF core header (new kernel)
|
|
|
*/
|
|
@@ -566,8 +658,8 @@ int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size)
|
|
|
|
|
|
mem_chunk_cnt = get_mem_chunk_cnt();
|
|
|
|
|
|
- alloc_size = 0x1000 + get_cpu_cnt() * 0x4a0 +
|
|
|
- mem_chunk_cnt * sizeof(Elf64_Phdr);
|
|
|
+ alloc_size = get_elfcorehdr_size(mem_chunk_cnt);
|
|
|
+
|
|
|
hdr = kzalloc_panic(alloc_size);
|
|
|
/* Init elf header */
|
|
|
ptr = ehdr_init(hdr, mem_chunk_cnt);
|