Antonello Dettori (dev@dettori.io) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/15525
-gerrit
commit 1f631b710e41a235e087bc8e5db65511ca1a6de3 Author: Antonello Dettori dev@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.
Change-Id: I27cd4358a1747a65a79995114df23e296d1410fd Signed-off-by: Antonello Dettori dev@dettori.io --- src/lib/selfboot.c | 104 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 61 insertions(+), 43 deletions(-)
diff --git a/src/lib/selfboot.c b/src/lib/selfboot.c index 75d6725..d55ade4 100644 --- a/src/lib/selfboot.c +++ b/src/lib/selfboot.c @@ -36,9 +36,10 @@ 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->offset is the distance from the beginning of the boot_device. + * src->size is the filesize of the boot_device. */ + struct region src; int compression; };
@@ -121,7 +122,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.size; end = start + seg->s_memsz;
printk(BIOS_SPEW, "segment: [0x%016lx, 0x%016lx, 0x%016lx)\n", @@ -139,12 +140,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; + seg->src.offset += len; + if (seg->src.size > len) { + new->src.size = len; + seg->src.size -= len; } else { - seg->s_filesz = 0; + seg->src.size = 0; }
/* Order by stream offset */ @@ -158,7 +159,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.size, new->s_dstaddr + new->s_memsz);
ret = 1; @@ -175,12 +176,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; + new->src.offset += len; + if (seg->src.size > len) { + seg->src.size = len; + new->src.size -= len; } else { - new->s_filesz = 0; + new->src.size = 0; } /* Order by stream offset */ new->next = seg->next; @@ -190,7 +191,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.size, new->s_dstaddr + new->s_memsz); } } @@ -204,7 +205,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.size, seg->s_dstaddr + seg->s_memsz);
return ret; @@ -226,17 +227,27 @@ static void cbfs_decode_payload_segment(struct cbfs_payload_segment *segment,
static int build_self_segment_list( struct segment *head, - struct cbfs_payload *cbfs_payload, uintptr_t *entry) + 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) { + rdev_readat(cbfs_payload, first_segment, 0, + sizeof(struct cbfs_payload_segment)); + memcpy(current_segment, first_segment, + sizeof(struct cbfs_payload_segment)); + + if (first_segment == NULL || current_segment == NULL) + return -1; + + 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; + new->src.size = segment.len; + new->src.offset = segment.offset;
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); + new->s_dstaddr, new->s_memsz, new->src.offset, + new->src.size);
/* Clean up the values */ - if (new->s_filesz > new->s_memsz) { - new->s_filesz = new->s_memsz; + if (new->src.size > new->s_memsz) { + new->src.size = new->s_memsz; printk(BIOS_DEBUG, " cleaned up filesize 0x%lx\n", - new->s_filesz); + new->src.size); } break;
@@ -280,12 +290,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; + new->src.size = 0; + new->src.offset = segment.offset; break;
case PAYLOAD_SEGMENT_ENTRY: @@ -315,8 +323,15 @@ static int build_self_segment_list( new->prev = head->prev; head->prev->next = new; head->prev = new; + + rdev_readat(cbfs_payload, current_segment, offset, + sizeof(struct cbfs_payload_segment)); + offset += sizeof(struct cbfs_payload_segment); }
+ free(first_segment); + free(current_segment); + return 1; }
@@ -332,7 +347,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.size != 0) last_non_empty = ptr;
for(ptr = head->next; ptr != head; ptr = ptr->next) { @@ -379,7 +394,7 @@ 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); + ptr->s_dstaddr, ptr->s_memsz, ptr->src.size);
/* Modify the segment to load onto the bounce_buffer if necessary. */ @@ -389,21 +404,24 @@ static int load_self_segments( }
printk(BIOS_DEBUG, "Post relocation: addr: 0x%016lx memsz: 0x%016lx filesz: 0x%016lx\n", - ptr->s_dstaddr, ptr->s_memsz, ptr->s_filesz); + ptr->s_dstaddr, ptr->s_memsz, ptr->src.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.size) { unsigned char *middle, *end; - size_t len = ptr->s_filesz; + size_t len = ptr->src.size; size_t memsz = ptr->s_memsz; + size_t offset = ptr->src.offset; switch(ptr->compression) { case CBFS_COMPRESS_LZMA: { printk(BIOS_DEBUG, "using LZMA\n"); timestamp_add_now(TS_START_ULZMA); + src = rdev_mmap(prog_rdev(payload), + offset, len); len = ulzman(src, len, dest, memsz); timestamp_add_now(TS_END_ULZMA); if (!len) /* Decompression Error. */ @@ -413,6 +431,8 @@ static int load_self_segments( case CBFS_COMPRESS_LZ4: { printk(BIOS_DEBUG, "using LZ4\n"); timestamp_add_now(TS_START_ULZ4F); + src = rdev_mmap(prog_rdev(payload), + offset, len); len = ulz4fn(src, len, dest, memsz); timestamp_add_now(TS_END_ULZ4F); if (!len) /* Decompression Error. */ @@ -421,7 +441,8 @@ static int load_self_segments( } case CBFS_COMPRESS_NONE: { printk(BIOS_DEBUG, "it's not compressed!\n"); - memcpy(dest, src, len); + rdev_readat(prog_rdev(payload), dest, + offset, len); break; } default: @@ -479,9 +500,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; @@ -496,8 +517,6 @@ void *selfload(struct prog *payload)
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 +526,5 @@ void *selfload(struct prog *payload) return (void *)entry;
out: - rdev_munmap(prog_rdev(payload), data); return NULL; }