10ae76531SDavid Feng/* 20ae76531SDavid Feng * relocate - common relocation function for AArch64 U-Boot 30ae76531SDavid Feng * 40ae76531SDavid Feng * (C) Copyright 2013 50ae76531SDavid Feng * Albert ARIBAUD <albert.u.boot@aribaud.net> 60ae76531SDavid Feng * David Feng <fenghua@phytium.com.cn> 70ae76531SDavid Feng * 80ae76531SDavid Feng * SPDX-License-Identifier: GPL-2.0+ 90ae76531SDavid Feng */ 100ae76531SDavid Feng 110ae76531SDavid Feng#include <asm-offsets.h> 120ae76531SDavid Feng#include <config.h> 13c70f74a0SSimon Glass#include <elf.h> 140ae76531SDavid Feng#include <linux/linkage.h> 1583571bcaSYork Sun#include <asm/macro.h> 160ae76531SDavid Feng 170ae76531SDavid Feng/* 180ae76531SDavid Feng * void relocate_code (addr_moni) 190ae76531SDavid Feng * 200ae76531SDavid Feng * This function relocates the monitor code. 210ae76531SDavid Feng * x0 holds the destination address. 220ae76531SDavid Feng */ 230ae76531SDavid FengENTRY(relocate_code) 2483571bcaSYork Sun stp x29, x30, [sp, #-32]! /* create a stack frame */ 2583571bcaSYork Sun mov x29, sp 2683571bcaSYork Sun str x0, [sp, #16] 270ae76531SDavid Feng /* 280ae76531SDavid Feng * Copy u-boot from flash to RAM 290ae76531SDavid Feng */ 30*559b4bfaSIbai Erkiaga adrp x1, __image_copy_start /* x1 <- address bits [31:12] */ 31*559b4bfaSIbai Erkiaga add x1, x1, :lo12:__image_copy_start/* x1 <- address bits [11:00] */ 32*559b4bfaSIbai Erkiaga subs x9, x0, x1 /* x9 <- Run to copy offset */ 330ae76531SDavid Feng b.eq relocate_done /* skip relocation */ 34f00ac1e5SStephen Warren /* 35f00ac1e5SStephen Warren * Don't ldr x1, __image_copy_start here, since if the code is already 36f00ac1e5SStephen Warren * running at an address other than it was linked to, that instruction 37f00ac1e5SStephen Warren * will load the relocated value of __image_copy_start. To 38f00ac1e5SStephen Warren * correctly apply relocations, we need to know the linked value. 39f00ac1e5SStephen Warren * 40f00ac1e5SStephen Warren * Linked &__image_copy_start, which we know was at 41f00ac1e5SStephen Warren * CONFIG_SYS_TEXT_BASE, which is stored in _TEXT_BASE, as a non- 42f00ac1e5SStephen Warren * relocated value, since it isn't a symbol reference. 43f00ac1e5SStephen Warren */ 44f00ac1e5SStephen Warren ldr x1, _TEXT_BASE /* x1 <- Linked &__image_copy_start */ 45f00ac1e5SStephen Warren subs x9, x0, x1 /* x9 <- Link to copy offset */ 460ae76531SDavid Feng 47*559b4bfaSIbai Erkiaga adrp x1, __image_copy_start /* x1 <- address bits [31:12] */ 48*559b4bfaSIbai Erkiaga add x1, x1, :lo12:__image_copy_start/* x1 <- address bits [11:00] */ 49*559b4bfaSIbai Erkiaga adrp x2, __image_copy_end /* x2 <- address bits [31:12] */ 50*559b4bfaSIbai Erkiaga add x2, x2, :lo12:__image_copy_end /* x2 <- address bits [11:00] */ 510ae76531SDavid Fengcopy_loop: 520ae76531SDavid Feng ldp x10, x11, [x1], #16 /* copy from source address [x1] */ 530ae76531SDavid Feng stp x10, x11, [x0], #16 /* copy to target address [x0] */ 540ae76531SDavid Feng cmp x1, x2 /* until source end address [x2] */ 550ae76531SDavid Feng b.lo copy_loop 5683571bcaSYork Sun str x0, [sp, #24] 570ae76531SDavid Feng 580ae76531SDavid Feng /* 590ae76531SDavid Feng * Fix .rela.dyn relocations 600ae76531SDavid Feng */ 61*559b4bfaSIbai Erkiaga adrp x2, __rel_dyn_start /* x2 <- address bits [31:12] */ 62*559b4bfaSIbai Erkiaga add x2, x2, :lo12:__rel_dyn_start /* x2 <- address bits [11:00] */ 63*559b4bfaSIbai Erkiaga adrp x3, __rel_dyn_end /* x3 <- address bits [31:12] */ 64*559b4bfaSIbai Erkiaga add x3, x3, :lo12:__rel_dyn_end /* x3 <- address bits [11:00] */ 650ae76531SDavid Fengfixloop: 660ae76531SDavid Feng ldp x0, x1, [x2], #16 /* (x0,x1) <- (SRC location, fixup) */ 670ae76531SDavid Feng ldr x4, [x2], #8 /* x4 <- addend */ 680ae76531SDavid Feng and x1, x1, #0xffffffff 69c70f74a0SSimon Glass cmp x1, #R_AARCH64_RELATIVE 700ae76531SDavid Feng bne fixnext 710ae76531SDavid Feng 720ae76531SDavid Feng /* relative fix: store addend plus offset at dest location */ 730ae76531SDavid Feng add x0, x0, x9 740ae76531SDavid Feng add x4, x4, x9 750ae76531SDavid Feng str x4, [x0] 760ae76531SDavid Fengfixnext: 770ae76531SDavid Feng cmp x2, x3 780ae76531SDavid Feng b.lo fixloop 790ae76531SDavid Feng 800ae76531SDavid Fengrelocate_done: 8183571bcaSYork Sun switch_el x1, 3f, 2f, 1f 8283571bcaSYork Sun bl hang 8383571bcaSYork Sun3: mrs x0, sctlr_el3 8483571bcaSYork Sun b 0f 8583571bcaSYork Sun2: mrs x0, sctlr_el2 8683571bcaSYork Sun b 0f 8783571bcaSYork Sun1: mrs x0, sctlr_el1 8883571bcaSYork Sun0: tbz w0, #2, 5f /* skip flushing cache if disabled */ 891f4f5e52SMasahiro Yamada tbz w0, #12, 4f /* skip invalidating i-cache if disabled */ 9083571bcaSYork Sun ic iallu /* i-cache invalidate all */ 9183571bcaSYork Sun isb sy 9283571bcaSYork Sun4: ldp x0, x1, [sp, #16] 9383571bcaSYork Sun bl __asm_flush_dcache_range 94d997bf6fSzijun_hu5: ldp x29, x30, [sp],#32 950ae76531SDavid Feng ret 960ae76531SDavid FengENDPROC(relocate_code) 97