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.  The ptr will move forward and doesn't seem to
have any 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.

      +----------------ptr      move --->
      |
      V
 +--------+        +--------+       +--------+
 |        |        |        |       |        |
 |  prev  | <--->  |  new   | <---> |current | <---> .....
 |        |        |        |       |        |
 +--------+        +--------+       +--------+

It is tested on my Family 10 board.

Signed-off-by: Zheng Bao <zheng.bao@amd.com>


Index: src/boot/selfboot.c
===================================================================
--- src/boot/selfboot.c	(revision 4892)
+++ src/boot/selfboot.c	(working copy)
@@ -211,19 +211,21 @@
 	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", 
 		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;
@@ -270,6 +272,8 @@
 				new->s_dstaddr, 
 				new->s_dstaddr + new->s_filesz,
 				new->s_dstaddr + new->s_memsz);
+
+			ret = 1;
 		}
 			
 		/* Slice off a piece at the end 
@@ -319,6 +323,8 @@
 		seg->s_dstaddr, 
 		seg->s_dstaddr + seg->s_filesz, 
 		seg->s_dstaddr + seg->s_memsz);
+
+	return ret;
 }
 
 
@@ -446,7 +452,10 @@
 		
 		/* 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);
