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

Antonello Dettori (dev@dettori.io) gerrit at coreboot.org
Sun Jul 10 15:46:39 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 ab7ae419731d055213e66a9072281f08c38298d0
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 | 126 +++++++++++++++++++++++++++++++----------------------
 1 file changed, 73 insertions(+), 53 deletions(-)

diff --git a/src/lib/selfboot.c b/src/lib/selfboot.c
index 75d6725..a72f978 100644
--- a/src/lib/selfboot.c
+++ b/src/lib/selfboot.c
@@ -36,9 +36,11 @@ struct segment {
 	struct segment *next;
 	struct segment *prev;
 	unsigned long s_dstaddr;
-	unsigned long s_srcaddr;
 	unsigned long s_memsz;
-	unsigned long s_filesz;
+	/* src->region->offset is the distance from the beginning of the
+	 * boot_device.
+	 * src->region->size is the filesize of the boot_device. */
+	struct region_device src;
 	int compression;
 };
 
@@ -121,7 +123,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 + seg->src.region.size;
 	end = start + seg->s_memsz;
 
 	printk(BIOS_SPEW, "segment: [0x%016lx, 0x%016lx, 0x%016lx)\n",
@@ -139,12 +141,12 @@ 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 (seg->src.region.size > len) {
+				new->src.region.size = len;
+				rdev_chain(&seg->src, &seg->src, len,
+					seg->src.region.size - len);
 			} else {
-				seg->s_filesz = 0;
+				rdev_chain(&seg->src, &seg->src, len, 0);
 			}
 
 			/* Order by stream offset */
@@ -158,7 +160,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 + new->src.region.size,
 				new->s_dstaddr + new->s_memsz);
 
 			ret = 1;
@@ -175,12 +177,12 @@ 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 (seg->src.region.size > len) {
+				seg->src.region.size = len;
+				rdev_chain(&new->src, &new->src, len,
+					new->src.region.size - len);
 			} else {
-				new->s_filesz = 0;
+				rdev_chain(&new->src, &new->src, len, 0);
 			}
 			/* Order by stream offset */
 			new->next = seg->next;
@@ -190,7 +192,7 @@ static int relocate_segment(unsigned long buffer, struct segment *seg)
 
 			printk(BIOS_SPEW, "   late: [0x%016lx, 0x%016lx, 0x%016lx)\n",
 				new->s_dstaddr,
-				new->s_dstaddr + new->s_filesz,
+				new->s_dstaddr + new->src.region.size,
 				new->s_dstaddr + new->s_memsz);
 		}
 	}
@@ -204,7 +206,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 + seg->src.region.size,
 		seg->s_dstaddr + seg->s_memsz);
 
 	return ret;
@@ -224,19 +226,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;
+	size_t offset = 0;
 
 	memset(head, 0, sizeof(*head));
 	head->next = head->prev = head;
 
-	first_segment = &cbfs_payload->segments;
+	first_segment = malloc(sizeof(struct cbfs_payload_segment));
+	current_segment = malloc(sizeof(struct cbfs_payload_segment));
 
-	for (current_segment = first_segment;; ++current_segment) {
+	if (first_segment == NULL || current_segment == NULL)
+		return -1;
+
+	rdev_readat(cbfs_payload, first_segment, 0,
+			sizeof(struct cbfs_payload_segment));
+	memcpy(current_segment, first_segment,
+			sizeof(struct cbfs_payload_segment));
+
+	while (true) {
 		printk(BIOS_DEBUG,
 			"Loading segment from rom address 0x%p\n",
 			current_segment);
@@ -258,20 +269,19 @@ 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;
+			region_device_init(&new->src, NULL, segment.offset,
+					segment.len);
 
-			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,
+				new->src.region.offset,	new->src.region.size);
 
 			/* Clean up the values */
-			if (new->s_filesz > new->s_memsz)  {
-				new->s_filesz = new->s_memsz;
+			if (new->src.region.size > new->s_memsz)  {
+				new->src.region.size = new->s_memsz;
 				printk(BIOS_DEBUG,
-					"  cleaned up filesize 0x%lx\n",
-					new->s_filesz);
+					"  cleaned up filesize 0x%zx\n",
+					new->src.region.size);
 			}
 			break;
 
@@ -280,12 +290,9 @@ 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;
+			region_device_init(&new->src, NULL, segment.offset, 0);
 			break;
 
 		case PAYLOAD_SEGMENT_ENTRY:
@@ -315,14 +322,23 @@ static int build_self_segment_list(
 		new->prev = head->prev;
 		head->prev->next = new;
 		head->prev = new;
+
+		int ret = rdev_readat(cbfs_payload, current_segment, offset,
+				sizeof(struct cbfs_payload_segment));
+		if (ret != sizeof(struct cbfs_payload_segment))
+			return -1;
+
+		offset += sizeof(struct cbfs_payload_segment);
 	}
 
+	free(first_segment);
+	free(current_segment);
+
 	return 1;
 }
 
-static int load_self_segments(
-	struct segment *head,
-	struct prog *payload)
+static int load_self_segments(struct segment *head,
+		struct region_device *payload)
 {
 	struct segment *ptr;
 	struct segment *last_non_empty;
@@ -332,7 +348,7 @@ static int load_self_segments(
 	/* Determine last non-empty loaded segment. */
 	last_non_empty = NULL;
 	for(ptr = head->next; ptr != head; ptr = ptr->next)
-		if (ptr->s_filesz != 0)
+		if (ptr->src.region.size != 0)
 			last_non_empty = ptr;
 
 	for(ptr = head->next; ptr != head; ptr = ptr->next) {
@@ -378,8 +394,8 @@ static int load_self_segments(
 
 	for(ptr = head->next; ptr != head; ptr = ptr->next) {
 		unsigned char *dest, *src;
-		printk(BIOS_DEBUG, "Loading Segment: addr: 0x%016lx memsz: 0x%016lx filesz: 0x%016lx\n",
-			ptr->s_dstaddr, ptr->s_memsz, ptr->s_filesz);
+		printk(BIOS_DEBUG, "Loading Segment: addr: 0x%016lx memsz: 0x%016lx filesz: 0x%016zx\n",
+			ptr->s_dstaddr, ptr->s_memsz, ptr->src.region.size);
 
 		/* Modify the segment to load onto the bounce_buffer if necessary.
 		 */
@@ -388,22 +404,24 @@ 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, ptr->src.region.size);
 
 		/* Compute the boundaries of the segment */
 		dest = (unsigned char *)(ptr->s_dstaddr);
-		src = (unsigned char *)(ptr->s_srcaddr);
+		src = NULL;
 
 		/* Copy data from the initial buffer */
-		if (ptr->s_filesz) {
+		if (ptr->src.region.size) {
 			unsigned char *middle, *end;
-			size_t len = ptr->s_filesz;
+			size_t len = ptr->src.region.size;
 			size_t memsz = ptr->s_memsz;
+			size_t offset = ptr->src.region.offset;
 			switch(ptr->compression) {
 				case CBFS_COMPRESS_LZMA: {
 					printk(BIOS_DEBUG, "using LZMA\n");
 					timestamp_add_now(TS_START_ULZMA);
+					src = rdev_mmap(payload, offset, len);
 					len = ulzman(src, len, dest, memsz);
 					timestamp_add_now(TS_END_ULZMA);
 					if (!len) /* Decompression Error. */
@@ -413,6 +431,7 @@ static int load_self_segments(
 				case CBFS_COMPRESS_LZ4: {
 					printk(BIOS_DEBUG, "using LZ4\n");
 					timestamp_add_now(TS_START_ULZ4F);
+					src = rdev_mmap(payload, offset, len);
 					len = ulz4fn(src, len, dest, memsz);
 					timestamp_add_now(TS_END_ULZ4F);
 					if (!len) /* Decompression Error. */
@@ -421,7 +440,7 @@ static int load_self_segments(
 				}
 				case CBFS_COMPRESS_NONE: {
 					printk(BIOS_DEBUG, "it's not compressed!\n");
-					memcpy(dest, src, len);
+					rdev_readat(payload, dest, offset, len);
 					break;
 				}
 				default:
@@ -470,6 +489,10 @@ static int load_self_segments(
 			prog_segment_loaded((uintptr_t)dest, ptr->s_memsz,
 					last_non_empty == ptr ? SEG_FINAL : 0);
 		}
+
+		/* munmap the segment that was compressed */
+		if (ptr->compression != CBFS_COMPRESS_NONE)
+			rdev_munmap(payload, src);
 	}
 
 	return 1;
@@ -479,9 +502,9 @@ 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;
@@ -491,13 +514,11 @@ void *selfload(struct prog *payload)
 		goto out;
 
 	/* Load the segments */
-	if (!load_self_segments(&head, payload))
+	if (!load_self_segments(&head, data))
 		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);
 
@@ -507,6 +528,5 @@ void *selfload(struct prog *payload)
 	return (void *)entry;
 
 out:
-	rdev_munmap(prog_rdev(payload), data);
 	return NULL;
 }



More information about the coreboot-gerrit mailing list