diff options
author | Patrick Georgi <patrick.georgi@coresystems.de> | 2009-04-25 07:32:24 +0000 |
---|---|---|
committer | Patrick Georgi <patrick.georgi@coresystems.de> | 2009-04-25 07:32:24 +0000 |
commit | 369bc7882a6fa26bbcbd4d050a26fbc496cfdc47 (patch) | |
tree | 0ed1014c5988bdc7c2fae375a211354af6a8c3f0 | |
parent | 7994164a0ee8c58c47ed2dbe06807cb91ac62778 (diff) |
Move decompression further down the code flow, so that - where
possible - code is decompressed directly to the right place
(instead of copying around, as before).
The downside of this approach is that it's not possible (without API
changes to the decompressors) to put partial segments into bounce
buffers. So if a segment collides with coreboot _and_ is compressed,
it's bounced entirely.
But, as this only brings back the copy we already had before, the new
worst case is better than the average before.
It also fixes handling of compressed segments.
Signed-off-by: Patrick Georgi <patrick.georgi@coresystems.de>
Acked-by: Ronald G. Minnich <rminnich@gmail.com>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@4207 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
-rw-r--r-- | src/boot/selfboot.c | 255 |
1 files changed, 115 insertions, 140 deletions
diff --git a/src/boot/selfboot.c b/src/boot/selfboot.c index 19b6007be0..72fb49fcad 100644 --- a/src/boot/selfboot.c +++ b/src/boot/selfboot.c @@ -55,6 +55,7 @@ struct segment { unsigned long s_srcaddr; unsigned long s_memsz; unsigned long s_filesz; + int compression; }; struct verify_callback { @@ -70,54 +71,6 @@ struct ip_checksum_vcb { unsigned short ip_checksum; }; -int cbfs_self_decompress(int algo, void *src,struct segment *new) -{ - u8 *dst; - - /* for uncompressed, it's easy: just point at the area in ROM */ - if (algo == CBFS_COMPRESS_NONE) { - new->s_srcaddr = (u32) src; - new->s_filesz = new->s_memsz; - return 0; - } - - /* for compression, let's keep it simple. We'll malloc the destination - * area and decompress to there. The compression overhead far outweighs - * any overhead for an extra copy. - */ - dst = malloc(new->s_memsz); - if (! dst) - return -1; - - switch(algo) { -#if CONFIG_COMPRESSED_PAYLOAD_LZMA==1 - case CBFS_COMPRESS_LZMA: { - unsigned long ulzma(unsigned char *src, unsigned char *dst); - ulzma(src, dst); - break; - } -#endif - -#if CONFIG_COMPRESSED_PAYLOAD_NRV2B==1 - case CBFS_COMPRESS_NRV2B: { - unsigned long unrv2b(u8 *src, u8 *dst, unsigned long *ilen_p); - unsigned long tmp; - unrv2b(src, dst, &tmp); - break; - } -#endif - default: - printk_info( "CBFS: Unknown compression type %d\n", - algo); - return -1; - } - - new->s_srcaddr = (u32) dst; - new->s_filesz = new->s_memsz; - return 0; - -} - /* The problem: * Static executables all want to share the same addresses * in memory because only a few addresses are reliably present on @@ -249,82 +202,84 @@ static void relocate_segment(unsigned long buffer, struct segment *seg) printk_spew("segment: [0x%016lx, 0x%016lx, 0x%016lx)\n", start, middle, end); - /* Slice off a piece at the beginning - * that doesn't conflict with coreboot. - */ - if (start < lb_start) { - struct segment *new; - unsigned long len = lb_start - start; - new = malloc(sizeof(*new)); - *new = *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; - } else { - seg->s_filesz = 0; - } - - /* Order by stream offset */ - new->next = seg; - new->prev = seg->prev; - seg->prev->next = new; - seg->prev = new; - /* Order by original program header order */ - new->phdr_next = seg; - new->phdr_prev = seg->phdr_prev; - seg->phdr_prev->phdr_next = new; - seg->phdr_prev = new; - - /* compute the new value of start */ - start = seg->s_dstaddr; - - printk_spew(" early: [0x%016lx, 0x%016lx, 0x%016lx)\n", - new->s_dstaddr, - new->s_dstaddr + new->s_filesz, - new->s_dstaddr + new->s_memsz); - } - - /* Slice off a piece at the end - * that doesn't conflict with coreboot - */ - if (end > lb_end) { - unsigned long len = lb_end - start; - struct segment *new; - new = malloc(sizeof(*new)); - *new = *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; - } else { - new->s_filesz = 0; + if (seg->compression == CBFS_COMPRESS_NONE) { + /* Slice off a piece at the beginning + * that doesn't conflict with coreboot. + */ + if (start < lb_start) { + struct segment *new; + unsigned long len = lb_start - start; + new = malloc(sizeof(*new)); + *new = *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; + } else { + seg->s_filesz = 0; + } + + /* Order by stream offset */ + new->next = seg; + new->prev = seg->prev; + seg->prev->next = new; + seg->prev = new; + /* Order by original program header order */ + new->phdr_next = seg; + new->phdr_prev = seg->phdr_prev; + seg->phdr_prev->phdr_next = new; + seg->phdr_prev = new; + + /* compute the new value of start */ + start = seg->s_dstaddr; + + printk_spew(" early: [0x%016lx, 0x%016lx, 0x%016lx)\n", + new->s_dstaddr, + new->s_dstaddr + new->s_filesz, + new->s_dstaddr + new->s_memsz); + } + + /* Slice off a piece at the end + * that doesn't conflict with coreboot + */ + if (end > lb_end) { + unsigned long len = lb_end - start; + struct segment *new; + new = malloc(sizeof(*new)); + *new = *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; + } else { + new->s_filesz = 0; + } + /* Order by stream offset */ + new->next = seg->next; + new->prev = seg; + seg->next->prev = new; + seg->next = new; + /* Order by original program header order */ + new->phdr_next = seg->phdr_next; + new->phdr_prev = seg; + seg->phdr_next->phdr_prev = new; + seg->phdr_next = new; + + /* compute the new value of end */ + end = start + len; + + printk_spew(" late: [0x%016lx, 0x%016lx, 0x%016lx)\n", + new->s_dstaddr, + new->s_dstaddr + new->s_filesz, + new->s_dstaddr + new->s_memsz); + } - /* Order by stream offset */ - new->next = seg->next; - new->prev = seg; - seg->next->prev = new; - seg->next = new; - /* Order by original program header order */ - new->phdr_next = seg->phdr_next; - new->phdr_prev = seg; - seg->phdr_next->phdr_prev = new; - seg->phdr_next = new; - - /* compute the new value of end */ - end = start + len; - - printk_spew(" late: [0x%016lx, 0x%016lx, 0x%016lx)\n", - new->s_dstaddr, - new->s_dstaddr + new->s_filesz, - new->s_dstaddr + new->s_memsz); - } /* Now retarget this segment onto the bounce buffer */ /* sort of explanation: the buffer is a 1:1 mapping to coreboot. @@ -371,15 +326,11 @@ static int build_self_segment_list( new = malloc(sizeof(*new)); new->s_dstaddr = ntohl((u32) segment->load_addr); new->s_memsz = ntohl(segment->mem_len); + new->compression = ntohl(segment->compression); datasize = ntohl(segment->len); - /* figure out decompression, do it, get pointer to the area */ - if (cbfs_self_decompress(ntohl(segment->compression), - ((unsigned char *) first_segment) + - ntohl(segment->offset), new)) { - printk_emerg("cbfs_self_decompress failed\n"); - return; - } + new->s_srcaddr = (u32) ((unsigned char *) first_segment) + ntohl(segment->offset); + new->s_filesz = ntohl(segment->len); printk_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); /* Clean up the values */ @@ -449,23 +400,47 @@ static int load_self_segments( /* Compute the boundaries of the segment */ dest = (unsigned char *)(ptr->s_dstaddr); - end = dest + ptr->s_memsz; - middle = dest + ptr->s_filesz; src = ptr->s_srcaddr; - printk_spew("[ 0x%016lx, %016lx, 0x%016lx) <- %016lx\n", - (unsigned long)dest, - (unsigned long)middle, - (unsigned long)end, - (unsigned long)src); /* Copy data from the initial buffer */ if (ptr->s_filesz) { size_t len; len = ptr->s_filesz; - memcpy(dest, src, len); - dest += len; + switch(ptr->compression) { +#if CONFIG_COMPRESSED_PAYLOAD_LZMA==1 + case CBFS_COMPRESS_LZMA: { + printk_debug("using LZMA\n"); + unsigned long ulzma(unsigned char *src, unsigned char *dst); + len = ulzma(src, dest); + break; + } +#endif +#if CONFIG_COMPRESSED_PAYLOAD_NRV2B==1 + case CBFS_COMPRESS_NRV2B: { + printk_debug("using NRV2B\n"); + unsigned long unrv2b(u8 *src, u8 *dst, unsigned long *ilen_p); + unsigned long tmp; + len = unrv2b(src, dest, &tmp); + break; + } +#endif + case CBFS_COMPRESS_NONE: { + printk_debug("it's not compressed!\n"); + memcpy(dest, src, len); + break; + } + default: + printk_info( "CBFS: Unknown compression type %d\n", ptr->compression); + return -1; + } + end = dest + ptr->s_memsz; + middle = dest + len; + printk_spew("[ 0x%016lx, %016lx, 0x%016lx) <- %016lx\n", + (unsigned long)dest, + (unsigned long)middle, + (unsigned long)end, + (unsigned long)src); } - /* Zero the extra bytes between middle & end */ if (middle < end) { printk_debug("Clearing Segment: addr: 0x%016lx memsz: 0x%016lx\n", |