barebox/arch/arm/cpu/start-pbl.c
Sascha Hauer c9dbd886ef ARM: Fix calling of arm_mem_barebox_image()
arm_mem_barebox_image() is used to pick a suitable place where to
put the final image to. This is called from both the PBL uncompression
code and also from the final image. To make it work properly it is
crucial that it's called with the same arguments both times. Currently
it is called with the wrong image size from the PBL uncompression code.
The size passed to arm_mem_barebox_image() has to be the size of the
whole uncompressed image including the BSS segment size. The PBL code
calls it with the compressed image size instead and without the BSS
segment. This patch fixes this by reading the uncompressed image size
from the compressed binary (the uncompressed size is appended to the
end of the compressed binary by our compression wrappers). The size
of the BSS segment is unknown though by the PBL uncompression code,
so we introduce a maximum BSS size which is used instead.

The code before this patch worked by accident because the base address
of the final image was aligned down to a 1MiB boundary. The alignment
was sufficient already to make enough space. This breaks though when
the uncompressed image including BSS becomes bigger than 1MiB while
the compressed image is smaller.

Fixes: 65071bd0: arm: Clarify memory layout calculation

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
2016-09-15 09:23:43 +02:00

105 lines
2.9 KiB
C

/*
* start-pbl.c
*
* Copyright (c) 2010-2012 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
* Copyright (c) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <common.h>
#include <init.h>
#include <linux/sizes.h>
#include <pbl.h>
#include <asm/barebox-arm.h>
#include <asm/barebox-arm-head.h>
#include <asm-generic/memory_layout.h>
#include <asm/sections.h>
#include <asm/pgtable.h>
#include <asm/cache.h>
#include <asm/unaligned.h>
#include "mmu-early.h"
unsigned long free_mem_ptr;
unsigned long free_mem_end_ptr;
/*
* First instructions in the pbl image
*/
void __naked __section(.text_head_entry) pbl_start(void)
{
barebox_arm_head();
}
extern void *input_data;
extern void *input_data_end;
__noreturn void barebox_single_pbl_start(unsigned long membase,
unsigned long memsize, void *boarddata)
{
uint32_t offset;
uint32_t pg_start, pg_end, pg_len, uncompressed_len;
void __noreturn (*barebox)(unsigned long, unsigned long, void *);
uint32_t endmem = membase + memsize;
unsigned long barebox_base;
if (IS_ENABLED(CONFIG_PBL_RELOCATABLE))
relocate_to_current_adr();
/* Get offset between linked address and runtime address */
offset = get_runtime_offset();
pg_start = (uint32_t)&input_data - offset;
pg_end = (uint32_t)&input_data_end - offset;
pg_len = pg_end - pg_start;
uncompressed_len = get_unaligned((const u32 *)(pg_start + pg_len - 4));
if (IS_ENABLED(CONFIG_RELOCATABLE))
barebox_base = arm_mem_barebox_image(membase, endmem, uncompressed_len + MAX_BSS_SIZE);
else
barebox_base = TEXT_BASE;
if (offset && (IS_ENABLED(CONFIG_PBL_FORCE_PIGGYDATA_COPY) ||
region_overlap(pg_start, pg_len, barebox_base, pg_len * 4))) {
/*
* copy piggydata binary to its link address
*/
memcpy(&input_data, (void *)pg_start, pg_len);
pg_start = (uint32_t)&input_data;
}
setup_c();
if (IS_ENABLED(CONFIG_MMU_EARLY)) {
unsigned long ttb = arm_mem_ttb(membase, endmem);
mmu_early_enable(membase, memsize, ttb);
}
free_mem_ptr = arm_mem_early_malloc(membase, endmem);
free_mem_end_ptr = arm_mem_early_malloc_end(membase, endmem);
pbl_barebox_uncompress((void*)barebox_base, (void *)pg_start, pg_len);
arm_early_mmu_cache_flush();
flush_icache();
if (IS_ENABLED(CONFIG_THUMB2_BAREBOX))
barebox = (void *)(barebox_base + 1);
else
barebox = (void *)barebox_base;
barebox(membase, memsize, boarddata);
}