All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Gibson <david@gibson.dropbear.id.au>
To: <linuxppc-dev@ozlabs.org>
Subject: [PATCH 5/14] zImage: Add more flexible gunzip convenience functions
Date: Tue, 20 Feb 2007 13:12:35 +1100 (EST)	[thread overview]
Message-ID: <20070220021235.042ABDDD0E@ozlabs.org> (raw)
In-Reply-To: <20070220020837.GF17818@localhost.localdomain>

At present, arch/powerpc/boot/main.c includes a gunzip() function
which is a convenient wrapper around zlib.  However, it doesn't
conveniently allow decompressing part of an image to one location,
then the remainder to a different address.

This patch adds a new set of more flexible convenience wrappers around
zlib, moving them to their own file, gunzip_util.c, in the process.
These wrappers allow decompressing sections of the compressed image to
different locations.  In addition, they transparently handle
uncompressed data, avoiding special case code to handle uncompressed
vmlinux images.

The patch also converts main.c to use the new wrappers, using the new
flexibility to avoid decompressing the vmlinux's ELF header twice as
we did previously.  That in turn means we avoid extending our
allocations for the vmlinux to allow space for the extra copy of the
ELF header.

Signed-off-by: David Gibson <dwg@au1.ibm.com>
---

 arch/powerpc/boot/Makefile      |    3 
 arch/powerpc/boot/gunzip_util.c |  140 ++++++++++++++++++++++++++++++++++++++++
 arch/powerpc/boot/gunzip_util.h |   30 ++++++++
 arch/powerpc/boot/main.c        |  113 +++++---------------------------
 4 files changed, 192 insertions(+), 94 deletions(-)

Index: working-2.6/arch/powerpc/boot/gunzip_util.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ working-2.6/arch/powerpc/boot/gunzip_util.c	2007-02-19 13:52:02.000000000 +1100
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2007 David Gibson, IBM Corporation.
+ * Based on earlier work, Copyright (C) Paul Mackerras 1997.
+ *
+ * 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; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <stddef.h>
+#include "string.h"
+#include "stdio.h"
+#include "ops.h"
+#include "gunzip_util.h"
+
+struct gunzip_state state;
+
+#define HEAD_CRC	2
+#define EXTRA_FIELD	4
+#define ORIG_NAME	8
+#define COMMENT		0x10
+#define RESERVED	0xe0
+
+void gunzip_start(struct gunzip_state *state, void *src, int srclen)
+{
+	char *hdr = src;
+	int hdrlen = 0;
+
+	memset(state, 0, sizeof(*state));
+
+	/* Check for gzip magic number */
+	if ((hdr[0] == 0x1f) && (hdr[1] == 0x8b)) {
+		/* gzip data, initialize zlib parameters */
+		int r, flags;
+
+		state->s.workspace = state->scratch;
+		if (zlib_inflate_workspacesize() > sizeof(state->scratch)) {
+			printf("insufficient scratch space for gunzip\n\r");
+			exit();
+		}
+
+		/* skip header */
+		hdrlen = 10;
+		flags = hdr[3];
+		if (hdr[2] != Z_DEFLATED || (flags & RESERVED) != 0) {
+			printf("bad gzipped data\n\r");
+			exit();
+		}
+		if ((flags & EXTRA_FIELD) != 0)
+			hdrlen = 12 + hdr[10] + (hdr[11] << 8);
+		if ((flags & ORIG_NAME) != 0)
+			while (hdr[hdrlen++] != 0)
+				;
+		if ((flags & COMMENT) != 0)
+			while (hdr[hdrlen++] != 0)
+				;
+		if ((flags & HEAD_CRC) != 0)
+			hdrlen += 2;
+		if (hdrlen >= srclen) {
+			printf("gunzip_start: ran out of data in header\n\r");
+			exit();
+		}
+
+		r = zlib_inflateInit2(&state->s, -MAX_WBITS);
+		if (r != Z_OK) {
+			printf("inflateInit2 returned %d\n\r", r);
+			exit();
+		}
+	}
+
+	state->s.next_in = src + hdrlen;
+	state->s.avail_in = srclen - hdrlen;
+}
+
+int gunzip_partial(struct gunzip_state *state, void *dst, int dstlen)
+{
+	int len;
+
+	if (state->s.workspace) {
+		/* gunzipping */
+		int r;
+
+		state->s.next_out = dst;
+		state->s.avail_out = dstlen;
+		r = zlib_inflate(&state->s, Z_FULL_FLUSH);
+		if (r != Z_OK && r != Z_STREAM_END) {
+			printf("inflate returned %d msg: %s\n\r", r, state->s.msg);
+			exit();
+		}
+		len = state->s.next_out - (unsigned char *)dst;
+	} else {
+		/* uncompressed image */
+		len = min(state->s.avail_in, (unsigned)dstlen);
+		memcpy(dst, state->s.next_in, len);
+		state->s.next_in += len;
+		state->s.avail_in -= len;
+	}
+	return len;
+}
+
+void gunzip_exactly(struct gunzip_state *state, void *dst, int dstlen)
+{
+	int len;
+
+	len  = gunzip_partial(state, dst, dstlen);
+	if (len < dstlen) {
+		printf("gunzip_block: ran out of data\n\r");
+		exit();
+	}
+}
+
+void gunzip_discard(struct gunzip_state *state, int len)
+{
+	static char discard_buf[128];
+
+	while (len > sizeof(discard_buf)) {
+		gunzip_exactly(state, discard_buf, sizeof(discard_buf));
+		len -= sizeof(discard_buf);
+	}
+
+	if (len > 0)
+		gunzip_exactly(state, discard_buf, len);
+}
+
+int gunzip_finish(struct gunzip_state *state, void *dst, int dstlen)
+{
+	int len;
+
+	if (state->s.workspace) {
+		len = gunzip_partial(state, dst, dstlen);
+		zlib_inflateEnd(&state->s);
+	} else {
+		/* uncompressed image */
+		len = min(state->s.avail_in, (unsigned)dstlen);
+		memcpy(dst, state->s.next_in, len);
+	}
+
+	return len;
+}
Index: working-2.6/arch/powerpc/boot/main.c
===================================================================
--- working-2.6.orig/arch/powerpc/boot/main.c	2007-02-19 13:51:27.000000000 +1100
+++ working-2.6/arch/powerpc/boot/main.c	2007-02-19 14:01:15.000000000 +1100
@@ -14,8 +14,8 @@
 #include "page.h"
 #include "string.h"
 #include "stdio.h"
-#include "zlib.h"
 #include "ops.h"
+#include "gunzip_util.h"
 #include "flatdevtree.h"
 
 extern void flush_cache(void *, unsigned long);
@@ -30,6 +30,8 @@ extern char _initrd_end[];
 extern char _dtb_start[];
 extern char _dtb_end[];
 
+static struct gunzip_state gzstate;
+
 struct addr_range {
 	unsigned long addr;
 	unsigned long size;
@@ -42,71 +44,12 @@ static struct addr_range initrd;
 static unsigned long elfoffset;
 static int is_64bit;
 
-/* scratch space for gunzip; 46912 is from zlib_inflate_workspacesize() */
-static char scratch[46912];
 static char elfheader[256];
 
 typedef void (*kernel_entry_t)(unsigned long, unsigned long, void *);
 
 #undef DEBUG
 
-#define HEAD_CRC	2
-#define EXTRA_FIELD	4
-#define ORIG_NAME	8
-#define COMMENT		0x10
-#define RESERVED	0xe0
-
-static void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
-{
-	z_stream s;
-	int r, i, flags;
-
-	/* skip header */
-	i = 10;
-	flags = src[3];
-	if (src[2] != Z_DEFLATED || (flags & RESERVED) != 0) {
-		printf("bad gzipped data\n\r");
-		exit();
-	}
-	if ((flags & EXTRA_FIELD) != 0)
-		i = 12 + src[10] + (src[11] << 8);
-	if ((flags & ORIG_NAME) != 0)
-		while (src[i++] != 0)
-			;
-	if ((flags & COMMENT) != 0)
-		while (src[i++] != 0)
-			;
-	if ((flags & HEAD_CRC) != 0)
-		i += 2;
-	if (i >= *lenp) {
-		printf("gunzip: ran out of data in header\n\r");
-		exit();
-	}
-
-	if (zlib_inflate_workspacesize() > sizeof(scratch)) {
-		printf("gunzip needs more mem\n");
-		exit();
-	}
-	memset(&s, 0, sizeof(s));
-	s.workspace = scratch;
-	r = zlib_inflateInit2(&s, -MAX_WBITS);
-	if (r != Z_OK) {
-		printf("inflateInit2 returned %d\n\r", r);
-		exit();
-	}
-	s.next_in = src + i;
-	s.avail_in = *lenp - i;
-	s.next_out = dst;
-	s.avail_out = dstlen;
-	r = zlib_inflate(&s, Z_FULL_FLUSH);
-	if (r != Z_OK && r != Z_STREAM_END) {
-		printf("inflate returned %d msg: %s\n\r", r, s.msg);
-		exit();
-	}
-	*lenp = s.next_out - (unsigned char *) dst;
-	zlib_inflateEnd(&s);
-}
-
 static int is_elf64(void *hdr)
 {
 	Elf64_Ehdr *elf64 = hdr;
@@ -132,8 +75,8 @@ static int is_elf64(void *hdr)
 		return 0;
 
 	elfoffset = (unsigned long)elf64ph->p_offset;
-	vmlinux.size = (unsigned long)elf64ph->p_filesz + elfoffset;
-	vmlinux.memsize = (unsigned long)elf64ph->p_memsz + elfoffset;
+	vmlinux.size = (unsigned long)elf64ph->p_filesz;
+	vmlinux.memsize = (unsigned long)elf64ph->p_memsz;
 
 	is_64bit = 1;
 	return 1;
@@ -164,8 +107,8 @@ static int is_elf32(void *hdr)
 		return 0;
 
 	elfoffset = elf32ph->p_offset;
-	vmlinux.size = elf32ph->p_filesz + elf32ph->p_offset;
-	vmlinux.memsize = elf32ph->p_memsz + elf32ph->p_offset;
+	vmlinux.size = elf32ph->p_filesz;
+	vmlinux.memsize = elf32ph->p_memsz;
 	return 1;
 }
 
@@ -177,13 +120,8 @@ static void prep_kernel(unsigned long a1
 	vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start);
 
 	/* gunzip the ELF header of the kernel */
-	if (*(unsigned short *)vmlinuz.addr == 0x1f8b) {
-		len = vmlinuz.size;
-		gunzip(elfheader, sizeof(elfheader),
-				(unsigned char *)vmlinuz.addr, &len);
-	} else
-		memcpy(elfheader, (const void *)vmlinuz.addr,
-		       sizeof(elfheader));
+	gunzip_start(&gzstate, (void *)vmlinuz.addr, vmlinuz.size);
+	gunzip_exactly(&gzstate, elfheader, sizeof(elfheader));
 
 	if (!is_elf64(elfheader) && !is_elf32(elfheader)) {
 		printf("Error: not a valid PPC32 or PPC64 ELF file!\n\r");
@@ -192,10 +130,10 @@ static void prep_kernel(unsigned long a1
 	if (platform_ops.image_hdr)
 		platform_ops.image_hdr(elfheader);
 
-	/* We need to alloc the memsize plus the file offset since gzip
-	 * will expand the header (file offset), then the kernel, then
-	 * possible rubbish we don't care about. But the kernel bss must
-	 * be claimed (it will be zero'd by the kernel itself)
+	/* We need to alloc the memsize: gzip will expand the kernel
+	 * text/data, then possible rubbish we don't care about. But
+	 * the kernel bss must be claimed (it will be zero'd by the
+	 * kernel itself)
 	 */
 	printf("Allocating 0x%lx bytes for kernel ...\n\r", vmlinux.memsize);
 	vmlinux.addr = (unsigned long)malloc(vmlinux.memsize);
@@ -237,24 +175,13 @@ static void prep_kernel(unsigned long a1
 	}
 
 	/* Eventually gunzip the kernel */
-	if (*(unsigned short *)vmlinuz.addr == 0x1f8b) {
-		printf("gunzipping (0x%lx <- 0x%lx:0x%0lx)...",
-		       vmlinux.addr, vmlinuz.addr, vmlinuz.addr+vmlinuz.size);
-		len = vmlinuz.size;
-		gunzip((void *)vmlinux.addr, vmlinux.memsize,
-			(unsigned char *)vmlinuz.addr, &len);
-		printf("done 0x%lx bytes\n\r", len);
-	} else {
-		memmove((void *)vmlinux.addr,(void *)vmlinuz.addr,
-			vmlinuz.size);
-	}
-
-	/* Skip over the ELF header */
-#ifdef DEBUG
-	printf("... skipping 0x%lx bytes of ELF header\n\r",
-			elfoffset);
-#endif
-	vmlinux.addr += elfoffset;
+	printf("gunzipping (0x%lx <- 0x%lx:0x%0lx)...",
+	       vmlinux.addr, vmlinuz.addr, vmlinuz.addr+vmlinuz.size);
+	/* discard up to the actual load data */
+	gunzip_discard(&gzstate, elfoffset - sizeof(elfheader));
+	len = gunzip_finish(&gzstate, (void *)vmlinux.addr,
+			    vmlinux.memsize);
+	printf("done 0x%lx bytes\n\r", len);
 
 	flush_cache((void *)vmlinux.addr, vmlinux.size);
 }
Index: working-2.6/arch/powerpc/boot/Makefile
===================================================================
--- working-2.6.orig/arch/powerpc/boot/Makefile	2007-02-19 13:51:30.000000000 +1100
+++ working-2.6/arch/powerpc/boot/Makefile	2007-02-19 14:00:50.000000000 +1100
@@ -41,7 +41,8 @@ $(addprefix $(obj)/,$(zlib) main.o): $(a
 		$(addprefix $(obj)/,$(zlibheader))
 
 src-wlib := string.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
-		ns16550.c serial.c simple_alloc.c div64.S util.S $(zlib)
+		ns16550.c serial.c simple_alloc.c div64.S util.S \
+		gunzip_util.c $(zlib)
 src-plat := of.c
 src-boot := crt0.S $(src-wlib) $(src-plat) empty.c
 
Index: working-2.6/arch/powerpc/boot/gunzip_util.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ working-2.6/arch/powerpc/boot/gunzip_util.h	2007-02-19 13:51:52.000000000 +1100
@@ -0,0 +1,30 @@
+/*
+ * Decompression convenience functions
+ *
+ * Copyright 2007 David Gibson, IBM Corporation.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#ifndef _PPC_BOOT_GUNZIP_UTIL_H_
+#define _PPC_BOOT_GUNZIP_UTIL_H_
+
+#include "zlib.h"
+
+/* scratch space for gunzip; 46912 is from zlib_inflate_workspacesize() */
+#define GUNZIP_SCRATCH_SIZE	46912
+
+struct gunzip_state {
+	z_stream s;
+	char scratch[46912];
+};
+
+void gunzip_start(struct gunzip_state *state, void *src, int srclen);
+int gunzip_partial(struct gunzip_state *state, void *dst, int dstlen);
+void gunzip_exactly(struct gunzip_state *state, void *dst, int len);
+void gunzip_discard(struct gunzip_state *state, int len);
+int gunzip_finish(struct gunzip_state *state, void *dst, int len);
+
+#endif /* _PPC_BOOT_GUNZIP_UTIL_H_ */
+

  parent reply	other threads:[~2007-02-20  2:12 UTC|newest]

Thread overview: 50+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-02-20  2:08 [0/14] Ebony support, 2nd spin David Gibson
2007-02-20  2:12 ` [PATCH 3/14] Define FIXED_PORT flag for serial_core David Gibson
2007-02-20  2:12 ` [PATCH 2/14] Automatically lmb_reserve() initrd David Gibson
2007-02-20  2:12 ` [PATCH 4/14] Use resource_size_t for serial port IO addresses David Gibson
2007-02-20 14:44   ` Sergei Shtylyov
2007-02-21  0:19     ` David Gibson
2007-02-20  2:12 ` [PATCH 1/14] powerpc: Allow duplicate lmb_reserve() calls David Gibson
2007-02-20  2:12 ` David Gibson [this message]
2007-02-21  0:56   ` [PATCH 5/14] zImage: Add more flexible gunzip convenience functions Geoff Levand
2007-02-20  2:12 ` [PATCH 11/14] Add arch/powerpc driver for UIC, PPC4xx interrupt controller David Gibson
2007-02-20  2:12 ` [PATCH 7/14] zImage: Cleanup and improve zImage entry point David Gibson
2007-02-21  0:57   ` Geoff Levand
2007-02-20  2:12 ` [PATCH 8/14] zImage wrapper for Ebony David Gibson
2007-02-20  2:12 ` [PATCH 9/14] Port 44x MMU definitions to ARCH=powerpc David Gibson
2007-02-20  2:12 ` [PATCH 6/14] zImage: Cleanup and improve prep_kernel() David Gibson
2007-02-21  0:56   ` Geoff Levand
2007-02-20  2:12 ` [PATCH 12/14] Add device tree for Ebony David Gibson
2007-02-20 15:09   ` Josh Boyer
2007-02-21  0:24     ` David Gibson
2007-02-21 12:25       ` Segher Boessenkool
2007-02-20 19:22   ` Yoder Stuart-B08248
2007-02-20 19:56     ` Segher Boessenkool
2007-02-21  4:57       ` David Gibson
2007-02-22  6:49       ` Segher Boessenkool
2007-02-20  2:12 ` [PATCH 10/14] Early serial debug support for PPC44x David Gibson
2007-02-20 13:26   ` Segher Boessenkool
2007-02-21  0:20     ` David Gibson
2007-02-20  2:12 ` [PATCH 13/14] Re-organize Kconfig code for 4xx in arch/powerpc David Gibson
2007-02-20 13:51   ` Josh Boyer
2007-02-21  0:26     ` David Gibson
2007-02-20  2:12 ` [PATCH 14/14] Support for Ebony " David Gibson
2007-02-20 14:05 ` [0/14] Ebony support, 2nd spin Josh Boyer
2007-02-20 14:14   ` Josh Boyer
2007-02-20 14:16   ` Arnd Bergmann
2007-02-20 14:46     ` Josh Boyer
2007-02-20 15:03       ` Josh Boyer
2007-02-20 15:07         ` [0/14] Ebony support, 2nd spi Arnd Bergmann
2007-02-20 15:17           ` Josh Boyer
2007-02-20 15:25           ` Segher Boessenkool
2007-02-20 18:02             ` Arnd Bergmann
2007-02-20 19:51               ` Segher Boessenkool
2007-02-20 20:29                 ` Josh Boyer
2007-02-21  0:38                   ` David Gibson
2007-02-21  1:30                     ` Josh Boyer
2007-02-21  0:44           ` David Gibson
2007-02-20 15:11         ` [0/14] Ebony support, 2nd spin Segher Boessenkool
2007-02-21  0:33         ` David Gibson
2007-02-21  0:35     ` David Gibson
2007-02-21  9:06       ` Arnd Bergmann
2007-02-25 23:57         ` David Gibson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20070220021235.042ABDDD0E@ozlabs.org \
    --to=david@gibson.dropbear.id.au \
    --cc=linuxppc-dev@ozlabs.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.