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