summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2012-10-07 19:06:30 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2013-03-07 12:38:01 +0100
commita81ec0225f5a100341c20b4329c8b1d81ab025c4 (patch)
tree0d38efb6ba77f80dc0759513d33ab73f7f9bc868 /arch
parentb08e08506b9752d3768e42d075283f91d2ed5180 (diff)
downloadbarebox-a81ec0225f5a100341c20b4329c8b1d81ab025c4.tar.gz
barebox-a81ec0225f5a100341c20b4329c8b1d81ab025c4.tar.xz
ARM: Add relocatable binary support
For making the same binary executable on different SoCs which have different DRAM addresses we have to be independent of the compile time link address. This patch adds relocatable binary support for the ARM architecture. With this two new functions are available. relocate_to_current_adr will fixup the binary to continue executing from the current position. relocate_to_adr will copy the binary to a given address, fixup the binary and continue executing from there. For the PBL and the real image relocatable support can be enabled independently. This is done to (hopefully) better cope with setups where the PBL runs from SRAM or ROM and the real binary does not. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/Makefile4
-rw-r--r--arch/arm/cpu/Makefile3
-rw-r--r--arch/arm/cpu/common.c66
-rw-r--r--arch/arm/cpu/setupc.S59
-rw-r--r--arch/arm/cpu/start-pbl.c18
-rw-r--r--arch/arm/cpu/start.c5
-rw-r--r--arch/arm/include/asm/barebox-arm.h26
-rw-r--r--arch/arm/lib/barebox.lds.S17
-rw-r--r--arch/arm/lib/runtime-offset.S4
-rw-r--r--arch/arm/pbl/Makefile3
-rw-r--r--arch/arm/pbl/zbarebox.lds.S16
11 files changed, 217 insertions, 4 deletions
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index b98d6b86a7..5125b8720b 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -181,6 +181,10 @@ CPPFLAGS += -fdata-sections -ffunction-sections
LDFLAGS_barebox += -static --gc-sections
endif
+ifdef CONFIG_RELOCATABLE
+LDFLAGS_barebox += -pie
+endif
+
ifdef CONFIG_IMAGE_COMPRESSION
KBUILD_BINARY := arch/arm/pbl/zbarebox.bin
KBUILD_TARGET := zbarebox.bin
diff --git a/arch/arm/cpu/Makefile b/arch/arm/cpu/Makefile
index 44410eec95..5935e1c5e4 100644
--- a/arch/arm/cpu/Makefile
+++ b/arch/arm/cpu/Makefile
@@ -21,3 +21,6 @@ pbl-$(CONFIG_CPU_32v7) += cache-armv7.o
obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o
pbl-y += start-pbl.o setupc.o
+
+obj-y += common.o
+pbl-y += common.o
diff --git a/arch/arm/cpu/common.c b/arch/arm/cpu/common.c
new file mode 100644
index 0000000000..40f784f02a
--- /dev/null
+++ b/arch/arm/cpu/common.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * 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 <sizes.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>
+
+/*
+ * relocate binary to the currently running address
+ */
+void relocate_to_current_adr(void)
+{
+ uint32_t offset;
+ uint32_t *dstart, *dend, *dynsym, *dynend;
+
+ /* Get offset between linked address and runtime address */
+ offset = get_runtime_offset();
+
+ dstart = (void *)(ld_var(__rel_dyn_start) - offset);
+ dend = (void *)(ld_var(__rel_dyn_end) - offset);
+
+ dynsym = (void *)(ld_var(__dynsym_start) - offset);
+ dynend = (void *)(ld_var(__dynsym_end) - offset);
+
+ while (dstart < dend) {
+ uint32_t *fixup = (uint32_t *)(*dstart - offset);
+ uint32_t type = *(dstart + 1);
+
+ if ((type & 0xff) == 0x17) {
+ *fixup = *fixup - offset;
+ } else {
+ int index = type >> 8;
+ uint32_t r = dynsym[index * 4 + 1];
+
+ *fixup = *fixup + r - offset;
+ }
+
+ *dstart -= offset;
+ dstart += 2;
+ }
+
+ memset(dynsym, 0, (unsigned long)dynend - (unsigned long)dynsym);
+
+ arm_early_mmu_cache_flush();
+ flush_icache();
+}
diff --git a/arch/arm/cpu/setupc.S b/arch/arm/cpu/setupc.S
index d0de87dd9b..7fd5d012f0 100644
--- a/arch/arm/cpu/setupc.S
+++ b/arch/arm/cpu/setupc.S
@@ -1,4 +1,5 @@
#include <linux/linkage.h>
+#include <asm/sections.h>
.section .text.setupc
@@ -35,3 +36,61 @@ ENTRY(setup_c)
pop {r4, r5}
mov pc, lr
ENDPROC(setup_c)
+
+#ifdef CONFIG_RELOCATABLE
+/*
+ * void relocate_to_adr(unsigned long targetadr)
+ *
+ * Copy binary to targetadr, relocate code, clear bss and continue
+ * executing at new address.
+ */
+.section .text.relocate_to_adr
+ENTRY(relocate_to_adr)
+ /* r0: target address */
+ push {r3, r4, r5, r6, r7, r8}
+ mov r7, lr
+
+ mov r6, r0
+
+ bl get_runtime_offset
+
+ mov r5, r0
+
+ ld_var _text, r0, r4
+ mov r8, r0
+
+ sub r1, r0, r5 /* r1: from address */
+
+ cmp r1, r6 /* already at correct address? */
+ beq 1f /* yes, skip copy to new address */
+
+ ld_var __bss_start, r2, r4
+
+ sub r2, r2, r0 /* r2: size */
+ mov r0, r6 /* r0: target */
+
+ add r7, r7, r0 /* adjust return address */
+ sub r7, r7, r1 /* lr += offset */
+
+ bl memcpy /* copy binary */
+
+#ifdef CONFIG_MMU
+ bl arm_early_mmu_cache_flush
+#endif
+ mov r0,#0
+ mcr p15, 0, r0, c7, c5, 0 /* flush icache */
+
+ ldr r0,=1f
+ sub r0, r0, r8
+ add r0, r0, r6
+ mov pc, r0 /* jump to relocated address */
+1:
+ bl relocate_to_current_adr /* relocate binary */
+
+ mov lr, r7
+
+ pop {r3, r4, r5, r6, r7, r8}
+ mov pc, lr
+
+ENDPROC(relocate_to_adr)
+#endif
diff --git a/arch/arm/cpu/start-pbl.c b/arch/arm/cpu/start-pbl.c
index 91bc8fe9ff..6f03c4a7df 100644
--- a/arch/arm/cpu/start-pbl.c
+++ b/arch/arm/cpu/start-pbl.c
@@ -55,9 +55,13 @@ static noinline __noreturn void __barebox_arm_entry(uint32_t membase,
uint32_t pg_start, pg_end, pg_len;
void __noreturn (*barebox)(uint32_t, uint32_t, uint32_t);
uint32_t endmem = membase + memsize;
+ unsigned long barebox_base;
endmem -= STACK_SIZE; /* stack */
+ if (IS_ENABLED(CONFIG_PBL_RELOCATABLE))
+ relocate_to_current_adr();
+
/* Get offset between linked address and runtime address */
offset = get_runtime_offset();
@@ -65,8 +69,13 @@ static noinline __noreturn void __barebox_arm_entry(uint32_t membase,
pg_end = (uint32_t)&input_data_end - offset;
pg_len = pg_end - pg_start;
+ if (IS_ENABLED(CONFIG_RELOCATABLE))
+ barebox_base = arm_barebox_image_place(membase + memsize);
+ else
+ barebox_base = TEXT_BASE;
+
if (offset && (IS_ENABLED(CONFIG_PBL_FORCE_PIGGYDATA_COPY) ||
- region_overlap(pg_start, pg_len, TEXT_BASE, pg_len * 4))) {
+ region_overlap(pg_start, pg_len, barebox_base, pg_len * 4))) {
/*
* copy piggydata binary to its link address
*/
@@ -86,14 +95,15 @@ static noinline __noreturn void __barebox_arm_entry(uint32_t membase,
free_mem_ptr = endmem;
free_mem_end_ptr = free_mem_ptr + SZ_128K;
- pbl_barebox_uncompress((void*)TEXT_BASE, (void *)pg_start, pg_len);
+ 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 *)(TEXT_BASE + 1);
+ barebox = (void *)(barebox_base + 1);
else
- barebox = (void *)TEXT_BASE;
+ barebox = (void *)barebox_base;
barebox(membase, memsize, boarddata);
}
diff --git a/arch/arm/cpu/start.c b/arch/arm/cpu/start.c
index cd34d9c66d..7c2bcd0631 100644
--- a/arch/arm/cpu/start.c
+++ b/arch/arm/cpu/start.c
@@ -37,6 +37,11 @@ static noinline __noreturn void __start(uint32_t membase, uint32_t memsize,
unsigned long endmem = membase + memsize;
unsigned long malloc_start, malloc_end;
+ if (IS_ENABLED(CONFIG_RELOCATABLE)) {
+ unsigned long barebox_base = arm_barebox_image_place(endmem);
+ relocate_to_adr(barebox_base);
+ }
+
setup_c();
arm_stack_top = endmem;
diff --git a/arch/arm/include/asm/barebox-arm.h b/arch/arm/include/asm/barebox-arm.h
index 11ef848773..54da10a1e4 100644
--- a/arch/arm/include/asm/barebox-arm.h
+++ b/arch/arm/include/asm/barebox-arm.h
@@ -26,6 +26,7 @@
#define _BAREBOX_ARM_H_
#include <sizes.h>
+#include <asm-generic/memory_layout.h>
/* cpu/.../cpu.c */
int cleanup_before_linux(void);
@@ -40,6 +41,8 @@ void board_init_lowlevel(void);
uint32_t get_runtime_offset(void);
void setup_c(void);
+void relocate_to_current_adr(void);
+void relocate_to_adr(unsigned long target);
void __noreturn barebox_arm_entry(uint32_t membase, uint32_t memsize, uint32_t boarddata);
#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_ARM_EXCEPTIONS)
@@ -50,4 +53,27 @@ static inline void arm_fixup_vectors(void)
}
#endif
+/*
+ * For relocatable binaries find a suitable start address for the
+ * relocated binary. Beginning at the memory end substract the reserved
+ * space and round down a bit at the end. This is used by the pbl to
+ * extract the image to a suitable place so that the uncompressed image
+ * does not have to copy itself to another place. Also it's used by
+ * the uncompressed image to relocate itself to the same place.
+ */
+static inline unsigned long arm_barebox_image_place(unsigned long endmem)
+{
+ endmem -= STACK_SIZE;
+ endmem -= SZ_32K; /* ttb */
+ endmem -= SZ_128K; /* early malloc */
+ endmem -= SZ_1M; /* place for barebox image */
+
+ /*
+ * round down to make translating the objdump easier
+ */
+ endmem &= ~(SZ_1M - 1);
+
+ return endmem;
+}
+
#endif /* _BAREBOX_ARM_H_ */
diff --git a/arch/arm/lib/barebox.lds.S b/arch/arm/lib/barebox.lds.S
index e5aee8cd82..abdd69e632 100644
--- a/arch/arm/lib/barebox.lds.S
+++ b/arch/arm/lib/barebox.lds.S
@@ -25,7 +25,11 @@ OUTPUT_ARCH(arm)
ENTRY(start)
SECTIONS
{
+#ifdef CONFIG_RELOCATABLE
+ . = 0x0;
+#else
. = TEXT_BASE;
+#endif
#ifndef CONFIG_PBL_IMAGE
PRE_IMAGE
@@ -88,7 +92,20 @@ SECTIONS
__usymtab : { BAREBOX_SYMS }
__usymtab_end = .;
+ .rel.dyn : {
+ __rel_dyn_start = .;
+ *(.rel*)
+ __rel_dyn_end = .;
+ }
+
+ .dynsym : {
+ __dynsym_start = .;
+ *(.dynsym)
+ __dynsym_end = .;
+ }
+
_edata = .;
+
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss*) }
diff --git a/arch/arm/lib/runtime-offset.S b/arch/arm/lib/runtime-offset.S
index aa56c7b105..15bf4149b7 100644
--- a/arch/arm/lib/runtime-offset.S
+++ b/arch/arm/lib/runtime-offset.S
@@ -35,6 +35,10 @@ __ld_var_base:
.endm
ld_var_entry _text
+ld_var_entry __rel_dyn_start
+ld_var_entry __rel_dyn_end
+ld_var_entry __dynsym_start
+ld_var_entry __dynsym_end
ld_var_entry _barebox_image_size
ld_var_entry __bss_start
ld_var_entry __bss_stop
diff --git a/arch/arm/pbl/Makefile b/arch/arm/pbl/Makefile
index 6eeee737c8..3f50f77bc0 100644
--- a/arch/arm/pbl/Makefile
+++ b/arch/arm/pbl/Makefile
@@ -23,6 +23,9 @@ $(obj)/zbarebox.S: $(obj)/zbarebox FORCE
PBL_CPPFLAGS += -fdata-sections -ffunction-sections
LDFLAGS_zbarebox := -Map $(obj)/zbarebox.map
LDFLAGS_zbarebox += -static --gc-sections
+ifdef CONFIG_PBL_RELOCATABLE
+LDFLAGS_zbarebox += -pie
+endif
zbarebox-common := $(barebox-pbl-common) $(obj)/$(piggy_o)
zbarebox-lds := $(obj)/zbarebox.lds
diff --git a/arch/arm/pbl/zbarebox.lds.S b/arch/arm/pbl/zbarebox.lds.S
index 564b3c6170..6b23bbe79c 100644
--- a/arch/arm/pbl/zbarebox.lds.S
+++ b/arch/arm/pbl/zbarebox.lds.S
@@ -29,7 +29,11 @@ OUTPUT_ARCH(arm)
ENTRY(pbl_start)
SECTIONS
{
+#ifdef CONFIG_PBL_RELOCATABLE
+ . = 0x0;
+#else
. = TEXT_BASE - SZ_2M;
+#endif
PRE_IMAGE
@@ -58,6 +62,18 @@ SECTIONS
. = ALIGN(4);
.data : { *(.data*) }
+ .rel.dyn : {
+ __rel_dyn_start = .;
+ *(.rel*)
+ __rel_dyn_end = .;
+ }
+
+ .dynsym : {
+ __dynsym_start = .;
+ *(.dynsym)
+ __dynsym_end = .;
+ }
+
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss*) }