mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-12 06:12:58 +00:00
81e712a917
The generic ARM relocate_code function was using its own function entry point as a relocation base, and it was obtaining that address by using the "adr" instruction on that entry point label. However that label is not just an ordinary label, instead we explicitly mark it as a function start address. Normally that doesn't change much (other than for debugging), but when assembled in Thumb mode, newer versions of the GNU assembler prepare everything for this address being used as the argument to a "bx" call, so make sure bit 0 is set in there to mark this function as Thumb code. Of course this doesn't end up very well when we use this address for the ensuing memcpy operation. To avoid this problem, and to solve it in a robust way, add an extra label, which is not marked as a function entry, and use that for the adr instruction. This lets all assemblers generate the right immediate offset in the "adr" instruction. This fixes in particular ARMv7-M ports when using GNU binutils v2.37 or newer (commit d3e52e120b68 seems to trigger the change in behaviour). Signed-off-by: Andre Przywara <andre.przywara@arm.com> Reported-by: Jesse Taube <mr.bossman075@gmail.com>
147 lines
3.8 KiB
ArmAsm
147 lines
3.8 KiB
ArmAsm
/* SPDX-License-Identifier: GPL-2.0+ */
|
|
/*
|
|
* relocate - common relocation function for ARM U-Boot
|
|
*
|
|
* Copyright (c) 2013 Albert ARIBAUD <albert.u.boot@aribaud.net>
|
|
*/
|
|
|
|
#include <asm-offsets.h>
|
|
#include <asm/assembler.h>
|
|
#include <config.h>
|
|
#include <elf.h>
|
|
#include <linux/linkage.h>
|
|
#ifdef CONFIG_CPU_V7M
|
|
#include <asm/armv7m.h>
|
|
#endif
|
|
|
|
/*
|
|
* Default/weak exception vectors relocation routine
|
|
*
|
|
* This routine covers the standard ARM cases: normal (0x00000000),
|
|
* high (0xffff0000) and VBAR. SoCs which do not comply with any of
|
|
* the standard cases must provide their own, strong, version.
|
|
*/
|
|
|
|
.section .text.relocate_vectors,"ax",%progbits
|
|
.weak relocate_vectors
|
|
|
|
ENTRY(relocate_vectors)
|
|
|
|
#ifdef CONFIG_CPU_V7M
|
|
/*
|
|
* On ARMv7-M we only have to write the new vector address
|
|
* to VTOR register.
|
|
*/
|
|
ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */
|
|
ldr r1, =V7M_SCB_BASE
|
|
str r0, [r1, V7M_SCB_VTOR]
|
|
#else
|
|
#ifdef CONFIG_HAS_VBAR
|
|
/*
|
|
* If the ARM processor has the security extensions,
|
|
* use VBAR to relocate the exception vectors.
|
|
*/
|
|
ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */
|
|
mcr p15, 0, r0, c12, c0, 0 /* Set VBAR */
|
|
#else
|
|
/*
|
|
* Copy the relocated exception vectors to the
|
|
* correct address
|
|
* CP15 c1 V bit gives us the location of the vectors:
|
|
* 0x00000000 or 0xFFFF0000.
|
|
*/
|
|
ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */
|
|
mrc p15, 0, r2, c1, c0, 0 /* V bit (bit[13]) in CP15 c1 */
|
|
ands r2, r2, #(1 << 13)
|
|
ldreq r1, =0x00000000 /* If V=0 */
|
|
ldrne r1, =0xFFFF0000 /* If V=1 */
|
|
ldmia r0!, {r2-r8,r10}
|
|
stmia r1!, {r2-r8,r10}
|
|
ldmia r0!, {r2-r8,r10}
|
|
stmia r1!, {r2-r8,r10}
|
|
#endif
|
|
#endif
|
|
bx lr
|
|
|
|
ENDPROC(relocate_vectors)
|
|
|
|
/*
|
|
* void relocate_code(addr_moni)
|
|
*
|
|
* This function relocates the monitor code.
|
|
*
|
|
* NOTE:
|
|
* To prevent the code below from containing references with an R_ARM_ABS32
|
|
* relocation record type, we never refer to linker-defined symbols directly.
|
|
* Instead, we declare literals which contain their relative location with
|
|
* respect to relocate_code, and at run time, add relocate_code back to them.
|
|
*/
|
|
|
|
ENTRY(relocate_code)
|
|
relocate_base:
|
|
adr r3, relocate_base
|
|
ldr r1, _image_copy_start_ofs
|
|
add r1, r3 /* r1 <- Run &__image_copy_start */
|
|
subs r4, r0, r1 /* r4 <- Run to copy offset */
|
|
beq relocate_done /* skip relocation */
|
|
ldr r1, _image_copy_start_ofs
|
|
add r1, r3 /* r1 <- Run &__image_copy_start */
|
|
ldr r2, _image_copy_end_ofs
|
|
add r2, r3 /* r2 <- Run &__image_copy_end */
|
|
copy_loop:
|
|
ldmia r1!, {r10-r11} /* copy from source address [r1] */
|
|
stmia r0!, {r10-r11} /* copy to target address [r0] */
|
|
cmp r1, r2 /* until source end address [r2] */
|
|
blo copy_loop
|
|
|
|
/*
|
|
* fix .rel.dyn relocations
|
|
*/
|
|
ldr r1, _rel_dyn_start_ofs
|
|
add r2, r1, r3 /* r2 <- Run &__rel_dyn_start */
|
|
ldr r1, _rel_dyn_end_ofs
|
|
add r3, r1, r3 /* r3 <- Run &__rel_dyn_end */
|
|
fixloop:
|
|
ldmia r2!, {r0-r1} /* (r0,r1) <- (SRC location,fixup) */
|
|
and r1, r1, #0xff
|
|
cmp r1, #R_ARM_RELATIVE
|
|
bne fixnext
|
|
|
|
/* relative fix: increase location by offset */
|
|
add r0, r0, r4
|
|
ldr r1, [r0]
|
|
add r1, r1, r4
|
|
str r1, [r0]
|
|
fixnext:
|
|
cmp r2, r3
|
|
blo fixloop
|
|
|
|
relocate_done:
|
|
|
|
#ifdef __XSCALE__
|
|
/*
|
|
* On xscale, icache must be invalidated and write buffers drained,
|
|
* even with cache disabled - 4.2.7 of xscale core developer's manual
|
|
*/
|
|
mcr p15, 0, r0, c7, c7, 0 /* invalidate icache */
|
|
mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */
|
|
#endif
|
|
|
|
/* ARMv4- don't know bx lr but the assembler fails to see that */
|
|
|
|
#ifdef __ARM_ARCH_4__
|
|
mov pc, lr
|
|
#else
|
|
bx lr
|
|
#endif
|
|
|
|
ENDPROC(relocate_code)
|
|
|
|
_image_copy_start_ofs:
|
|
.word __image_copy_start - relocate_code
|
|
_image_copy_end_ofs:
|
|
.word __image_copy_end - relocate_code
|
|
_rel_dyn_start_ofs:
|
|
.word __rel_dyn_start - relocate_code
|
|
_rel_dyn_end_ofs:
|
|
.word __rel_dyn_end - relocate_code
|