diff options
author | Zheng Bao <zheng.bao@amd.com> | 2009-11-05 10:02:59 +0000 |
---|---|---|
committer | Zheng Bao <Zheng.Bao@amd.com> | 2009-11-05 10:02:59 +0000 |
commit | e6ad7fa4a6a8456ed229b4797addb97ceb35d7cc (patch) | |
tree | f68ad167927e7dedcba32097903d82666094b50d /src | |
parent | 448509bb4e93b3ffe870f048c6b4a82b1f2cb9a7 (diff) |
If the coreboot and filo overlap, it will "slice off" a piece at the
"beginning" or "end". In the beginning case, a new segment is inserted
before the current one. But the ptr will move forward and doesn't
seem to have any other chance to process the "new" segment.
ptr ---------+ move --->
|
V
+--------+ +--------+
| | | |
| new | <---> |current | <---> .....
| | | |
+--------+ +--------+
Now we change the ptr to the previous one and restart the loop. The
new and current segment will both be processed. Even if the current
segment is done twice, no new segment will come up and ptr will move
forward as we expect.
+----------------ptr move --->
|
V
+--------+ +--------+ +--------+
| | | | | |
| prev | <---> | new | <---> |current | <---> .....
| | | | | |
+--------+ +--------+ +--------+
It is tested and fixes the crashing on my AMD Family 10 board.
Some trailing whitespaces were deleted.
Signed-off-by: Zheng Bao <zheng.bao@amd.com>
Acked-by: Stefan Reinauer <stepan@coresystems.de>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@4912 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src')
-rw-r--r-- | src/boot/selfboot.c | 77 |
1 files changed, 43 insertions, 34 deletions
diff --git a/src/boot/selfboot.c b/src/boot/selfboot.c index e75b72f7dd..a26318f97a 100644 --- a/src/boot/selfboot.c +++ b/src/boot/selfboot.c @@ -60,7 +60,7 @@ struct segment { struct verify_callback { struct verify_callback *next; - int (*callback)(struct verify_callback *vcb, + int (*callback)(struct verify_callback *vcb, Elf_ehdr *ehdr, Elf_phdr *phdr, struct segment *head); unsigned long desc_offset; unsigned long desc_addr; @@ -88,7 +88,7 @@ void * cbfs_load_payload(struct lb_memory *lb_mem, const char *name) return (void *) -1; } -/* The problem: +/* The problem: * Static executables all want to share the same addresses * in memory because only a few addresses are reliably present on * a machine, and implementing general relocation is hard. @@ -97,16 +97,16 @@ void * cbfs_load_payload(struct lb_memory *lb_mem, const char *name) * - Allocate a buffer the size of the coreboot image plus additional * required space. * - Anything that would overwrite coreboot copy into the lower part of - * the buffer. + * the buffer. * - After loading an ELF image copy coreboot to the top of the buffer. * - Then jump to the loaded image. - * + * * Benefits: * - Nearly arbitrary standalone executables can be loaded. * - Coreboot is preserved, so it can be returned to. * - The implementation is still relatively simple, * and much simpler than the general case implemented in kexec. - * + * */ static unsigned long bounce_size, bounce_buffer; @@ -138,7 +138,7 @@ static void get_bounce_buffer(struct lb_memory *mem, unsigned long req_size) msize = unpack_lb64(mem->map[i].size); mend = mstart + msize; tbuffer = mend - lb_size; - if (tbuffer < buffer) + if (tbuffer < buffer) continue; buffer = tbuffer; } @@ -190,10 +190,10 @@ static int valid_area(struct lb_memory *mem, unsigned long buffer, mstart = unpack_lb64(mem->map[i].start); mend = mstart + unpack_lb64(mem->map[i].size); printk_err(" [0x%016lx, 0x%016lx) %s\n", - (unsigned long)mstart, - (unsigned long)mend, + (unsigned long)mstart, + (unsigned long)mend, (mtype == LB_MEM_RAM)?"RAM":"Reserved"); - + } return 0; } @@ -211,25 +211,27 @@ static int overlaps_coreboot(struct segment *seg) return !((end <= lb_start) || (start >= lb_end)); } -static void relocate_segment(unsigned long buffer, struct segment *seg) +static int relocate_segment(unsigned long buffer, struct segment *seg) { /* Modify all segments that want to load onto coreboot * to load onto the bounce buffer instead. */ - unsigned long start, middle, end; + /* ret: 1 : A new segment is inserted before the seg. + * 0 : A new segment is inserted after the seg, or no new one. */ + unsigned long start, middle, end, ret = 0; - printk_spew("lb: [0x%016lx, 0x%016lx)\n", + printk_spew("lb: [0x%016lx, 0x%016lx)\n", lb_start, lb_end); /* I don't conflict with coreboot so get out of here */ if (!overlaps_coreboot(seg)) - return; + return 0; start = seg->s_dstaddr; middle = start + seg->s_filesz; end = start + seg->s_memsz; - printk_spew("segment: [0x%016lx, 0x%016lx, 0x%016lx)\n", + printk_spew("segment: [0x%016lx, 0x%016lx, 0x%016lx)\n", start, middle, end); if (seg->compression == CBFS_COMPRESS_NONE) { @@ -265,15 +267,17 @@ static void relocate_segment(unsigned long buffer, struct segment *seg) /* compute the new value of start */ start = seg->s_dstaddr; - - printk_spew(" early: [0x%016lx, 0x%016lx, 0x%016lx)\n", - new->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); + + ret = 1; } - - /* Slice off a piece at the end - * that doesn't conflict with coreboot + + /* Slice off a piece at the end + * that doesn't conflict with coreboot */ if (end > lb_end) { unsigned long len = lb_end - start; @@ -301,29 +305,31 @@ static void relocate_segment(unsigned long buffer, struct segment *seg) seg->phdr_next->phdr_prev = new; seg->phdr_next = new; - printk_spew(" late: [0x%016lx, 0x%016lx, 0x%016lx)\n", - new->s_dstaddr, + 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. + /* sort of explanation: the buffer is a 1:1 mapping to coreboot. * so you will make the dstaddr be this buffer, and it will get copied * later to where coreboot lives. */ seg->s_dstaddr = buffer + (seg->s_dstaddr - lb_start); - printk_spew(" bounce: [0x%016lx, 0x%016lx, 0x%016lx)\n", - seg->s_dstaddr, - seg->s_dstaddr + seg->s_filesz, + printk_spew(" bounce: [0x%016lx, 0x%016lx, 0x%016lx)\n", + seg->s_dstaddr, + seg->s_dstaddr + seg->s_filesz, seg->s_dstaddr + seg->s_memsz); + + return ret; } static int build_self_segment_list( - struct segment *head, + struct segment *head, struct lb_memory *mem, struct cbfs_payload *payload, u32 *entry) { @@ -345,7 +351,7 @@ static int build_self_segment_list( case PAYLOAD_SEGMENT_CODE: case PAYLOAD_SEGMENT_DATA: - printk_debug(" %s (compression=%x)\n", + printk_debug(" %s (compression=%x)\n", segment->type == PAYLOAD_SEGMENT_CODE ? "code" : "data", ntohl(segment->compression)); new = malloc(sizeof(*new)); @@ -394,7 +400,7 @@ static int build_self_segment_list( segment++; - // FIXME: Explain what this is + // FIXME: Explain what this is for(ptr = head->next; ptr != head; ptr = ptr->next) { if (new->s_srcaddr < ntohl((u32) segment->load_addr)) break; @@ -422,7 +428,7 @@ static int load_self_segments( struct cbfs_payload *payload) { struct segment *ptr; - + unsigned long bounce_high = lb_end; for(ptr = head->next; ptr != head; ptr = ptr->next) { if (!overlaps_coreboot(ptr)) continue; @@ -443,10 +449,13 @@ static int load_self_segments( unsigned char *dest, *src; printk_debug("Loading Segment: addr: 0x%016lx memsz: 0x%016lx filesz: 0x%016lx\n", ptr->s_dstaddr, ptr->s_memsz, ptr->s_filesz); - + /* Modify the segment to load onto the bounce_buffer if necessary. */ - relocate_segment(bounce_buffer, ptr); + if (relocate_segment(bounce_buffer, ptr)) { + ptr = (ptr->prev)->prev; + continue; + } printk_debug("Post relocation: addr: 0x%016lx memsz: 0x%016lx filesz: 0x%016lx\n", ptr->s_dstaddr, ptr->s_memsz, ptr->s_filesz); @@ -454,7 +463,7 @@ static int load_self_segments( /* Compute the boundaries of the segment */ dest = (unsigned char *)(ptr->s_dstaddr); src = (unsigned char *)(ptr->s_srcaddr); - + /* Copy data from the initial buffer */ if (ptr->s_filesz) { unsigned char *middle, *end; @@ -496,7 +505,7 @@ static int load_self_segments( if (middle < end) { printk_debug("Clearing Segment: addr: 0x%016lx memsz: 0x%016lx\n", (unsigned long)middle, (unsigned long)(end - middle)); - + /* Zero the extra bytes */ memset(middle, 0, end - middle); } |