xref: /rk3399_ARM-atf/lib/aarch32/misc_helpers.S (revision 4324a14bf548f5c56edc48128aba1aca0da2edf5)
1f24307deSSoby Mathew/*
2*4324a14bSYann Gautier * 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>
10*4324a14bSYann Gautier#include <common/bl_common.h>
11*4324a14bSYann 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
19*4324a14bSYann Gautier	.globl	fixup_gdt_reloc
20*4324a14bSYann Gautier
21*4324a14bSYann 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
195*4324a14bSYann Gautier
196*4324a14bSYann Gautier/* ---------------------------------------------------------------------------
197*4324a14bSYann Gautier * Helper to fixup Global Descriptor table (GDT) and dynamic relocations
198*4324a14bSYann Gautier * (.rel.dyn) at runtime.
199*4324a14bSYann Gautier *
200*4324a14bSYann Gautier * This function is meant to be used when the firmware is compiled with -fpie
201*4324a14bSYann Gautier * and linked with -pie options. We rely on the linker script exporting
202*4324a14bSYann Gautier * appropriate markers for start and end of the section. For GOT, we
203*4324a14bSYann Gautier * expect __GOT_START__ and __GOT_END__. Similarly for .rela.dyn, we expect
204*4324a14bSYann Gautier * __RELA_START__ and __RELA_END__.
205*4324a14bSYann Gautier *
206*4324a14bSYann Gautier * The function takes the limits of the memory to apply fixups to as
207*4324a14bSYann Gautier * arguments (which is usually the limits of the relocable BL image).
208*4324a14bSYann Gautier *   r0 -  the start of the fixup region
209*4324a14bSYann Gautier *   r1 -  the limit of the fixup region
210*4324a14bSYann Gautier * These addresses have to be 4KB page aligned.
211*4324a14bSYann Gautier * ---------------------------------------------------------------------------
212*4324a14bSYann Gautier */
213*4324a14bSYann Gautier
214*4324a14bSYann Gautier/* Relocation codes */
215*4324a14bSYann Gautier#define R_ARM_RELATIVE 	23
216*4324a14bSYann Gautier
217*4324a14bSYann Gautierfunc fixup_gdt_reloc
218*4324a14bSYann Gautier	mov	r6, r0
219*4324a14bSYann Gautier	mov	r7, r1
220*4324a14bSYann Gautier
221*4324a14bSYann Gautier#if ENABLE_ASSERTIONS
222*4324a14bSYann Gautier	/* Test if the limits are 4K aligned */
223*4324a14bSYann Gautier	orr	r0, r0, r1
224*4324a14bSYann Gautier	mov	r1, #(PAGE_SIZE_MASK)
225*4324a14bSYann Gautier	tst	r0, r1
226*4324a14bSYann Gautier	ASM_ASSERT(eq)
227*4324a14bSYann Gautier#endif
228*4324a14bSYann Gautier	/*
229*4324a14bSYann Gautier	 * Calculate the offset based on return address in lr.
230*4324a14bSYann Gautier	 * Assume that this function is called within a page at the start of
231*4324a14bSYann Gautier	 * fixup region.
232*4324a14bSYann Gautier	 */
233*4324a14bSYann Gautier	ldr	r1, =PAGE_START_MASK
234*4324a14bSYann Gautier	and	r2, lr, r1
235*4324a14bSYann Gautier	subs	r0, r2, r6	/* Diff(S) = Current Address - Compiled Address */
236*4324a14bSYann Gautier	beq	3f		/* Diff(S) = 0. No relocation needed */
237*4324a14bSYann Gautier
238*4324a14bSYann Gautier	ldr	r1, =__GOT_START__
239*4324a14bSYann Gautier	add	r1, r1, r0
240*4324a14bSYann Gautier	ldr	r2, =__GOT_END__
241*4324a14bSYann Gautier	add	r2, r2, r0
242*4324a14bSYann Gautier
243*4324a14bSYann Gautier	/*
244*4324a14bSYann Gautier	 * GOT is an array of 32_bit addresses which must be fixed up as
245*4324a14bSYann Gautier	 * new_addr = old_addr + Diff(S).
246*4324a14bSYann Gautier	 * The new_addr is the address currently the binary is executing from
247*4324a14bSYann Gautier	 * and old_addr is the address at compile time.
248*4324a14bSYann Gautier	 */
249*4324a14bSYann Gautier1:	ldr	r3, [r1]
250*4324a14bSYann Gautier
251*4324a14bSYann Gautier	/* Skip adding offset if address is < lower limit */
252*4324a14bSYann Gautier	cmp	r3, r6
253*4324a14bSYann Gautier	blo	2f
254*4324a14bSYann Gautier
255*4324a14bSYann Gautier	/* Skip adding offset if address is > upper limit */
256*4324a14bSYann Gautier	cmp	r3, r7
257*4324a14bSYann Gautier	bhi	2f
258*4324a14bSYann Gautier	add	r3, r3, r0
259*4324a14bSYann Gautier	str	r3, [r1]
260*4324a14bSYann Gautier
261*4324a14bSYann Gautier2:	add	r1, r1, #4
262*4324a14bSYann Gautier	cmp	r1, r2
263*4324a14bSYann Gautier	blo	1b
264*4324a14bSYann Gautier
265*4324a14bSYann Gautier	/* Starting dynamic relocations. Use ldr to get RELA_START and END */
266*4324a14bSYann Gautier3:	ldr	r1, =__RELA_START__
267*4324a14bSYann Gautier	add	r1, r1, r0
268*4324a14bSYann Gautier	ldr	r2, =__RELA_END__
269*4324a14bSYann Gautier	add	r2, r2, r0
270*4324a14bSYann Gautier
271*4324a14bSYann Gautier	/*
272*4324a14bSYann Gautier	 * According to ELF-32 specification, the RELA data structure is as
273*4324a14bSYann Gautier	 * follows:
274*4324a14bSYann Gautier	 *	typedef struct {
275*4324a14bSYann Gautier	 *		Elf32_Addr r_offset;
276*4324a14bSYann Gautier	 *		Elf32_Xword r_info;
277*4324a14bSYann Gautier	 *	} Elf32_Rela;
278*4324a14bSYann Gautier	 *
279*4324a14bSYann Gautier	 * r_offset is address of reference
280*4324a14bSYann Gautier	 * r_info is symbol index and type of relocation (in this case
281*4324a14bSYann Gautier	 * code 23  which corresponds to R_ARM_RELATIVE).
282*4324a14bSYann Gautier	 *
283*4324a14bSYann Gautier	 * Size of Elf32_Rela structure is 8 bytes.
284*4324a14bSYann Gautier	 */
285*4324a14bSYann Gautier
286*4324a14bSYann Gautier	/* Skip R_ARM_NONE entry with code 0 */
287*4324a14bSYann Gautier1:	ldr	r3, [r1, #4]
288*4324a14bSYann Gautier	ands	r3, r3, #0xff
289*4324a14bSYann Gautier	beq	2f
290*4324a14bSYann Gautier
291*4324a14bSYann Gautier#if ENABLE_ASSERTIONS
292*4324a14bSYann Gautier	/* Assert that the relocation type is R_ARM_RELATIVE */
293*4324a14bSYann Gautier	cmp	r3, #R_ARM_RELATIVE
294*4324a14bSYann Gautier	ASM_ASSERT(eq)
295*4324a14bSYann Gautier#endif
296*4324a14bSYann Gautier	ldr	r3, [r1]	/* r_offset */
297*4324a14bSYann Gautier	add	r3, r0, r3	/* Diff(S) + r_offset */
298*4324a14bSYann Gautier	ldr 	r4, [r3]
299*4324a14bSYann Gautier
300*4324a14bSYann Gautier	/* Skip adding offset if address is < lower limit */
301*4324a14bSYann Gautier	cmp	r4, r6
302*4324a14bSYann Gautier	blo	2f
303*4324a14bSYann Gautier
304*4324a14bSYann Gautier	/* Skip adding offset if address is >= upper limit */
305*4324a14bSYann Gautier	cmp	r4, r7
306*4324a14bSYann Gautier	bhs	2f
307*4324a14bSYann Gautier
308*4324a14bSYann Gautier	add 	r4, r0, r4
309*4324a14bSYann Gautier	str	r4, [r3]
310*4324a14bSYann Gautier
311*4324a14bSYann Gautier2:	add	r1, r1, #8
312*4324a14bSYann Gautier	cmp	r1, r2
313*4324a14bSYann Gautier	blo	1b
314*4324a14bSYann Gautier	bx	lr
315*4324a14bSYann Gautierendfunc fixup_gdt_reloc
316