Hi,

attached patches do:
* dynamic-bounce-buffer-size
Eliminate the assumption that the bouncebuffer is twice the size of coreboot.

* flexible-self-bounce-buffer
Bouncebuffer handling with compressed segments was changed so that the entire 
segment ends up in the buffer and isn't split into "overlaps coreboot" and 
"doesn't overlap coreboot".
That can lead to problems if the segment is larger than coreboot, incl. 
corruption of the high memory tables, or crashes in extreme cases.

This patch builds on dynamic-bounce-buffer-size and allocates the bouncebuffer 
so that all segments that overlap coreboot fit into it entirely.

* update-comments
Update comments accordingly

The patches have some different line numbers than upstream, but apply 
correctly. The remaining changes are just debug prints.

Tested on Kontron. Together with the other patch by me this morning and the 
commited FILO change, ACPI and e820 tables are seen correctly by Linux.

Signed-off-by: Patrick Georgi <[email protected]>
Index: coreboot-v2/src/arch/i386/boot/boot.c
===================================================================
--- coreboot-v2.orig/src/arch/i386/boot/boot.c
+++ coreboot-v2/src/arch/i386/boot/boot.c
@@ -68,7 +68,7 @@ int elf_check_arch(Elf_ehdr *ehdr)
 	
 }
 
-void jmp_to_elf_entry(void *entry, unsigned long buffer)
+void jmp_to_elf_entry(void *entry, unsigned long buffer, unsigned long bounce_size)
 {
 	extern unsigned char _ram_seg, _eram_seg;
 	unsigned long lb_start, lb_size;
@@ -79,7 +79,7 @@ void jmp_to_elf_entry(void *entry, unsig
 
 	lb_start = (unsigned long)&_ram_seg;
 	lb_size = (unsigned long)(&_eram_seg - &_ram_seg);
-	adjust = buffer + lb_size - lb_start;
+	adjust = buffer + bounce_size - lb_start;
 
 	adjusted_boot_notes = (unsigned long)&elf_boot_notes;
 	adjusted_boot_notes += adjust; 
Index: coreboot-v2/src/arch/ppc/boot/boot.c
===================================================================
--- coreboot-v2.orig/src/arch/ppc/boot/boot.c
+++ coreboot-v2/src/arch/ppc/boot/boot.c
@@ -16,7 +16,7 @@ int elf_check_arch(Elf_ehdr *ehdr)
 	
 }
 
-void jmp_to_elf_entry(void *entry, unsigned long buffer)
+void jmp_to_elf_entry(void *entry, unsigned long buffer, unsigned long bounce_size)
 {
 	void (*kernel_entry)(void);       
 
Index: coreboot-v2/src/boot/elfboot.c
===================================================================
--- coreboot-v2.orig/src/boot/elfboot.c
+++ coreboot-v2/src/boot/elfboot.c
@@ -122,6 +122,8 @@ int verify_ip_checksum(
  * 
  */
 
+static unsigned long bounce_size;
+
 static unsigned long get_bounce_buffer(struct lb_memory *mem)
 {
 	unsigned long lb_size;
@@ -130,7 +132,8 @@ static unsigned long get_bounce_buffer(s
 	int i;
 	lb_size = (unsigned long)(&_eram_seg - &_ram_seg);
 	/* Double coreboot size so I have somewhere to place a copy to return to */
-	lb_size = lb_size + lb_size;
+	bounce_size = lb_size;
+	lb_size = bounce_size + lb_size;
 	mem_entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
 	buffer = 0;
 	for(i = 0; i < mem_entries; i++) {
@@ -610,7 +613,7 @@ int elfload(struct lb_memory *mem,
 	post_code(0xfe);
 
 	/* Jump to kernel */
-	jmp_to_elf_entry(entry, bounce_buffer);
+	jmp_to_elf_entry(entry, bounce_buffer, bounce_size);
 	return 1;
 
  out:
Index: coreboot-v2/src/boot/selfboot.c
===================================================================
--- coreboot-v2.orig/src/boot/selfboot.c
+++ coreboot-v2/src/boot/selfboot.c
@@ -92,6 +92,8 @@ struct ip_checksum_vcb {
  * 
  */
 
+static unsigned long bounce_size;
+
 static unsigned long get_bounce_buffer(struct lb_memory *mem)
 {
 	unsigned long lb_size;
@@ -100,7 +102,8 @@ static unsigned long get_bounce_buffer(s
 	int i;
 	lb_size = (unsigned long)(&_eram_seg - &_ram_seg);
 	/* Double coreboot size so I have somewhere to place a copy to return to */
-	lb_size = lb_size + lb_size;
+	bounce_size = lb_size;
+	lb_size = bounce_size + lb_size;
 	mem_entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
 	buffer = 0;
 	for(i = 0; i < mem_entries; i++) {
@@ -482,7 +485,7 @@ int selfboot(struct lb_memory *mem, stru
 	post_code(0xfe);
 
 	/* Jump to kernel */
-	jmp_to_elf_entry((void*)entry, bounce_buffer);
+	jmp_to_elf_entry((void*)entry, bounce_buffer, bounce_size);
 	return 1;
 
  out:
Index: coreboot-v2/src/include/boot/elf.h
===================================================================
--- coreboot-v2.orig/src/include/boot/elf.h
+++ coreboot-v2/src/include/boot/elf.h
@@ -390,7 +390,7 @@ typedef Elf64_Phdr Elf_phdr;
 #endif
 
 int elf_check_arch(Elf_ehdr *ehdr);
-void jmp_to_elf_entry(void *entry, unsigned long buffer);
+void jmp_to_elf_entry(void *entry, unsigned long buffer, unsigned long bounce_size);
 struct lb_memory;
 int elfboot(struct lb_memory *mem);
 /* Temporary compile fix, FILO should be dropped from coreboot */
Index: coreboot-v2/src/boot/selfboot.c
===================================================================
--- coreboot-v2.orig/src/boot/selfboot.c
+++ coreboot-v2/src/boot/selfboot.c
@@ -92,9 +92,9 @@ struct ip_checksum_vcb {
  * 
  */
 
-static unsigned long bounce_size;
+static unsigned long bounce_size, bounce_buffer;
 
-static unsigned long get_bounce_buffer(struct lb_memory *mem)
+static void get_bounce_buffer(struct lb_memory *mem, unsigned long bounce_size)
 {
 	unsigned long lb_size;
 	unsigned long mem_entries;
@@ -102,7 +102,6 @@ static unsigned long get_bounce_buffer(s
 	int i;
 	lb_size = (unsigned long)(&_eram_seg - &_ram_seg);
 	/* Double coreboot size so I have somewhere to place a copy to return to */
-	bounce_size = lb_size;
 	lb_size = bounce_size + lb_size;
 	mem_entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
 	buffer = 0;
@@ -126,7 +125,7 @@ static unsigned long get_bounce_buffer(s
 			continue;
 		buffer = tbuffer;
 	}
-	return buffer;
+	bounce_buffer = buffer;
 }
 
 static int valid_area(struct lb_memory *mem, unsigned long buffer,
@@ -183,24 +182,34 @@ static int valid_area(struct lb_memory *
 	return 1;
 }
 
+static const unsigned long lb_start = (unsigned long)&_ram_seg;
+static const unsigned long lb_end = (unsigned long)&_eram_seg;
+
+static int overlaps_coreboot(struct segment *seg)
+{
+	unsigned long start, end;
+	start = seg->s_dstaddr;
+	end = start + seg->s_memsz;
+	return !((end <= lb_start) || (start >= lb_end));
+}
+
 static void 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 lb_start = (unsigned long)&_ram_seg;
-	unsigned long lb_end = (unsigned long)&_eram_seg;
 	unsigned long start, middle, end;
 
 	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;
+
 	start = seg->s_dstaddr;
 	middle = start + seg->s_filesz;
 	end = start + seg->s_memsz;
-	/* I don't conflict with coreboot so get out of here */
-	if ((end <= lb_start) || (start >= lb_end))
-		return;
 
 	printk_spew("segment: [0x%016lx, 0x%016lx, 0x%016lx)\n", 
 		start, middle, end);
@@ -301,7 +310,7 @@ static void relocate_segment(unsigned lo
 
 static int build_self_segment_list(
 	struct segment *head, 
-	unsigned long bounce_buffer, struct lb_memory *mem,
+	struct lb_memory *mem,
 	struct cbfs_payload *payload, u32 *entry)
 {
 	struct segment *new;
@@ -374,32 +383,47 @@ static int build_self_segment_list(
 		new->phdr_prev = head->phdr_prev;
 		head->phdr_prev->phdr_next  = new;
 		head->phdr_prev = new;
-
-		/* Verify the memory addresses in the segment are valid */
-		if (!valid_area(mem, bounce_buffer, new->s_dstaddr, new->s_memsz)) 
-			goto out;
-
-		/* Modify the segment to load onto the bounce_buffer if necessary.
-		 */
-		relocate_segment(bounce_buffer, new);
 	}
 	return 1;
- out:
-	return 0;
 }
 
 static int load_self_segments(
-	struct segment *head, struct cbfs_payload *payload)
+	struct segment *head,
+	struct lb_memory *mem,
+	struct cbfs_payload *payload)
 {
 	unsigned long offset;
 	struct segment *ptr;
 	
 	offset = 0;
+	unsigned long required_bounce_size = 0;
+	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;
+	}
+	get_bounce_buffer(mem, required_bounce_size);
+	if (!bounce_buffer) {
+		printk_err("Could not find a bounce buffer...\n");
+		return 0;
+	}
+	for(ptr = head->next; ptr != head; ptr = ptr->next) {
+		/* Verify the memory addresses in the segment are valid */
+		if (!valid_area(mem, bounce_buffer, ptr->s_dstaddr, ptr->s_memsz))
+			return 0;
+	}
 	for(ptr = head->next; ptr != head; ptr = ptr->next) {
 		unsigned char *dest, *middle, *end, *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);
+
+		printk_debug("Post relocation: addr: 0x%016lx memsz: 0x%016lx filesz: 0x%016lx\n",
+			ptr->s_dstaddr, ptr->s_memsz, ptr->s_filesz);
+
 		/* Compute the boundaries of the segment */
 		dest = (unsigned char *)(ptr->s_dstaddr);
 		src = (unsigned char *)(ptr->s_srcaddr);
@@ -459,21 +483,13 @@ int selfboot(struct lb_memory *mem, stru
 {
 	u32 entry=0;
 	struct segment head;
-	unsigned long bounce_buffer;
-
-	/* Find a bounce buffer so I can load to coreboot's current location */
-	bounce_buffer = get_bounce_buffer(mem);
-	if (!bounce_buffer) {
-		printk_err("Could not find a bounce buffer...\n");
-		goto out;
-	}
 
 	/* Preprocess the self segments */
-	if (!build_self_segment_list(&head, bounce_buffer, mem, payload, &entry))
+	if (!build_self_segment_list(&head, mem, payload, &entry))
 		goto out;
 
 	/* Load the segments */
-	if (!load_self_segments(&head, payload))
+	if (!load_self_segments(&head, mem, payload))
 		goto out;
 
 	printk_spew("Loaded segments\n");
Index: coreboot-v2/src/boot/elfboot.c
===================================================================
--- coreboot-v2.orig/src/boot/elfboot.c
+++ coreboot-v2/src/boot/elfboot.c
@@ -107,10 +107,11 @@ int verify_ip_checksum(
  * a machine, and implementing general relocation is hard.
  *
  * The solution:
- * - Allocate a buffer twice the size of the coreboot image.
- * - Anything that would overwrite coreboot copy into the lower half of
+ * - 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. 
- * - After loading an ELF image copy coreboot to the upper half of the
+ * - After loading an ELF image copy coreboot to the top of the
  *   buffer.
  * - Then jump to the loaded image.
  * 
Index: coreboot-v2/src/boot/selfboot.c
===================================================================
--- coreboot-v2.orig/src/boot/selfboot.c
+++ coreboot-v2/src/boot/selfboot.c
@@ -77,10 +77,11 @@ struct ip_checksum_vcb {
  * a machine, and implementing general relocation is hard.
  *
  * The solution:
- * - Allocate a buffer twice the size of the coreboot image.
- * - Anything that would overwrite coreboot copy into the lower half of
+ * - 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. 
- * - After loading an ELF image copy coreboot to the upper half of the
+ * - After loading an ELF image copy coreboot to the top of the
  *   buffer.
  * - Then jump to the loaded image.
  * 
-- 
coreboot mailing list: [email protected]
http://www.coreboot.org/mailman/listinfo/coreboot

Reply via email to