[coreboot-gerrit] Patch set updated for coreboot: selfboot: add sequential lz4 payload decompression

Antonello Dettori (dev@dettori.io) gerrit at coreboot.org
Sat Jul 23 16:38:57 CEST 2016


Antonello Dettori (dev at dettori.io) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/15816

-gerrit

commit d6cebf943f8aa4ed63137cb67e045a03b0bc0a7e
Author: Antonello Dettori <dev at dettori.io>
Date:   Sat Jul 23 16:03:34 2016 +0200

    selfboot: add sequential lz4 payload decompression
    
    Split the loading of lz4 compressed segments into multiple
    parts in order to reduce the overall amount of resource required
    to load them.
    
    Change-Id: I889daca0d6232e6e88296150148ba847059c9de8
    Signed-off-by: Antonello Dettori <dev at dettori.io>
---
 src/commonlib/include/commonlib/compression.h |  6 ++
 src/commonlib/lz4_wrapper.c                   | 88 +++++++++++++++++++++++++++
 src/lib/selfboot.c                            |  6 +-
 3 files changed, 95 insertions(+), 5 deletions(-)

diff --git a/src/commonlib/include/commonlib/compression.h b/src/commonlib/include/commonlib/compression.h
index 428ee42..a64cdf2 100644
--- a/src/commonlib/include/commonlib/compression.h
+++ b/src/commonlib/include/commonlib/compression.h
@@ -17,6 +17,7 @@
 #define _COMMONLIB_COMPRESSION_H_
 
 #include <stddef.h>
+#include <commonlib/region.h>
 
 /* Decompresses an LZ4F image (multiple LZ4 blocks with frame header) from src
  * to dst, ensuring that it doesn't read more than srcn bytes and doesn't write
@@ -28,6 +29,11 @@
  */
 size_t ulz4fn(const void *src, size_t srcn, void *dst, size_t dstn);
 
+/* Same as ulz4fn() but it reads the content of the region_device
+ *  procedurally. */
+size_t rdev_ulz4fn(const struct region_device *src, size_t srcn, void *dst,
+		size_t dstn);
+
 /* Same as ulz4fn() but does not perform any bounds checks. */
 size_t ulz4f(const void *src, void *dst);
 
diff --git a/src/commonlib/lz4_wrapper.c b/src/commonlib/lz4_wrapper.c
index 0342868..832c356 100644
--- a/src/commonlib/lz4_wrapper.c
+++ b/src/commonlib/lz4_wrapper.c
@@ -32,8 +32,11 @@
 #include <commonlib/compression.h>
 #include <commonlib/endian.h>
 #include <commonlib/helpers.h>
+#include <commonlib/region.h>
+#include <stdlib.h>
 #include <stdint.h>
 #include <string.h>
+#include <console/console.h>
 
 /* LZ4 comes with its own supposedly portable memory access functions, but they
  * seem to be very inefficient in practice (at least on ARM64). Since coreboot
@@ -200,3 +203,88 @@ size_t ulz4f(const void *src, void *dst)
 	/* LZ4 uses signed size parameters, so can't just use ((u32)-1) here. */
 	return ulz4fn(src, 1*GiB, dst, 1*GiB);
 }
+
+size_t rdev_ulz4fn(const struct region_device *src, size_t srcn, void *dst,
+		size_t dstn)
+{
+	void *out = dst;
+	size_t out_size = 0;
+	int has_block_checksum;
+	size_t rdev_offset = 0;
+
+	{ /* With in-place decompression the header may become invalid later. */
+		struct lz4_frame_header h;
+
+		rdev_readat(src, &h, rdev_offset, sizeof(h));
+
+		if (srcn < sizeof(h) + sizeof(uint64_t) + sizeof(uint8_t))
+			return 0;	/* input overrun */
+
+		/* We assume there's always only a single, standard frame. */
+		if (read_le32(&h.magic) != LZ4F_MAGICNUMBER || h.version != 1)
+			return 0;	/* unknown format */
+		if (h.reserved0 || h.reserved1 || h.reserved2)
+			return 0;	/* reserved must be zero */
+		if (!h.independent_blocks)
+			return 0;	/* we don't support block dependency */
+		has_block_checksum = h.has_block_checksum;
+
+		rdev_offset += sizeof(h);
+		if (h.has_content_size)
+			rdev_offset += sizeof(uint64_t);
+		rdev_offset += sizeof(uint8_t);
+	}
+
+	void *in;
+
+	while (1) {
+		struct lz4_block_header b;
+		uint32_t tmp_le;
+
+		rdev_readat(src, &tmp_le, rdev_offset, sizeof(uint32_t));
+		b.raw = read_le32(&tmp_le);
+		rdev_offset += sizeof(struct lz4_block_header);
+
+		if (rdev_offset + b.size > srcn)
+			break;			/* input overrun */
+
+		if (!b.size) {
+			out_size = out - dst;
+			break;			/* decompression successful */
+		}
+
+
+		if (b.not_compressed) {
+			size_t size = MIN((uintptr_t)b.size,
+				(uintptr_t)dst + dstn - (uintptr_t)out);
+
+			rdev_readat(src, out, rdev_offset, size);
+
+			if (size < b.size)
+				break;		/* output overrun */
+
+			out += size;
+
+		} else {
+			/* constant folding essential, do not touch params! */
+			in = rdev_mmap(src, rdev_offset, b.size);
+
+			int ret = LZ4_decompress_generic(in, out, b.size,
+					dst + dstn - out, endOnInputSize,
+					full, 0, noDict, out, NULL, 0);
+			rdev_munmap(src, in);
+
+			if (ret < 0)
+				break;		/* decompression error */
+
+			out += ret;
+
+		}
+
+		rdev_offset += b.size;
+		if (has_block_checksum)
+			rdev_offset += sizeof(uint32_t);
+	}
+
+	return out_size;
+}
diff --git a/src/lib/selfboot.c b/src/lib/selfboot.c
index a380165..f2c0e4f 100644
--- a/src/lib/selfboot.c
+++ b/src/lib/selfboot.c
@@ -440,11 +440,7 @@ static int load_self_segments(struct segment *head)
 			case CBFS_COMPRESS_LZ4: {
 				printk(BIOS_DEBUG, "using LZ4\n");
 				timestamp_add_now(TS_START_ULZ4F);
-				src = rdev_mmap_full(&ptr->src);
-				if (src == NULL)
-					return 0;
-
-				len = ulz4fn(src, len, dest, memsz);
+				len = rdev_ulz4fn(&ptr->src, len, dest, memsz);
 				timestamp_add_now(TS_END_ULZ4F);
 				if (!len) /* Decompression Error. */
 					return 0;



More information about the coreboot-gerrit mailing list