diff options
author | Magnus Damm <magnus@valinux.co.jp> | 2006-11-22 00:01:47 +0900 |
---|---|---|
committer | Simon Horman <horms@verge.net.au> | 2006-11-27 12:25:12 +0900 |
commit | c80198e78ce26783e092645b9ac8587e1374f22f (patch) | |
tree | 5ca85a6bb221c09d6855eb4a6ad4fb04c5e0cc01 /kexec/crashdump-elf.c | |
parent | f8b0123231e9ca2cb124aa290b9df7785ff135e0 (diff) |
kexec-tools: Introduce crashdump-elf.c and crash_create_elf32/64_headers() V2
kexec-tools: Introduce crashdump-elf.c and crash_create_elf32/64_headers() V2
This patch adds the new file crashdump-elf.c that implements a single generic
function which is used to create elf headers. The file gets included twice by
crash.c to create two functions from the same source. These two functions are
named crash_create_elf32_headers() and crash_create_elf64_headers().
The new code differs from prepare_crash_memory_elf32/64_headers() in the sense
that both allocation and setup now are done in the same function.
This patch only adds the new code, following patches make sure the different
architecture-specific files make use of the new code.
This version contains a new comment as suggested by Vivek, together with
that the alignment now is fixed at 1024 regardless of architecture. The cpu
elf note callback code has been slightly reworked to become cleaner. Also,
FUNCTION has been renamed to FUNC.
Signed-off-by: Magnus Damm <magnus@valinux.co.jp>
Removed trainling whitespace
Signed-off-by: Simon Horman <horms@verge.net.au>
Diffstat (limited to 'kexec/crashdump-elf.c')
-rw-r--r-- | kexec/crashdump-elf.c | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/kexec/crashdump-elf.c b/kexec/crashdump-elf.c new file mode 100644 index 0000000..9e3121f --- /dev/null +++ b/kexec/crashdump-elf.c @@ -0,0 +1,184 @@ + +#if !defined(FUNC) || !defined(EHDR) || !defined(PHDR) +#error FUNC, EHDR and PHDR must be defined +#endif + +/* Prepares the crash memory headers and stores in supplied buffer. */ +int FUNC(struct kexec_info *info, + struct crash_elf_info *elf_info, + struct memory_range *range, int ranges, + void **buf, unsigned long *size) +{ + EHDR *elf; + PHDR *phdr; + int i, sz; + char *bufp; + long int nr_cpus = 0; + int align = 1024; + uint64_t notes_addr, notes_len; + int (*get_note_info)(int cpu, uint64_t *addr, uint64_t *len); + + nr_cpus = sysconf(_SC_NPROCESSORS_CONF); + if (nr_cpus < 0) { + return -1; + } + + sz = sizeof(EHDR) + nr_cpus * sizeof(PHDR) + ranges * sizeof(PHDR); + + /* + * Certain architectures such as x86_64 and ia64 require a separate + * PT_LOAD program header for the kernel. This is controlled through + * info->kern_size. + * + * The separate PT_LOAD program header is required either because the + * kernel is mapped at a different location than the rest of the + * physical memory or because we need to support relocatable kernels. + * Or both as on x86_64. + * + * In the relocatable kernel case this PT_LOAD segment is used to tell + * where the kernel was actually loaded which may be different from + * the load address present in the vmlinux file. + * + * The extra kernel PT_LOAD program header results in a vmcore file + * which is larger than the size of the physical memory. This is + * because the memory for the kernel is present both in the kernel + * PT_LOAD program header and in the physical RAM program headers. + */ + + if (info->kern_size) { + sz += sizeof(PHDR); + } + + sz += align - 1; + sz &= ~(align - 1); + + bufp = xmalloc(sz); + memset(bufp, 0, sz); + + *buf = bufp; + *size = sz; + + /* Setup ELF Header*/ + elf = (EHDR *) bufp; + bufp += sizeof(EHDR); + memcpy(elf->e_ident, ELFMAG, SELFMAG); + elf->e_ident[EI_CLASS] = elf_info->class; + elf->e_ident[EI_DATA] = elf_info->data; + elf->e_ident[EI_VERSION]= EV_CURRENT; + elf->e_ident[EI_OSABI] = ELFOSABI_NONE; + memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); + elf->e_type = ET_CORE; + elf->e_machine = elf_info->machine; + elf->e_version = EV_CURRENT; + elf->e_entry = 0; + elf->e_phoff = sizeof(EHDR); + elf->e_shoff = 0; + elf->e_flags = 0; + elf->e_ehsize = sizeof(EHDR); + elf->e_phentsize= sizeof(PHDR); + elf->e_phnum = 0; + elf->e_shentsize= 0; + elf->e_shnum = 0; + elf->e_shstrndx = 0; + + /* Default way to get crash notes is by get_crash_notes_per_cpu() */ + + get_note_info = elf_info->get_note_info; + if (!get_note_info) + get_note_info = get_crash_notes_per_cpu; + + /* PT_NOTE program headers. One per cpu */ + + for (i = 0; i < nr_cpus; i++) { + if (get_note_info(i, ¬es_addr, ¬es_len) < 0) { + /* This cpu is not present. Skip it. */ + continue; + } + + phdr = (PHDR *) bufp; + bufp += sizeof(PHDR); + phdr->p_type = PT_NOTE; + phdr->p_flags = 0; + phdr->p_offset = phdr->p_paddr = notes_addr; + phdr->p_vaddr = 0; + phdr->p_filesz = phdr->p_memsz = notes_len; + /* Do we need any alignment of segments? */ + phdr->p_align = 0; + + /* Increment number of program headers. */ + (elf->e_phnum)++; + dfprintf(stdout, "Elf header: p_type = %d, p_offset = 0x%lx " + "p_paddr = 0x%lx p_vaddr = 0x%lx " + "p_filesz = 0x%lx p_memsz = 0x%lx\n", + phdr->p_type, phdr->p_offset, phdr->p_paddr, + phdr->p_vaddr, phdr->p_filesz, phdr->p_memsz); + } + + /* Setup an PT_LOAD type program header for the region where + * Kernel is mapped if info->kern_size is non-zero. + */ + + if (info->kern_size) { + phdr = (PHDR *) bufp; + bufp += sizeof(PHDR); + phdr->p_type = PT_LOAD; + phdr->p_flags = PF_R|PF_W|PF_X; + phdr->p_offset = phdr->p_paddr = info->kern_paddr_start; + phdr->p_vaddr = info->kern_vaddr_start; + phdr->p_filesz = phdr->p_memsz = info->kern_size; + phdr->p_align = 0; + (elf->e_phnum)++; + dfprintf(stdout, "Kernel text Elf header: " + "p_type = %d, p_offset = 0x%lx " + "p_paddr = 0x%lx p_vaddr = 0x%lx " + "p_filesz = 0x%lx p_memsz = 0x%lx\n", + phdr->p_type, phdr->p_offset, phdr->p_paddr, + phdr->p_vaddr, phdr->p_filesz, phdr->p_memsz); + } + + /* Setup PT_LOAD type program header for every system RAM chunk. + * A seprate program header for Backup Region*/ + for (i = 0; i < ranges; i++, range++) { + unsigned long long mstart, mend; + if (range->type != RANGE_RAM) + continue; + mstart = range->start; + mend = range->end; + if (!mstart && !mend) + continue; + phdr = (PHDR *) bufp; + bufp += sizeof(PHDR); + phdr->p_type = PT_LOAD; + phdr->p_flags = PF_R|PF_W|PF_X; + phdr->p_offset = mstart; + + if (mstart == elf_info->backup_src_start + && mend == elf_info->backup_src_end) + phdr->p_offset = info->backup_start; + + /* We already prepared the header for kernel text. Map + * rest of the memory segments to kernel linearly mapped + * memory region. + */ + phdr->p_paddr = mstart; + phdr->p_vaddr = mstart + elf_info->page_offset; + phdr->p_filesz = phdr->p_memsz = mend - mstart + 1; + /* Do we need any alignment of segments? */ + phdr->p_align = 0; + + /* HIGMEM has a virtual address of -1 */ + + if (elf_info->lowmem_limit + && (mend > (elf_info->lowmem_limit - 1))) + phdr->p_vaddr = -1; + + /* Increment number of program headers. */ + (elf->e_phnum)++; + dfprintf(stdout, "Elf header: p_type = %d, p_offset = 0x%lx " + "p_paddr = 0x%lx p_vaddr = 0x%lx " + "p_filesz = 0x%lx p_memsz = 0x%lx\n", + phdr->p_type, phdr->p_offset, phdr->p_paddr, + phdr->p_vaddr, phdr->p_filesz, phdr->p_memsz); + } + return 0; +} |