--- /dev/null
+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
--- /dev/null
+/* ----------------------------------------------------------------------- *
+ *
+ * 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;
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/* ----------------------------------------------------------------------- *
+ *
+ * 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 */
--- /dev/null
+/* ----------------------------------------------------------------------- *
+ *
+ * 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;
+}
--- /dev/null
+/* ----------------------------------------------------------------------- *
+ *
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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:
--- /dev/null
+/* ----------------------------------------------------------------------- *
+ *
+ * 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(®s, 0, sizeof regs);
+
+ if ( ch == '\n' ) {
+ /* \n -> \r\n */
+ putchar('\r');
+ }
+
+ regs.eax.w[0] = 0x0e00|(ch&0xff);
+ intcall(0x10, ®s, 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;
+}
--- /dev/null
+/* ----------------------------------------------------------------------- *
+ *
+ * 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
--- /dev/null
+/* ----------------------------------------------------------------------- *
+ *
+ * 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
--- /dev/null
+/* ----------------------------------------------------------------------- *
+ *
+ * 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 */
--- /dev/null
+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
--- /dev/null
+/* ----------------------------------------------------------------------- *
+ *
+ * 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:
--- /dev/null
+/* ----------------------------------------------------------------------- *
+ *
+ * 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(®s, 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, ®s, ®s);
+ 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(®s, 0, sizeof regs);
+ regs.eax.w[0] = 0xe801;
+ intcall(0x15, ®s, ®s);
+
+ 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(®s, 0, sizeof regs);
+ regs.eax.b[1] = 0x88;
+ intcall(0x15, ®s, ®s);
+
+ 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... */
+}
--- /dev/null
+/* ----------------------------------------------------------------------- *
+ *
+ * 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 */
--- /dev/null
+#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 */
--- /dev/null
+/* ----------------------------------------------------------------------- *
+ *
+ * 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