/* * * 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 /* * 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)