| /* |
| * relocate - common relocation function for ARM U-Boot |
| * |
| * Copyright (c) 2013 Albert ARIBAUD <albert.u.boot@aribaud.net> |
| * |
| * 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 as |
| * published by the Free Software Foundation; either version 2 of |
| * the License, or (at your option) any later version. |
| * |
| * 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. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
| * MA 02111-1307 USA |
| */ |
| |
| #include <linux/linkage.h> |
| |
| /* |
| * 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) |
| ldr r1, =__image_copy_start /* r1 <- SRC &__image_copy_start */ |
| subs r9, r0, r1 /* r9 <- relocation offset */ |
| beq relocate_done /* skip relocation */ |
| ldr r2, =__image_copy_end /* r2 <- SRC &__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 r2, =__rel_dyn_start /* r2 <- SRC &__rel_dyn_start */ |
| ldr r3, =__rel_dyn_end /* r3 <- SRC &__rel_dyn_end */ |
| fixloop: |
| ldmia r2!, {r0-r1} /* (r0,r1) <- (SRC location,fixup) */ |
| and r1, r1, #0xff |
| cmp r1, #23 /* relative fixup? */ |
| bne fixnext |
| |
| /* relative fix: increase location by offset */ |
| add r0, r0, r9 |
| ldr r1, [r0] |
| add r1, r1, r9 |
| 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) |