diff options
Diffstat (limited to 'src/soc/qualcomm/ipq40xx/tz_wrapper.S')
-rw-r--r-- | src/soc/qualcomm/ipq40xx/tz_wrapper.S | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/src/soc/qualcomm/ipq40xx/tz_wrapper.S b/src/soc/qualcomm/ipq40xx/tz_wrapper.S new file mode 100644 index 0000000000..70cc170f64 --- /dev/null +++ b/src/soc/qualcomm/ipq40xx/tz_wrapper.S @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * TZ expects the ARM core to be in 'ARM' mode. However, coreboot seems + * to be compiled in mixed thumb/arm mode. Hence create a glue function + * to invoke TZ. + */ + +#include <arch/asm.h> + +/* + * Force ARM mode. Else this gets assembled with mixed ARM and + * Thumb instructions. We set up everything and jump to TZBSP + * using the 'blx' instruction. For 'blx' if the last bit of the + * destination address is zero, it switches to ARM mode. Since, + * we are already in ARM mode, nothing to switch as such. + * + * However, when TZBSP returns, the CPU is still in ARM mode. + * If the assembler inserts Thumb instructions between the point + * of return from TZBSP to the 'bx' instruction we are hosed. + * Hence forcing ARM mode. + * + * Rest of the code can be compiled in mixed ARM/Thumb mode. + * Since tz_init_wrapper is being forced as an ARM symbol, + * callers will use 'blx' to come here forcing a switch to + * ARM mode. The wrapper does its job and returns back to the + * Thumb caller. + */ +.arm +/* + * int tz_init_wrapper(int, int, void *); + */ +ENTRY(tz_init_wrapper) + .global tz_init_wrapper + + /* + * r0 = tz_arg1 + * r1 = tz_arg2 + * r2 = tz_load_addr + */ + + /* + * Per the AAPCS + * r0, r1, r2, r3, r12 can be clobbered + * r4, r5, r6, r7, r8, r9, r10, r11 have to be preserved + * + * Following code clobbers + * r0 - Setting return value to zero + * r1 - For doing a thumb return + * r3 - Passing 'SP' from current mode to 'svc' mode + * r4 - To save & restore CPSR + * + * Per AAPCS, save and restore r4, rest are 'clobberable' :) + * The invoked code takes care of saving and restoring the other + * preserved registers (i.e. r5 - r11) + * + * Stack Usage: + * SP -> | LR | (Lower address) + * | r4 | + * | CPSR | + * |-------| + * | . | + * | . | + * | . | (Higher address) + */ + + sub sp, sp, #12 /* Allocate stack frame */ + str lr, [sp] /* Save return address */ + str r4, [sp, #4] /* Use r4 to hold the new CPSR value */ + + mov r3, sp /* Get current stack pointer */ + + mrs r4, CPSR /* save CPSR */ + str r4, [sp, #8] + + bic r4, r4, 0x1f /* Clear mode bits */ + orr r4, r4, 0x13 /* 'svc' mode */ + msr cpsr_cxf, r4 /* Switch to Supervisor mode. */ + mov sp, r3 /* Use the same stack as the previous mode */ + + blx r2 /* Jump to TZ in ARM mode */ + + nop /* back from TZ, in ARM mode */ + + ldr r4, [sp, #8] /* restore CPSR */ + msr cpsr_cxf, r4 + + ldr r4, [sp, #4] /* restore r4 */ + + ldr lr, [sp] /* saved return address */ + add sp, sp, #12 /* free stack frame */ + + bx lr /* back to thumb caller */ + +ENDPROC(tz_init_wrapper) |