Fix payload loading in various corner cases when working
authorPatrick Georgi <patrick.georgi@coresystems.de>
Wed, 30 Sep 2009 21:36:38 +0000 (21:36 +0000)
committerPatrick Georgi <patrick.georgi@coresystems.de>
Wed, 30 Sep 2009 21:36:38 +0000 (21:36 +0000)
with the bounce buffer.
In particular, the not-so-rare configuration of AMD boards with RAMBASE at
2MB shouldn't crash anymore for payloads that take > 1MB in total

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@4697 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1

src/boot/selfboot.c

index 9f5fb5c4408e41884e924a762e11a2a09862085d..bedb719808fee2acf924c4bf17c8d621a591c643 100644 (file)
@@ -423,14 +423,13 @@ static int load_self_segments(
 {
        struct segment *ptr;
        
-       unsigned long required_bounce_size = lb_end - lb_start;
+       unsigned long bounce_high = lb_end;
        for(ptr = head->next; ptr != head; ptr = ptr->next) {
                if (!overlaps_coreboot(ptr)) continue;
-               unsigned long bounce = ptr->s_dstaddr + ptr->s_memsz - lb_start;
-               if (bounce > required_bounce_size)
-                       required_bounce_size = bounce;
+               if (ptr->s_dstaddr + ptr->s_memsz > bounce_high)
+                       bounce_high = ptr->s_dstaddr + ptr->s_memsz;
        }
-       get_bounce_buffer(mem, required_bounce_size);
+       get_bounce_buffer(mem, bounce_high - lb_start);
        if (!bounce_buffer) {
                printk_err("Could not find a bounce buffer...\n");
                return 0;
@@ -502,6 +501,24 @@ static int load_self_segments(
                                /* Zero the extra bytes */
                                memset(middle, 0, end - middle);
                        }
+                       /* Copy the data that's outside the area that shadows coreboot_ram */
+                       printk_debug("dest %lx, end %lx, bouncebuffer %lx\n", dest, end, bounce_buffer);
+                       if ((unsigned long)end > bounce_buffer) {
+                               if ((unsigned long)dest < bounce_buffer) {
+                                       unsigned long from = dest;
+                                       unsigned long to = lb_start-(bounce_buffer-(unsigned long)dest);
+                                       unsigned long amount = bounce_buffer-(unsigned long)dest;
+                                       printk_debug("move prefix around: from %lx, to %lx, amount: %lx\n", from, to, amount);
+                                       memcpy(to, from, amount);
+                               }
+                               if ((unsigned long)end > bounce_buffer + (lb_end - lb_start)) {
+                                       unsigned long from = bounce_buffer + (lb_end - lb_start);
+                                       unsigned long to = lb_end;
+                                       unsigned long amount = end - from;
+                                       printk_debug("move suffix around: from %lx, to %lx, amount: %lx\n", from, to, amount);
+                                       memcpy(to, from, amount);
+                               }
+                       }
                }
        }
        return 1;