[LWN Logo]
[LWN.net]
From:	 ebiederm@xmission.com (Eric W. Biederman)
To:	 Linus Torvalds <torvalds@transmeta.com>, Dave Jones <davej@suse.de>
Subject: [PATCH 2.5.12] x86 Boot enhancements, build beancounting 8/11
Date:	 02 May 2002 09:07:22 -0600
Cc:	 <linux-kernel@vger.kernel.org>

Please apply,

This patch reorganizes the build of the x86 boot image so
that we preserve enough information to accurately track how
much memory will be used.

Eric

diff -uNr linux-2.5.12.boot.footprint/Makefile linux-2.5.12.boot.build/Makefile
--- linux-2.5.12.boot.footprint/Makefile	Tue Apr 30 22:55:20 2002
+++ linux-2.5.12.boot.build/Makefile	Wed May  1 09:40:42 2002
@@ -93,15 +93,6 @@
 AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS)
 
 #
-# ROOT_DEV specifies the default root-device when making the image.
-# This can be either FLOPPY, CURRENT, /dev/xxxx or empty, in which case
-# the default of FLOPPY is used by 'build'.
-# This is i386 specific.
-#
-
-export ROOT_DEV = CURRENT
-
-#
 # If you want to preset the SVGA mode, uncomment the next line and
 # set SVGA_MODE to whatever number you want.
 # Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode.
diff -uNr linux-2.5.12.boot.footprint/arch/i386/boot/Makefile linux-2.5.12.boot.build/arch/i386/boot/Makefile
--- linux-2.5.12.boot.footprint/arch/i386/boot/Makefile	Sun Aug  5 14:13:19 2001
+++ linux-2.5.12.boot.build/arch/i386/boot/Makefile	Wed May  1 09:40:42 2002
@@ -12,13 +12,11 @@
 		$(TOPDIR)/include/linux/autoconf.h \
 		$(TOPDIR)/include/asm/boot.h
 
-zImage: $(CONFIGURE) bootsect setup compressed/vmlinux tools/build
-	$(OBJCOPY) compressed/vmlinux compressed/vmlinux.out
-	tools/build bootsect setup compressed/vmlinux.out $(ROOT_DEV) > zImage
-
-bzImage: $(CONFIGURE) bbootsect bsetup compressed/bvmlinux tools/build
-	$(OBJCOPY) compressed/bvmlinux compressed/bvmlinux.out
-	tools/build -b bbootsect bsetup compressed/bvmlinux.out $(ROOT_DEV) > bzImage
+zImage: $(CONFIGURE) tools/build $(TOPDIR)/vmlinux realmode compressed/vmlinux 
+	tools/build $(TOPDIR)/vmlinux realmode compressed/vmlinux zImage
+
+bzImage: $(CONFIGURE) tools/build $(TOPDIR)/vmlinux brealmode compressed/bvmlinux 
+	tools/build -b $(TOPDIR)/vmlinux brealmode compressed/bvmlinux bzImage
 
 compressed/vmlinux: $(TOPDIR)/vmlinux
 	@$(MAKE) -C compressed vmlinux
@@ -39,49 +37,43 @@
 install: $(CONFIGURE) $(BOOTIMAGE)
 	sh -x ./install.sh $(KERNELRELEASE) $(BOOTIMAGE) $(TOPDIR)/System.map "$(INSTALL_PATH)"
 
-tools/build: tools/build.c
+tools/build: tools/build.c $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h $(TOPDIR)/include/asm-i386/boot.h
 	$(HOSTCC) $(HOSTCFLAGS) -o $@ $< -I$(TOPDIR)/include
 
-bootsect: bootsect.o
-	$(LD) -Ttext 0x0 -s --oformat binary -o $@ $<
-
 bootsect.o: bootsect.s
 	$(AS) -o $@ $<
 
 bootsect.s: bootsect.S Makefile $(BOOT_INCL)
 	$(CPP) $(CPPFLAGS) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
 
-bbootsect: bbootsect.o
-	$(LD) -Ttext 0x0 -s --oformat binary $< -o $@
-
 bbootsect.o: bbootsect.s
 	$(AS) -o $@ $<
 
 bbootsect.s: bootsect.S Makefile $(BOOT_INCL)
 	$(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
 
-setup: setup.o
-	$(LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $<
-
 setup.o: setup.s
 	$(AS) -o $@ $<
 
 setup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
 	$(CPP) $(CPPFLAGS) -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
 
-bsetup: bsetup.o
-	$(LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $<
-
 bsetup.o: bsetup.s
 	$(AS) -o $@ $<
 
 bsetup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
 	$(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
 
+realmode: bootsect.o setup.o
+	$(LD) -T realmode.lds -o $@ $^
+
+brealmode: bbootsect.o bsetup.o
+	$(LD) -T realmode.lds -o $@ $^
+
 dep:
 
 clean:
 	rm -f tools/build
-	rm -f setup bootsect zImage compressed/vmlinux.out
-	rm -f bsetup bbootsect bzImage compressed/bvmlinux.out
+	rm -f realmode zImage
+	rm -f brealmode bzImage
 	@$(MAKE) -C compressed clean
diff -uNr linux-2.5.12.boot.footprint/arch/i386/boot/bootsect.S linux-2.5.12.boot.build/arch/i386/boot/bootsect.S
--- linux-2.5.12.boot.footprint/arch/i386/boot/bootsect.S	Sun Mar 10 20:07:02 2002
+++ linux-2.5.12.boot.build/arch/i386/boot/bootsect.S	Wed May  1 09:40:42 2002
@@ -54,7 +54,7 @@
 #endif
 
 .code16
-.text
+.section ".bootsect", "ax", @progbits
 
 .global _start
 _start:
diff -uNr linux-2.5.12.boot.footprint/arch/i386/boot/realmode.lds linux-2.5.12.boot.build/arch/i386/boot/realmode.lds
--- linux-2.5.12.boot.footprint/arch/i386/boot/realmode.lds	Wed Dec 31 17:00:00 1969
+++ linux-2.5.12.boot.build/arch/i386/boot/realmode.lds	Wed May  1 09:40:42 2002
@@ -0,0 +1,18 @@
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+ENTRY(_start)
+OUTPUT_ARCH(i386)
+SECTIONS
+{
+	.bootsect 0 : AT(0x10000) {
+		*(.bootsect)
+	}
+	.setup 0 : AT(LOADADDR(.bootsect) + SIZEOF(.bootsect)) {
+		*(.setup)
+	}
+	.setup.heap SIZEOF(.setup) : AT(LOADADDR(.setup) + SIZEOF(.setup)) {
+		*(.setup.heap)
+	}
+	/DISCARD/ : {
+		*(*)
+	}
+}
diff -uNr linux-2.5.12.boot.footprint/arch/i386/boot/setup.S linux-2.5.12.boot.build/arch/i386/boot/setup.S
--- linux-2.5.12.boot.footprint/arch/i386/boot/setup.S	Wed May  1 09:40:06 2002
+++ linux-2.5.12.boot.build/arch/i386/boot/setup.S	Wed May  1 09:40:42 2002
@@ -83,7 +83,7 @@
 .code16
 .globl _setup, _esetup
 
-.text
+.section ".setup", "ax", @progbits
 _setup:	
 
 start:
@@ -174,6 +174,9 @@
 		.long	(_esetup_heap - _setup) + DELTA_BOOTSECT
 real_filesz:				# Datasize of the real mode kernel
 		.long (_esetup - _setup) + DELTA_BOOTSECT
+kern_base:	.long	KERNEL_START	# Kernel load address
+kern_memsz:	.long	0x00000000	# Kernel memory usage
+kern_filesz:	.long	0x00000000	# Kernel datasize
 trampoline:	call	start_of_setup
 		# Don't let the E820 map overlap code
 		. = (E820MAP - DELTA_BOOTSECT) + (E820MAX * E820ENTRY_SIZE)
diff -uNr linux-2.5.12.boot.footprint/arch/i386/boot/tools/build.c linux-2.5.12.boot.build/arch/i386/boot/tools/build.c
--- linux-2.5.12.boot.footprint/arch/i386/boot/tools/build.c	Wed May  1 09:40:06 2002
+++ linux-2.5.12.boot.build/arch/i386/boot/tools/build.c	Wed May  1 09:40:42 2002
@@ -1,19 +1,24 @@
+
 /*
  *  $Id: build.c,v 1.5 1997/05/19 12:29:58 mj Exp $
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *  Copyright (C) 1997 Martin Mares
+ *  Copyright (C) 2002 Eric Biederman
+ *
  */
 
 /*
  * This file builds a disk-image from three different files:
  *
- * - bootsect: exactly 512 bytes of 8086 machine code, loads the rest
- * - setup: 8086 machine code, sets up system parm
+ * - vmlinux: kernel before compression
+ * - realmode: composed of:
+ *    - bootsect: exactly 512 bytes of 8086 machine code, loads the rest
+ *    - setup: 8086 machine code, sets up system parm
  * - system: 80386 code for actual system
  *
  * It does some checking that all files are of the correct type, and
- * just writes the result to stdout, removing headers and padding to
+ * just writes the result, removing headers and padding to
  * the right amount. It also writes some system data to stderr.
  */
 
@@ -22,26 +27,29 @@
  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
  * Cross compiling fixes by Gertjan van Wingerde, July 1996
  * Rewritten by Martin Mares, April 1997
+ * Rewriten by Eric Biederman to remove the need for objcopy and
+ *   to stop losing information. 29 Mary 2002
  */
 
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <stddef.h>
 #include <stdint.h>
 #include <byteswap.h>
 #include <endian.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <sys/sysmacros.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <errno.h>
+#include <elf.h>
+/* To stay in sync with the kernel we must include these headers */
+#include <linux/version.h>
+#include <linux/compile.h>
 #include <asm/boot.h>
 
-typedef unsigned char byte;
-typedef unsigned short word;
-typedef unsigned long u32;
-
 #define DEFAULT_MAJOR_ROOT 0
 #define DEFAULT_MINOR_ROOT 0
 
@@ -64,6 +72,84 @@
 #define le64_to_cpu(x) bswap_64(x)
 #endif
 
+
+/* Input segments */
+#define IKERN  0
+#define IREAL  1
+#define IZKERN 2
+#define ISEGS  3
+
+/* Segments of the output file */
+#define OREAL 0
+#define OKERN 1
+#define OBSS1 2
+#define OBSS2 3
+#define OSEGS 4
+
+struct file_seg
+{
+	size_t mem_addr;
+	size_t mem_size;
+	size_t data_size;
+	off_t  file_offset;
+	size_t entry;
+	unsigned char *data;
+};
+
+struct boot_params {
+	uint8_t  reserved1[0x1f1];		/* 0x000 */
+	uint8_t  setup_sects;			/* 0x1f1 */
+	uint16_t mount_root_rdonly;		/* 0x1f2 */
+	uint16_t syssize;			/* 0x1f4 */
+	uint16_t swapdev;			/* 0x1f6 */
+	uint16_t ramdisk_flags;			/* 0x1f8 */
+#define RAMDISK_IMAGE_START_MASK  	0x07FF
+#define RAMDISK_PROMPT_FLAG		0x8000
+#define RAMDISK_LOAD_FLAG		0x4000	
+	uint16_t vid_mode;			/* 0x1fa */
+	uint16_t root_dev;			/* 0x1fc */
+	uint8_t  reserved9[1];			/* 0x1fe */
+	uint8_t  aux_device_info;		/* 0x1ff */
+	/* 2.00+ */
+	uint8_t  jump[2];			/* 0x200 */
+	uint8_t  header_magic[4];		/* 0x202 */
+	uint16_t version;			/* 0x206 */
+	uint8_t  reserved11[8];			/* 0x208 */
+	uint8_t  type_of_loader;		/* 0x210 */
+#define LOADER_LILO            0x00
+#define LOADER_LOADLIN         0x10
+#define LOADER_BOOTSECT_LOADER 0x20
+#define LOADER_SYSLINUX        0x30
+#define LOADER_ETHERBOOT       0x40
+#define LOADER_UNKNOWN         0xFF
+	uint8_t  loadflags;			/* 0x211 */
+#define LOADFLAG_LOADED_HIGH  1
+#define LOADFLAG_STAY_PUT     0x40
+#define LOADFLAG_CAN_USE_HEAP 0x80
+	uint8_t  reserved12[2];			/* 0x212 */
+	uint32_t code32_start;			/* 0x214 */
+	uint32_t initrd_start;			/* 0x218 */
+	uint32_t initrd_size;			/* 0x21c */
+	uint8_t  reserved13[4];			/* 0x220 */
+	/* 2.01+ */
+	uint16_t heap_end_ptr;			/* 0x224 */
+	uint8_t  reserved14[2];			/* 0x226 */
+	/* 2.02+ */
+	uint32_t cmd_line_ptr;			/* 0x228 */
+	/* 2.03+ */
+	uint32_t ramdisk_max;			/* 0x22c */
+	/* 2.04+ */
+	uint16_t entry32_off;			/* 0x230 */
+	uint16_t internal_cmdline_off;		/* 0x232 */
+	uint32_t real_base;			/* 0x240 */
+	uint32_t real_memsz;			/* 0x244 */
+	uint32_t real_filesz;			/* 0x248 */
+	uint32_t kern_base;			/* 0x24C */
+	uint32_t kern_memsz;			/* 0x250 */
+	uint32_t kern_filesz;			/* 0x254 */
+						/* 0x258 */
+};
+
 #define OF(args) args
 #define STATIC static
 				/* and a power of two */
@@ -103,6 +189,7 @@
 #include "../../../../lib/inflate.c"
 
 struct zkernel_header {
+	/* 2.04+ */
 	uint8_t  jump[4];
 	uint32_t input_addr;
 	uint32_t input_len;
@@ -147,22 +234,28 @@
 		oh.overhang = overhang;
 	}
 }
-static size_t compute_unzip_overhang(unsigned char *data, size_t data_size)
+static size_t compute_unzip_overhang(struct file_seg *iseg)
 {
 	struct zkernel_header *zhdr;
+	unsigned char *data;
+	size_t data_size;
 	size_t result_size;
 	size_t offset;
 	
-
 	/* Set up the input buffer */
+	data = iseg[IZKERN].data;
+	data_size = iseg[IZKERN].data_size;
 	zhdr = (struct zkernel_header *)data;
-	offset = le32_to_cpu(zhdr->input_addr) - HIGH_BASE;
+	offset = le32_to_cpu(zhdr->input_addr) - iseg[IZKERN].mem_addr;
 	inbuf = data + offset;
 	insize = le32_to_cpu(zhdr->input_len);
 	if (insize != data_size - offset)
 		die("Compressed kernel sizes(%d,%d) do not match!\n",
 			insize, data_size - offset);
 	result_size = le32_to_cpu(*(uint32_t *)(inbuf + insize - 4));
+	if (result_size != iseg[IKERN].data_size)
+		die("Uncompressed kernel sizes(%d,%d) do not match!\n",
+			result_size, iseg[IKERN].data_size);
 	inptr = 0;
 
 	/* Setup the overhang computation */
@@ -172,20 +265,10 @@
 	makecrc();
 	gunzip();
 	
-	zhdr->output_overhang = cpu_to_le32(oh.overhang);
-	zhdr->kernel_memsz = cpu_to_le32(result_size);
-	zhdr->kernel_filesz = cpu_to_le32(result_size);
 	return oh.overhang;
 }
 
-
-
-byte buf[1024];
-byte *bigbuf;
-int fd;
-int is_big_kernel;
-
-void die(const char * str, ...)
+static void die(const char * str, ...)
 {
 	va_list args;
 	va_start(args, str);
@@ -194,147 +277,430 @@
 	exit(1);
 }
 
-void file_open(const char *name)
+static int checked_open(const char *pathname, int flags, mode_t mode)
 {
-	if ((fd = open(name, O_RDONLY, 0)) < 0)
-		die("Unable to open `%s': %m", name);
+	int result;
+	result = open(pathname, flags, mode);
+	if (result < 0) {
+		die("Cannot open %s : %s", 
+			pathname,
+			strerror(errno));
+	}
+	return result;
 }
 
-void usage(void)
+static void checked_read(int fd, void *buf, size_t count, const char *pathname)
 {
-	die("Usage: build [-b] bootsect setup system [rootdev] [> image]");
+	ssize_t result;
+	result = read(fd, buf, count);
+	if (result != count) {
+		die("Cannot read %d bytes from %s: %s",
+			count, 
+			pathname,
+			strerror(errno));
+	}
 }
 
-int main(int argc, char ** argv)
+static void checked_write(int fd, void *buf, size_t count, const char *pathname)
 {
-	unsigned int i, c, sz, setup_sectors;
-	u32 sys_size;
-	byte major_root, minor_root;
-	struct stat sb;
-
-	if (argc > 2 && !strcmp(argv[1], "-b"))
-	  {
-	    is_big_kernel = 1;
-	    argc--, argv++;
-	  }
-	if ((argc < 4) || (argc > 5))
-		usage();
-	if (argc > 4) {
-		if (!strcmp(argv[4], "CURRENT")) {
-			if (stat("/", &sb)) {
-				perror("/");
-				die("Couldn't stat /");
+	ssize_t result;
+	result = write(fd, buf, count);
+	if (result != count) {
+		die("Cannot write %d bytes from %s: %s",
+			count, 
+			pathname,
+			strerror(errno));
+	}
+}
+
+static off_t checked_lseek(int fd, off_t offset, int whence, const char *pathname)
+{
+	off_t result;
+	result = lseek(fd, offset, whence);
+	if (result == (off_t)-1) {
+		die("lseek failed on %s: %s",
+			pathname, strerror(errno));
+	}
+	return result;
+}
+
+static void *checked_malloc(size_t size)
+{
+	void *result;
+	result = malloc(size);
+	if (result == 0) {
+		die("malloc of %d bytes failed: %s",
+			size, strerror(errno));
+	}
+	return result;
+}
+
+static void check_ehdr(Elf32_Ehdr *ehdr, char *name)
+{
+	/* Do some basic to ensure it is an ELF image */
+	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) {
+		die("%s is not an ELF binary", name);
+	}
+	if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) {
+		die("%s is not a 32bit ELF object", name);
+	}
+	if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
+		die("%s does not have little endian data", name);
+	}
+	if ((ehdr->e_ident[EI_VERSION] != EV_CURRENT) ||
+		ehdr->e_version != EV_CURRENT) {
+		die("%s has invalid ELF version", name);
+	}
+	if (ehdr->e_type != ET_EXEC) {
+		die("%s is not an ELF executable", name);
+	}
+	if (ehdr->e_machine != EM_386) {
+		die("%s is not for x86", name);
+	}
+	if ((ehdr->e_phoff == 0) || (ehdr->e_phnum == 0)) {
+		die("%s has no program header", name);
+	}
+	if (ehdr->e_phentsize != sizeof(Elf32_Phdr)) {
+		die("%s has invalid program header size", name);
+	}
+}
+
+static Elf32_Phdr *read_sorted_phdr(char *name, int fd, 
+	Elf32_Ehdr *ehdr, struct file_seg *seg)
+{
+	int i, j;
+	Elf32_Phdr *phdr, *plow, *phigh;
+	size_t phdr_size;
+	seg->mem_addr = 0;
+	seg->mem_size = 0;
+	seg->data_size = 0;
+	seg->file_offset = 0;
+	seg->entry = ehdr->e_entry;
+	seg->data = 0;
+
+	phdr_size = ehdr->e_phnum * sizeof(*phdr);
+	phdr = checked_malloc(phdr_size);
+	checked_lseek(fd, ehdr->e_phoff, SEEK_SET, name);
+	checked_read(fd, phdr, phdr_size, name);
+
+	plow = 0;
+	phigh = 0;
+	/* Do an insertion sort on the program headers */
+	for(i = 0; i < ehdr->e_phnum; i++) {
+		Elf32_Phdr *least;
+		least = phdr +i;
+		for(j = i+1; j < ehdr->e_phnum; j++) {
+			if (phdr[j].p_type != PT_LOAD) {
+				continue;
 			}
-			major_root = major(sb.st_dev);
-			minor_root = minor(sb.st_dev);
-		} else if (strcmp(argv[4], "FLOPPY")) {
-			if (stat(argv[4], &sb)) {
-				perror(argv[4]);
-				die("Couldn't stat root device.");
+			if ((least->p_type != PT_LOAD) || 
+				(phdr[j].p_paddr < least->p_paddr)) {
+				least = phdr + j;
 			}
-			major_root = major(sb.st_rdev);
-			minor_root = minor(sb.st_rdev);
-		} else {
-			major_root = 0;
-			minor_root = 0;
 		}
-	} else {
-		major_root = DEFAULT_MAJOR_ROOT;
-		minor_root = DEFAULT_MINOR_ROOT;
+		if (least != phdr +i) {
+			Elf32_Phdr tmp;
+			tmp = phdr[i];
+			phdr[i] = *least;
+			*least = tmp;
+		}
+	}
+	plow = phdr;
+	phigh = 0;
+	for(i = 0; i < ehdr->e_phnum; i++) {
+		if (phdr[i].p_type != PT_LOAD)
+			break;
+		phigh = phdr +i;
+	}
+	if (phigh) {
+		size_t start, middle, end;
+		start = plow->p_paddr;
+		middle = phigh->p_paddr + phigh->p_filesz;
+		end = phigh->p_paddr + phigh->p_memsz;
+		seg->mem_addr = start;
+		seg->mem_size = end - start;
+		seg->data_size = middle - start;
 	}
-	fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root);
+	return phdr;
+	
+}
 
-	file_open(argv[1]);
-	i = read(fd, buf, sizeof(buf));
-	fprintf(stderr,"Boot sector %d bytes.\n",i);
-	if (i != 512)
-		die("Boot block must be exactly 512 bytes");
-	if (buf[510] != 0x55 || buf[511] != 0xaa)
-		die("Boot block hasn't got boot flag (0xAA55)");
-	buf[508] = minor_root;
-	buf[509] = major_root;
-	if (write(1, buf, 512) != 512)
-		die("Write call failed");
-	close (fd);
-
-	file_open(argv[2]);				    /* Copy the setup code */
-	for (i=0 ; (c=read(fd, buf, sizeof(buf)))>0 ; i+=c )
-		if (write(1, buf, c) != c)
-			die("Write call failed");
-	if (c != 0)
-		die("read-error on `setup'");
-	close (fd);
-
-	setup_sectors = (i + 511) / 512;	/* Pad unused space with zeros */
-	/* for compatibility with ancient versions of LILO. */
-	if (setup_sectors < SETUP_SECTS)
-		setup_sectors = SETUP_SECTS;
-	fprintf(stderr, "Setup is %d bytes.\n", i);
-	memset(buf, 0, sizeof(buf));
-	while (i < setup_sectors * 512) {
-		c = setup_sectors * 512 - i;
-		if (c > sizeof(buf))
-			c = sizeof(buf);
-		if (write(1, buf, c) != c)
-			die("Write call failed");
-		i += c;
-	}
-
-	file_open(argv[3]);
-	if (fstat (fd, &sb))
-		die("Unable to stat `%s': %m", argv[3]);
-	sz = sb.st_size;
-	fprintf (stderr, "System is %d kB\n", sz/1024);
-	sys_size = (sz + 15) / 16;
-	/* 0x28000*16 = 2.5 MB, conservative estimate for the current maximum */
-	if (sys_size > (is_big_kernel ? 0x28000 : DEF_SYSSIZE))
-		die("System is too big. Try using %smodules.",
-			is_big_kernel ? "" : "bzImage or ");
-	if (sys_size > 0xefff)
-		fprintf(stderr,"warning: kernel is too big for standalone boot "
-		    "from floppy\n");
-	bigbuf = malloc(sz);
-	if (!bigbuf)
-		die("Out of memory\n");
-	while (sz > 0) {
-		int off, n;
-
-		off = sb.st_size - sz;
-		if ((n=read(fd, bigbuf +off, sz)) <= 0) {
-			if (n < 0)
-				die("Error reading %s: %m", argv[3]);
-			else
-				die("%s: Unexpected EOF", argv[3]);
-		}
-		sz -= n;
+static void get_elf_sizes(char *name, size_t pstart, struct file_seg *sizes)
+{
+	int fd;
+	Elf32_Ehdr ehdr;
+	Elf32_Phdr *phdr;
+	fd = checked_open(name, O_RDONLY, 0);
+	checked_read(fd, &ehdr, sizeof(ehdr), name);
+	check_ehdr(&ehdr, name);
+
+	phdr = read_sorted_phdr(name, fd, &ehdr, sizes);
+	if (sizes->mem_addr != pstart) {
+		die("Low PHDR in %s not at 0x%08x", name, pstart);
 	}
+
+	free(phdr);
 	close(fd);
-	compute_unzip_overhang(bigbuf, sb.st_size);
-	sz = sb.st_size;
-	while(sz > 0) {
-		int off, n;
-		
-		off = sb.st_size - sz;
-		if ((n=write(1, bigbuf+off, sz)) <= 0) {
-			if (n < 0)
-				die("Error writing %s: %m", "<stdout>");
-			else
-				die("%s: Unexpected EOF", "<stdout>");
+	return;
+}
+
+static void read_elf(char *name, size_t pstart, struct file_seg *seg)
+{
+	int src_fd;
+	Elf32_Ehdr ehdr;
+	Elf32_Phdr *phdr;
+	size_t last_paddr;
+	size_t loc;
+	int i;
+
+	src_fd = checked_open(name, O_RDONLY, 0);
+	checked_read(src_fd, &ehdr, sizeof(ehdr), name);
+	check_ehdr(&ehdr, name);
+
+	phdr = read_sorted_phdr(name, src_fd, &ehdr, seg);
+	if (seg->mem_addr != pstart) {
+		die("Low PHDR in %s not at 0x%08x", name, pstart);
+	}
+	
+	last_paddr = phdr[0].p_paddr;
+	seg->data = checked_malloc(seg->data_size);
+	loc = 0;
+	for(i = 0; i < ehdr.e_phnum; i++) {
+		size_t size;
+		if (phdr[i].p_type != PT_LOAD) {
+			break;
+		}
+		if (last_paddr != phdr[i].p_paddr) {
+			size = phdr[i].p_paddr - last_paddr;
+			memset(seg->data + loc, 0, size);
+			loc += size;
 		}
-		sz -= n;
+		last_paddr = phdr[i].p_paddr + phdr[i].p_filesz;
+
+		size = phdr[i].p_filesz;
+		checked_lseek(src_fd, phdr[i].p_offset, SEEK_SET, name);
+		checked_read(src_fd, seg->data + loc, size, name);
+		loc += size;
 	}
+	free(phdr);
+	close(src_fd);
+	return;
+}
 
-	if (lseek(1, 497, SEEK_SET) != 497)		    /* Write sizes to the bootsector */
-		die("Output: seek failed");
-	buf[0] = setup_sectors;
-	if (write(1, buf, 1) != 1)
-		die("Write of setup sector count failed");
-	if (lseek(1, 500, SEEK_SET) != 500)
-		die("Output: seek failed");
-	buf[0] = (sys_size & 0xff);
-	buf[1] = ((sys_size >> 8) & 0xff);
-	if (write(1, buf, 2) != 2)
-		die("Write of image length failed");
+struct image_info {
+	int is_big_kernel;
+	size_t entry32;
+	size_t setup_sectors;
+	size_t sys_size;
+	size_t root_dev;
+	size_t unzip_overhang;
+	struct boot_params *param;
+	struct zkernel_header *zhdr;
+};
 
-	return 0;					    /* Everything is OK */
+static void update_image(
+	struct file_seg *iseg, struct file_seg *oseg, struct image_info *info)
+{
+	struct boot_params *param = info->param;
+	struct zkernel_header *zhdr = info->zhdr;
+	info->setup_sectors &= 0xff;
+	info->sys_size &= 0xffff;
+	info->root_dev &= 0xffff;
+	param->setup_sects    = info->setup_sectors;
+	param->syssize        = cpu_to_le16(info->sys_size);
+	param->root_dev       = cpu_to_le16(info->root_dev);
+	param->real_base      = cpu_to_le32(oseg[OREAL].mem_addr);
+	param->real_memsz     = cpu_to_le32(oseg[OREAL].mem_size);
+	param->real_filesz    = cpu_to_le32(oseg[OREAL].data_size);
+	param->kern_base      = cpu_to_le32(oseg[OKERN].mem_addr);
+	param->kern_memsz     = cpu_to_le32(oseg[OKERN].mem_size);
+	param->kern_filesz    = cpu_to_le32(oseg[OKERN].data_size);
+	zhdr->output_overhang = cpu_to_le32(info->unzip_overhang);
+	zhdr->kernel_memsz    = cpu_to_le32(iseg[IKERN].mem_size);
+	zhdr->kernel_filesz   = cpu_to_le32(iseg[IKERN].data_size);
+}
+
+static void usage(void)
+{
+	die("Usage: build [-b] vmlinux realmode compressed/vmlinux image");
+}
+
+int main(int argc, char ** argv)
+{
+	char *kernel;
+	char *realmode;
+	char *zkernel;
+	char *image;
+	int image_fd;
+	size_t major_root, minor_root;
+	size_t zkernel_base;
+	struct image_info info;
+	struct file_seg iseg[ISEGS];
+	struct file_seg oseg[OSEGS];
+	struct stat st;
+	int i;
+
+	memset(iseg, 0, sizeof(iseg));
+	memset(oseg, 0, sizeof(oseg));
+	memset(&info, 0, sizeof(info));
+	info.is_big_kernel = 0;
+	if (argc > 2 && (strcmp(argv[1], "-b") == 0)) {
+		info.is_big_kernel = 1;
+		argc--;
+		argv++;
+	}
+	if (argc != 5) {
+		usage();
+	}
+	kernel = argv[1];
+	realmode = argv[2];
+	zkernel = argv[3];
+	image = argv[4];
+
+	/* Compute the current root device */
+	major_root = DEFAULT_MAJOR_ROOT;
+	minor_root = DEFAULT_MINOR_ROOT;
+	if (stat("/", &st) == 0) {
+		major_root = major(st.st_dev);
+		minor_root = minor(st.st_dev);
+	}
+	major_root &= 0xff;
+	minor_root &= 0xff;
+	info.root_dev = (major_root << 8) | minor_root;
+	printf("Root device is (%d, %d)\n", major_root, minor_root);
+
+	/* Read in the file information */
+	zkernel_base = info.is_big_kernel? HIGH_BASE : LOW_BASE;
+	get_elf_sizes(kernel, HIGH_BASE,    &iseg[IKERN]);
+	read_elf(realmode,    REAL_BASE,     &iseg[IREAL]);
+	read_elf(zkernel,     zkernel_base, &iseg[IZKERN]);
+	
+	oseg[OREAL] = iseg[IREAL];
+	oseg[OKERN] = iseg[IZKERN];
+
+	info.param = (struct boot_params *)oseg[OREAL].data;
+	info.zhdr = (struct zkernel_header *)oseg[OKERN].data;
+	info.unzip_overhang = compute_unzip_overhang(iseg);
+
+	/* Compute the memory usage when the compressed data
+	 * and the BSS stop overlapping.
+	 */
+	oseg[OKERN].mem_size = oseg[OKERN].data_size + 
+		(le32_to_cpu(info.zhdr->unzip_memsz) - 
+			le32_to_cpu(info.zhdr->unzip_filesz));
+	if (!info.is_big_kernel) {
+		/* zImage */
+		size_t kern_end;
+		/* zImages are wacky, they load at 64K but then
+		 * setup.S relocates them down to 4K.
+		 */
+		/* Check the decompression address and ensure we
+		 * have enough space, to decompress.
+		 */
+		oseg[OREAL].mem_addr = DEF_INITSEG << 4;
+		kern_end = oseg[OKERN].mem_addr + oseg[OKERN].mem_size;
+		kern_end = (kern_end + 15) & ~15; 
+		if (kern_end > oseg[OREAL].mem_addr) {
+			die("System is to big.  Try using bzImage or modules");
+		}
+
+		/* Describe the initial hole */
+		oseg[OBSS1].mem_addr = oseg[OKERN].mem_addr;
+		oseg[OBSS1].data_size = 0;
+		oseg[OBSS1].mem_size = 	(DEF_SYSSEG << 4) - oseg[OBSS1].mem_addr;
+
+		/* Check the load time address and verify we
+		 * have enough space to load.
+		 */
+		oseg[OKERN].mem_addr = DEF_SYSSEG << 4;
+		kern_end = oseg[OKERN].mem_addr + oseg[OKERN].data_size;
+		kern_end = (kern_end + 15) & ~15;
+		if (kern_end > oseg[OREAL].mem_addr) {
+			die("System is to big.  Try using bzImage or modules");
+		}
+		
+		/* Describe where the kernel actually runs */
+		oseg[OBSS2].mem_addr = HIGH_BASE;
+		oseg[OBSS2].mem_size = iseg[IKERN].mem_size;
+		oseg[OBSS2].data_size = 0;
+	} else {
+		/* bzImage */
+		size_t unzip_bufsz;
+		
+		/* Compute the bzImage decompressor memory size */
+		unzip_bufsz = iseg[IKERN].data_size + info.unzip_overhang;
+		if (unzip_bufsz > oseg[OKERN].mem_size) {
+			oseg[OKERN].mem_size = unzip_bufsz;
+		}
+
+		/* Compute how much real memory we need */
+		oseg[OREAL].mem_size += 
+			((le32_to_cpu(info.zhdr->unzip_memsz) - 
+				oseg[OKERN].mem_addr) + 0xfff) & ~0xfff;
+		oseg[OREAL].mem_size += COMMAND_LINE_SIZE;
+		if (oseg[OREAL].mem_size > REAL_MAX - REAL_BASE) {
+			die("Kernel requires %d bytes low memory %d available!\n",
+				oseg[OREAL].mem_size,
+				REAL_MAX - REAL_BASE);
+		}
+		/* See if the loaded kernel uses more memory */
+		if (iseg[IKERN].mem_size > oseg[OKERN].mem_size) {
+			oseg[OKERN].mem_size = iseg[IKERN].mem_size;
+		}
+	}
+
+	/* Compute the file offsets */
+	info.setup_sectors = (oseg[OREAL].data_size - 512 + 511)/512;
+	if (info.setup_sectors < SETUP_SECTS)
+		info.setup_sectors = SETUP_SECTS;
+
+	oseg[OKERN].file_offset = oseg[OREAL].file_offset + (info.setup_sectors +1)*512;
+
+	/* Check and print the values to write back. */
+	info.entry32 = oseg[OREAL].mem_addr + 
+		le32_to_cpu(info.param->entry32_off);
+	printf("Boot sector is 512 bytes\n");
+	printf("Setup is %d bytes\n", oseg[OREAL].data_size - 512);
+
+	info.sys_size = (oseg[OKERN].data_size + 15)/16;
+	if ((iseg[IKERN].mem_addr + iseg[IKERN].mem_size) 
+		>= INITIAL_PAGE_TABLE_SIZE) {
+		die("System is to big.  Try using modules.");
+	}
+	if (info.sys_size > 0xefff) {
+		fprintf(stderr, "warning: kernel is too big for standalone boot " 
+			"from floppy\n");
+	}
+	printf("System is %d KB\n", (info.sys_size*16)/1024);
+	printf("entry32: 0x%x\n", info.entry32);
+	printf("[real] base: %08x filesz %5d B  memsz= %5d KB\n", 
+		oseg[OREAL].mem_addr,
+		oseg[OREAL].data_size,
+		oseg[OREAL].mem_size/1024);
+	printf("[kern] base: %08x filesz %5d KB memsz= %5d KB\n", 
+		oseg[OKERN].mem_addr, 
+		oseg[OKERN].data_size/1024,
+		oseg[OKERN].mem_size/1024); 
+	printf("[bss1] base: %08x filesz %5d KB memsz= %5d KB\n",
+		oseg[OBSS1].mem_addr,
+		oseg[OBSS1].data_size/1024,
+		oseg[OBSS1].mem_size/1024);
+	printf("[bss2] base: %08x filesz %5d KB memsz= %5d KB\n",
+		oseg[OBSS2].mem_addr,
+		oseg[OBSS2].data_size/1024,
+		oseg[OBSS2].mem_size/1024);
+
+	/* Write the values back */
+	update_image(iseg, oseg, &info);
+
+	/* Write destination file */
+	image_fd = checked_open(image, O_RDWR | O_CREAT | O_TRUNC, 0666);
+	for(i = 0; i < OSEGS; i++) {
+		if (oseg[i].data_size == 0)
+			continue;
+		checked_lseek(image_fd, oseg[i].file_offset, SEEK_SET, image);
+		checked_write(image_fd, oseg[i].data, oseg[i].data_size, image);
+	}
+	close(image_fd);
+	return 0;
 }
diff -uNr linux-2.5.12.boot.footprint/arch/x86_64/boot/Makefile linux-2.5.12.boot.build/arch/x86_64/boot/Makefile
--- linux-2.5.12.boot.footprint/arch/x86_64/boot/Makefile	Sun Mar 10 20:08:39 2002
+++ linux-2.5.12.boot.build/arch/x86_64/boot/Makefile	Wed May  1 09:40:42 2002
@@ -14,11 +14,11 @@
 
 zImage: $(CONFIGURE) bootsect setup compressed/vmlinux tools/build
 	$(OBJCOPY) compressed/vmlinux compressed/vmlinux.out
-	tools/build bootsect setup compressed/vmlinux.out $(ROOT_DEV) > zImage
+	tools/build bootsect setup compressed/vmlinux.out CURRENT > zImage
 
 bzImage: $(CONFIGURE) bbootsect bsetup compressed/bvmlinux tools/build
 	$(OBJCOPY) compressed/bvmlinux compressed/bvmlinux.out
-	tools/build -b bbootsect bsetup compressed/bvmlinux.out $(ROOT_DEV) > bzImage
+	tools/build -b bbootsect bsetup compressed/bvmlinux.out CURRENT > bzImage
 
 bzImage-padded: bzImage
 	dd if=/dev/zero bs=1k count=70 >> bzImage
diff -uNr linux-2.5.12.boot.footprint/include/asm-i386/boot_param.h linux-2.5.12.boot.build/include/asm-i386/boot_param.h
--- linux-2.5.12.boot.footprint/include/asm-i386/boot_param.h	Wed May  1 09:40:06 2002
+++ linux-2.5.12.boot.build/include/asm-i386/boot_param.h	Wed May  1 09:40:42 2002
@@ -88,7 +88,10 @@
 	__u32 real_base;			/* 0x234 */
 	__u32 real_memsz;			/* 0x238 */
 	__u32 real_filesz;			/* 0x23c */
-	__u8  reserved15[0x2d0 - 0x240];	/* 0x240 */
+ 	__u32 kern_base;			/* 0x240 */
+ 	__u32 kern_memsz;			/* 0x244 */
+ 	__u32 kern_filesz;			/* 0x248 */
+ 	__u8  reserved15[0x2d0 - 0x24c];	/* 0x24c */
 	struct e820entry e820_map[E820MAX];	/* 0x2d0 */
 						/* 0x550 */
 } __attribute__((packed));
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/