Author: zbao Date: 2009-11-05 10:02:59 +0000 (Thu, 05 Nov 2009) New Revision: 4912
Modified: trunk/src/boot/selfboot.c Log: 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
Modified: trunk/src/boot/selfboot.c =================================================================== --- trunk/src/boot/selfboot.c 2009-11-05 09:09:20 UTC (rev 4911) +++ trunk/src/boot/selfboot.c 2009-11-05 10:02:59 UTC (rev 4912) @@ -60,7 +60,7 @@
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 @@ 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 @@ * - 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 @@ 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 @@ 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 @@ 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 @@
/* 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 @@ 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 @@
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 @@
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 @@ 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 @@ 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 @@ /* 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 @@ 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); }