Initial commit: functional for newer bzImage kernels
authorH. Peter Anvin <hpa@zytor.com>
Fri, 4 Jan 2008 05:54:24 +0000 (21:54 -0800)
committerH. Peter Anvin <hpa@zytor.com>
Fri, 4 Jan 2008 05:54:24 +0000 (21:54 -0800)
18 files changed:
Makefile [new file with mode: 0644]
elf.c [new file with mode: 0644]
elf32.h [new file with mode: 0644]
elfcommon.h [new file with mode: 0644]
le.h [new file with mode: 0644]
linux.c [new file with mode: 0644]
main.c [new file with mode: 0644]
reloc.S [new file with mode: 0644]
reloc/conio.c [new file with mode: 0644]
reloc/conio.h [new file with mode: 0644]
reloc/memmove.S [new file with mode: 0644]
reloc/reloc.h [new file with mode: 0644]
reloc/reloc.ld [new file with mode: 0644]
reloc/reloc_init.S [new file with mode: 0644]
reloc/reloc_linux.c [new file with mode: 0644]
segment.h [new file with mode: 0644]
setup.h [new file with mode: 0644]
wraplinux.h [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..cba4dae
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,42 @@
+CC                     = gcc
+CFLAGS                 = -O2 -g -W -Wall -D_GNU_SOURCE
+LDFLAGS                        =
+
+CC_FOR_TARGET          = gcc -m32
+LD_FOR_TARGET          = ld -m elf_i386
+OBJCOPY_FOR_TARGET     = objcopy
+CFLAGS_FOR_TARGET      = -I. -g -Os -march=i386 -mregparm=3 \
+                         -fPIC -ffreestanding
+LDFLAGS_FOR_TARGET     =
+
+RELOC_OBJS             = $(patsubst %.c,%.o,$(wildcard reloc/*.c)) \
+                         $(patsubst %.S,%.o,$(wildcard reloc/*.S))
+
+all: wraplinux
+
+reloc/%.o: reloc/%.c
+       $(CC_FOR_TARGET) $(CFLAGS_FOR_TARGET) -c -o $@ $<
+
+reloc/%.o: reloc/%.S
+       $(CC_FOR_TARGET) $(CFLAGS_FOR_TARGET) -c -D__ASSEMBLY__ -o $@ $<
+
+%.o: %.S
+       $(CC) $(CFLAGS) -c -o $@ $<
+
+%.o: %.c
+       $(CC) $(CFLAGS) -c -o $@ $<
+
+reloc/reloc.bin: reloc/reloc.elf
+       $(OBJCOPY_FOR_TARGET) -O binary $< $@
+
+reloc/reloc.elf: $(RELOC_OBJS) reloc/reloc.ld
+       $(LD_FOR_TARGET) $(LDFLAGS_FOR_TARGET) -T reloc/reloc.ld \
+               -o $@ $(RELOC_OBJS)
+
+reloc.o: reloc.S reloc/reloc.bin 
+
+wraplinux: main.o linux.o reloc.o elf.o
+       $(CC) $(LDFLAGS) -o $@ $^
+
+clean:
+       rm -f wraplinux *.o reloc/*.o reloc/*.bin reloc/*.elf
diff --git a/elf.c b/elf.c
new file mode 100644 (file)
index 0000000..211df31
--- /dev/null
+++ b/elf.c
@@ -0,0 +1,178 @@
+/* ----------------------------------------------------------------------- *
+ *   
+ *   Copyright 2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ *   Boston MA 02110-1301, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * elf.c
+ *
+ * Take a linked list of segments and output it as an ELF32 image
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include "elf32.h"
+#include "segment.h"
+#include "le.h"
+
+int output_elf(struct segment *segs, addr_t entry, FILE *out)
+{
+       Elf32_Ehdr ehdr;
+       Elf32_Shdr shdr;
+       Elf32_Phdr phdr;
+       int nsections = 0;
+       int namebytes = 11;     /* Null entry plus .shstrtab */
+       struct segment *s;
+       uint32_t data_start, data_offset;
+       uint32_t data_size = 0;
+       uint32_t name_offset;
+       uint32_t shoff;
+
+       for (s = segs; s; s = s->next) {
+               nsections++;
+               if (s->name)
+                       namebytes += strlen(s->name)+1;
+               if (s->sh_type != SHT_NOBITS)
+                       data_size += s->length;
+       }
+
+       memset(&ehdr, 0, sizeof ehdr);
+       ehdr.e_ident[EI_MAG0]    = ELFMAG0;
+       ehdr.e_ident[EI_MAG1]    = ELFMAG1;
+       ehdr.e_ident[EI_MAG2]    = ELFMAG2;
+       ehdr.e_ident[EI_MAG3]    = ELFMAG3;
+       ehdr.e_ident[EI_CLASS]   = ELFCLASS32;
+       ehdr.e_ident[EI_DATA]    = ELFDATA2LSB;
+       ehdr.e_ident[EI_VERSION] = EV_CURRENT;
+       ehdr.e_ident[EI_OSABI]   = ELFOSABI_STANDALONE;
+       
+       wrle16(ET_EXEC, &ehdr.e_type);
+       wrle16(EM_386, &ehdr.e_machine);
+       wrle32(EV_CURRENT, &ehdr.e_version);
+       wrle32(entry, &ehdr.e_entry);
+       wrle32(sizeof ehdr, &ehdr.e_phoff);
+       shoff = sizeof ehdr + nsections*(sizeof phdr) + data_size + namebytes;
+       shoff = (shoff+3) & ~3;
+       wrle32(shoff, &ehdr.e_shoff);
+       wrle16(sizeof ehdr, &ehdr.e_ehsize);
+       wrle16(sizeof phdr, &ehdr.e_phentsize);
+       wrle16(nsections, &ehdr.e_phnum);
+       wrle16(sizeof shdr, &ehdr.e_shentsize);
+       wrle16(nsections+2, &ehdr.e_shnum);
+       wrle16(nsections+1, &ehdr.e_shstrndx);
+       fwrite(&ehdr, 1, sizeof ehdr, out);
+
+       /* First actual data byte */
+       data_start = (sizeof ehdr) + nsections*(sizeof phdr);
+
+       /* Program header table */
+       data_offset = data_start;
+       for (s = segs; s; s = s->next) {
+               uint32_t filesize, memsize;
+               uint32_t p_type, p_flags;
+
+               filesize = (s->sh_type == SHT_NOBITS) ? 0 : s->length;
+               memsize = (s->sh_flags & SHF_ALLOC) ? s->length : 0;
+               
+               switch (s->sh_type) {
+               case SHT_PROGBITS:
+               case SHT_NOBITS:
+                       p_type = PT_LOAD;
+                       break;
+               case SHT_NOTE:
+                       p_type = PT_NOTE;
+                       break;
+               default:
+                       p_type = PT_NULL; /* No other types supported */
+                       break;
+               }
+
+               p_flags = 0;
+               if (s->sh_flags & SHF_ALLOC) /* Somewhat cheesy... */
+                       p_flags |= PF_R;
+               if (s->sh_flags & SHF_EXECINSTR)
+                       p_flags |= PF_X;
+               if (s->sh_flags & SHF_WRITE)
+                       p_flags |= PF_W;
+
+               memset(&phdr, 0, sizeof phdr);
+               wrle32(p_type, &phdr.p_type);
+               wrle32(data_offset, &phdr.p_offset);
+               wrle32(s->address, &phdr.p_vaddr);
+               wrle32(s->address, &phdr.p_paddr);
+               wrle32(filesize, &phdr.p_filesz);
+               wrle32(memsize, &phdr.p_memsz);
+               wrle32(p_flags, &phdr.p_flags);
+               wrle32(1, &phdr.p_align);
+
+               fwrite(&phdr, 1, sizeof phdr, out);
+
+               data_offset += filesize;
+       }
+
+       /* Actual file data */
+       for (s = segs; s; s = s->next) {
+               if (s->sh_type != SHT_NOBITS)
+                       fwrite(s->data, 1, s->length, out);
+       }
+
+       /* String table */
+       putc(0, out);           /* Null string table entry */
+       data_offset++;
+       for (s = segs; s; s = s->next) {
+               uint32_t len = strlen(s->name)+1;
+               fwrite(s->name, 1, len, out);
+               data_offset += len;
+       }
+       fwrite(".shstrtab", 1, 10, out);
+       data_offset += 10;
+
+       while (data_offset & 3) {
+               putc(0, out);   /* Align the section header table */
+               data_offset++;
+       }
+
+       /* Section header table */
+       memset(&shdr, 0, sizeof shdr);
+       fwrite(&shdr, 1, sizeof shdr, out); /* Null section header */
+
+       data_offset = data_start;
+       name_offset = 1;
+       for (s = segs; s; s = s->next) {
+               memset(&shdr, 0, sizeof shdr);
+               wrle32(name_offset, &shdr.sh_name);
+               wrle32(s->sh_type, &shdr.sh_type);
+               wrle32(s->sh_flags, &shdr.sh_flags);
+               wrle32(s->address, &shdr.sh_addr);
+               wrle32(data_offset, &shdr.sh_offset); /* Even for SHT_NOBITS */
+               wrle32(s->length, &shdr.sh_size);
+               wrle32(1, &shdr.sh_addralign);
+
+               fwrite(&shdr, 1, sizeof shdr, out);
+
+               name_offset += strlen(s->name)+1;
+
+               if (s->sh_type != SHT_NOBITS)
+                       data_offset += s->length;
+       }
+
+       /* String table section header */
+       memset(&shdr, 0, sizeof shdr);
+       wrle32(name_offset, &shdr.sh_name);
+       wrle32(SHT_STRTAB, &shdr.sh_type);
+       wrle32(data_offset, &shdr.sh_offset);
+       wrle32(namebytes, &shdr.sh_size);
+       
+       fwrite(&shdr, 1, sizeof shdr, out);
+
+       return 0;
+}
diff --git a/elf32.h b/elf32.h
new file mode 100644 (file)
index 0000000..86f1c87
--- /dev/null
+++ b/elf32.h
@@ -0,0 +1,117 @@
+/*
+ * elf32.h
+ */
+
+#ifndef SYS_ELF32_H
+#define SYS_ELF32_H
+
+#include "elfcommon.h"
+
+/* ELF standard typedefs (yet more proof that <stdint.h> was way overdue) */
+typedef uint16_t Elf32_Half;
+typedef int16_t Elf32_SHalf;
+typedef uint32_t Elf32_Word;
+typedef int32_t Elf32_Sword;
+typedef uint64_t Elf32_Xword;
+typedef int64_t Elf32_Sxword;
+
+typedef uint32_t Elf32_Off;
+typedef uint32_t Elf32_Addr;
+typedef uint16_t Elf32_Section;
+
+/* Dynamic header */
+
+typedef struct elf32_dyn {
+       Elf32_Sword d_tag;
+       union {
+               Elf32_Sword d_val;
+               Elf32_Addr d_ptr;
+       } d_un;
+} Elf32_Dyn;
+
+/* Relocations */
+
+#define ELF32_R_SYM(x) ((x) >> 8)
+#define ELF32_R_TYPE(x)        ((x) & 0xff)
+
+typedef struct elf32_rel {
+       Elf32_Addr r_offset;
+       Elf32_Word r_info;
+} Elf32_Rel;
+
+typedef struct elf32_rela {
+       Elf32_Addr r_offset;
+       Elf32_Word r_info;
+       Elf32_Sword r_addend;
+} Elf32_Rela;
+
+/* Symbol */
+
+typedef struct elf32_sym {
+       Elf32_Word st_name;
+       Elf32_Addr st_value;
+       Elf32_Word st_size;
+       unsigned char st_info;
+       unsigned char st_other;
+       Elf32_Half st_shndx;
+} Elf32_Sym;
+
+/* Main file header */
+
+typedef struct elf32_hdr {
+       unsigned char e_ident[EI_NIDENT];
+       Elf32_Half e_type;
+       Elf32_Half e_machine;
+       Elf32_Word e_version;
+       Elf32_Addr e_entry;
+       Elf32_Off e_phoff;
+       Elf32_Off e_shoff;
+       Elf32_Word e_flags;
+       Elf32_Half e_ehsize;
+       Elf32_Half e_phentsize;
+       Elf32_Half e_phnum;
+       Elf32_Half e_shentsize;
+       Elf32_Half e_shnum;
+       Elf32_Half e_shstrndx;
+} Elf32_Ehdr;
+
+/* Program header */
+
+typedef struct elf32_phdr {
+       Elf32_Word p_type;
+       Elf32_Off p_offset;
+       Elf32_Addr p_vaddr;
+       Elf32_Addr p_paddr;
+       Elf32_Word p_filesz;
+       Elf32_Word p_memsz;
+       Elf32_Word p_flags;
+       Elf32_Word p_align;
+} Elf32_Phdr;
+
+/* Section header */
+
+typedef struct elf32_shdr {
+       Elf32_Word sh_name;
+       Elf32_Word sh_type;
+       Elf32_Word sh_flags;
+       Elf32_Addr sh_addr;
+       Elf32_Off sh_offset;
+       Elf32_Word sh_size;
+       Elf32_Word sh_link;
+       Elf32_Word sh_info;
+       Elf32_Word sh_addralign;
+       Elf32_Word sh_entsize;
+} Elf32_Shdr;
+
+/* Note header */
+typedef struct elf32_note {
+       Elf32_Word n_namesz;    /* Name size */
+       Elf32_Word n_descsz;    /* Content size */
+       Elf32_Word n_type;      /* Content type */
+} Elf32_Nhdr;
+
+/* 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)
+
+#endif                         /* _SYS_ELF32_H */
diff --git a/elfcommon.h b/elfcommon.h
new file mode 100644 (file)
index 0000000..0348906
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * elfcommon.h
+ */
+
+#ifndef ELFCOMMON_H
+#define ELFCOMMON_H
+
+#include <stdint.h>
+
+/* Segment types */
+#define PT_NULL        0
+#define PT_LOAD        1
+#define PT_DYNAMIC     2
+#define PT_INTERP      3
+#define PT_NOTE        4
+#define PT_SHLIB       5
+#define PT_PHDR        6
+#define PT_LOOS        0x60000000
+#define PT_HIOS        0x6fffffff
+#define PT_LOPROC      0x70000000
+#define PT_HIPROC      0x7fffffff
+#define PT_GNU_EH_FRAME        0x6474e550      /* Extension, eh? */
+
+/* ELF file types */
+#define ET_NONE        0
+#define ET_REL         1
+#define ET_EXEC        2
+#define ET_DYN         3
+#define ET_CORE        4
+#define ET_LOPROC      0xff00
+#define ET_HIPROC      0xffff
+
+/* ELF machine types */
+#define EM_NONE        0
+#define EM_M32         1
+#define EM_SPARC       2
+#define EM_386         3
+#define EM_68K         4
+#define EM_88K         5
+#define EM_486         6       /* Not used in Linux at least */
+#define EM_860         7
+#define EM_MIPS         8      /* R3k, bigendian(?) */
+#define EM_MIPS_RS4_BE         10      /* R4k BE */
+#define EM_PARISC              15
+#define EM_SPARC32PLUS         18
+#define EM_PPC                 20
+#define EM_PPC64               21
+#define EM_S390         22
+#define EM_SH                  42
+#define EM_SPARCV9     43      /* v9 = SPARC64 */
+#define EM_H8_300H      47
+#define EM_H8S          48
+#define EM_IA_64        50     /* Itanic */
+#define EM_X86_64       62
+#define EM_CRIS         76
+#define EM_V850         87
+#define EM_ALPHA        0x9026 /* Interrim Alpha that stuck around */
+#define EM_CYGNUS_V850  0x9080 /* Old v850 ID used by Cygnus */
+#define EM_S390_OLD     0xA390 /* Obsolete interrim value for S/390 */
+
+/* Dynamic type values */
+#define DT_NULL                0
+#define DT_NEEDED      1
+#define DT_PLTRELSZ    2
+#define DT_PLTGOT      3
+#define DT_HASH                4
+#define DT_STRTAB      5
+#define DT_SYMTAB      6
+#define DT_RELA                7
+#define DT_RELASZ      8
+#define DT_RELAENT     9
+#define DT_STRSZ       10
+#define DT_SYMENT      11
+#define DT_INIT                12
+#define DT_FINI                13
+#define DT_SONAME      14
+#define DT_RPATH       15
+#define DT_SYMBOLIC    16
+#define DT_REL         17
+#define DT_RELSZ       18
+#define DT_RELENT      19
+#define DT_PLTREL      20
+#define DT_DEBUG       21
+#define DT_TEXTREL     22
+#define DT_JMPREL      23
+#define DT_LOPROC      0x70000000
+#define DT_HIPROC      0x7fffffff
+
+/* Auxilliary table entries */
+#define AT_NULL                0       /* end of vector */
+#define AT_IGNORE      1       /* entry should be ignored */
+#define AT_EXECFD      2       /* file descriptor of program */
+#define AT_PHDR                3       /* program headers for program */
+#define AT_PHENT       4       /* size of program header entry */
+#define AT_PHNUM       5       /* number of program headers */
+#define AT_PAGESZ      6       /* system page size */
+#define AT_BASE                7       /* base address of interpreter */
+#define AT_FLAGS       8       /* flags */
+#define AT_ENTRY       9       /* entry point of program */
+#define AT_NOTELF      10      /* program is not ELF */
+#define AT_UID         11      /* real uid */
+#define AT_EUID                12      /* effective uid */
+#define AT_GID         13      /* real gid */
+#define AT_EGID                14      /* effective gid */
+#define AT_PLATFORM    15      /* string identifying CPU for optimizations */
+#define AT_HWCAP       16      /* arch dependent hints at CPU capabilities */
+#define AT_CLKTCK      17      /* frequency at which times() increments */
+/* 18..22 = ? */
+#define AT_SECURE      23      /* secure mode boolean */
+
+/* Program header permission flags */
+#define PF_X            0x1
+#define PF_W            0x2
+#define PF_R            0x4
+
+/* Section header types */
+#define SHT_NULL        0
+#define SHT_PROGBITS    1
+#define SHT_SYMTAB      2
+#define SHT_STRTAB      3
+#define SHT_RELA        4
+#define SHT_HASH        5
+#define SHT_DYNAMIC     6
+#define SHT_NOTE        7
+#define SHT_NOBITS      8
+#define SHT_REL         9
+#define SHT_SHLIB       10
+#define SHT_DYNSYM      11
+#define SHT_NUM         12
+#define SHT_LOPROC      0x70000000
+#define SHT_HIPROC      0x7fffffff
+#define SHT_LOUSER      0x80000000
+#define SHT_HIUSER      0xffffffff
+
+/* Section header flags */
+#define SHF_WRITE       0x1
+#define SHF_ALLOC       0x2
+#define SHF_EXECINSTR   0x4
+#define SHF_MASKPROC    0xf0000000
+
+/* Special section numbers */
+#define SHN_UNDEF       0
+#define SHN_LORESERVE   0xff00
+#define SHN_LOPROC      0xff00
+#define SHN_HIPROC      0xff1f
+#define SHN_ABS         0xfff1
+#define SHN_COMMON      0xfff2
+#define SHN_HIRESERVE   0xffff
+
+/* Lenght of magic at the start of a file */
+#define EI_NIDENT      16
+
+/* Magic number constants... */
+#define EI_MAG0         0      /* e_ident[] indexes */
+#define EI_MAG1         1
+#define EI_MAG2         2
+#define EI_MAG3         3
+#define EI_CLASS        4
+#define EI_DATA         5
+#define EI_VERSION      6
+#define EI_OSABI        7
+#define EI_PAD          8
+
+#define ELFMAG0         0x7f   /* EI_MAG */
+#define ELFMAG1         'E'
+#define ELFMAG2         'L'
+#define ELFMAG3         'F'
+#define ELFMAG          "\177ELF"
+#define SELFMAG         4
+
+#define ELFCLASSNONE    0      /* EI_CLASS */
+#define ELFCLASS32      1
+#define ELFCLASS64      2
+#define ELFCLASSNUM     3
+
+#define ELFDATANONE     0      /* e_ident[EI_DATA] */
+#define ELFDATA2LSB     1
+#define ELFDATA2MSB     2
+
+#define EV_NONE         0      /* e_version, EI_VERSION */
+#define EV_CURRENT      1
+#define EV_NUM          2
+
+#define ELFOSABI_NONE          0
+#define ELFOSABI_SYSV          0
+#define ELFOSABI_HPUX          1
+#define ELFOSABI_NETBSD                2
+#define ELFOSABI_LINUX         3
+#define ELFOSABI_SOLARIS       6
+#define ELFOSABI_AIX           7
+#define ELFOSABI_IRIX          8
+#define ELFOSABI_FREEBSD       9
+#define ELFOSABI_TRU64         10
+#define ELFOSABI_MODESTO       11
+#define ELFOSABI_OPENBSD       12
+#define ELFOSABI_ARM           97
+#define ELFOSABI_STANDALONE    255
+
+/* Legal values for ST_BIND subfield of st_info (symbol binding).  */
+#define STB_LOCAL      0               /* Local symbol */
+#define STB_GLOBAL     1               /* Global symbol */
+#define STB_WEAK       2               /* Weak symbol */
+#define STB_NUM                3               /* Number of defined types.  */
+#define STB_LOOS       10              /* Start of OS-specific */
+#define STB_HIOS       12              /* End of OS-specific */
+#define STB_LOPROC     13              /* Start of processor-specific */
+#define STB_HIPROC     15              /* End of processor-specific */
+
+#endif                         /* _SYS_ELFCOMMON_H */
diff --git a/le.h b/le.h
new file mode 100644 (file)
index 0000000..ee06d57
--- /dev/null
+++ b/le.h
@@ -0,0 +1,82 @@
+/* ----------------------------------------------------------------------- *
+ *   
+ *   Copyright 2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ *   Boston MA 02110-1301, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * le.h
+ *
+ * Write unaligned littleendian data
+ */
+
+#ifndef LE_H
+#define LE_H
+
+#include <inttypes.h>
+
+#if defined(__i386__) || defined(__x86_64__)
+
+/* Littleendian architecture, unaligned accesses permitted */
+
+static inline uint16_t rdle16(const uint16_t *p)
+{
+       return *p;
+}
+
+static inline uint32_t rdle32(const uint32_t *p)
+{
+       return *p;
+}
+
+static inline void wrle16(uint16_t v, uint16_t *p)
+{
+       *p = v;
+}
+
+static inline void wrle32(uint32_t v, uint32_t *p)
+{
+       *p = v;
+}
+
+#else
+
+static inline uint16_t rdle16(const uint16_t *p)
+{
+       const uint8_t *_p = (const uint8_t *)p;
+       return _p[0] + (_p[1] << 8);
+}
+
+static inline uint32_t rdle32(const uint32_t *p)
+{
+       const uint8_t *_p = (const uint8_t *)p;
+       return _p[0] + (_p[1] << 8) + (_p[2] << 16) + (_p[3] << 24);
+}
+
+static inline void wrle16(uint16_t v, uint16_t *p)
+{
+       uint8_t *_p = (uint8_t *)p;
+
+       _p[0] = v;
+       _p[1] = v >> 8;
+}
+
+static inline void wrle32(uint32_t v, uint32_t *p)
+{
+       uint8_t *_p = (uint8_t *)p;
+
+       _p[0] = v;
+       _p[1] = v >> 8;
+       _p[2] = v >> 16;
+       _p[3] = v >> 24;
+}
+
+#endif
+
+#endif /* LE_H */
diff --git a/linux.c b/linux.c
new file mode 100644 (file)
index 0000000..71ded0f
--- /dev/null
+++ b/linux.c
@@ -0,0 +1,217 @@
+/* ----------------------------------------------------------------------- *
+ *   
+ *   Copyright 2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ *   Boston MA 02110-1301, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * wrap.c
+ *
+ * Actually wrap the kernel image...
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sysexits.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "segment.h"
+#include "setup.h"
+#include "elf32.h"
+#include "le.h"
+#include "wraplinux.h"
+
+extern const char reloc[];
+extern uint32_t reloc_size;
+
+int wrap_kernel(const char *kernel_file, const char *cmdline,
+               const struct string_list *initrd_list, FILE *out)
+{
+  struct initrd_info {
+    int fd;
+    struct segment seg;
+  } *ird = NULL;
+  int kernel_fd = -1;
+  char *kernel = NULL;
+  size_t kernel_len = 0;
+  struct stat st;
+  struct segment srel, sinf, ssup, scmd, skrn;
+  struct startup_info info;
+  struct setup_header *hdr;
+  size_t setup_len;
+  size_t initrd_len;
+  size_t initrd_addr;
+  int rv = -1;
+  int ninitrd = 0;
+  int i;
+  const struct string_list *ip;
+
+  ninitrd = 0;
+  for (ip = initrd_list; ip; ip = ip->next)
+    ninitrd++;
+
+  if (ninitrd) {
+    ird = calloc(ninitrd, sizeof *ird);
+    if (!ird)
+      goto err;
+  }
+
+  kernel_fd = open(kernel_file, O_RDONLY);
+  if (kernel_fd < 0)
+    goto err;
+
+  if (fstat(kernel_fd, &st))
+    goto err;
+
+  kernel_len = st.st_size;
+
+  if (kernel_len < 1024)
+    goto err;
+
+  kernel = mmap(NULL, kernel_len, PROT_READ|PROT_WRITE, MAP_PRIVATE,
+               kernel_fd, 0);
+  if (kernel == MAP_FAILED) {
+    kernel = NULL;
+    goto err;
+  }
+
+  initrd_len = 0;
+  for (ip = initrd_list, i = 0; ip; ip = ip->next, i++) {
+    ird[i].fd = open(ip->str, O_RDONLY);
+    if (ird[i].fd < 0)
+      return -1;
+  
+    if (fstat(ird[i].fd, &st))
+      goto err;
+
+    ird[i].seg.length = st.st_size;
+    ird[i].seg.data = mmap(NULL, ird[i].seg.length, PROT_READ,
+                          MAP_SHARED, ird[i].fd, 0);
+    if (ird[i].seg.data == MAP_FAILED) {
+      ird[i].seg.data = NULL;
+      goto err;
+    }
+    
+    /* We need to pad the space between initrds to a 4-byte boundary.
+       This is safe because an mmap is always padded with zero
+       to a page boundary... */
+    if (i < ninitrd-1)
+      ird[i].seg.length = (ird[i].seg.length + 3) & ~3;
+
+    initrd_len += ird[i].seg.length;
+  }
+
+  hdr = (struct setup_header *)(kernel + 0x1f1);
+  setup_len = (hdr->setup_sects + 1) << 9;
+  if (setup_len == 512)
+    setup_len += 2048;         /* Really old kernel */
+  
+  /* Segment 1 is the relocation code */
+  srel.next     = &ssup;
+  srel.address  = 0xc000;      /* Can be adjusted (align 16),
+                                  code is relocatable */
+  srel.length   = reloc_size;
+  srel.sh_type  = SHT_PROGBITS;
+  srel.sh_flags = SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR;
+  srel.name     = "reloc";
+  srel.data    = reloc;
+
+  /* Segment 0 is the struct startup_info */
+  sinf.next     = &srel;
+  sinf.address  = srel.address - sizeof info;
+  sinf.length   = sizeof info;
+  sinf.sh_type  = SHT_PROGBITS;
+  sinf.sh_flags = SHF_ALLOC;
+  sinf.name     = "startup_info";
+  sinf.data     = &info;
+
+  /* Segment 2 is the Linux kernel setup */
+  ssup.next     = &scmd;
+  ssup.address  = 0x10000;     /* XXX */
+  ssup.length   = setup_len;
+  ssup.sh_type  = SHT_PROGBITS;
+  ssup.sh_flags = SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR;
+  ssup.name     = "setup";
+  ssup.data     = kernel;
+  hdr->type_of_loader = 0xff;  /* "Other modern loader" */
+
+  /* Segment 3 is the kernel command line */
+  scmd.next     = &skrn;
+  scmd.address  = 0x20000;     /* XXX */
+  scmd.length   = strlen(cmdline)+1;
+  scmd.sh_type  = SHT_PROGBITS;
+  scmd.sh_flags = SHF_ALLOC;
+  scmd.name     = "cmdline";
+  scmd.data     = cmdline;
+  wrle32(scmd.address, &hdr->cmd_line_ptr); /* XXX */
+  wrle16(scmd.address - ssup.address - 0x200, &hdr->heap_end_ptr);
+  hdr->loadflags |= CAN_USE_HEAP;
+
+  /* Segment 4 is the Linux kernel proper */
+  skrn.next     = ninitrd ? &ird[0].seg : NULL;
+  skrn.address  = 0x100000;    /* XXX */
+  skrn.length   = kernel_len - setup_len;
+  skrn.sh_type  = SHT_PROGBITS;
+  skrn.sh_flags = SHF_ALLOC;
+  skrn.name     = "kernel";
+  skrn.data     = kernel + setup_len;
+
+  /* Segment 5 is the initrd */
+  if (skrn.address < 0x100000)
+    initrd_addr = 0x100000;
+  else
+    initrd_addr = (skrn.address + skrn.length + 3) & ~3;
+
+  for (i = 0; i < ninitrd; i++) {
+    char *name;
+
+    ird[i].seg.next     = (i < ninitrd-1) ? &ird[i+1].seg : 0;
+    ird[i].seg.address  = initrd_addr;
+    ird[i].seg.sh_type  = SHT_PROGBITS;
+    ird[i].seg.sh_flags = SHF_ALLOC;
+    asprintf(&name, "initrd.%d", i);
+    ird[i].seg.name = name;
+
+    initrd_addr += ird[i].seg.length;
+  }
+  wrle32(initrd_len, &hdr->ramdisk_size);
+
+  /* Set up the startup info */
+  wrle32(ninitrd ? ird[0].seg.address : 0, &info.rd_addr);
+  wrle32(initrd_len, &info.rd_len);
+  wrle32(rdle32(&hdr->initrd_addr_max), &info.rd_maxaddr); /* XXX */
+  wrle32(ssup.address, &info.setup_addr);
+  wrle32(scmd.address, &info.cmdline_addr);
+
+  rv = output_elf(&sinf, srel.address, out);
+
+ err:
+  if (ird) {
+    for (i = 0; i < ninitrd; i++) {
+      if (ird[i].seg.data)
+       munmap((void *)ird[i].seg.data, ird[i].seg.length);
+      if (ird[i].fd > 0)
+      close(ird[i].fd);
+    }
+    free(ird);
+  }
+
+  if (kernel)
+    munmap(kernel, kernel_len);
+  if (kernel_fd >= 0)
+    close(kernel_fd);
+  
+  return rv;
+}
diff --git a/main.c b/main.c
new file mode 100644 (file)
index 0000000..3972ae9
--- /dev/null
+++ b/main.c
@@ -0,0 +1,87 @@
+/* ----------------------------------------------------------------------- *
+ *   
+ *   Copyright 2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ *   Boston MA 02110-1301, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * main.c
+ *
+ * Wrap a Linux image in an ELF (or other) container
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include "wraplinux.h"
+
+const char *program;
+
+struct opt {
+  const char *params;
+} opt;
+
+const struct option long_options[] = {
+  { "params",          1, 0, 'p' },
+  { "initrd",          1, 0, 'i' },
+  { 0, 0, 0, 0 }
+};
+#define OPTSTRING "p:i:"
+
+static void usage(int err)
+{
+  exit(err);
+}
+
+int main(int argc, char *argv[])
+{
+  int optch;
+  const char *kernel;
+  struct string_list *ird = NULL, **irdp = &ird, *ip;
+
+  program = argv[0];
+
+  while ( (optch = getopt_long(argc, argv, OPTSTRING, long_options, NULL))
+         != EOF ) {
+    switch (optch) {
+    case 'p':
+      opt.params = optarg;
+      break;
+    case 'i':
+      ip = malloc(sizeof *ip);
+      ip->str = optarg;
+      ip->next = NULL;
+      *irdp = ip;
+      irdp = &ip->next;
+      break;
+    default:
+      usage(EX_USAGE);
+      break;
+    }
+  }
+
+  if ((argc-optind) != 1)
+    usage(EX_USAGE);
+
+  kernel = argv[optind];
+
+  if (!opt.params)
+    opt.params = "";
+
+  wrap_kernel(kernel, opt.params, ird, stdout);
+  return 0;
+}
+
diff --git a/reloc.S b/reloc.S
new file mode 100644 (file)
index 0000000..f7d1310
--- /dev/null
+++ b/reloc.S
@@ -0,0 +1,17 @@
+/*
+ * All this does is it wraps reloc/reloc.bin in a .o file.
+ * This could also be done with a binary-to-C converter.
+ */
+       
+               .section ".rodata","a"
+               .balign 4
+               .globl  reloc_size
+reloc_size:
+               .long   .L_reloc_end-reloc
+               .size   reloc_size, 4
+       
+               .globl  reloc
+reloc:
+               .incbin "reloc/reloc.bin"
+               .size   reloc,.-reloc
+.L_reloc_end:
diff --git a/reloc/conio.c b/reloc/conio.c
new file mode 100644 (file)
index 0000000..dcff13b
--- /dev/null
@@ -0,0 +1,364 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2001-2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * conio.c
+ *
+ * Output to the screen
+ */
+
+#include <stdint.h>
+#include "reloc.h"
+#include "conio.h"
+
+int putchar(int ch)
+{
+  com32sys_t regs;
+  memset(&regs, 0, sizeof regs);
+
+  if ( ch == '\n' ) {
+    /* \n -> \r\n */
+    putchar('\r');
+  }
+
+  regs.eax.w[0] = 0x0e00|(ch&0xff);
+  intcall(0x10, &regs, NULL);
+
+  return ch;
+}
+
+int puts(const char *s)
+{
+  int count = 0;
+
+  while ( *s ) {
+    putchar(*s);
+    count++;
+    s++;
+  }
+
+  return count;
+}
+
+/*
+ * Oh, it's a waste of space, but oh-so-yummy for debugging.  It's just
+ * initialization code anyway, so it doesn't take up space when we're
+ * actually running.  This version of printf() does not include 64-bit
+ * support.  "Live with it."
+ *
+ * Most of this code was shamelessly snarfed from the Linux kernel, then
+ * modified.
+ */
+
+static inline int
+isdigit(int ch)
+{
+  return (ch >= '0') && (ch <= '9');
+}
+
+static int skip_atoi(const char **s)
+{
+  int i=0;
+
+  while (isdigit(**s))
+    i = i*10 + *((*s)++) - '0';
+  return i;
+}
+
+unsigned int atou(const char *s)
+{
+  unsigned int i = 0;
+  while (isdigit(*s))
+    i = i*10 + (*s++ - '0');
+  return i;
+}
+
+static int strnlen(const char *s, int maxlen)
+{
+  const char *es = s;
+  while ( *es && maxlen ) {
+    es++; maxlen--;
+  }
+
+  return (es-s);
+}
+
+#define ZEROPAD        1               /* pad with zero */
+#define SIGN   2               /* unsigned/signed long */
+#define PLUS   4               /* show plus */
+#define SPACE  8               /* space if plus */
+#define LEFT   16              /* left justified */
+#define SPECIAL        32              /* 0x */
+#define LARGE  64              /* use 'ABCDEF' instead of 'abcdef' */
+
+#define do_div(n,base) ({ \
+int __res; \
+__res = ((unsigned long) n) % (unsigned) base; \
+n = ((unsigned long) n) / (unsigned) base; \
+__res; })
+
+static char * number(char * str, long num, int base, int size, int precision
+       ,int type)
+{
+  char c,sign,tmp[66];
+  const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
+  int i;
+
+  if (type & LARGE)
+    digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  if (type & LEFT)
+    type &= ~ZEROPAD;
+  if (base < 2 || base > 36)
+    return 0;
+  c = (type & ZEROPAD) ? '0' : ' ';
+  sign = 0;
+  if (type & SIGN) {
+    if (num < 0) {
+      sign = '-';
+      num = -num;
+      size--;
+    } else if (type & PLUS) {
+      sign = '+';
+      size--;
+    } else if (type & SPACE) {
+      sign = ' ';
+      size--;
+    }
+  }
+  if (type & SPECIAL) {
+    if (base == 16)
+      size -= 2;
+    else if (base == 8)
+      size--;
+  }
+  i = 0;
+  if (num == 0)
+    tmp[i++]='0';
+  else while (num != 0)
+    tmp[i++] = digits[do_div(num,base)];
+  if (i > precision)
+    precision = i;
+  size -= precision;
+  if (!(type&(ZEROPAD+LEFT)))
+    while(size-->0)
+      *str++ = ' ';
+  if (sign)
+    *str++ = sign;
+  if (type & SPECIAL) {
+    if (base==8)
+      *str++ = '0';
+    else if (base==16) {
+      *str++ = '0';
+      *str++ = digits[33];
+    }
+  }
+  if (!(type & LEFT))
+    while (size-- > 0)
+      *str++ = c;
+  while (i < precision--)
+    *str++ = '0';
+  while (i-- > 0)
+    *str++ = tmp[i];
+  while (size-- > 0)
+    *str++ = ' ';
+  return str;
+}
+
+/* Forward decl. needed for IP address printing stuff... */
+int sprintf(char * buf, const char *fmt, ...);
+
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+  int len;
+  unsigned long num;
+  int i, base;
+  char * str;
+  const char *s;
+
+  int flags;           /* flags to number() */
+
+  int field_width;     /* width of output field */
+  int precision;               /* min. # of digits for integers; max
+                                  number of chars for from string */
+  int qualifier;               /* 'h', 'l', or 'L' for integer fields */
+
+  for (str=buf ; *fmt ; ++fmt) {
+    if (*fmt != '%') {
+      *str++ = *fmt;
+      continue;
+    }
+
+    /* process flags */
+    flags = 0;
+  repeat:
+    ++fmt;             /* this also skips first '%' */
+    switch (*fmt) {
+    case '-': flags |= LEFT; goto repeat;
+    case '+': flags |= PLUS; goto repeat;
+    case ' ': flags |= SPACE; goto repeat;
+    case '#': flags |= SPECIAL; goto repeat;
+    case '0': flags |= ZEROPAD; goto repeat;
+    }
+
+    /* get field width */
+    field_width = -1;
+    if (isdigit(*fmt))
+      field_width = skip_atoi(&fmt);
+    else if (*fmt == '*') {
+      ++fmt;
+      /* it's the next argument */
+      field_width = va_arg(args, int);
+      if (field_width < 0) {
+       field_width = -field_width;
+       flags |= LEFT;
+      }
+    }
+
+    /* get the precision */
+    precision = -1;
+    if (*fmt == '.') {
+      ++fmt;
+      if (isdigit(*fmt))
+       precision = skip_atoi(&fmt);
+      else if (*fmt == '*') {
+       ++fmt;
+       /* it's the next argument */
+       precision = va_arg(args, int);
+      }
+      if (precision < 0)
+       precision = 0;
+    }
+
+    /* get the conversion qualifier */
+    qualifier = -1;
+    if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
+      qualifier = *fmt;
+      ++fmt;
+    }
+
+    /* default base */
+    base = 10;
+
+    switch (*fmt) {
+    case 'c':
+      if (!(flags & LEFT))
+       while (--field_width > 0)
+         *str++ = ' ';
+      *str++ = (unsigned char) va_arg(args, int);
+      while (--field_width > 0)
+       *str++ = ' ';
+      continue;
+
+    case 's':
+      s = va_arg(args, char *);
+      len = strnlen(s, precision);
+
+      if (!(flags & LEFT))
+       while (len < field_width--)
+         *str++ = ' ';
+      for (i = 0; i < len; ++i)
+       *str++ = *s++;
+      while (len < field_width--)
+       *str++ = ' ';
+      continue;
+
+    case 'p':
+      if (field_width == -1) {
+       field_width = 2*sizeof(void *);
+       flags |= ZEROPAD;
+      }
+      str = number(str,
+                  (unsigned long) va_arg(args, void *), 16,
+                  field_width, precision, flags);
+      continue;
+
+
+    case 'n':
+      if (qualifier == 'l') {
+       long * ip = va_arg(args, long *);
+       *ip = (str - buf);
+      } else {
+       int * ip = va_arg(args, int *);
+       *ip = (str - buf);
+      }
+      continue;
+
+    case '%':
+      *str++ = '%';
+      continue;
+
+      /* integer number formats - set up the flags and "break" */
+    case 'o':
+      base = 8;
+      break;
+
+    case 'X':
+      flags |= LARGE;
+    case 'x':
+      base = 16;
+      break;
+
+    case 'd':
+    case 'i':
+      flags |= SIGN;
+    case 'u':
+      break;
+
+    default:
+      *str++ = '%';
+      if (*fmt)
+       *str++ = *fmt;
+      else
+       --fmt;
+      continue;
+    }
+    if (qualifier == 'l')
+      num = va_arg(args, unsigned long);
+    else if (qualifier == 'h') {
+      num = (unsigned short) va_arg(args, int);
+      if (flags & SIGN)
+       num = (short) num;
+    } else if (flags & SIGN)
+      num = va_arg(args, int);
+    else
+      num = va_arg(args, unsigned int);
+    str = number(str, num, base, field_width, precision, flags);
+  }
+  *str = '\0';
+  return str-buf;
+}
+
+int sprintf(char * buf, const char *fmt, ...)
+{
+  va_list args;
+  int i;
+
+  va_start(args, fmt);
+  i=vsprintf(buf,fmt,args);
+  va_end(args);
+  return i;
+}
+
+int printf(const char *fmt, ...)
+{
+  char printf_buf[1024];
+  va_list args;
+  int printed;
+
+  va_start(args, fmt);
+  printed = vsprintf(printf_buf, fmt, args);
+  va_end(args);
+
+  puts(printf_buf);
+
+  return printed;
+}
diff --git a/reloc/conio.h b/reloc/conio.h
new file mode 100644 (file)
index 0000000..aab7a52
--- /dev/null
@@ -0,0 +1,31 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2001 H. Peter Anvin - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * conio.h
+ *
+ * Limited console I/O
+ */
+
+#ifndef CONIO_H
+#define CONIO_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdarg.h>
+
+int putchar(int);
+int puts(const char *);
+int printf(const char *, ...);
+unsigned int atou(const char *);
+
+#endif
diff --git a/reloc/memmove.S b/reloc/memmove.S
new file mode 100644 (file)
index 0000000..00559d4
--- /dev/null
@@ -0,0 +1,81 @@
+/* ----------------------------------------------------------------------- *
+ *   
+ *   Copyright 2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *   
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *   
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * memmove.S
+ *
+ * Reasonably efficient memmove
+ */
+
+       .globl  memmove
+       .type   memmove,@function
+       .text
+memmove:
+       pushl   %ebx
+       pushl   %esi
+       pushl   %edi
+
+       movl    %eax,%edi
+       movl    %edx,%esi
+
+       cmpl    %edi,%esi
+       jb      1f
+
+       /* source >= dest, forwards move */
+       movl    %ecx,%eax
+       shrl    $2,%ecx
+       andl    $3,%eax
+
+       rep; movsl
+       movl    %eax,%ecx
+       rep; movsb
+
+       jmp     2f
+1:
+       /* source < dest, backwards move */
+       leal    -4(%ecx,%esi),%esi
+       leal    -4(%ecx,%edi),%edi
+
+       movl    %ecx,%eax
+       shrl    $2,%ecx
+       andl    $3,%eax
+
+       std
+       rep; movsl
+       movl    %eax,%ecx
+       addl    $3,%esi
+       addl    $3,%edi
+       rep; movsb
+       cld
+
+2:
+       popl    %edi
+       popl    %esi
+       popl    %ebx
+       ret
+
+       .size   memmove, .-memmove
diff --git a/reloc/reloc.h b/reloc/reloc.h
new file mode 100644 (file)
index 0000000..7b2a4aa
--- /dev/null
@@ -0,0 +1,112 @@
+/* ----------------------------------------------------------------------- *
+ *   
+ *   Copyright 2001-2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *   
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *   
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef RELOC_H
+#define RELOC_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+void memmove(void *, void *, size_t);
+
+void jump_to_kernel(uint32_t rm_segment, uint32_t esp);
+
+static inline void memset(void *dst, int c, size_t len)
+{
+       uint32_t ecx = len >> 2;
+
+       asm volatile("rep; stosl; "
+                    "movl %3,%%ecx; "
+                    "rep; stosb"
+                    : "+D" (dst), "+c" (ecx)
+                    : "a" ((uint8_t)c*0x01010101), "bdS" (len & 3)
+                    : "memory");
+}
+
+/*
+ * This structure defines the register frame used by the
+ * system call interface.
+ *
+ * The syscall interface is:
+ *
+ * intcall(interrupt_#, source_regs, return_regs)
+ */
+typedef union {
+       uint32_t l;
+       uint16_t w[2];
+       uint8_t  b[4];
+} reg32_t;
+
+typedef struct {
+       uint16_t gs;                    /* Offset  0 */
+       uint16_t fs;                    /* Offset  2 */
+       uint16_t es;                    /* Offset  4 */
+       uint16_t ds;                    /* Offset  6 */
+       
+       reg32_t edi;                    /* Offset  8 */
+       reg32_t esi;                    /* Offset 12 */
+       reg32_t ebp;                    /* Offset 16 */
+       reg32_t _unused_esp;            /* Offset 20 */
+       reg32_t ebx;                    /* Offset 24 */
+       reg32_t edx;                    /* Offset 28 */
+       reg32_t ecx;                    /* Offset 32 */
+       reg32_t eax;                    /* Offset 36 */
+
+       reg32_t eflags;                 /* Offset 40 */
+} com32sys_t;
+
+/* EFLAGS definitions */
+#define EFLAGS_CF              0x00000001
+#define EFLAGS_PF              0x00000004
+#define EFLAGS_AF              0x00000010
+#define EFLAGS_ZF              0x00000040
+#define EFLAGS_SF              0x00000080
+#define EFLAGS_TF              0x00000100
+#define EFLAGS_IF              0x00000200
+#define EFLAGS_DF              0x00000400
+#define EFLAGS_OF              0x00000800
+#define EFLAGS_IOPL            0x00003000
+#define EFLAGS_NT              0x00004000
+#define EFLAGS_RF              0x00010000
+#define EFLAGS_VM              0x00020000
+#define EFLAGS_AC              0x00040000
+#define EFLAGS_VIF             0x00080000
+#define EFLAGS_VIP             0x00100000
+#define EFLAGS_ID              0x00200000
+
+static inline uint16_t SEG(const volatile void *__p)
+{
+  return (uint16_t)(((uintptr_t)__p) >> 4);
+}
+
+static inline uint16_t OFFS(const volatile void *__p)
+{
+  /* The double cast here is to shut up gcc */
+  return (uint16_t)(uintptr_t)__p & 0x000F;
+}
+
+#endif /* RELOC_H */
diff --git a/reloc/reloc.ld b/reloc/reloc.ld
new file mode 100644 (file)
index 0000000..dc63c62
--- /dev/null
@@ -0,0 +1,27 @@
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+SECTIONS
+{
+       . = 0;                  /* Required for relocatabilty */
+       .start          : { *(.start) }
+       .text           : { *(.text) }
+       .text16         : { *(.text16) }
+       .rodata         : { *(.rodata) }
+       . = ALIGN(4);
+       .data           : { *(.data) }
+       .got            : { *(.got) }
+       .got.plt        : { *(.got.plt) }
+       . = ALIGN(4);
+       .bss            : 
+       {
+               __bss_start = .;
+               *(.bss)
+               . = ALIGN(4);
+               __bss_end = .;
+       }
+       _end = .;
+       /DISCARD/       : { *(.discard*) }
+}
+
+       
\ No newline at end of file
diff --git a/reloc/reloc_init.S b/reloc/reloc_init.S
new file mode 100644 (file)
index 0000000..b2da82e
--- /dev/null
@@ -0,0 +1,306 @@
+/* ----------------------------------------------------------------------- *
+ *   
+ *   Copyright 2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *   
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *   
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Relocation stub start.  This needs to be position-independent code.
+ */
+
+CS32   = 0x10
+DS32   = 0x18
+CS16   = 0x20
+DS16   = 0x28
+       
+               /* We will be entered in flat 32-bit protected mode... */
+               .section ".start","ax",@progbits
+               .globl  _start
+               .code32
+_start:
+               popl    %edx            /* return address */
+               pushl   %cs
+               pushl   %edx
+               pushfl
+               pushl   %ds
+               pushl   %es
+               pushl   %fs
+               pushl   %gs
+               cli
+               cld
+       
+               calll   1f
+1:             popl    %ebx            /* Figure out where we are */
+               subl    $1b, %ebx       /* %ebx -> offset */
+
+               movl    %esp, orig_esp(%ebx)
+               movw    %ss, orig_ss(%ebx)
+
+               sgdtl   orig_gdt(%ebx)  /* Save current GDT */
+               sidtl   orig_idt(%ebx)  /* Save current IDT */
+
+               addl    %ebx, my_gdt+2(%ebx)
+               lidtl   rm_idt(%ebx)
+               lgdtl   my_gdt(%ebx)
+
+               /* Reinitialize segments */
+               movw    $DS32,%dx
+               movw    %dx,%ss
+               leal    stack_end(%ebx),%esp
+               movw    %dx,%ds
+               movw    %dx,%es
+               movw    %dx,%fs
+               movw    %dx,%gs
+       
+               leal    2f(%ebx),%edx
+               pushl   $CS32
+               pushl   %edx
+               lretl
+2:
+               /* Adjust the real-mode segment bases */
+               addl    %ebx,my_gdt+CS16+2(%ebx)
+               addl    %ebx,my_gdt+DS16+2(%ebx)
+               addl    %ebx,intcall_rm_ret_jmp+2(%ebx)
+
+               /* Zero the .bss - stack must be empty here! */
+               leal    __bss_start(%ebx), %edi
+               leal    _end(%ebx), %ecx
+               subl    %edi, %ecx
+               shrl    $2, %ecx
+               xorl    %eax, %eax
+               rep; stosl
+
+               calll   main
+
+               /* If main() returns, try to return to the original
+                  protected-mode environment.  %eax is live here
+                  and contains the exit code. */
+
+               .globl  _exit
+_exit: 
+               lidtl   orig_idt(%ebx)
+               lgdtl   orig_gdt(%ebx)
+               lssl    orig_esp(%ebx),%esp
+               popl    %gs
+               popl    %fs
+               popl    %es
+               popl    %ds
+               popfl
+               lretl
+
+               /* Call a real-mode interrupt from 32-bit protected mode
+                *
+                * %eax -> interrupt number,
+                * %edx -> input register image,
+                * %ecx -> output register image
+                *
+                */
+               .text
+               .globl  intcall
+intcall:       pushl   %ebx
+               pushl   %esi
+               pushl   %edi
+               pushl   %ebp
+               pushl   %ecx
+
+               calll   1f
+1:             popl    %ebx
+               subl    $1b,%ebx
+
+               movl    %edx,%esi
+               leal    rm_stack_end-(44+12)(%ebx),%edi
+               movl    $11,%ecx
+               rep; movsl
+
+               movl    (,%eax,4),%eax  /* cs:ip */
+               stosl
+               movw    $intcall_rm_return,(%edi)
+               movl    %ebx,%eax
+               shrl    $4,%eax         /* real mode segment */
+               movw    %ax,2(%edi)
+               movw    $2,4(%edi)      /* iret return flags */
+
+               pushl   %ebx
+               leal    intcall_pm_return(%ebx),%ecx
+               movl    %esp,pm_stack(%ebx)
+
+               movw    $DS16,%dx
+               ljmpw   $CS16, $intcall_rm
+
+               .section ".text16","ax",@progbits
+               .code16
+intcall_rm:
+               movw    %dx,%ss
+               movl    $rm_stack_end-(44+12),%esp
+               movw    %dx,%ds
+               movw    %dx,%es
+               movw    %dx,%fs
+               movw    %dx,%gs
+
+               pushw   %ax             /* Real mode segment */
+               pushw   $1f
+       
+               movl    %cr0,%edx
+               andb    $~1,%dl
+               movl    %edx,%cr0
+               lretw
+1:
+               movw    %ax,%ss
+               popw    %gs
+               popw    %fs
+               popw    %es
+               popw    %ds
+               popal
+               popfl
+               lretw
+
+intcall_rm_return:
+               movw    $rm_stack_end,%sp
+               pushfl
+               pushal
+               pushw   %ds
+               pushw   %es
+               pushw   %fs
+               pushw   %gs
+               cli
+               cld
+               movw    $DS32,%dx
+               movl    %cs:pm_stack,%esp
+               movl    %cr0,%eax
+               orb     $1,%al
+               movl    %eax,%cr0
+intcall_rm_ret_jmp:
+               .byte   0x66, 0xea      /* ljmpl */
+               .long   intcall_pm_return
+               .short  CS32
+
+               .text
+               .code32
+intcall_pm_return:
+               movw    %dx,%ss
+               movw    %dx,%ds
+               movw    %dx,%es
+               movw    %dx,%fs
+               movw    %dx,%gs
+       
+               popl    %ebx
+               popl    %edi
+               andl    %edi,%edi
+               jz      1f
+               leal    rm_stack_end-44(%ebx),%esi
+               movl    $11,%ecx
+               rep; movsl
+1:
+               popl    %ebp
+               popl    %edi
+               popl    %esi
+               popl    %ebx
+               retl
+
+/*
+ * Code to invoke the Linux kernel
+ *
+ * %eax: setup segment address
+ * %edx: kernel initial (e)sp
+ */
+               .globl  jump_to_kernel
+jump_to_kernel:
+               calll   1f
+1:             popl    %ebx
+               subl    $1b,%ebx
+               movw    $DS16, %si
+               movw    %si,%ss
+               movl    $rm_stack_end, %esp
+               movw    %si,%ds
+               movw    %si,%es
+               movw    %si,%fs
+               movw    %si,%gs
+               shrl    $4,%ebx         /* %bx <- our real mode segment */
+               ljmpw   $CS16, $jump_to_kernel_rm
+
+               .section ".text16","ax",@progbits
+               .code16
+jump_to_kernel_rm:
+               pushw   %bx
+               pushw   $1f
+               movl    %cr0,%ecx
+               andb    $~1,%cl
+               movl    %ecx,%cr0
+               lretw
+1:
+               movw    %ax,%ss
+               movl    %edx,%esp
+               movw    %ax,%ds
+               movw    %ax,%es
+               movw    %ax,%fs
+               movw    %ax,%gs
+               addw    $0x20,%ax
+               pushw   %ax
+               pushw   $0
+               lretw
+       
+
+               .section ".rodata","a",@progbits
+               .code32
+               .balign 4
+rm_idt:                .short  256*4-1
+               .long   0
+               .short  0
+       
+               .section ".data","aw",@progbits
+               /* Not really initialized, but can't be in .bss */
+orig_esp:      .long   0
+orig_ss:       .short  0       /* Must follow orig_esp */
+orig_gdt:      .short  0, 0, 0
+orig_idt:      .short  0, 0, 0
+
+               .balign 16
+my_gdt:                .short  my_gdt_end-my_gdt-1
+               .long   my_gdt
+               .short  0
+       /* Unused */
+               .long   0, 0
+       
+       /* CS32 */
+               .long   0x0000ffff
+               .long   0x00cf9b00
+       /* DS32 */
+               .long   0x0000ffff
+               .long   0x00cf9300
+       /* CS16 */
+               .long   0x0000ffff
+               .long   0x00009b00
+       /* DS16 */
+               .long   0x0000ffff
+               .long   0x00009300
+my_gdt_end:
+       
+               .section ".bss","aw",@nobits
+               .balign 4
+pm_stack:      .space 4
+kernel_entry:  .space 4
+rm_stack:      .space  1024
+rm_stack_end:
+stack:         .space  1024
+stack_end:
diff --git a/reloc/reloc_linux.c b/reloc/reloc_linux.c
new file mode 100644 (file)
index 0000000..5849c54
--- /dev/null
@@ -0,0 +1,187 @@
+/* ----------------------------------------------------------------------- *
+ *   
+ *   Copyright 2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *   
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *   
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * reloc_linux.c
+ *
+ * This is the initial program run before the Linux kernel.
+ * It serves to hoist the initrd as high as permitted.
+ *
+ * This runs in protected mode, but in low memory, and should be kept
+ * as small as possible.
+ */
+
+#include "reloc.h"
+#include "setup.h"
+#include "conio.h"
+
+static uint32_t initrd_len, initrd_addr;
+static uint64_t max_addr;
+
+static int initrd_fit(uint32_t base, uint32_t end)
+{
+       uint64_t ibase;
+
+       printf("Fit: base = %08x, end = %08x\n", base, end);
+
+       if (end <= base)
+               return -1;      /* Invalid */
+
+       if (base > max_addr)
+               return -1;      /* Not accessible */
+
+       if (end > max_addr)
+               end = max_addr;
+
+       if (end < initrd_len)
+               return -1;
+
+       ibase = (end - initrd_len) & ~0xfff;
+       if (ibase < base)
+               return -1;
+
+       if (initrd_addr < ibase) {
+               initrd_addr = ibase; /* This is a better one... */
+               printf("Best: initrd_addr = %08x\n", initrd_addr);
+       }
+
+       return 0;
+}
+
+static int probe_memory_e820(void)
+{
+       com32sys_t regs;
+       struct e820_info {
+               uint64_t base;
+               uint64_t len;
+               uint32_t type;
+       } buf;
+       uint64_t base, end;
+       int rv = -1;
+       uint32_t copied;
+
+       memset(&regs, 0, sizeof regs);
+
+       do {
+               regs.eax.l = 0x0000e820;
+               regs.ecx.l = sizeof buf;
+               regs.edx.l = 0x534d4150;
+               regs.edi.w[0] = OFFS(&buf);
+               regs.es = SEG(&buf);
+
+               intcall(0x15, &regs, &regs);
+               copied = (regs.eflags.l & EFLAGS_CF)
+                       ? 0 : regs.ecx.l;
+               
+               if ( regs.eax.l != 0x534d4150 || copied < 20 )
+                       break;
+
+               if (buf.type != 1)
+                       continue; /* Not memory */
+
+               rv &= initrd_fit(buf.base, buf.base+buf.len);
+       } while (regs.ebx.l);
+
+       return rv;
+}
+
+static int probe_memory_e801(void)
+{
+       com32sys_t regs;
+       uint64_t base, end;
+
+       memset(&regs, 0, sizeof regs);
+       regs.eax.w[0] = 0xe801;
+       intcall(0x15, &regs, &regs);
+
+       if (regs.eflags.l & EFLAGS_CF)
+               return -1;      /* No e801 */
+
+       if (regs.eax.w[0] < 15*1024)
+               end = (uint64_t)(regs.eax.w[0] << 10) + 0x100000;
+       else
+               end = (uint64_t)(regs.ebx.w[0] << 16) + 0x1000000;
+
+       return initrd_fit(0x100000, end);
+}
+
+static int probe_memory_88(void)
+{
+       com32sys_t regs;
+
+       memset(&regs, 0, sizeof regs);
+       regs.eax.b[1] = 0x88;
+       intcall(0x15, &regs, &regs);
+
+       if (regs.eflags.l & EFLAGS_CF)
+               return -1;
+
+       return initrd_fit(0x100000, (regs.eax.w[0] << 10)+0x100000);
+}
+
+static int place_initrd(void)
+{
+       int rv;
+
+       rv = probe_memory_e820();
+       if (!rv)
+               return 0;
+
+       rv = probe_memory_e801();
+       if (!rv)
+               return 0;
+
+       return probe_memory_88();
+}
+
+int main(void)
+{
+       extern struct startup_info _start[]; /* Cute hack, eh? */
+       struct startup_info *info = _start - 1;
+       struct setup_header *hdr = (void *)(info->setup_addr + 0x1f1);
+
+       if (info->rd_len) {
+               initrd_len = info->rd_len;
+               max_addr   = info->rd_maxaddr;
+
+               if (place_initrd())
+                       return -1;
+
+               /* Move the initrd into place */
+               printf("Moving initrd: 0x%08x -> 0x%08x (0x%08x bytes)\n",
+                      info->rd_addr, initrd_addr, info->rd_len);
+
+               memmove((void *)initrd_addr, (void *)info->rd_addr,
+                       info->rd_len);
+               
+               hdr->ramdisk_image = initrd_addr;
+       }
+
+       jump_to_kernel(info->setup_addr >> 4,
+                      info->cmdline_addr - info->setup_addr);
+       return -1;              /* Shouldn't return... */
+}
diff --git a/segment.h b/segment.h
new file mode 100644 (file)
index 0000000..4d1097f
--- /dev/null
+++ b/segment.h
@@ -0,0 +1,39 @@
+/* ----------------------------------------------------------------------- *
+ *   
+ *   Copyright 2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ *   Boston MA 02110-1301, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * segment.h
+ *
+ * Descriptor for memory segments
+ */
+
+#ifndef SEGMENT_H
+#define SEGMENT_H
+
+#include <inttypes.h>
+
+typedef uint32_t addr_t;
+
+struct segment {
+       struct segment *next;
+       addr_t address;
+       addr_t length;
+       uint32_t sh_type;       /* Uses ELF constants, in host byte order */
+       uint32_t sh_flags;      /* d:o */
+       uint32_t p_flags;
+       const char *name;
+       const void *data;
+};
+
+int output_elf(struct segment *segs, addr_t entry, FILE *out);
+
+#endif /* SEGMENT_H */
diff --git a/setup.h b/setup.h
new file mode 100644 (file)
index 0000000..e203be8
--- /dev/null
+++ b/setup.h
@@ -0,0 +1,53 @@
+#ifndef SETUP_H
+#define SETUP_H
+
+#include <stdint.h>
+
+struct startup_info {
+       uint32_t rd_addr;
+       uint32_t rd_len;
+       uint32_t rd_maxaddr;
+       uint32_t setup_addr;
+       uint32_t cmdline_addr;
+};
+
+struct setup_header {
+       uint8_t  setup_sects;
+       uint16_t root_flags;
+       uint32_t syssize;
+       uint16_t ram_size;
+#define RAMDISK_IMAGE_START_MASK       0x07FF
+#define RAMDISK_PROMPT_FLAG            0x8000
+#define RAMDISK_LOAD_FLAG              0x4000
+       uint16_t vid_mode;
+       uint16_t root_dev;
+       uint16_t boot_flag;
+       uint16_t jump;
+       uint32_t header;
+       uint16_t version;
+       uint32_t realmode_swtch;
+       uint16_t start_sys;
+       uint16_t kernel_version;
+       uint8_t  type_of_loader;
+       uint8_t  loadflags;
+#define LOADED_HIGH    (1<<0)
+#define KEEP_SEGMENTS  (1<<6)
+#define CAN_USE_HEAP   (1<<7)
+       uint16_t setup_move_size;
+       uint32_t code32_start;
+       uint32_t ramdisk_image;
+       uint32_t ramdisk_size;
+       uint32_t bootsect_kludge;
+       uint16_t heap_end_ptr;
+       uint16_t _pad1;
+       uint32_t cmd_line_ptr;
+       uint32_t initrd_addr_max;
+       uint32_t kernel_alignment;
+       uint8_t  relocatable_kernel;
+       uint8_t  _pad2[3];
+       uint32_t cmdline_size;
+       uint32_t hardware_subarch;
+       uint64_t hardware_subarch_data;
+} __attribute__((packed));
+
+#endif /* SETUP_H */
diff --git a/wraplinux.h b/wraplinux.h
new file mode 100644 (file)
index 0000000..6fa5fdb
--- /dev/null
@@ -0,0 +1,26 @@
+/* ----------------------------------------------------------------------- *
+ *   
+ *   Copyright 2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ *   Boston MA 02110-1301, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef WRAPLINUX_H
+#define WRAPLINUX_H
+
+#include <stdio.h>
+
+struct string_list {
+  struct string_list *next;
+  const char *str;
+};
+
+int wrap_kernel(const char *kernel, const char *cmdline,
+               const struct string_list *initrd_list, FILE *out);
+
+#endif