[coreboot-gerrit] Patch set updated for coreboot: lib/selfboot: Replace rdev_mmap_full()
Antonello Dettori (dev@dettori.io)
gerrit at coreboot.org
Thu Jul 14 15:53:02 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 bfba7d5b58e89af656cc6ccb22ace731ac1d9d75
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 | 135 ++++++++++++++++++++++++++++++++---------------------
1 file changed, 81 insertions(+), 54 deletions(-)
diff --git a/src/lib/selfboot.c b/src/lib/selfboot.c
index 75d6725..6e890c4 100644
--- a/src/lib/selfboot.c
+++ b/src/lib/selfboot.c
@@ -36,12 +36,24 @@ 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 is used to track the subregion of the payload loaded
+ * from the CBFS. */
+ struct region_device src;
int compression;
};
+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
@@ -121,7 +133,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",
@@ -139,12 +151,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 (segment_file_sz(seg) > len) {
+ new->src.region.size = len;
+ rdev_chain(&seg->src, &seg->src, len,
+ segment_file_sz(seg) - len);
} else {
- seg->s_filesz = 0;
+ rdev_chain(&seg->src, &seg->src, len, 0);
}
/* Order by stream offset */
@@ -158,7 +170,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;
@@ -175,12 +187,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 (segment_file_sz(seg) > len) {
+ seg->src.region.size = len;
+ rdev_chain(&new->src, &new->src, len,
+ segment_file_sz(new) - len);
} else {
- new->s_filesz = 0;
+ rdev_chain(&new->src, &new->src, len, 0);
}
/* Order by stream offset */
new->next = seg->next;
@@ -190,7 +202,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 + segment_file_sz(new),
new->s_dstaddr + new->s_memsz);
}
}
@@ -204,7 +216,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;
@@ -224,19 +236,25 @@ 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 *current_segment, segment;
+ size_t offset = 0;
memset(head, 0, sizeof(*head));
head->next = head->prev = head;
- first_segment = &cbfs_payload->segments;
+ current_segment = malloc(sizeof(struct cbfs_payload_segment));
+
+ if (current_segment == NULL)
+ return -1;
- for (current_segment = first_segment;; ++current_segment) {
+ rdev_readat(cbfs_payload, current_segment, 0,
+ sizeof(struct cbfs_payload_segment));
+
+ while (true) {
printk(BIOS_DEBUG,
"Loading segment from rom address 0x%p\n",
current_segment);
@@ -258,20 +276,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;
+ rdev_chain(&new->src, cbfs_payload, 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,
+ 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) {
+ 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",
+ segment_file_sz(new));
}
break;
@@ -280,12 +297,10 @@ 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;
+ rdev_chain(&new->src, cbfs_payload, segment.offset,
+ 0);
break;
case PAYLOAD_SEGMENT_ENTRY:
@@ -315,14 +330,22 @@ static int build_self_segment_list(
new->prev = head->prev;
head->prev->next = new;
head->prev = new;
+
+ ssize_t 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(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 +355,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 (segment_file_sz(ptr) != 0)
last_non_empty = ptr;
for(ptr = head->next; ptr != head; ptr = ptr->next) {
@@ -378,8 +401,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, segment_file_sz(ptr));
/* Modify the segment to load onto the bounce_buffer if necessary.
*/
@@ -388,22 +411,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, segment_file_sz(ptr));
/* 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 (segment_file_sz(ptr)) {
unsigned char *middle, *end;
- size_t len = ptr->s_filesz;
+ size_t len = segment_file_sz(ptr);
size_t memsz = ptr->s_memsz;
+ size_t offset = segment_file_offset(ptr);
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);
len = ulzman(src, len, dest, memsz);
timestamp_add_now(TS_END_ULZMA);
if (!len) /* Decompression Error. */
@@ -413,6 +438,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 +447,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 +496,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 +509,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 +521,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 +535,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