Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5bbf89fc authored by Rusty Russell's avatar Rusty Russell
Browse files

Loading bzImage directly.



Now arch/i386/boot/compressed/head.S understands the hardware_platform field,
we can directly execute bzImages.  No more horrific unpacking code.

Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 814a0e5c
Loading
Loading
Loading
Loading
+29 −64
Original line number Diff line number Diff line
@@ -326,74 +326,39 @@ static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr)
	return ehdr->e_entry;
}

/*L:160 Unfortunately the entire ELF image isn't compressed: the segments
 * which need loading are extracted and compressed raw.  This denies us the
 * information we need to make a fully-general loader. */
static unsigned long unpack_bzimage(int fd)
{
	gzFile f;
	int ret, len = 0;
	/* A bzImage always gets loaded at physical address 1M.  This is
	 * actually configurable as CONFIG_PHYSICAL_START, but as the comment
	 * there says, "Don't change this unless you know what you are doing".
	 * Indeed. */
	void *img = from_guest_phys(0x100000);

	/* gzdopen takes our file descriptor (carefully placed at the start of
	 * the GZIP header we found) and returns a gzFile. */
	f = gzdopen(fd, "rb");
	/* We read it into memory in 64k chunks until we hit the end. */
	while ((ret = gzread(f, img + len, 65536)) > 0)
		len += ret;
	if (ret < 0)
		err(1, "reading image from bzImage");

	verbose("Unpacked size %i addr %p\n", len, img);

	/* The entry point for a bzImage is always the first byte */
	return (unsigned long)img;
}

/*L:150 A bzImage, unlike an ELF file, is not meant to be loaded.  You're
 * supposed to jump into it and it will unpack itself.  We can't do that
 * because the Guest can't run the unpacking code, and adding features to
 * lguest kills puppies, so we don't want to.
 * supposed to jump into it and it will unpack itself.  We used to have to
 * perform some hairy magic because the unpacking code scared me.
 *
 * The bzImage is formed by putting the decompressing code in front of the
 * compressed kernel code.  So we can simple scan through it looking for the
 * first "gzip" header, and start decompressing from there. */
 * Fortunately, Jeremy Fitzhardinge convinced me it wasn't that hard and wrote
 * a small patch to jump over the tricky bits in the Guest, so now we just read
 * the funky header so we know where in the file to load, and away we go! */
static unsigned long load_bzimage(int fd)
{
	unsigned char c;
	int state = 0;

	/* GZIP header is 0x1F 0x8B <method> <flags>... <compressed-by>. */
	while (read(fd, &c, 1) == 1) {
		switch (state) {
		case 0:
			if (c == 0x1F)
				state++;
			break;
		case 1:
			if (c == 0x8B)
				state++;
			else
				state = 0;
			break;
		case 2 ... 8:
			state++;
			break;
		case 9:
			/* Seek back to the start of the gzip header. */
			lseek(fd, -10, SEEK_CUR);
			/* One final check: "compressed under UNIX". */
			if (c != 0x03)
				state = -1;
			else
				return unpack_bzimage(fd);
		}
	}
	errx(1, "Could not find kernel in bzImage");
	u8 hdr[1024];
	int r;
	/* Modern bzImages get loaded at 1M. */
	void *p = from_guest_phys(0x100000);

	/* Go back to the start of the file and read the header.  It should be
	 * a Linux boot header (see Documentation/i386/boot.txt) */
	lseek(fd, 0, SEEK_SET);
	read(fd, hdr, sizeof(hdr));

	/* At offset 0x202, we expect the magic "HdrS" */
	if (memcmp(hdr + 0x202, "HdrS", 4) != 0)
		errx(1, "This doesn't look like a bzImage to me");

	/* The byte at 0x1F1 tells us how many extra sectors of
	 * header: skip over them all. */
	lseek(fd, (unsigned long)(hdr[0x1F1]+1) * 512, SEEK_SET);

	/* Now read everything into memory. in nice big chunks. */
	while ((r = read(fd, p, 65536)) > 0)
		p += r;

	/* Finally, 0x214 tells us where to start the kernel. */
	return *(unsigned long *)&hdr[0x214];
}

/*L:140 Loading the kernel is easy when it's a "vmlinux", but most kernels