summaryrefslogtreecommitdiff
path: root/kexec/kexec-elf-exec.c
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2006-07-27 02:36:23 -0600
committerEric W. Biederman <ebiederm@xmission.com>2006-07-27 02:36:23 -0600
commit283261998a9846019d898bc454b363e4aaf3d181 (patch)
treea4af6da4c5a2c6f7669d918c1f07dc68d6aa0ab2 /kexec/kexec-elf-exec.c
kexec-tools-1.101
- Initial import into git - initial nbi image formage support - ppc32 initial register setting fixes. - gzipped multiboot file support
Diffstat (limited to 'kexec/kexec-elf-exec.c')
-rw-r--r--kexec/kexec-elf-exec.c149
1 files changed, 149 insertions, 0 deletions
diff --git a/kexec/kexec-elf-exec.c b/kexec/kexec-elf-exec.c
new file mode 100644
index 0000000..324516c
--- /dev/null
+++ b/kexec/kexec-elf-exec.c
@@ -0,0 +1,149 @@
+#include <limits.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "elf.h"
+#include <boot/elf_boot.h>
+#include "kexec.h"
+#include "kexec-elf.h"
+
+static const int probe_debug = 0;
+
+int build_elf_exec_info(const char *buf, off_t len, struct mem_ehdr *ehdr)
+{
+ struct mem_phdr *phdr, *end_phdr;
+ int result;
+ result = build_elf_info(buf, len, ehdr);
+ if (result < 0) {
+ return result;
+ }
+ if ((ehdr->e_type != ET_EXEC) && (ehdr->e_type != ET_DYN)) {
+ /* not an ELF executable */
+ if (probe_debug) {
+ fprintf(stderr, "Not ELF type ET_EXEC or ET_DYN\n");
+ }
+ return -1;
+ }
+ if (!ehdr->e_phdr) {
+ /* No program header */
+ fprintf(stderr, "No ELF program header\n");
+ return -1;
+ }
+ end_phdr = &ehdr->e_phdr[ehdr->e_phnum];
+ for(phdr = ehdr->e_phdr; phdr != end_phdr; phdr++) {
+ /* Kexec does not support loading interpreters.
+ * In addition this check keeps us from attempting
+ * to kexec ordinay executables.
+ */
+ if (phdr->p_type == PT_INTERP) {
+ fprintf(stderr, "Requires an ELF interpreter\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+int elf_exec_load(const struct mem_ehdr *ehdr, struct kexec_info *info)
+{
+ unsigned long base;
+ int result;
+ int i;
+
+ if (!ehdr->e_phdr) {
+ fprintf(stderr, "No program header?\n");
+ result = -1;
+ goto out;
+ }
+
+ /* If I have a dynamic executable find it's size
+ * and then find a location for it in memory.
+ */
+ base = 0;
+ if (ehdr->e_type == ET_DYN) {
+ unsigned long first, last, align;
+ first = ULONG_MAX;
+ last = 0;
+ align = 0;
+ for(i = 0; i < ehdr->e_phnum; i++) {
+ unsigned long start, stop;
+ struct mem_phdr *phdr;
+ phdr = &ehdr->e_phdr[i];
+ if ((phdr->p_type != PT_LOAD) ||
+ (phdr->p_memsz == 0))
+ {
+ continue;
+ }
+ start = phdr->p_paddr;
+ stop = start + phdr->p_memsz;
+ if (start > first) {
+ start = first;
+ }
+ if (last < stop) {
+ last = stop;
+ }
+ if (align < phdr->p_align) {
+ align = phdr->p_align;
+ }
+ }
+ /* If I can't use the default paddr find a new
+ * hole for the dynamic executable.
+ */
+ if (!valid_memory_range(first, last)) {
+ unsigned long hole;
+ hole = locate_hole(info,
+ last - first + 1, align,
+ 0, elf_max_addr(ehdr), 1);
+ if (hole == ULONG_MAX) {
+ result = -1;
+ goto out;
+ }
+ /* Base is the value that when added
+ * to any virtual address in the file
+ * yields it's load virtual address.
+ */
+ base = hole - first;
+ }
+
+ }
+
+ /* Read in the PT_LOAD segments */
+ for(i = 0; i < ehdr->e_phnum; i++) {
+ struct mem_phdr *phdr;
+ size_t size;
+ phdr = &ehdr->e_phdr[i];
+ if (phdr->p_type != PT_LOAD) {
+ continue;
+ }
+ size = phdr->p_filesz;
+ if (size > phdr->p_memsz) {
+ size = phdr->p_memsz;
+ }
+ add_segment(info,
+ phdr->p_data, size,
+ phdr->p_paddr + base, phdr->p_memsz);
+ }
+ result = 0;
+ out:
+ return result;
+}
+
+void elf_exec_build_load(struct kexec_info *info, struct mem_ehdr *ehdr,
+ const char *buf, off_t len)
+{
+ int result;
+ /* Parse the Elf file */
+ result = build_elf_exec_info(buf, len, ehdr);
+ if (result < 0) {
+ die("ELF exec parse failed\n");
+ }
+
+ /* Load the Elf data */
+ result = elf_exec_load(ehdr, info);
+ if (result < 0) {
+ die("ELF exec load failed\n");
+ }
+}