patch-2.1.44 linux/arch/mips/boot/mkboot.c

Next file: linux/arch/mips/config.in
Previous file: linux/arch/mips/boot/Makefile
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.43/linux/arch/mips/boot/mkboot.c linux/arch/mips/boot/mkboot.c
@@ -0,0 +1,659 @@
+/*
+ * Make a bootable image from a Linux/MIPS kernel.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1996 by Ralf Baechle
+ *
+ * This file is written in plain Kernighan & Ritchie C as it has to run
+ * on all crosscompile hosts no matter how braindead.  This code might
+ * also become part of Milo.  It's therefore important that we don't use
+ * seek because the Seek() call of the Magnum 4000 ARC BIOS is broken.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+/*
+ * Define this for verbose debugging output.
+ */
+#undef VERBOSE
+
+/*
+ * Don't use the host's elf.h - it might be using incompatible defines
+ */
+
+#define EI_NIDENT 16
+
+/*
+ * Basic ELF types.
+ */
+typedef unsigned short Elf32_Half;
+typedef unsigned short Elf32_Section;
+typedef unsigned int Elf32_Word;
+typedef unsigned int Elf32_Addr;
+typedef unsigned int Elf32_Off;
+
+typedef struct
+{
+  unsigned char e_ident[EI_NIDENT];     /* Magic number and other info */
+  Elf32_Half    e_type;                 /* Object file type */
+  Elf32_Half    e_machine;              /* Architecture */
+  Elf32_Word    e_version;              /* Object file version */
+  Elf32_Addr    e_entry;                /* Entry point virtual address */
+  Elf32_Off     e_phoff;                /* Program header table file offset */
+  Elf32_Off     e_shoff;                /* Section header table file offset */
+  Elf32_Word    e_flags;                /* Processor-specific flags */
+  Elf32_Half    e_ehsize;               /* ELF header size in bytes */
+  Elf32_Half    e_phentsize;            /* Program header table entry size */
+  Elf32_Half    e_phnum;                /* Program header table entry count */
+  Elf32_Half    e_shentsize;            /* Section header table entry size */
+  Elf32_Half    e_shnum;                /* Section header table entry count */
+  Elf32_Half    e_shstrndx;             /* Section header string table index */
+} Elf32_Ehdr;
+
+/*
+ * ELF magic number
+ */
+#define ELFMAG          "\177ELF"
+#define SELFMAG         4
+
+#define EI_CLASS        4               /* File class byte index */
+#define ELFCLASSNONE    0               /* Invalid class */
+#define ELFCLASS32      1               /* 32-bit objects */
+#define ELFCLASS64      2               /* 64-bit objects */
+
+#define EI_DATA         5               /* Data encoding byte index */
+#define ELFDATA2LSB     1               /* 2's complement, little endian */
+#define ELFDATA2MSB     2               /* 2's complement, big endian */
+
+#define EI_VERSION      6               /* File version byte index */
+#define EV_CURRENT      1               /* Current version */
+
+/*
+ * Acceptable machine type in e_machine.
+ */
+#define EM_MIPS         8               /* MIPS R3000 big-endian */
+#define EM_MIPS_RS4_BE 10               /* MIPS R4000 big-endian */
+
+/*
+ * The type of ELF file we accept.
+ */
+#define ET_EXEC         2               /* Executable file */
+
+/*
+ * Definition of a single program header structure
+ */
+typedef struct
+{
+  Elf32_Word    p_type;                 /* Segment type */
+  Elf32_Off     p_offset;               /* Segment file offset */
+  Elf32_Addr    p_vaddr;                /* Segment virtual address */
+  Elf32_Addr    p_paddr;                /* Segment physical address */
+  Elf32_Word    p_filesz;               /* Segment size in file */
+  Elf32_Word    p_memsz;                /* Segment size in memory */
+  Elf32_Word    p_flags;                /* Segment flags */
+  Elf32_Word    p_align;                /* Segment alignment */
+} Elf32_Phdr;
+
+/*
+ * Legal values for p_type
+ */
+#define PT_NULL         0               /* Program header table entry unused */
+#define PT_LOAD         1               /* Loadable program segment */
+#define PT_DYNAMIC      2               /* Dynamic linking information */
+#define PT_INTERP       3               /* Program interpreter */
+#define PT_NOTE         4               /* Auxiliary information */
+#define PT_SHLIB        5               /* Reserved */
+#define PT_PHDR         6               /* Entry for header table itself */
+#define PT_NUM          7               /* Number of defined types.  */
+#define PT_LOPROC       0x70000000      /* Start of processor-specific */
+#define PT_HIPROC       0x7fffffff      /* End of processor-specific */
+
+typedef struct
+{
+  Elf32_Word    sh_name;                /* Section name (string tbl index) */
+  Elf32_Word    sh_type;                /* Section type */
+  Elf32_Word    sh_flags;               /* Section flags */
+  Elf32_Addr    sh_addr;                /* Section virtual addr at execution */
+  Elf32_Off     sh_offset;              /* Section file offset */
+  Elf32_Word    sh_size;                /* Section size in bytes */
+  Elf32_Word    sh_link;                /* Link to another section */
+  Elf32_Word    sh_info;                /* Additional section information */
+  Elf32_Word    sh_addralign;           /* Section alignment */
+  Elf32_Word    sh_entsize;             /* Entry size if section holds table */
+} Elf32_Shdr;
+
+typedef struct
+{
+  Elf32_Word    st_name;                /* Symbol name (string tbl index) */
+  Elf32_Addr    st_value;               /* Symbol value */
+  Elf32_Word    st_size;                /* Symbol size */
+  unsigned char st_info;                /* Symbol type and binding */
+  unsigned char st_other;               /* No defined meaning, 0 */
+  Elf32_Section st_shndx;               /* Section index */
+} Elf32_Sym;
+
+/* How to extract and insert information held in the st_info field.  */
+#define ELF32_ST_BIND(val)              (((unsigned char) (val)) >> 4)
+#define ELF32_ST_TYPE(val)              ((val) & 0xf)
+
+/* Legal values for ST_BIND subfield of st_info (symbol binding).  */
+#define STB_GLOBAL      1               /* Global symbol */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
+#define STT_NOTYPE      0               /* Symbol type is unspecified */
+#define STT_OBJECT      1               /* Symbol is a data object */
+#define STT_FUNC        2               /* Symbol is a code object */
+
+static unsigned int
+get_Elf32_Half(unsigned char *p)
+{
+	return p[0] | (p[1] << 8);
+}
+#define get_Elf32_Section(p) get_Elf32_Half(p)
+
+static unsigned int
+get_Elf32_Word(unsigned char *p)
+{
+	return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
+}
+#define get_Elf32_Addr(p) get_Elf32_Word(p)
+#define get_Elf32_Off(p) get_Elf32_Word(p)
+
+static void
+put_byte(p, x)
+	unsigned char *p;
+	unsigned char x;
+{
+	p[0] = x;
+}
+
+static void
+put_half(p, x)
+	unsigned char *p;
+	unsigned short x;
+{
+	p[0] = x & 0xff;
+	p[1] = (x >> 8) & 0xff;
+}
+
+static void
+put_word(p, x)
+	unsigned char *p;
+	unsigned long x;
+{
+	p[0] = x & 0xff;
+	p[1] = (x >> 8) & 0xff;
+	p[2] = (x >> 16) & 0xff;
+	p[3] = (x >> 24) & 0xff;
+}
+
+/*
+ * Swap a program header in.
+ */
+static void
+get_elfph(p, ph)
+	unsigned char *p;
+	Elf32_Phdr *ph;
+{
+	ph->p_type   = get_Elf32_Word(p);
+	ph->p_offset = get_Elf32_Off(p + 4);
+	ph->p_vaddr  = get_Elf32_Addr(p + 8);
+	ph->p_paddr  = get_Elf32_Addr(p + 12);
+	ph->p_filesz = get_Elf32_Word(p + 16);
+	ph->p_memsz  = get_Elf32_Word(p + 20);
+	ph->p_flags  = get_Elf32_Word(p + 24);
+	ph->p_align  = get_Elf32_Word(p + 28);
+}
+
+/*
+ * Swap a section header in.
+ */
+static void
+get_elfsh(p, sh)
+	unsigned char *p;
+	Elf32_Shdr *sh;
+{
+	sh->sh_name      = get_Elf32_Word(p);
+	sh->sh_type      = get_Elf32_Word(p + 4);
+	sh->sh_flags     = get_Elf32_Word(p + 8);
+	sh->sh_addr      = get_Elf32_Addr(p + 12);
+	sh->sh_offset    = get_Elf32_Off(p + 16);
+	sh->sh_size      = get_Elf32_Word(p + 20);
+	sh->sh_link      = get_Elf32_Word(p + 24);
+	sh->sh_info      = get_Elf32_Word(p + 28);
+	sh->sh_addralign = get_Elf32_Word(p + 32);
+	sh->sh_entsize   = get_Elf32_Word(p + 36);
+}
+
+/*
+ * Swap a section header in.
+ */
+static void
+get_elfsym(p, sym)
+	unsigned char *p;
+	Elf32_Sym *sym;
+{
+	sym->st_name      = get_Elf32_Word(p);
+	sym->st_value     = get_Elf32_Addr(p + 4);
+	sym->st_size      = get_Elf32_Word(p + 8);
+	sym->st_info      = *(p + 12);
+	sym->st_other     = *(p + 13);
+	sym->st_shndx     = get_Elf32_Section(p + 14);
+}
+
+/*
+ * The a.out magic number
+ */
+#define OMAGIC 0407	/* Code indicating object file or impure executable. */
+#define M_MIPS1 151	/* MIPS R3000/R3000 binary */
+#define M_MIPS2 152	/* MIPS R6000/R4000 binary */
+
+/*
+ * Compute and return an a.out magic number.
+ */
+#define AOUT_INFO(magic, type, flags) \
+        (((magic) & 0xffff) | \
+         (((int)(type) & 0xff) << 16) | \
+         (((flags) & 0xff) << 24))
+
+/*
+ * a.out symbols
+ */
+#define N_UNDF 0
+#define N_ABS 2
+#define N_TEXT 4
+#define N_DATA 6
+#define N_BSS 8
+#define N_FN 15
+#define N_EXT 1
+
+#define min(x,y) (((x)<(y))?(x):(y))
+
+static void
+do_read(fd, buf, size)
+	int fd;
+	char *buf;
+	ssize_t size;
+{
+	ssize_t rd;
+
+	while(size != 0) {
+		rd = read(fd, buf, size);
+		if (rd == -1) {
+			perror("Can't read from file.");
+			exit(1);
+		}
+		size -= rd;
+	}
+}
+
+static void
+writepad(fd, size)
+	int fd;
+	size_t size;
+{
+	static void *zeropage = NULL;
+	ssize_t written;
+
+	if (zeropage == NULL) {
+		zeropage = malloc(4096);
+		if (zeropage == NULL) {
+			fprintf(stderr, "Couldn't allocate zero buffer.\n");
+			exit(1);
+		}
+		memset(zeropage, '\0', 4096);
+	}
+	while(size != 0) {
+		written = write(fd, zeropage, min(4096, size));
+		if (written == -1) {
+			perror("Can't write to boot image");
+			exit(1);
+		}
+		size -= written;
+	}
+}
+
+static void
+do_write(fd, buf, size)
+	int fd;
+	char *buf;
+	ssize_t size;
+{
+	ssize_t written;
+
+	while(size != 0) {
+		written = write(fd, buf, size);
+		if (written == -1) {
+			perror("Can't write to boot image");
+			exit(1);
+		}
+		size -= written;
+	}
+}
+
+static int
+usage(program_name)
+	char *program_name;
+{
+	fprintf(stderr, "Usage: %s infile outfile\n", program_name);
+	exit(0);
+}
+
+int
+main(argc, argv)
+	int argc;
+	char *argv[];
+{
+	char *infile, *outfile;
+	struct stat ifstat;
+	off_t ifsize;
+	char *image;
+	int ifd, ofd, i, symtabix, strtabix;
+	Elf32_Ehdr eh;
+	Elf32_Phdr *ph;
+	Elf32_Shdr *sh;
+	unsigned long vaddr, entry, bss, kernel_entry, kernel_end;
+	unsigned char ahdr[32];
+	Elf32_Sym sym;
+	int	symnum;
+	char *symname;
+
+	/*
+	 * Verify some basic assuptions about type sizes made in this code
+	 */
+	if (sizeof(Elf32_Half) != 2) {
+		fprintf(stderr, "Fix mkboot: sizeof(Elf32_Half) != 2\n");
+		exit(1);
+	}
+	if (sizeof(Elf32_Word) != 4) {
+		fprintf(stderr, "Fix mkboot: sizeof(Elf32_Word) != 4\n");
+		exit(1);
+	}
+	if (sizeof(Elf32_Addr) != 4) {
+		fprintf(stderr, "Fix mkboot: sizeof(Elf32_Addr) != 4\n");
+		exit(1);
+	}
+
+	if (argc != 3)
+		usage(argv[0]);
+
+	infile = argv[1];
+	outfile = argv[2];
+
+	if (stat(infile, &ifstat) < 0) {
+		perror("Can't stat kernel image.");
+		exit(1);
+	}
+
+	if (!S_ISREG(ifstat.st_mode)) {
+		fprintf(stderr, "Input file isn't a regular file.\n");
+		exit(1);
+	}
+	ifsize = ifstat.st_size;
+
+	image = malloc((size_t)ifsize);
+	if (image == NULL) {
+		fprintf(stderr, "Can't allocate memory to read file\n");
+		exit(1);
+	}
+
+	/*
+	 * Read the entire input file in.
+	 */
+	ifd = open(infile, O_RDONLY);
+	if(ifd == 0) {
+		fprintf(stderr, "Can't open input file\n");
+		exit(1);
+	}
+	do_read(ifd, image, ifsize);
+	close(ifd);
+
+	/*
+	 * Now swap the ELF header in.  This is ugly but we the file
+	 * we're reading might have different type sizes, byteorder
+	 * or alignment than the host.
+	 */
+	memcpy(eh.e_ident, (void *)image, sizeof(eh.e_ident));
+	if(memcmp(eh.e_ident, ELFMAG, SELFMAG)) {
+		fprintf(stderr, "Input file isn't a ELF file\n");
+		exit(1);
+	}
+	if(eh.e_ident[EI_CLASS] != ELFCLASS32) {
+		fprintf(stderr, "Input file isn't a 32 bit ELF file\n");
+		exit(1);
+	}
+	if(eh.e_ident[EI_DATA] != ELFDATA2LSB) {
+		fprintf(stderr, "Input file isn't a little endian ELF file\n");
+		exit(1);
+	}
+	if(eh.e_ident[EI_VERSION] != EV_CURRENT) {
+		fprintf(stderr, "Input file isn't a version %d ELF file\n",
+		        EV_CURRENT);
+		exit(1);
+	}
+
+	/*
+	 * Ok, so far the file looks ok.  Now swap the rest of the header in
+	 * and do some more paranoia checks.
+	 */
+	eh.e_type      = get_Elf32_Half(image + 16);
+	eh.e_machine   = get_Elf32_Half(image + 18);
+	eh.e_version   = get_Elf32_Word(image + 20);
+	eh.e_entry     = get_Elf32_Addr(image + 24);
+	eh.e_phoff     = get_Elf32_Off(image + 28);
+	eh.e_shoff     = get_Elf32_Off(image + 32);
+	eh.e_flags     = get_Elf32_Word(image + 36);
+	eh.e_ehsize    = get_Elf32_Half(image + 40);
+	eh.e_phentsize = get_Elf32_Half(image + 42);
+	eh.e_phnum     = get_Elf32_Half(image + 44);
+	eh.e_shentsize = get_Elf32_Half(image + 46);
+	eh.e_shnum     = get_Elf32_Half(image + 48);
+	eh.e_shstrndx  = get_Elf32_Half(image + 50);
+
+	if(eh.e_type != ET_EXEC) {
+		fprintf(stderr, "Input file isn't a executable.\n");
+		exit(1);
+	}
+	if(eh.e_machine != EM_MIPS && eh.e_machine != EM_MIPS_RS4_BE) {
+		fprintf(stderr, "Input file isn't a MIPS executable.\n");
+		exit(1);
+	}
+
+	/*
+	 * Now read the program headers ...
+	 */
+	ph = malloc(sizeof(Elf32_Phdr) * eh.e_phnum);
+	if (ph == NULL) {
+		fprintf(stderr, "No memory for program header table.\n");
+		exit(1);
+	}
+	for(i = 0;i < eh.e_phnum; i++)
+		get_elfph((void *)(image + eh.e_phoff + i * 32), ph + i);
+
+	/*
+	 * ... and then the section headers.
+	 */
+	sh = malloc(sizeof(Elf32_Shdr) * eh.e_shnum);
+	if (sh == NULL) {
+		fprintf(stderr, "No memory for section header table.\n");
+		exit(1);
+	}
+	for(i = 0;i < eh.e_shnum; i++)
+		get_elfsh((void *)(image + eh.e_shoff + (i * 40)), sh + i);
+
+	/*
+	 * Find the symboltable and the stringtable in the file.
+	 */
+	for(i = 0;i < eh.e_shnum; i++) {
+		if (!strcmp (image + sh [eh.e_shstrndx].sh_offset + sh[i].sh_name,
+		             ".symtab")) {
+			symtabix = i;
+			continue;
+		}
+		if (!strcmp (image + sh [eh.e_shstrndx].sh_offset + sh[i].sh_name,
+		             ".strtab")) {
+			strtabix = i;
+			continue;
+		}
+	}
+
+	if (symtabix == -1) {
+		fprintf(stderr, "The executable doesn't have a symbol table\n");
+		exit(1);
+	}
+	if (strtabix == -1) {
+		fprintf(stderr, "The executable doesn't have a string table\n");
+		exit(1);
+	}
+
+	/*
+	 * Dig for the two required symbols in the symbol table.
+	 */
+	symnum = sh[symtabix].sh_size / 16;
+	for(i = 0;i < symnum;i++) {
+		get_elfsym(image + sh[symtabix].sh_offset + (i * 16), &sym);
+		symname = image + sh[strtabix].sh_offset + sym.st_name;
+		if (ELF32_ST_BIND(sym.st_info) != STB_GLOBAL)
+			continue;
+		if (ELF32_ST_TYPE(sym.st_info) != STT_NOTYPE &&
+		    ELF32_ST_TYPE(sym.st_info) != STT_OBJECT &&
+		    ELF32_ST_TYPE(sym.st_info) != STT_FUNC)
+			continue;
+		if (strcmp("kernel_entry", symname) == 0) {
+			kernel_entry = sym.st_value;
+			continue;
+		}
+		if (strcmp("_end", symname) == 0) {
+			kernel_end = sym.st_value;
+			continue;
+		}
+	}
+
+#ifdef VERBOSE
+	/*
+	 * And print what we will be loaded into memory.
+	 */
+	for(i = 0;i < eh.e_phnum; i++) {
+		if (ph[i].p_type != PT_LOAD) {
+			continue;
+		}
+		printf("  Offset: %08lx\n", ph[i].p_offset);
+		printf("  file size: %08lx\n", ph[i].p_filesz);
+		printf("  mem size: %08lx\n", ph[i].p_memsz);
+		printf("    Loading: %08lx - %08lx\n",
+		       ph[i].p_vaddr, ph[i].p_vaddr + ph[i].p_filesz);
+		printf("    Zero mapping: %08lx - %08lx\n",
+		       ph[i].p_vaddr + ph[i].p_filesz,
+		       ph[i].p_vaddr + ph[i].p_memsz);
+	}
+#endif
+
+	/*
+	 * Time to open the outputfile.
+	 */
+	ofd = open(outfile, O_WRONLY|O_CREAT|O_TRUNC, 0666);
+	if (ofd == -1) {
+		perror("Can't open boot image for output.");
+		exit(1);
+	}
+
+	/*
+	 * First compute the layout of the file.  We need to do this
+	 * first because we can't seek back to the beginning due to the
+	 * broken Seek() call in the Magnum firmware.
+	 */
+	entry = vaddr = 0xffffffff;
+	bss = 0;
+	for(i = 0;i < eh.e_phnum; i++) {
+		if (ph[i].p_type != PT_LOAD)
+			continue;
+		if (vaddr == 0xffffffff)
+			entry = vaddr = ph[i].p_vaddr;
+		vaddr = ph[i].p_vaddr + ph[i].p_filesz;
+		bss = ph[i].p_memsz - ph[i].p_filesz;
+	}
+
+	/*
+	 * In the next step we construct the boot image.  The boot file
+	 * looks essentially like a dump of the loaded kernel with a
+	 * minimal header.  Because Milo supports already a.out image
+	 * we simply dump the image in an a.out image ...  First let's
+	 * write the header.
+	 */
+
+	/*
+	 * Create and write the a.out header.
+	 */
+	put_word(ahdr, AOUT_INFO(OMAGIC, M_MIPS1, 0));
+	put_word(ahdr + 4, vaddr - entry);	/* text size */
+	put_word(ahdr + 8, 0);			/* data size */
+	put_word(ahdr + 12, bss);		/* bss size */
+	put_word(ahdr + 16, 2 * 12);		/* size of symbol table */
+	put_word(ahdr + 20, entry);		/* base address */
+	put_word(ahdr + 24, 0);			/* size of text relocations */
+	put_word(ahdr + 28, 0);			/* size of data relocations */
+	do_write(ofd, ahdr, 32);
+
+	/*
+	 * Write text and data segment combined into the a.out text segment
+	 * and a zero length data segment into the file.
+	 */
+	vaddr = 0xffffffff;
+	bss = 0;
+	for(i = 0;i < eh.e_phnum; i++) {
+		if (ph[i].p_type != PT_LOAD)
+			continue;
+		if (vaddr == 0xffffffff)
+			vaddr = ph[i].p_vaddr;
+		writepad(ofd, ph[i].p_vaddr - vaddr);	/* Write zero pad */
+		do_write(ofd, image + ph[i].p_offset, ph[i].p_filesz);
+		vaddr = ph[i].p_vaddr + ph[i].p_filesz;
+		bss = ph[i].p_memsz - ph[i].p_filesz;
+	}
+
+	/*
+	 * Now write the symbol table.  It has only two symbols,
+	 * kernel_entry and _end which we need for booting.
+	 */
+	put_word(ahdr    , 4);			/* n_un.n_strx */
+	put_byte(ahdr + 4, N_TEXT | N_EXT);	/* n_type */
+	put_byte(ahdr + 5, 0);			/* n_other */
+	put_half(ahdr + 6, 0);			/* n_desc */
+	put_word(ahdr + 8, kernel_entry);	/* n_value */
+	do_write(ofd, ahdr, 12);
+
+	put_word(ahdr    , 4 + 13);		/* n_un.n_strx */
+	put_byte(ahdr + 4, N_ABS | N_EXT);	/* n_type */
+	put_byte(ahdr + 5, 0);			/* n_other */
+	put_half(ahdr + 6, 0);			/* n_desc */
+	put_word(ahdr + 8, kernel_end);		/* n_value */
+	do_write(ofd, ahdr, 12);
+
+	/*
+	 * Now write stringtable size and the strings.
+	 */
+	put_word(ahdr, 4 + 20);
+	do_write(ofd, ahdr, 4);
+	do_write(ofd, "kernel_entry\0_end\0\0", 20);
+
+	/*
+	 * That's is all ...
+	 */
+	close(ofd);
+
+#ifdef VERBOSE
+	printf("Entry: %08lx\n", entry);
+	printf("Dumped image %08lx - %08lx\n", 0x80000000, vaddr);
+	printf("Extra bss at end: %08lx\n", bss);
+#endif
+
+	return 0;
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov