summaryrefslogtreecommitdiff
path: root/util/mkelfImage/main
diff options
context:
space:
mode:
Diffstat (limited to 'util/mkelfImage/main')
-rw-r--r--util/mkelfImage/main/Makefile18
-rw-r--r--util/mkelfImage/main/mkelfImage.c663
-rw-r--r--util/mkelfImage/main/mkelfImage.man166
3 files changed, 847 insertions, 0 deletions
diff --git a/util/mkelfImage/main/Makefile b/util/mkelfImage/main/Makefile
new file mode 100644
index 0000000000..403b0a4245
--- /dev/null
+++ b/util/mkelfImage/main/Makefile
@@ -0,0 +1,18 @@
+MKELF_OBJS=$(OBJDIR)/main/mkelfImage.o \
+ $(OBJDIR)/linux-i386/mkelf-linux-i386.o \
+ $(OBJDIR)/linux-ia64/mkelf-linux-ia64.o
+
+$(OBJDIR)/sbin/mkelfImage: $(MKELF_OBJS) $(DEPS)
+ $(MKDIR) -p $(@D)
+ $(HOST_CC) $(HOST_CFLAGS) $(MKELF_OBJS) -o $@ $(LIBS)
+
+$(OBJDIR)/main/mkelfImage.o: main/mkelfImage.c include/mkelfImage.h $(DEPS)
+ $(MKDIR) -p $(@D)
+ $(HOST_CC) $(HOST_CFLAGS) -c $< -o $@
+
+$(OBJDIR)/man/man8/mkelfImage.8: main/mkelfImage.man
+ $(MKDIR) -p $(@D)
+ $(SED) \
+ -e 's,^.TH MKELFIMAGE 8 "RELEASE_DATE" "VERSION"$$,.TH MKELFIMAGE 8 "$(RELEASE_DATE)" "$(VERSION)",' \
+ $< > $@
+ $(CP) $< $@
diff --git a/util/mkelfImage/main/mkelfImage.c b/util/mkelfImage/main/mkelfImage.c
new file mode 100644
index 0000000000..bb318b3f37
--- /dev/null
+++ b/util/mkelfImage/main/mkelfImage.c
@@ -0,0 +1,663 @@
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <getopt.h>
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif
+#include "elf.h"
+#include "elf_boot.h"
+#include "mkelfImage.h"
+
+static struct file_type file_type[] = {
+ { "linux-i386", linux_i386_probe, linux_i386_mkelf, linux_i386_usage },
+ { "bzImage-i386", bzImage_i386_probe, linux_i386_mkelf, linux_i386_usage },
+ { "vmlinux-i386", vmlinux_i386_probe, linux_i386_mkelf, linux_i386_usage },
+ { "linux-ia64", linux_ia64_probe, linux_ia64_mkelf, linux_ia64_usage },
+};
+static const int file_types = sizeof(file_type)/sizeof(file_type[0]);
+
+void die(char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ exit(1);
+}
+
+
+
+/**************************************************************************
+IPCHKSUM - Checksum IP Header
+**************************************************************************/
+uint16_t ipchksum(const void *data, unsigned long length)
+{
+ unsigned long sum;
+ unsigned long i;
+ const uint8_t *ptr;
+
+ /* In the most straight forward way possible,
+ * compute an ip style checksum.
+ */
+ sum = 0;
+ ptr = data;
+ for(i = 0; i < length; i++) {
+ unsigned long value;
+ value = ptr[i];
+ if (i & 1) {
+ value <<= 8;
+ }
+ /* Add the new value */
+ sum += value;
+ /* Wrap around the carry */
+ if (sum > 0xFFFF) {
+ sum = (sum + (sum >> 16)) & 0xFFFF;
+ }
+ }
+ return (~cpu_to_le16(sum)) & 0xFFFF;
+}
+
+uint16_t add_ipchksums(unsigned long offset, uint16_t sum, uint16_t new)
+{
+ unsigned long checksum;
+ sum = ~sum & 0xFFFF;
+ new = ~new & 0xFFFF;
+ if (offset & 1) {
+ /* byte swap the sum if it came from an odd offset
+ * since the computation is endian independant this
+ * works.
+ */
+ new = bswap_16(new);
+ }
+ checksum = sum + new;
+ if (checksum > 0xFFFF) {
+ checksum -= 0xFFFF;
+ }
+ return (~checksum) & 0xFFFF;
+}
+
+void *xmalloc(size_t size, const char *name)
+{
+ void *buf;
+ buf = malloc(size);
+ if (!buf) {
+ die("Cannot malloc %ld bytes to hold %s: %s\n",
+ size + 0UL, name, strerror(errno));
+ }
+ return buf;
+}
+
+void *xrealloc(void *ptr, size_t size, const char *name)
+{
+ void *buf;
+ buf = realloc(ptr, size);
+ if (!buf) {
+ die("Cannot realloc %ld bytes to hold %s: %s\n",
+ size + 0UL, name, strerror(errno));
+ }
+ return buf;
+}
+
+
+char *slurp_file(const char *filename, off_t *r_size)
+{
+ int fd;
+ char *buf;
+ off_t size, progress;
+ ssize_t result;
+ struct stat stats;
+
+
+ if (!filename) {
+ *r_size = 0;
+ return 0;
+ }
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ die("Cannot open `%s': %s\n",
+ filename, strerror(errno));
+ }
+ result = fstat(fd, &stats);
+ if (result < 0) {
+ die("Cannot stat: %s: %s\n",
+ filename, strerror(errno));
+ }
+ size = stats.st_size;
+ *r_size = size;
+ buf = xmalloc(size, filename);
+ progress = 0;
+ while(progress < size) {
+ result = read(fd, buf + progress, size - progress);
+ if (result < 0) {
+ if ((errno == EINTR) || (errno == EAGAIN))
+ continue;
+ die("read on %s of %ld bytes failed: %s\n",
+ filename, (size - progress)+ 0UL, strerror(errno));
+ }
+ progress += result;
+ }
+ result = close(fd);
+ if (result < 0) {
+ die("Close of %s failed: %s\n",
+ filename, strerror(errno));
+ }
+ return buf;
+}
+
+#if HAVE_ZLIB_H
+char *slurp_decompress_file(const char *filename, off_t *r_size)
+{
+ gzFile fp;
+ int errnum;
+ const char *msg;
+ char *buf;
+ off_t size, allocated;
+ ssize_t result;
+
+ if (!filename) {
+ *r_size = 0;
+ return 0;
+ }
+ fp = gzopen(filename, "rb");
+ if (fp == 0) {
+ msg = gzerror(fp, &errnum);
+ if (errnum == Z_ERRNO) {
+ msg = strerror(errno);
+ }
+ die("Cannot open `%s': %s\n", filename, msg);
+ }
+ size = 0;
+ allocated = 65536;
+ buf = xmalloc(allocated, filename);
+ do {
+ if (size == allocated) {
+ allocated <<= 1;
+ buf = xrealloc(buf, allocated, filename);
+ }
+ result = gzread(fp, buf + size, allocated - size);
+ if (result < 0) {
+ if ((errno == EINTR) || (errno == EAGAIN))
+ continue;
+
+ msg = gzerror(fp, &errnum);
+ if (errnum == Z_ERRNO) {
+ msg = strerror(errno);
+ }
+ die ("read on %s of %ld bytes failed: %s\n",
+ filename, (allocated - size) + 0UL, msg);
+ }
+ size += result;
+ } while(result > 0);
+ result = gzclose(fp);
+ if (result != Z_OK) {
+ msg = gzerror(fp, &errnum);
+ if (errnum == Z_ERRNO) {
+ msg = strerror(errno);
+ }
+ die ("Close of %s failed: %s\n", filename, msg);
+ }
+ *r_size = size;
+ return buf;
+}
+#else
+char *slurp_decompress_file(const char *filename, off_t *r_size)
+{
+ return slurp_file(filename, r_size);
+}
+#endif
+
+struct memelfphdr *add_program_headers(struct memelfheader *ehdr, int count)
+{
+ struct memelfphdr *phdr;
+ int i;
+ ehdr->e_phnum = count;
+ ehdr->e_phdr = phdr = xmalloc(count *sizeof(*phdr), "Program headers");
+ /* Set the default values */
+ for(i = 0; i < count; i++) {
+ phdr[i].p_type = PT_LOAD;
+ phdr[i].p_flags = PF_R | PF_W | PF_X;
+ phdr[i].p_vaddr = 0;
+ phdr[i].p_paddr = 0;
+ phdr[i].p_filesz = 0;
+ phdr[i].p_memsz = 0;
+ phdr[i].p_data = 0;
+ }
+ return phdr;
+}
+
+struct memelfnote *add_notes(struct memelfheader *ehdr, int count)
+{
+ struct memelfnote *notes;
+ ehdr->e_notenum = count;
+ ehdr->e_notes = notes = xmalloc(count *sizeof(*notes), "Notes");
+ memset(notes, 0, count *sizeof(*notes));
+ return notes;
+}
+
+static int sizeof_notes(struct memelfnote *note, int notes)
+{
+ int size;
+ int i;
+
+ size = 0;
+ for(i = 0; i < notes; i++) {
+ size += sizeof(Elf_Nhdr);
+ size += roundup(strlen(note[i].n_name)+1, 4);
+ size += roundup(note[i].n_descsz, 4);
+ }
+ return size;
+}
+
+static uint16_t cpu_to_elf16(struct memelfheader *ehdr, uint16_t val)
+{
+ if (ehdr->ei_data == ELFDATA2LSB) {
+ return cpu_to_le16(val);
+ }
+ else if (ehdr->ei_data == ELFDATA2MSB) {
+ return cpu_to_be16(val);
+ }
+ die("Uknown elf layout in cpu_to_elf16");
+ return 0;
+}
+
+static uint32_t cpu_to_elf32(struct memelfheader *ehdr, uint32_t val)
+{
+ if (ehdr->ei_data == ELFDATA2LSB) {
+ return cpu_to_le32(val);
+ }
+ else if (ehdr->ei_data == ELFDATA2MSB) {
+ return cpu_to_be32(val);
+ }
+ die("Uknown elf layout in cpu_to_elf32");
+ return 0;
+}
+
+static uint64_t cpu_to_elf64(struct memelfheader *ehdr, uint64_t val)
+{
+ if (ehdr->ei_data == ELFDATA2LSB) {
+ return cpu_to_le64(val);
+ }
+ else if (ehdr->ei_data == ELFDATA2MSB) {
+ return cpu_to_be64(val);
+ }
+ die("Uknown elf layout in cpu_to_elf64");
+ return 0;
+}
+
+static void serialize_notes(char *buf, struct memelfheader *ehdr)
+{
+ struct Elf_Nhdr hdr;
+ struct memelfnote *note;
+ int notes;
+ size_t size, offset;
+ int i;
+
+ /* Clear the buffer */
+ note = ehdr->e_notes;
+ notes = ehdr->e_notenum;
+ size = sizeof_notes(note, notes);
+ memset(buf, 0, size);
+
+ /* Write the Elf Notes */
+ offset = 0;
+ for(i = 0; i < notes; i++) {
+ /* Compute the note header */
+ size_t n_namesz;
+ n_namesz = strlen(note[i].n_name) +1;
+ hdr.n_namesz = cpu_to_elf32(ehdr, n_namesz);
+ hdr.n_descsz = cpu_to_elf32(ehdr, note[i].n_descsz);
+ hdr.n_type = cpu_to_elf32(ehdr, note[i].n_type);
+
+ /* Copy the note into the buffer */
+ memcpy(buf + offset, &hdr, sizeof(hdr));
+ offset += sizeof(hdr);
+ memcpy(buf + offset, note[i].n_name, n_namesz);
+ offset += roundup(n_namesz, 4);
+ memcpy(buf + offset, note[i].n_desc, note[i].n_descsz);
+ offset += roundup(note[i].n_descsz, 4);
+
+ }
+}
+static void serialize_ehdr(char *buf, struct memelfheader *ehdr)
+{
+ if (ehdr->ei_class == ELFCLASS32) {
+ Elf32_Ehdr *hdr = (Elf32_Ehdr *)buf;
+ hdr->e_ident[EI_MAG0] = ELFMAG0;
+ hdr->e_ident[EI_MAG1] = ELFMAG1;
+ hdr->e_ident[EI_MAG2] = ELFMAG2;
+ hdr->e_ident[EI_MAG3] = ELFMAG3;
+ hdr->e_ident[EI_CLASS] = ehdr->ei_class;
+ hdr->e_ident[EI_DATA] = ehdr->ei_data;
+ hdr->e_ident[EI_VERSION] = EV_CURRENT;
+ hdr->e_type = cpu_to_elf16(ehdr, ehdr->e_type);
+ hdr->e_machine = cpu_to_elf16(ehdr, ehdr->e_machine);
+ hdr->e_version = cpu_to_elf32(ehdr, EV_CURRENT);
+ hdr->e_entry = cpu_to_elf32(ehdr, ehdr->e_entry);
+ hdr->e_phoff = cpu_to_elf32(ehdr, sizeof(*hdr));
+ hdr->e_shoff = cpu_to_elf32(ehdr, 0);
+ hdr->e_flags = cpu_to_elf32(ehdr, ehdr->e_flags);
+ hdr->e_ehsize = cpu_to_elf16(ehdr, sizeof(*hdr));
+ hdr->e_phentsize = cpu_to_elf16(ehdr, sizeof(Elf32_Phdr));
+ hdr->e_phnum = cpu_to_elf16(ehdr, ehdr->e_phnum);
+ hdr->e_shentsize = cpu_to_elf16(ehdr, 0);
+ hdr->e_shnum = cpu_to_elf16(ehdr, 0);
+ hdr->e_shstrndx = cpu_to_elf16(ehdr, 0);
+ }
+ else if (ehdr->ei_class == ELFCLASS64) {
+ Elf64_Ehdr *hdr = (Elf64_Ehdr *)buf;
+ hdr->e_ident[EI_MAG0] = ELFMAG0;
+ hdr->e_ident[EI_MAG1] = ELFMAG1;
+ hdr->e_ident[EI_MAG2] = ELFMAG2;
+ hdr->e_ident[EI_MAG3] = ELFMAG3;
+ hdr->e_ident[EI_CLASS] = ehdr->ei_class;
+ hdr->e_ident[EI_DATA] = ehdr->ei_data;
+ hdr->e_ident[EI_VERSION] = EV_CURRENT;
+ hdr->e_type = cpu_to_elf16(ehdr, ehdr->e_type);
+ hdr->e_machine = cpu_to_elf16(ehdr, ehdr->e_machine);
+ hdr->e_version = cpu_to_elf32(ehdr, EV_CURRENT);
+ hdr->e_entry = cpu_to_elf64(ehdr, ehdr->e_entry);
+ hdr->e_phoff = cpu_to_elf64(ehdr, sizeof(*hdr));
+ hdr->e_shoff = cpu_to_elf64(ehdr, 0);
+ hdr->e_flags = cpu_to_elf32(ehdr, ehdr->e_flags);
+ hdr->e_ehsize = cpu_to_elf16(ehdr, sizeof(*hdr));
+ hdr->e_phentsize = cpu_to_elf16(ehdr, sizeof(Elf64_Phdr));
+ hdr->e_phnum = cpu_to_elf16(ehdr, ehdr->e_phnum);
+ hdr->e_shentsize = cpu_to_elf16(ehdr, 0);
+ hdr->e_shnum = cpu_to_elf16(ehdr, 0);
+ hdr->e_shstrndx = cpu_to_elf16(ehdr, 0);
+ }
+ else die("Uknown elf class: %x\n", ehdr->ei_class);
+}
+static void serialize_phdrs(char *buf, struct memelfheader *ehdr, size_t note_size)
+{
+ int i;
+ size_t offset, note_offset;
+ if (ehdr->ei_class == ELFCLASS32) {
+ Elf32_Phdr *phdr = (Elf32_Phdr *)buf;
+ note_offset =
+ sizeof(Elf32_Ehdr) + (sizeof(Elf32_Phdr)*ehdr->e_phnum);
+ offset = note_offset + note_size;
+ for(i = 0; i < ehdr->e_phnum; i++) {
+ struct memelfphdr *hdr = ehdr->e_phdr + i;
+ phdr[i].p_type = cpu_to_elf32(ehdr, hdr->p_type);
+ phdr[i].p_offset = cpu_to_elf32(ehdr, offset);
+ phdr[i].p_vaddr = cpu_to_elf32(ehdr, hdr->p_vaddr);
+ phdr[i].p_paddr = cpu_to_elf32(ehdr, hdr->p_paddr);
+ phdr[i].p_filesz = cpu_to_elf32(ehdr, hdr->p_filesz);
+ phdr[i].p_memsz = cpu_to_elf32(ehdr, hdr->p_memsz);
+ phdr[i].p_flags = cpu_to_elf32(ehdr, hdr->p_flags);
+ phdr[i].p_align = cpu_to_elf32(ehdr, 0);
+ if (phdr[i].p_type == PT_NOTE) {
+ phdr[i].p_filesz = cpu_to_elf32(ehdr, note_size);
+ phdr[i].p_memsz = cpu_to_elf32(ehdr, note_size);
+ phdr[i].p_offset = cpu_to_elf32(ehdr, note_offset);
+ } else {
+ offset += hdr->p_filesz;
+ }
+ }
+ }
+ else if (ehdr->ei_class == ELFCLASS64) {
+ Elf64_Phdr *phdr = (Elf64_Phdr *)buf;
+ note_offset =
+ sizeof(Elf64_Ehdr) + (sizeof(Elf64_Phdr)*ehdr->e_phnum);
+ offset = note_offset + note_size;
+ for(i = 0; i < ehdr->e_phnum; i++) {
+ struct memelfphdr *hdr = ehdr->e_phdr + i;
+ phdr[i].p_type = cpu_to_elf32(ehdr, hdr->p_type);
+ phdr[i].p_flags = cpu_to_elf32(ehdr, hdr->p_flags);
+ phdr[i].p_offset = cpu_to_elf64(ehdr, offset);
+ phdr[i].p_vaddr = cpu_to_elf64(ehdr, hdr->p_vaddr);
+ phdr[i].p_paddr = cpu_to_elf64(ehdr, hdr->p_paddr);
+ phdr[i].p_filesz = cpu_to_elf64(ehdr, hdr->p_filesz);
+ phdr[i].p_memsz = cpu_to_elf64(ehdr, hdr->p_memsz);
+ phdr[i].p_align = cpu_to_elf64(ehdr, 0);
+ if (phdr[i].p_type == PT_NOTE) {
+ phdr[i].p_filesz = cpu_to_elf64(ehdr, note_size);
+ phdr[i].p_memsz = cpu_to_elf64(ehdr, note_size);
+ phdr[i].p_offset = cpu_to_elf64(ehdr, note_offset);
+ } else {
+ offset += hdr->p_filesz;
+ }
+ }
+ }
+ else {
+ die("Unknwon elf class: %x\n", ehdr->ei_class);
+ }
+}
+
+static void write_buf(int fd, char *buf, size_t size)
+{
+ size_t progress = 0;
+ ssize_t result;
+ while(progress < size) {
+ result = write(fd, buf + progress, size - progress);
+ if (result < 0) {
+ if ((errno == EAGAIN) || (errno == EINTR)) {
+ continue;
+ }
+ die ("write of %ld bytes failed: %s\n",
+ size - progress, strerror(errno));
+ }
+ progress += result;
+ }
+}
+static void write_elf(struct memelfheader *ehdr, char *output)
+{
+ size_t ehdr_size;
+ size_t phdr_size;
+ size_t note_size;
+ size_t size;
+ uint16_t checksum;
+ size_t bytes;
+ char *buf;
+ int result, fd;
+ int i;
+ /* Prep for adding the checksum */
+ for(i = 0; i < ehdr->e_notenum; i++) {
+ if ((memcmp(ehdr->e_notes[i].n_name, "ELFBoot", 8) == 0) &&
+ (ehdr->e_notes[i].n_type == EIN_PROGRAM_CHECKSUM)) {
+ ehdr->e_notes[i].n_desc = &checksum;
+ ehdr->e_notes[i].n_descsz = 2;
+ }
+ }
+ /* Compute the sizes */
+ ehdr_size = 0;
+ phdr_size = 0;
+ note_size = 0;
+ if (ehdr->e_notenum) {
+ note_size = sizeof_notes(ehdr->e_notes, ehdr->e_notenum);
+ }
+ if (ehdr->ei_class == ELFCLASS32) {
+ ehdr_size = sizeof(Elf32_Ehdr);
+ phdr_size = sizeof(Elf32_Phdr) * ehdr->e_phnum;
+ }
+ else if (ehdr->ei_class == ELFCLASS64) {
+ ehdr_size = sizeof(Elf64_Ehdr);
+ phdr_size = sizeof(Elf64_Phdr) * ehdr->e_phnum;
+ }
+ else {
+ die("Unknown elf class: %x\n", ehdr->ei_class);
+ }
+
+ /* Allocate a buffer to temporarily hold the serialized forms */
+ size = ehdr_size + phdr_size + note_size;
+ buf = xmalloc(size, "Elf Headers");
+ memset(buf, 0, size);
+ serialize_ehdr(buf, ehdr);
+ serialize_phdrs(buf + ehdr_size, ehdr, note_size);
+
+ /* Compute the checksum... */
+ checksum = ipchksum(buf, ehdr_size + phdr_size);
+ bytes = ehdr_size + phdr_size;
+ for(i = 0; i < ehdr->e_phnum; i++) {
+ checksum = add_ipchksums(bytes, checksum,
+ ipchksum(ehdr->e_phdr[i].p_data, ehdr->e_phdr[i].p_filesz));
+ bytes += ehdr->e_phdr[i].p_memsz;
+ }
+
+ /* Compute the final form of the notes */
+ serialize_notes(buf + ehdr_size + phdr_size, ehdr);
+
+ /* Now write the elf image */
+ fd = open(output, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IRGRP | S_IROTH);
+ if (fd < 0) {
+ die("Cannot open ``%s'':%s\n",
+ output, strerror(errno));
+ }
+ write_buf(fd, buf, size);
+ for(i = 0; i < ehdr->e_phnum; i++) {
+ write_buf(fd, ehdr->e_phdr[i].p_data, ehdr->e_phdr[i].p_filesz);
+ }
+ result = close(fd);
+ if (result < 0) {
+ die("Close on %s failed: %s\n",
+ output, strerror(errno));
+ }
+}
+
+static void version(void)
+{
+ printf("mkelfImage " VERSION " released " RELEASE_DATE "\n");
+}
+void usage(void)
+{
+ int i;
+ version();
+ printf(
+ "Usage: mkelfImage [OPTION]... <kernel> <elf_kernel>\n"
+ "Build an ELF bootable kernel image from a normal kernel image\n"
+ "\n"
+ " -h, --help Print this help.\n"
+ " -v, --version Print the version of kexec.\n"
+ " --kernel=<filename> Set the kernel to <filename>\n"
+ " --output=<filename> Output to <filename>\n"
+ " -t, --type=TYPE Specify the new kernel is of <type>.\n"
+ "\n"
+ "Supported kernel types: \n"
+ );
+ for(i = 0; i < file_types; i++) {
+ printf("%s\n", file_type[i].name);
+ file_type[i].usage();
+ }
+ printf("\n");
+}
+
+void error(char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ usage();
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ int opt;
+ int fileind;
+ char *type, *kernel, *output;
+ off_t kernel_size;
+ char *kernel_buf;
+ int result;
+ int i;
+ struct memelfheader hdr;
+
+ static const struct option options[] = {
+ MKELF_OPTIONS
+ { 0, 0, 0, 0 },
+ };
+ static const char short_options[] = MKELF_OPT_STR;
+
+ memset(&hdr, 0, sizeof(hdr));
+ kernel = 0;
+ output = 0;
+
+ /* Get the default type from the program name */
+ type = strrchr(argv[0], '/');
+ if (!type) type = argv[0];
+ if (memcmp(type, "mkelf-", 6) == 0) {
+ type = type + 6;
+ } else {
+ type = 0;
+ }
+ opterr = 0; /* Don't complain about unrecognized options here */
+ while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
+ switch(opt) {
+ case OPT_HELP:
+ usage();
+ return 0;
+ case OPT_VERSION:
+ version();
+ return 0;
+ case OPT_KERNEL:
+ kernel = optarg;
+ break;
+ case OPT_OUTPUT:
+ output = optarg;
+ break;
+ case OPT_TYPE:
+ type = optarg;
+ break;
+ default:
+ break;
+ }
+ }
+ fileind = optind;
+
+ /* Reset getopt for the next pass */
+ opterr = 1;
+ optind = 1;
+
+ if (argc - fileind > 0) {
+ kernel = argv[fileind++];
+ }
+ if (argc - fileind > 0) {
+ output = argv[fileind++];
+ }
+ if (!kernel) {
+ error("No kernel specified!\n");
+ }
+ if (!output) {
+ error("No output file specified!\n");
+ }
+ if (argc - fileind > 0) {
+ error("%d extra options specified!\n", argc - fileind);
+ }
+
+ /* slurp in the input kernel */
+ kernel_buf = slurp_decompress_file(kernel, &kernel_size);
+
+ /* Find/verify the kernel type */
+ for(i = 0; i < file_types; i++) {
+ char *reason;
+ if (type && (strcmp(type, file_type[i].name) != 0)) {
+ continue;
+ }
+ reason = file_type[i].probe(kernel_buf, kernel_size);
+ if (reason == 0) {
+ break;
+ }
+ if (type) {
+ die("Not %s: %s\n", type, reason);
+ }
+ }
+ if (i == file_types) {
+ die("Can not determine the file type of %s\n", kernel);
+ }
+ result = file_type[i].mkelf(argc, argv, &hdr, kernel_buf, kernel_size);
+ if (result < 0) {
+ die("Cannot create %s result: %d\n", output, result);
+ }
+ /* open the output file */
+ write_elf(&hdr, output);
+ return 0;
+}
diff --git a/util/mkelfImage/main/mkelfImage.man b/util/mkelfImage/main/mkelfImage.man
new file mode 100644
index 0000000000..f3f50d56d0
--- /dev/null
+++ b/util/mkelfImage/main/mkelfImage.man
@@ -0,0 +1,166 @@
+.\" Automatically generated by Pod::Man v1.3, Pod::Parser v1.13
+.\" But now manually maintained
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sh \" Subsection heading
+.br
+.if t .Sp
+.ne 5
+.PP
+\fB\\$1\fR
+.PP
+..
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+
+.fi
+..
+.\" Set up some character translations and predefined strings. \*(-- will
+.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
+.\" double quote, and \*(R" will give a right double quote. | will give a
+.\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to
+.\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C'
+.\" expand to `' in nroff, nothing in troff, for use with C<>.
+.tr \(*W-|\(bv\*(Tr
+.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
+.ie n \{\
+. ds -- \(*W-
+. ds PI pi
+. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
+. ds L" ""
+. ds R" ""
+. ds C` ""
+. ds C' ""
+'br\}
+.el\{\
+. ds -- \|\(em\|
+. ds PI \(*p
+. ds L" ``
+. ds R" ''
+'br\}
+.\"
+.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
+.\" entries marked with X<> in POD. Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.if \nF \{\
+. de IX
+. tm Index:\\$1\t\\n%\t"\\$2"
+..
+. nr % 0
+. rr F
+.\}
+.\"
+.\" For nroff, turn off justification. Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.hy 0
+.if n .na
+.\"
+.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
+.\" Fear. Run. Save yourself. No user-serviceable parts.
+. \" fudge factors for nroff and troff
+.if n \{\
+. ds #H 0
+. ds #V .8m
+. ds #F .3m
+. ds #[ \f1
+. ds #] \fP
+.\}
+.if t \{\
+. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
+. ds #V .6m
+. ds #F 0
+. ds #[ \&
+. ds #] \&
+.\}
+. \" simple accents for nroff and troff
+.if n \{\
+. ds ' \&
+. ds ` \&
+. ds ^ \&
+. ds , \&
+. ds ~ ~
+. ds /
+.\}
+.if t \{\
+. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
+. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
+. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
+. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
+. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
+. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
+.\}
+. \" troff and (daisy-wheel) nroff accents
+.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
+.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
+.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
+.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
+.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
+.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
+.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
+.ds ae a\h'-(\w'a'u*4/10)'e
+.ds Ae A\h'-(\w'A'u*4/10)'E
+. \" corrections for vroff
+.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
+.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
+. \" for low resolution devices (crt and lpr)
+.if \n(.H>23 .if \n(.V>19 \
+\{\
+. ds : e
+. ds 8 ss
+. ds o a
+. ds d- d\h'-1'\(ga
+. ds D- D\h'-1'\(hy
+. ds th \o'bp'
+. ds Th \o'LP'
+. ds ae ae
+. ds Ae AE
+.\}
+.rm #[ #] #H #V #F C
+.\" ========================================================================
+.\"
+.IX Title "MKELFIMAGE 8"
+.TH MKELFIMAGE 8 "RELEASE_DATE" "VERSION"
+.UC
+.SH "NAME"
+mkelfImage \- make an elf network bootable image for linux
+.SH "SYNOPSIS"
+.IX Header "SYNOPSIS"
+\&\fBmkelfImage\fR [\-\-command\-line=\fIcommand line\fR] [\-\-kernel=\fIpath to vmlinux\fR] [\-\-ramdisk=\fIpath to ramdisk\fR] [\-\-output=\fIfile\fR] [\-\-ramdisk\-base=<start addr>]
+.SH "DESCRIPTION"
+.IX Header "DESCRIPTION"
+\&\fBmkelfImage\fR is a program that makes a elf boot image for linux kernel
+images. The image should work with any i386 multiboot compliant boot loader,
+an \s-1ELF\s0 bootloader that passes no options, a loader compliant with the linuxBIOS
+elf booting spec or with the linux kexec kernel patch. A key feature
+here is that nothing relies upon \s-1BIOS\s0 calls, but they are made when
+necessary. This is useful for systems running linuxbios.
+.SH "BUGS"
+.IX Header "BUGS"
+Not all kernel parameters can be passed with the multiboot image format.
+ip configuration is not automatically passed to a node.
+The ramdisk base is hard coded to 8MB by default.
+This man page need to be updated.
+.SH "SEE ALSO"
+.IX Header "SEE ALSO"
+The kexec kernel patch.
+LinuxBIOS.
+Etherboot.
+The multiboot standard.
+.SH "COPYRIGHT"
+.IX Header "COPYRIGHT"
+mkelfImage is under the \s-1GNU\s0 Public License version 2
+.SH "AUTHOR"
+.IX Header "AUTHOR"
+Eric Biederman <ebiederman@lnxi.com>