[coreboot-gerrit] Patch set updated for coreboot: lib/selfboot: Replace rdev_mmap_full()

Antonello Dettori (dev@dettori.io) gerrit at coreboot.org
Sat Jul 23 16:38:55 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/15525

-gerrit

commit 7db9bfc3c68fe20ee660ab5b1d31d5773cda0299
Author: Antonello Dettori <dev at dettori.io>
Date:   Fri Jul 1 14:28:17 2016 +0200

    lib/selfboot: Replace rdev_mmap_full()
    
    Avoid loading the entire payload into memory, instead read each segment
    when it is required.
    If the segment is uncompressed rdev_readat() it into memory,
    otherwise rdev_mmap() the segment and uncompress it.
    The purpose of the change is to improve the performance during the
    payload load phase by avoiding any unnecessary mmap operation where
    possible.
    
    Change-Id: I27cd4358a1747a65a79995114df23e296d1410fd
    Signed-off-by: Antonello Dettori <dev at dettori.io>
---
 src/lib/selfboot.c | 152 ++++++++++++++++++++++++++++++++---------------------
 1 file changed, 93 insertions(+), 59 deletions(-)

diff --git a/src/lib/selfboot.c b/src/lib/selfboot.c
index 8e84a68..a380165 100644
--- a/src/lib/selfboot.c
+++ b/src/lib/selfboot.c
@@ -36,9 +36,8 @@ struct segment {
 	struct segment *next;
 	struct segment *prev;
 	unsigned long s_dstaddr;
-	unsigned long s_srcaddr;
 	unsigned long s_memsz;
-	unsigned long s_filesz;
+	struct region_device src;
 	int compression;
 };
 
@@ -58,6 +57,16 @@ static void segment_insert_after(struct segment *seg, struct segment *new)
 	seg->next = new;
 }
 
+static size_t segment_file_sz(const struct segment *seg)
+{
+	return region_device_sz(&seg->src);
+}
+
+static size_t segment_file_offset(const struct segment *seg)
+{
+	return region_device_offset(&seg->src);
+}
+
 /* The problem:
  * Static executables all want to share the same addresses
  * in memory because only a few addresses are reliably present on
@@ -137,7 +146,7 @@ static int relocate_segment(unsigned long buffer, struct segment *seg)
 		die ("bounce buffer not supported");
 
 	start = seg->s_dstaddr;
-	middle = start + seg->s_filesz;
+	middle = start + segment_file_sz(seg);
 	end = start + seg->s_memsz;
 
 	printk(BIOS_SPEW, "segment: [0x%016lx, 0x%016lx, 0x%016lx)\n",
@@ -155,12 +164,16 @@ static int relocate_segment(unsigned long buffer, struct segment *seg)
 			new->s_memsz = len;
 			seg->s_memsz -= len;
 			seg->s_dstaddr += len;
-			seg->s_srcaddr += len;
-			if (seg->s_filesz > len) {
-				new->s_filesz = len;
-				seg->s_filesz -= len;
+			if (segment_file_sz(seg) > len) {
+				if (rdev_chain(&new->src, &new->src, 0, len) < 0)
+					return 0;
+
+				if (rdev_chain(&seg->src, &seg->src, len,
+						segment_file_sz(seg) - len) < 0)
+					return 0;
 			} else {
-				seg->s_filesz = 0;
+				if (rdev_chain(&seg->src, &seg->src, len, 0) < 0)
+					return 0;
 			}
 
 			/* Order by stream offset */
@@ -171,7 +184,7 @@ static int relocate_segment(unsigned long buffer, struct segment *seg)
 
 			printk(BIOS_SPEW, "   early: [0x%016lx, 0x%016lx, 0x%016lx)\n",
 				new->s_dstaddr,
-				new->s_dstaddr + new->s_filesz,
+				new->s_dstaddr + segment_file_sz(new),
 				new->s_dstaddr + new->s_memsz);
 
 			ret = 1;
@@ -188,19 +201,23 @@ static int relocate_segment(unsigned long buffer, struct segment *seg)
 			seg->s_memsz = len;
 			new->s_memsz -= len;
 			new->s_dstaddr += len;
-			new->s_srcaddr += len;
-			if (seg->s_filesz > len) {
-				seg->s_filesz = len;
-				new->s_filesz -= len;
+			if (segment_file_sz(seg) > len) {
+				if (rdev_chain(&seg->src, &seg->src, 0, len) < 0)
+					return 0;
+
+				if (rdev_chain(&new->src, &new->src, len,
+					segment_file_sz(new) - len))
+					return 0;
 			} else {
-				new->s_filesz = 0;
+				if (rdev_chain(&new->src, &new->src, len, 0) < 0)
+					return 0;
 			}
 			/* Order by stream offset */
 			segment_insert_after(seg, new);
 
 			printk(BIOS_SPEW, "   late: [0x%016lx, 0x%016lx, 0x%016lx)\n",
 				new->s_dstaddr,
-				new->s_dstaddr + new->s_filesz,
+				new->s_dstaddr + segment_file_sz(new),
 				new->s_dstaddr + new->s_memsz);
 		}
 	}
@@ -214,7 +231,7 @@ static int relocate_segment(unsigned long buffer, struct segment *seg)
 
 	printk(BIOS_SPEW, " bounce: [0x%016lx, 0x%016lx, 0x%016lx)\n",
 		seg->s_dstaddr,
-		seg->s_dstaddr + seg->s_filesz,
+		seg->s_dstaddr + segment_file_sz(seg),
 		seg->s_dstaddr + seg->s_memsz);
 
 	return ret;
@@ -234,24 +251,28 @@ static void cbfs_decode_payload_segment(struct cbfs_payload_segment *segment,
 	segment->mem_len     = read_be32(&src->mem_len);
 }
 
-static int build_self_segment_list(
-	struct segment *head,
-	struct cbfs_payload *cbfs_payload, uintptr_t *entry)
+static int build_self_segment_list(struct segment *head,
+	struct region_device *cbfs_payload, uintptr_t *entry)
 {
 	struct segment *new;
-	struct cbfs_payload_segment *current_segment, *first_segment, segment;
+	struct cbfs_payload_segment segment;
+	size_t offset = 0;
 
 	memset(head, 0, sizeof(*head));
 	head->next = head->prev = head;
 
-	first_segment = &cbfs_payload->segments;
+	while (true) {
+		ssize_t ret = rdev_readat(cbfs_payload, &segment, offset,
+				sizeof(struct cbfs_payload_segment));
+
+		if (ret != sizeof(struct cbfs_payload_segment))
+			return 0;
 
-	for (current_segment = first_segment;; ++current_segment) {
 		printk(BIOS_DEBUG,
 			"Loading segment from rom address 0x%p\n",
-			current_segment);
+			&segment);
 
-		cbfs_decode_payload_segment(&segment, current_segment);
+		cbfs_decode_payload_segment(&segment, &segment);
 
 		switch (segment.type) {
 		case PAYLOAD_SEGMENT_PARAMS:
@@ -268,20 +289,22 @@ static int build_self_segment_list(
 			new->s_dstaddr = segment.load_addr;
 			new->s_memsz = segment.mem_len;
 			new->compression = segment.compression;
-			new->s_srcaddr = (uintptr_t)
-				((unsigned char *)first_segment)
-				+ segment.offset;
-			new->s_filesz = segment.len;
+			if (rdev_chain(&new->src, cbfs_payload, segment.offset,
+					segment.len) < 0)
+				return 0;
 
-			printk(BIOS_DEBUG, "  New segment dstaddr 0x%lx memsize 0x%lx srcaddr 0x%lx filesize 0x%lx\n",
-				new->s_dstaddr, new->s_memsz, new->s_srcaddr, new->s_filesz);
+			printk(BIOS_DEBUG, "  New segment dstaddr 0x%lx memsize 0x%lx offset 0x%zx filesize 0x%zx\n",
+				new->s_dstaddr, new->s_memsz,
+				segment_file_offset(new), segment_file_sz(new));
 
 			/* Clean up the values */
-			if (new->s_filesz > new->s_memsz)  {
-				new->s_filesz = new->s_memsz;
+			if (segment_file_sz(new) > new->s_memsz) {
+				if (rdev_chain(&new->src, &new->src, 0, new->s_memsz) < 0)
+					return 0;
+
 				printk(BIOS_DEBUG,
-					"  cleaned up filesize 0x%lx\n",
-					new->s_filesz);
+					"  cleaned up filesize 0x%zx\n",
+					segment_file_sz(new));
 			}
 			break;
 
@@ -290,13 +313,11 @@ static int build_self_segment_list(
 				(intptr_t)segment.load_addr, segment.mem_len);
 
 			new = malloc(sizeof(*new));
-			new->s_filesz = 0;
-			new->s_srcaddr = (uintptr_t)
-				((unsigned char *)first_segment)
-				+ segment.offset;
 			new->s_dstaddr = segment.load_addr;
 			new->s_memsz = segment.mem_len;
 			new->compression = CBFS_COMPRESS_NONE;
+			if (rdev_chain(&new->src, cbfs_payload, segment.offset, 0) < 0)
+				return 0;
 			break;
 
 		case PAYLOAD_SEGMENT_ENTRY:
@@ -323,14 +344,14 @@ static int build_self_segment_list(
 		/* We have found another CODE, DATA or BSS segment */
 		/* Insert new segment at the end of the list */
 		segment_insert_before(head, new);
+
+		offset += sizeof(struct cbfs_payload_segment);
 	}
 
 	return 1;
 }
 
-static int load_self_segments(
-	struct segment *head,
-	struct prog *payload)
+static int load_self_segments(struct segment *head)
 {
 	struct segment *ptr;
 	const unsigned long one_meg = (1UL << 20);
@@ -378,10 +399,10 @@ static int load_self_segments(
 	}
 
 	for(ptr = head->next; ptr != head; ptr = ptr->next) {
-		unsigned char *dest, *src, *middle, *end;
-		size_t len, memsz;
-		printk(BIOS_DEBUG, "Loading Segment: addr: 0x%016lx memsz: 0x%016lx filesz: 0x%016lx\n",
-			ptr->s_dstaddr, ptr->s_memsz, ptr->s_filesz);
+		unsigned char *dest, *src;
+
+		printk(BIOS_DEBUG, "Loading Segment: addr: 0x%016lx memsz: 0x%016lx filesz: 0x%016zx\n",
+			ptr->s_dstaddr, ptr->s_memsz, segment_file_sz(ptr));
 
 		/* Modify the segment to load onto the bounce_buffer if necessary.
 		 */
@@ -390,21 +411,26 @@ static int load_self_segments(
 			continue;
 		}
 
-		printk(BIOS_DEBUG, "Post relocation: addr: 0x%016lx memsz: 0x%016lx filesz: 0x%016lx\n",
-			ptr->s_dstaddr, ptr->s_memsz, ptr->s_filesz);
+		printk(BIOS_DEBUG, "Post relocation: addr: 0x%016lx memsz: 0x%016lx filesz: 0x%016zx\n",
+			ptr->s_dstaddr, ptr->s_memsz, segment_file_sz(ptr));
 
 		/* Compute the boundaries of the segment */
 		dest = (unsigned char *)(ptr->s_dstaddr);
-		src = (unsigned char *)(ptr->s_srcaddr);
-		len = ptr->s_filesz;
-		memsz = ptr->s_memsz;
-		end = dest + memsz;
+		src = NULL;
 
 		/* Copy data from the initial buffer */
+		unsigned char *middle, *end;
+		size_t len = segment_file_sz(ptr);
+		size_t memsz = ptr->s_memsz;
+		end = dest + memsz;
 		switch(ptr->compression) {
 			case CBFS_COMPRESS_LZMA: {
 				printk(BIOS_DEBUG, "using LZMA\n");
 				timestamp_add_now(TS_START_ULZMA);
+				src = rdev_mmap_full(&ptr->src);
+				if (src == NULL)
+					return 0;
+
 				len = ulzman(src, len, dest, memsz);
 				timestamp_add_now(TS_END_ULZMA);
 				if (!len) /* Decompression Error. */
@@ -414,6 +440,10 @@ static int load_self_segments(
 			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);
 				timestamp_add_now(TS_END_ULZ4F);
 				if (!len) /* Decompression Error. */
@@ -422,13 +452,15 @@ static int load_self_segments(
 			}
 			case CBFS_COMPRESS_NONE: {
 				printk(BIOS_DEBUG, "it's not compressed!\n");
-				memcpy(dest, src, len);
+				if (rdev_readat(&ptr->src, dest, 0, len) < 0)
+					return 0;
 				break;
 			}
 			default:
 				printk(BIOS_INFO,  "CBFS:  Unknown compression type %d\n", ptr->compression);
 				return -1;
 		}
+
 		/* Calculate middle after any changes to len. */
 		middle = dest + len;
 		printk(BIOS_SPEW, "[ 0x%08lx, %08lx, 0x%08lx) <- %08lx\n",
@@ -471,6 +503,11 @@ static int load_self_segments(
 		 */
 		prog_segment_loaded((uintptr_t)dest, ptr->s_memsz,
 				ptr->next == head ? SEG_FINAL : 0);
+
+		/* munmap the segment that was compressed */
+		if (ptr->compression != CBFS_COMPRESS_NONE)
+			if (rdev_munmap(&ptr->src, src) < 0)
+				return 0;
 	}
 
 	return 1;
@@ -480,31 +517,28 @@ void *selfload(struct prog *payload)
 {
 	uintptr_t entry = 0;
 	struct segment head;
-	void *data;
+	struct region_device *data;
 
-	data = rdev_mmap_full(prog_rdev(payload));
+	data = prog_rdev(payload);
 
 	if (data == NULL)
-		return NULL;
+		goto out;
 
 	/* Preprocess the self segments */
 	if (!build_self_segment_list(&head, data, &entry))
 		goto out;
 
 	/* Load the segments */
-	if (!load_self_segments(&head, payload))
+	if (!load_self_segments(&head))
 		goto out;
 
 	printk(BIOS_SPEW, "Loaded segments\n");
 
-	rdev_munmap(prog_rdev(payload), data);
-
 	/* Update the payload's area with the bounce buffer information. */
 	prog_set_area(payload, (void *)(uintptr_t)bounce_buffer, bounce_size);
 
 	return (void *)entry;
 
 out:
-	rdev_munmap(prog_rdev(payload), data);
 	return NULL;
 }



More information about the coreboot-gerrit mailing list