[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 22:21:08 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 a2d64175f59ae3b705cab530949a5023c274e845
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