xref: /rk3399_ARM-atf/lib/aarch32/misc_helpers.S (revision 72e8f2456af54b75a0a1d92aadfce0b4bcde6ba1)
1f24307deSSoby Mathew/*
2*4c700c15SGovindraj Raja * Copyright (c) 2016-2021, Arm Limited and Contributors. All rights reserved.
3f24307deSSoby Mathew *
482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause
5f24307deSSoby Mathew */
6f24307deSSoby Mathew
7f24307deSSoby Mathew#include <arch.h>
8f24307deSSoby Mathew#include <asm_macros.S>
9f24307deSSoby Mathew#include <assert_macros.S>
104324a14bSYann Gautier#include <common/bl_common.h>
114324a14bSYann Gautier#include <lib/xlat_tables/xlat_tables_defs.h>
12f24307deSSoby Mathew
131a0a3f06SYatharth Kochar	.globl	smc
14f24307deSSoby Mathew	.globl	zeromem
15308d359bSDouglas Raillard	.globl	zero_normalmem
169c1dceb1SYatharth Kochar	.globl	memcpy4
171a0a3f06SYatharth Kochar	.globl	disable_mmu_icache_secure
181a0a3f06SYatharth Kochar	.globl	disable_mmu_secure
194324a14bSYann Gautier	.globl	fixup_gdt_reloc
204324a14bSYann Gautier
214324a14bSYann Gautier#define PAGE_START_MASK		~(PAGE_SIZE_MASK)
221a0a3f06SYatharth Kochar
231a0a3f06SYatharth Kocharfunc smc
241a0a3f06SYatharth Kochar	/*
251a0a3f06SYatharth Kochar	 * For AArch32 only r0-r3 will be in the registers;
261a0a3f06SYatharth Kochar	 * rest r4-r6 will be pushed on to the stack. So here, we'll
271a0a3f06SYatharth Kochar	 * have to load them from the stack to registers r4-r6 explicitly.
281a0a3f06SYatharth Kochar	 * Clobbers: r4-r6
291a0a3f06SYatharth Kochar	 */
301a0a3f06SYatharth Kochar	ldm	sp, {r4, r5, r6}
311a0a3f06SYatharth Kochar	smc	#0
321a0a3f06SYatharth Kocharendfunc smc
33f24307deSSoby Mathew
34f24307deSSoby Mathew/* -----------------------------------------------------------------------
35308d359bSDouglas Raillard * void zeromem(void *mem, unsigned int length)
36f24307deSSoby Mathew *
37308d359bSDouglas Raillard * Initialise a region in normal memory to 0. This functions complies with the
38308d359bSDouglas Raillard * AAPCS and can be called from C code.
39308d359bSDouglas Raillard *
40f24307deSSoby Mathew * -----------------------------------------------------------------------
41f24307deSSoby Mathew */
42f24307deSSoby Mathewfunc zeromem
43308d359bSDouglas Raillard	/*
44308d359bSDouglas Raillard	 * Readable names for registers
45308d359bSDouglas Raillard	 *
46308d359bSDouglas Raillard	 * Registers r0, r1 and r2 are also set by zeromem which
47308d359bSDouglas Raillard	 * branches into the fallback path directly, so cursor, length and
48308d359bSDouglas Raillard	 * stop_address should not be retargeted to other registers.
49308d359bSDouglas Raillard	 */
50308d359bSDouglas Raillard	cursor       .req r0 /* Start address and then current address */
51308d359bSDouglas Raillard	length       .req r1 /* Length in bytes of the region to zero out */
52308d359bSDouglas Raillard	/*
53308d359bSDouglas Raillard	 * Reusing the r1 register as length is only used at the beginning of
54308d359bSDouglas Raillard	 * the function.
55308d359bSDouglas Raillard	 */
56308d359bSDouglas Raillard	stop_address .req r1  /* Address past the last zeroed byte */
57308d359bSDouglas Raillard	zeroreg1     .req r2  /* Source register filled with 0 */
58308d359bSDouglas Raillard	zeroreg2     .req r3  /* Source register filled with 0 */
59308d359bSDouglas Raillard	tmp	     .req r12 /* Temporary scratch register */
60308d359bSDouglas Raillard
61308d359bSDouglas Raillard	mov	zeroreg1, #0
62308d359bSDouglas Raillard
63308d359bSDouglas Raillard	/* stop_address is the address past the last to zero */
64308d359bSDouglas Raillard	add	stop_address, cursor, length
65308d359bSDouglas Raillard
66308d359bSDouglas Raillard	/*
67308d359bSDouglas Raillard	 * Length cannot be used anymore as it shares the same register with
68308d359bSDouglas Raillard	 * stop_address.
69308d359bSDouglas Raillard	 */
70308d359bSDouglas Raillard	.unreq	length
71308d359bSDouglas Raillard
72308d359bSDouglas Raillard	/*
73308d359bSDouglas Raillard	 * If the start address is already aligned to 8 bytes, skip this loop.
74308d359bSDouglas Raillard	 */
75308d359bSDouglas Raillard	tst	cursor, #(8-1)
76308d359bSDouglas Raillard	beq	.Lzeromem_8bytes_aligned
77308d359bSDouglas Raillard
78308d359bSDouglas Raillard	/* Calculate the next address aligned to 8 bytes */
79308d359bSDouglas Raillard	orr	tmp, cursor, #(8-1)
80308d359bSDouglas Raillard	adds	tmp, tmp, #1
81308d359bSDouglas Raillard	/* If it overflows, fallback to byte per byte zeroing */
82308d359bSDouglas Raillard	beq	.Lzeromem_1byte_aligned
83308d359bSDouglas Raillard	/* If the next aligned address is after the stop address, fall back */
84308d359bSDouglas Raillard	cmp	tmp, stop_address
85308d359bSDouglas Raillard	bhs	.Lzeromem_1byte_aligned
86308d359bSDouglas Raillard
87308d359bSDouglas Raillard	/* zero byte per byte */
88308d359bSDouglas Raillard1:
89308d359bSDouglas Raillard	strb	zeroreg1, [cursor], #1
90308d359bSDouglas Raillard	cmp	cursor, tmp
91308d359bSDouglas Raillard	bne	1b
92308d359bSDouglas Raillard
93308d359bSDouglas Raillard	/* zero 8 bytes at a time */
94308d359bSDouglas Raillard.Lzeromem_8bytes_aligned:
95308d359bSDouglas Raillard
96308d359bSDouglas Raillard	/* Calculate the last 8 bytes aligned address. */
97308d359bSDouglas Raillard	bic	tmp, stop_address, #(8-1)
98308d359bSDouglas Raillard
99308d359bSDouglas Raillard	cmp	cursor, tmp
100308d359bSDouglas Raillard	bhs	2f
101308d359bSDouglas Raillard
102308d359bSDouglas Raillard	mov	zeroreg2, #0
103308d359bSDouglas Raillard1:
104308d359bSDouglas Raillard	stmia	cursor!, {zeroreg1, zeroreg2}
105308d359bSDouglas Raillard	cmp	cursor, tmp
106308d359bSDouglas Raillard	blo	1b
107308d359bSDouglas Raillard2:
108308d359bSDouglas Raillard
109308d359bSDouglas Raillard	/* zero byte per byte */
110308d359bSDouglas Raillard.Lzeromem_1byte_aligned:
111308d359bSDouglas Raillard	cmp	cursor, stop_address
112308d359bSDouglas Raillard	beq	2f
113308d359bSDouglas Raillard1:
114308d359bSDouglas Raillard	strb	zeroreg1, [cursor], #1
115308d359bSDouglas Raillard	cmp	cursor, stop_address
116308d359bSDouglas Raillard	bne	1b
117308d359bSDouglas Raillard2:
118f24307deSSoby Mathew	bx	lr
119308d359bSDouglas Raillard
120308d359bSDouglas Raillard	.unreq	cursor
121308d359bSDouglas Raillard	/*
122308d359bSDouglas Raillard	 * length is already unreq'ed to reuse the register for another
123308d359bSDouglas Raillard	 * variable.
124308d359bSDouglas Raillard	 */
125308d359bSDouglas Raillard	.unreq	stop_address
126308d359bSDouglas Raillard	.unreq	zeroreg1
127308d359bSDouglas Raillard	.unreq	zeroreg2
128308d359bSDouglas Raillard	.unreq	tmp
129f24307deSSoby Mathewendfunc zeromem
1301a0a3f06SYatharth Kochar
131308d359bSDouglas Raillard/*
132308d359bSDouglas Raillard * AArch32 does not have special ways of zeroing normal memory as AArch64 does
133308d359bSDouglas Raillard * using the DC ZVA instruction, so we just alias zero_normalmem to zeromem.
134308d359bSDouglas Raillard */
135308d359bSDouglas Raillard.equ	zero_normalmem, zeromem
136308d359bSDouglas Raillard
1379c1dceb1SYatharth Kochar/* --------------------------------------------------------------------------
1389c1dceb1SYatharth Kochar * void memcpy4(void *dest, const void *src, unsigned int length)
1399c1dceb1SYatharth Kochar *
1409c1dceb1SYatharth Kochar * Copy length bytes from memory area src to memory area dest.
1419c1dceb1SYatharth Kochar * The memory areas should not overlap.
1429c1dceb1SYatharth Kochar * Destination and source addresses must be 4-byte aligned.
1439c1dceb1SYatharth Kochar * --------------------------------------------------------------------------
1449c1dceb1SYatharth Kochar */
1459c1dceb1SYatharth Kocharfunc memcpy4
146044bb2faSAntonio Nino Diaz#if ENABLE_ASSERTIONS
1479c1dceb1SYatharth Kochar	orr	r3, r0, r1
1489c1dceb1SYatharth Kochar	tst	r3, #0x3
1499c1dceb1SYatharth Kochar	ASM_ASSERT(eq)
1509c1dceb1SYatharth Kochar#endif
1519c1dceb1SYatharth Kochar/* copy 4 bytes at a time */
1529c1dceb1SYatharth Kocharm_loop4:
1539c1dceb1SYatharth Kochar	cmp	r2, #4
154355a5d03SDouglas Raillard	blo	m_loop1
1559c1dceb1SYatharth Kochar	ldr	r3, [r1], #4
1569c1dceb1SYatharth Kochar	str	r3, [r0], #4
157e6e7d712SAlexei Fedorov	subs	r2, r2, #4
158e6e7d712SAlexei Fedorov	bne	m_loop4
159e6e7d712SAlexei Fedorov	bx	lr
160e6e7d712SAlexei Fedorov
1619c1dceb1SYatharth Kochar/* copy byte per byte */
1629c1dceb1SYatharth Kocharm_loop1:
1639c1dceb1SYatharth Kochar	ldrb	r3, [r1], #1
1649c1dceb1SYatharth Kochar	strb	r3, [r0], #1
1659c1dceb1SYatharth Kochar	subs	r2, r2, #1
1669c1dceb1SYatharth Kochar	bne	m_loop1
1679c1dceb1SYatharth Kochar	bx	lr
1689c1dceb1SYatharth Kocharendfunc memcpy4
1699c1dceb1SYatharth Kochar
1701a0a3f06SYatharth Kochar/* ---------------------------------------------------------------------------
1711a0a3f06SYatharth Kochar * Disable the MMU in Secure State
1721a0a3f06SYatharth Kochar * ---------------------------------------------------------------------------
1731a0a3f06SYatharth Kochar */
1741a0a3f06SYatharth Kochar
1751a0a3f06SYatharth Kocharfunc disable_mmu_secure
1761a0a3f06SYatharth Kochar	mov	r1, #(SCTLR_M_BIT | SCTLR_C_BIT)
1771a0a3f06SYatharth Kochardo_disable_mmu:
178dd4cf2c7SJoel Hutton#if ERRATA_A9_794073
179dd4cf2c7SJoel Hutton	stcopr	r0, BPIALL
180dd4cf2c7SJoel Hutton	dsb
181dd4cf2c7SJoel Hutton#endif
1821a0a3f06SYatharth Kochar	ldcopr	r0, SCTLR
1831a0a3f06SYatharth Kochar	bic	r0, r0, r1
1841a0a3f06SYatharth Kochar	stcopr	r0, SCTLR
1851a0a3f06SYatharth Kochar	isb				// ensure MMU is off
1861a0a3f06SYatharth Kochar	dsb	sy
1871a0a3f06SYatharth Kochar	bx	lr
1881a0a3f06SYatharth Kocharendfunc disable_mmu_secure
1891a0a3f06SYatharth Kochar
1901a0a3f06SYatharth Kochar
1911a0a3f06SYatharth Kocharfunc disable_mmu_icache_secure
1921a0a3f06SYatharth Kochar	ldr	r1, =(SCTLR_M_BIT | SCTLR_C_BIT | SCTLR_I_BIT)
1931a0a3f06SYatharth Kochar	b	do_disable_mmu
1941a0a3f06SYatharth Kocharendfunc disable_mmu_icache_secure
1954324a14bSYann Gautier
1964324a14bSYann Gautier/* ---------------------------------------------------------------------------
1974324a14bSYann Gautier * Helper to fixup Global Descriptor table (GDT) and dynamic relocations
1984324a14bSYann Gautier * (.rel.dyn) at runtime.
1994324a14bSYann Gautier *
2004324a14bSYann Gautier * This function is meant to be used when the firmware is compiled with -fpie
2014324a14bSYann Gautier * and linked with -pie options. We rely on the linker script exporting
2024324a14bSYann Gautier * appropriate markers for start and end of the section. For GOT, we
2034324a14bSYann Gautier * expect __GOT_START__ and __GOT_END__. Similarly for .rela.dyn, we expect
2044324a14bSYann Gautier * __RELA_START__ and __RELA_END__.
2054324a14bSYann Gautier *
2064324a14bSYann Gautier * The function takes the limits of the memory to apply fixups to as
2074324a14bSYann Gautier * arguments (which is usually the limits of the relocable BL image).
2084324a14bSYann Gautier *   r0 -  the start of the fixup region
2094324a14bSYann Gautier *   r1 -  the limit of the fixup region
2104324a14bSYann Gautier * These addresses have to be 4KB page aligned.
2114324a14bSYann Gautier * ---------------------------------------------------------------------------
2124324a14bSYann Gautier */
2134324a14bSYann Gautier
2144324a14bSYann Gautier/* Relocation codes */
2154324a14bSYann Gautier#define R_ARM_RELATIVE 	23
2164324a14bSYann Gautier
2174324a14bSYann Gautierfunc fixup_gdt_reloc
2184324a14bSYann Gautier	mov	r6, r0
2194324a14bSYann Gautier	mov	r7, r1
2204324a14bSYann Gautier
2214324a14bSYann Gautier#if ENABLE_ASSERTIONS
2224324a14bSYann Gautier	/* Test if the limits are 4K aligned */
2234324a14bSYann Gautier	orr	r0, r0, r1
2244324a14bSYann Gautier	mov	r1, #(PAGE_SIZE_MASK)
2254324a14bSYann Gautier	tst	r0, r1
2264324a14bSYann Gautier	ASM_ASSERT(eq)
2274324a14bSYann Gautier#endif
2284324a14bSYann Gautier	/*
2294324a14bSYann Gautier	 * Calculate the offset based on return address in lr.
2304324a14bSYann Gautier	 * Assume that this function is called within a page at the start of
2314324a14bSYann Gautier	 * fixup region.
2324324a14bSYann Gautier	 */
2334324a14bSYann Gautier	ldr	r1, =PAGE_START_MASK
2344324a14bSYann Gautier	and	r2, lr, r1
2354324a14bSYann Gautier	subs	r0, r2, r6	/* Diff(S) = Current Address - Compiled Address */
2364324a14bSYann Gautier	beq	3f		/* Diff(S) = 0. No relocation needed */
2374324a14bSYann Gautier
2384324a14bSYann Gautier	ldr	r1, =__GOT_START__
2394324a14bSYann Gautier	add	r1, r1, r0
2404324a14bSYann Gautier	ldr	r2, =__GOT_END__
2414324a14bSYann Gautier	add	r2, r2, r0
2424324a14bSYann Gautier
2434324a14bSYann Gautier	/*
2444324a14bSYann Gautier	 * GOT is an array of 32_bit addresses which must be fixed up as
2454324a14bSYann Gautier	 * new_addr = old_addr + Diff(S).
2464324a14bSYann Gautier	 * The new_addr is the address currently the binary is executing from
2474324a14bSYann Gautier	 * and old_addr is the address at compile time.
2484324a14bSYann Gautier	 */
2494324a14bSYann Gautier1:	ldr	r3, [r1]
2504324a14bSYann Gautier
2514324a14bSYann Gautier	/* Skip adding offset if address is < lower limit */
2524324a14bSYann Gautier	cmp	r3, r6
2534324a14bSYann Gautier	blo	2f
2544324a14bSYann Gautier
2554324a14bSYann Gautier	/* Skip adding offset if address is > upper limit */
2564324a14bSYann Gautier	cmp	r3, r7
2574324a14bSYann Gautier	bhi	2f
2584324a14bSYann Gautier	add	r3, r3, r0
2594324a14bSYann Gautier	str	r3, [r1]
2604324a14bSYann Gautier
2614324a14bSYann Gautier2:	add	r1, r1, #4
2624324a14bSYann Gautier	cmp	r1, r2
2634324a14bSYann Gautier	blo	1b
2644324a14bSYann Gautier
2654324a14bSYann Gautier	/* Starting dynamic relocations. Use ldr to get RELA_START and END */
2664324a14bSYann Gautier3:	ldr	r1, =__RELA_START__
2674324a14bSYann Gautier	add	r1, r1, r0
2684324a14bSYann Gautier	ldr	r2, =__RELA_END__
2694324a14bSYann Gautier	add	r2, r2, r0
2704324a14bSYann Gautier
2714324a14bSYann Gautier	/*
2724324a14bSYann Gautier	 * According to ELF-32 specification, the RELA data structure is as
2734324a14bSYann Gautier	 * follows:
2744324a14bSYann Gautier	 *	typedef struct {
2754324a14bSYann Gautier	 *		Elf32_Addr r_offset;
2764324a14bSYann Gautier	 *		Elf32_Xword r_info;
2774324a14bSYann Gautier	 *	} Elf32_Rela;
2784324a14bSYann Gautier	 *
2794324a14bSYann Gautier	 * r_offset is address of reference
2804324a14bSYann Gautier	 * r_info is symbol index and type of relocation (in this case
2814324a14bSYann Gautier	 * code 23  which corresponds to R_ARM_RELATIVE).
2824324a14bSYann Gautier	 *
2834324a14bSYann Gautier	 * Size of Elf32_Rela structure is 8 bytes.
2844324a14bSYann Gautier	 */
2854324a14bSYann Gautier
2864324a14bSYann Gautier	/* Skip R_ARM_NONE entry with code 0 */
2874324a14bSYann Gautier1:	ldr	r3, [r1, #4]
2884324a14bSYann Gautier	ands	r3, r3, #0xff
2894324a14bSYann Gautier	beq	2f
2904324a14bSYann Gautier
2914324a14bSYann Gautier#if ENABLE_ASSERTIONS
2924324a14bSYann Gautier	/* Assert that the relocation type is R_ARM_RELATIVE */
2934324a14bSYann Gautier	cmp	r3, #R_ARM_RELATIVE
2944324a14bSYann Gautier	ASM_ASSERT(eq)
2954324a14bSYann Gautier#endif
2964324a14bSYann Gautier	ldr	r3, [r1]	/* r_offset */
2974324a14bSYann Gautier	add	r3, r0, r3	/* Diff(S) + r_offset */
2984324a14bSYann Gautier	ldr 	r4, [r3]
2994324a14bSYann Gautier
3004324a14bSYann Gautier	/* Skip adding offset if address is < lower limit */
3014324a14bSYann Gautier	cmp	r4, r6
3024324a14bSYann Gautier	blo	2f
3034324a14bSYann Gautier
3044f1a658fSYann Gautier	/* Skip adding offset if address is > upper limit */
3054324a14bSYann Gautier	cmp	r4, r7
3064f1a658fSYann Gautier	bhi	2f
3074324a14bSYann Gautier
3084324a14bSYann Gautier	add 	r4, r0, r4
3094324a14bSYann Gautier	str	r4, [r3]
3104324a14bSYann Gautier
3114324a14bSYann Gautier2:	add	r1, r1, #8
3124324a14bSYann Gautier	cmp	r1, r2
3134324a14bSYann Gautier	blo	1b
3144324a14bSYann Gautier	bx	lr
3154324a14bSYann Gautierendfunc fixup_gdt_reloc
316