blob: 70cc170f643e62aac3d953bc7867a0d1ec619cda [file] [log] [blame]
/*
* 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)