| /* SPDX-License-Identifier: GPL-2.0+ */ | 
 | /* | 
 |  * relocate - common relocation function for AArch64 U-Boot | 
 |  * | 
 |  * (C) Copyright 2013 | 
 |  * Albert ARIBAUD <albert.u.boot@aribaud.net> | 
 |  * David Feng <fenghua@phytium.com.cn> | 
 |  */ | 
 |  | 
 | #include <asm-offsets.h> | 
 | #include <config.h> | 
 | #include <elf.h> | 
 | #include <linux/linkage.h> | 
 | #include <asm/macro.h> | 
 |  | 
 | /* | 
 |  * void relocate_code (addr_moni) | 
 |  * | 
 |  * This function relocates the monitor code. | 
 |  * x0 holds the destination address. | 
 |  */ | 
 | ENTRY(relocate_code) | 
 | 	stp	x29, x30, [sp, #-32]!	/* create a stack frame */ | 
 | 	mov	x29, sp | 
 | 	str	x0, [sp, #16] | 
 | 	/* | 
 | 	 * Copy u-boot from flash to RAM | 
 | 	 */ | 
 | 	ldr	x1, =__image_copy_start	/* x1 <- Run &__image_copy_start */ | 
 | 	subs	x9, x0, x1		/* x8 <- Run to copy offset */ | 
 | 	b.eq	relocate_done		/* skip relocation */ | 
 | 	/* | 
 | 	 * Don't ldr x1, __image_copy_start here, since if the code is already | 
 | 	 * running at an address other than it was linked to, that instruction | 
 | 	 * will load the relocated value of __image_copy_start. To | 
 | 	 * correctly apply relocations, we need to know the linked value. | 
 | 	 * | 
 | 	 * Linked &__image_copy_start, which we know was at | 
 | 	 * CONFIG_SYS_TEXT_BASE, which is stored in _TEXT_BASE, as a non- | 
 | 	 * relocated value, since it isn't a symbol reference. | 
 | 	 */ | 
 | 	ldr	x1, _TEXT_BASE		/* x1 <- Linked &__image_copy_start */ | 
 | 	subs	x9, x0, x1		/* x9 <- Link to copy offset */ | 
 |  | 
 | 	ldr	x1, =__image_copy_start	/* x1 <- Run &__image_copy_start */ | 
 | 	ldr	x2, =__image_copy_end	/* x2 <- Run &__image_copy_end */ | 
 | copy_loop: | 
 | 	ldp	x10, x11, [x1], #16	/* copy from source address [x1] */ | 
 | 	stp	x10, x11, [x0], #16	/* copy to   target address [x0] */ | 
 | 	cmp	x1, x2			/* until source end address [x2] */ | 
 | 	b.lo	copy_loop | 
 | 	str	x0, [sp, #24] | 
 |  | 
 | 	/* | 
 | 	 * Fix .rela.dyn relocations | 
 | 	 */ | 
 | 	ldr	x2, =__rel_dyn_start	/* x2 <- Run &__rel_dyn_start */ | 
 | 	ldr	x3, =__rel_dyn_end	/* x3 <- Run &__rel_dyn_end */ | 
 | fixloop: | 
 | 	ldp	x0, x1, [x2], #16	/* (x0,x1) <- (SRC location, fixup) */ | 
 | 	ldr	x4, [x2], #8		/* x4 <- addend */ | 
 | 	and	x1, x1, #0xffffffff | 
 | 	cmp	x1, #R_AARCH64_RELATIVE | 
 | 	bne	fixnext | 
 |  | 
 | 	/* relative fix: store addend plus offset at dest location */ | 
 | 	add	x0, x0, x9 | 
 | 	add	x4, x4, x9 | 
 | 	str	x4, [x0] | 
 | fixnext: | 
 | 	cmp	x2, x3 | 
 | 	b.lo	fixloop | 
 |  | 
 | relocate_done: | 
 | 	switch_el x1, 3f, 2f, 1f | 
 | 	bl	hang | 
 | 3:	mrs	x0, sctlr_el3 | 
 | 	b	0f | 
 | 2:	mrs	x0, sctlr_el2 | 
 | 	b	0f | 
 | 1:	mrs	x0, sctlr_el1 | 
 | 0:	tbz	w0, #2, 5f	/* skip flushing cache if disabled */ | 
 | 	tbz	w0, #12, 4f	/* skip invalidating i-cache if disabled */ | 
 | 	ic	iallu		/* i-cache invalidate all */ | 
 | 	isb	sy | 
 | 4:	ldp	x0, x1, [sp, #16] | 
 | 	bl	__asm_flush_dcache_range | 
 | 5:	ldp	x29, x30, [sp],#32 | 
 | 	ret | 
 | ENDPROC(relocate_code) |