Reserve ELF section destinations in CVMX bootmem before copying the
image there.

Index: arch/mips/mach-octeon/bootoctlinux.c
--- arch/mips/mach-octeon/bootoctlinux.c.orig
+++ arch/mips/mach-octeon/bootoctlinux.c
@@ -38,6 +38,65 @@ DECLARE_GLOBAL_DATA_PTR;
 #define DEFAULT_STACK_SIZE			(1 * 1024 * 1024)
 #define DEFAULT_HEAP_SIZE			(3 * 1024 * 1024)
 
+static void octeon_elf64_shdr_bounds(unsigned long addr, u64 *base, u64 *end)
+{
+	Elf64_Ehdr *ehdr = (Elf64_Ehdr *)addr;
+	int i;
+
+	for (i = 0; i < ehdr->e_shnum; i++) {
+		Elf64_Shdr *shdr = (Elf64_Shdr *)(addr + (ulong)ehdr->e_shoff +
+						  i * sizeof(Elf64_Shdr));
+		u64 start;
+
+		if (!(shdr->sh_flags & SHF_ALLOC) ||
+		    shdr->sh_addr == 0 || shdr->sh_size == 0)
+			continue;
+
+		start = virt_to_phys((void *)(uintptr_t)shdr->sh_addr);
+		*base = min(*base, start);
+		*end = max(*end, start + shdr->sh_size);
+	}
+}
+
+static void octeon_elf32_shdr_bounds(unsigned long addr, u64 *base, u64 *end)
+{
+	Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr;
+	int i;
+
+	for (i = 0; i < ehdr->e_shnum; i++) {
+		Elf32_Shdr *shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff +
+						  i * sizeof(Elf32_Shdr));
+		u64 start;
+
+		if (!(shdr->sh_flags & SHF_ALLOC) ||
+		    shdr->sh_addr == 0 || shdr->sh_size == 0)
+			continue;
+
+		start = virt_to_phys((void *)(uintptr_t)shdr->sh_addr);
+		*base = min(*base, start);
+		*end = max(*end, start + shdr->sh_size);
+	}
+}
+
+static void octeon_elf_shdr_bounds(unsigned long addr, u64 *base, u64 *end)
+{
+	Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr;
+
+	*base = ~0ULL;
+	*end = 0;
+
+	if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
+		octeon_elf64_shdr_bounds(addr, base, end);
+	else
+		octeon_elf32_shdr_bounds(addr, base, end);
+
+	if (*base < *end) {
+		*base &= ~(CVMX_BOOTMEM_ALIGNMENT_SIZE - 1);
+		*end = (*end + CVMX_BOOTMEM_ALIGNMENT_SIZE - 1) &
+		       ~(CVMX_BOOTMEM_ALIGNMENT_SIZE - 1);
+	}
+}
+
 /**
  * NOTE: This must duplicate octeon_boot_descriptor_t in the toolchain
  * octeon-app-init.h file.
@@ -360,10 +419,13 @@ int do_bootoctlinux(struct cmd_tbl *cmdtp, int flag, i
 	int arg_start = 1;
 	int arg_count;
 	u64 addr = 0;		/* Address of the ELF image     */
+	u64 elf_base = 0;
+	u64 elf_end = 0;
 	int arg0;
 	u64 arg1;
 	u64 arg2;
 	u64 arg3;
+	bool is_elf;
 	int ret;
 	struct cvmx_coremask core_mask;
 	struct cvmx_coremask coremask_to_run;
@@ -468,19 +530,12 @@ int do_bootoctlinux(struct cmd_tbl *cmdtp, int flag, i
 	 */
 	cvmx_coremask_or(&coremask_to_run, &coremask_to_run, &core_mask);
 
-	/*
-	 * Load kernel ELF image, or try binary if ELF is not detected.
-	 * This way the much smaller vmlinux.bin can also be started but
-	 * has to be loaded at the correct address (ep as parameter).
-	 */
-	if (!valid_elf_image(addr))
-		printf("Booting binary image instead (vmlinux.bin)...\n");
+	is_elf = valid_elf_image(addr);
+	if (is_elf)
+		octeon_elf_shdr_bounds(addr, &elf_base, &elf_end);
 	else
-		addr = load_elf_image_shdr(addr);
+		printf("Booting binary image instead (vmlinux.bin)...\n");
 
-	/* Set kernel entry point */
-	kernel = (kernel_entry_t)addr;
-
 	/* Init bootmem list for Linux kernel booting */
 	if (!cvmx_bootmem_phy_mem_list_init(
 		    gd->ram_size, OCTEON_RESERVED_LOW_MEM_SIZE,
@@ -488,6 +543,17 @@ int do_bootoctlinux(struct cmd_tbl *cmdtp, int flag, i
 		printf("FATAL: Error initializing free memory list\n");
 		return 0;
 	}
+	if (elf_base < elf_end &&
+	    cvmx_bootmem_phy_alloc(elf_end - elf_base, elf_base,
+				   elf_end, 0, 0) < 0) {
+		printf("FATAL: Error reserving loaded image memory\n");
+		return 0;
+	}
+	if (is_elf)
+		addr = load_elf_image_shdr(addr);
+
+	/* Set kernel entry point */
+	kernel = (kernel_entry_t)addr;
 
 	first_core = cvmx_coremask_get_first_core(&coremask_to_run);
 
