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