aboutsummaryrefslogtreecommitdiff
path: root/core/arch/arm32/tee
diff options
context:
space:
mode:
authorPascal Brand <pascal.brand@st.com>2014-06-12 15:56:20 +0200
committerPascal Brand <pascal.brand@st.com>2014-06-12 15:56:20 +0200
commitb01047730e77127c23a36591643eeb8bb0487d68 (patch)
treec6460d72a0f05fb1b9655b3fb0b434ff8c7be053 /core/arch/arm32/tee
Open-source the TEE Core
Signed-off-by: Pascal Brand <pascal.brand@st.com>
Diffstat (limited to 'core/arch/arm32/tee')
-rw-r--r--core/arch/arm32/tee/entry.c448
-rw-r--r--core/arch/arm32/tee/sub.mk2
-rw-r--r--core/arch/arm32/tee/tee_svc_asm.S257
3 files changed, 707 insertions, 0 deletions
diff --git a/core/arch/arm32/tee/entry.c b/core/arch/arm32/tee/entry.c
new file mode 100644
index 0000000..710ee13
--- /dev/null
+++ b/core/arch/arm32/tee/entry.c
@@ -0,0 +1,448 @@
+/*
+ * Copyright (c) 2014, STMicroelectronics International N.V.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <tee/entry.h>
+#include <sm/teesmc.h>
+#include <sm/teesmc_st.h>
+#include <kernel/tee_common_unpg.h>
+#include <kernel/tee_dispatch.h>
+#include <kernel/panic.h>
+#include <mm/core_mmu.h>
+
+#include <assert.h>
+
+#define SHM_CACHE_ATTRS \
+ (core_mmu_is_shm_cached() ? \
+ (TEESMC_ATTR_CACHE_DEFAULT << TEESMC_ATTR_CACHE_SHIFT) : 0 )
+
+static bool copy_in_params(const struct teesmc32_param *params,
+ uint32_t num_params, uint32_t *param_types,
+ uint32_t param_attr[TEE_NUM_PARAMS],
+ TEE_Param tee_params[TEE_NUM_PARAMS])
+{
+ size_t n;
+ uint8_t pt[4];
+
+ *param_types = 0;
+
+ if (num_params > TEE_NUM_PARAMS)
+ return false;
+
+ for (n = 0; n < num_params; n++) {
+ if (params[n].attr & TEESMC_ATTR_META)
+ return false;
+
+ pt[n] = params[n].attr & TEESMC_ATTR_TYPE_MASK;
+
+ param_attr[n] = (params[n].attr >> TEESMC_ATTR_CACHE_SHIFT) &
+ TEESMC_ATTR_CACHE_MASK;
+
+ if ((params[n].attr & TEESMC_ATTR_TYPE_MASK) ==
+ TEESMC_ATTR_TYPE_NONE) {
+ tee_params[n].value.a = 0;
+ tee_params[n].value.b = 0;
+ } else {
+ tee_params[n].value.a = params[n].u.value.a;
+ tee_params[n].value.b = params[n].u.value.b;
+ }
+ }
+ for (; n < TEE_NUM_PARAMS; n++) {
+ pt[n] = TEE_PARAM_TYPE_NONE;
+ param_attr[n] = 0;
+ tee_params[n].value.a = 0;
+ tee_params[n].value.b = 0;
+ }
+
+ *param_types = TEE_PARAM_TYPES(pt[0], pt[1], pt[2], pt[3]);
+
+ return true;
+}
+
+static void copy_out_param(const TEE_Param tee_params[TEE_NUM_PARAMS],
+ uint32_t param_types, uint32_t num_params,
+ struct teesmc32_param *params)
+{
+ size_t n;
+
+ for (n = 0; n < num_params; n++) {
+ switch (TEE_PARAM_TYPE_GET(param_types, n)) {
+ case TEE_PARAM_TYPE_MEMREF_OUTPUT:
+ case TEE_PARAM_TYPE_MEMREF_INOUT:
+ params[n].u.memref.size = tee_params[n].memref.size;
+ break;
+ case TEE_PARAM_TYPE_VALUE_OUTPUT:
+ case TEE_PARAM_TYPE_VALUE_INOUT:
+ params[n].u.value.a = tee_params[n].value.a;
+ params[n].u.value.b = tee_params[n].value.b;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/*
+ * Extracts mandatory parameter for open session.
+ *
+ * Returns
+ * false : mandatory parameter wasn't found or malformatted
+ * true : paramater found and OK
+ */
+static bool get_open_session_meta(struct teesmc32_arg *arg32,
+ uint32_t num_params, size_t *num_meta,
+ struct teesmc_meta_open_session **meta)
+{
+ struct teesmc32_param *params = TEESMC32_GET_PARAMS(arg32);
+ uint32_t phmeta;
+ const uint8_t req_attr = TEESMC_ATTR_META |
+ TEESMC_ATTR_TYPE_MEMREF_INPUT |
+ SHM_CACHE_ATTRS;
+
+ if (num_params < (*num_meta + 1))
+ return false;
+
+ if (params[*num_meta].attr != req_attr)
+ return false;
+
+ if (params[*num_meta].u.memref.size !=
+ sizeof(struct teesmc_meta_open_session))
+ return false;
+
+ phmeta = params[*num_meta].u.memref.buf_ptr;
+ if (!tee_pbuf_is_non_sec(phmeta,
+ sizeof(struct teesmc_meta_open_session)))
+ return false;
+
+ if (core_pa2va(phmeta, (void *)meta))
+ return false;
+
+ (*num_meta)++;
+ return true;
+}
+
+/*
+ * Extracts optional pointer to a Trusted Application.
+ *
+ * Returns
+ * false : malformatted TA parameter
+ * true : if TA parameter wasn't found or if it was found and OK
+ */
+static bool get_open_session_ta(struct teesmc32_arg *arg32, size_t num_params,
+ size_t *num_meta, kta_signed_header_t **ta)
+{
+ struct teesmc32_param *params = TEESMC32_GET_PARAMS(arg32);
+ uint32_t ph;
+ size_t len;
+ const uint8_t req_attr = TEESMC_ATTR_META |
+ TEESMC_ATTR_TYPE_MEMREF_INPUT |
+ SHM_CACHE_ATTRS;
+
+ if (num_params < (*num_meta + 1))
+ return false;
+
+ if (!(params[*num_meta].attr & TEESMC_ATTR_META))
+ return true;
+
+ if (params[*num_meta].attr != req_attr)
+ return false;
+
+ ph = params[*num_meta].u.memref.buf_ptr;
+ if (params[*num_meta].u.memref.size < sizeof(kta_signed_header_t))
+ return false;
+
+ if (!tee_pbuf_is_non_sec(ph, sizeof(kta_signed_header_t)))
+ return false;
+
+ if (core_pa2va(ph, (void *)ta))
+ return false;
+
+ len = (*ta)->size_of_signed_header + (*ta)->size_of_payload;
+ if (params[*num_meta].u.memref.size < len)
+ return false;
+
+ if (!tee_pbuf_is_non_sec(ph, len))
+ return false;
+
+ (*num_meta)++;
+ return true;
+}
+
+static void entry_open_session(struct thread_smc_args *args,
+ struct teesmc32_arg *arg32, uint32_t num_params)
+{
+ struct tee_dispatch_open_session_in in;
+ struct tee_dispatch_open_session_out out;
+ struct teesmc_meta_open_session *meta;
+ struct teesmc32_param *params = TEESMC32_GET_PARAMS(arg32);
+ size_t num_meta = 0;
+
+ if (!get_open_session_meta(arg32, num_params, &num_meta, &meta))
+ goto bad_params;
+
+ in.ta = NULL;
+ if (!get_open_session_ta(arg32, num_params, &num_meta, &in.ta))
+ goto bad_params;
+
+ TEE_COMPILE_TIME_ASSERT(sizeof(TEE_UUID) == TEESMC_UUID_LEN);
+ memcpy(&in.uuid, &meta->uuid, sizeof(TEE_UUID));
+ memcpy(&in.clnt_id.uuid, &meta->clnt_uuid, sizeof(TEE_UUID));
+ in.clnt_id.login = meta->clnt_login;
+
+ if (!copy_in_params(params + num_meta, num_params - num_meta,
+ &in.param_types, in.param_attr, in.params))
+ goto bad_params;
+
+ (void)tee_dispatch_open_session(&in, &out);
+ if (out.msg.res == TEE_STE_ERROR_SYSTEM_BUSY) {
+ args->a0 = TEESMC_RETURN_EBUSY;
+ return;
+ }
+
+ copy_out_param(out.params, in.param_types, num_params - num_meta,
+ params + num_meta);
+
+ arg32->session = (uint32_t)out.sess;
+ arg32->ret = out.msg.res;
+ arg32->ret_origin = out.msg.err;
+ args->a0 = TEESMC_RETURN_OK;
+ return;
+
+bad_params:
+ DMSG("Bad params");
+ arg32->ret = TEE_ERROR_BAD_PARAMETERS;
+ arg32->ret_origin = TEE_ORIGIN_TEE;
+ args->a0 = TEESMC_RETURN_OK;
+}
+
+static void entry_close_session(struct thread_smc_args *args,
+ struct teesmc32_arg *arg32, uint32_t num_params)
+{
+
+ if (num_params == 0) {
+ struct tee_close_session_in in;
+ uint32_t ret;
+
+ in.sess = arg32->session;
+ ret = tee_dispatch_close_session(&in);
+ if (ret == TEE_STE_ERROR_SYSTEM_BUSY) {
+ args->a0 = TEESMC_RETURN_EBUSY;
+ return;
+ }
+ arg32->ret = ret;
+ } else {
+ arg32->ret = TEE_ERROR_BAD_PARAMETERS;
+ }
+
+ arg32->ret_origin = TEE_ORIGIN_TEE;
+ args->a0 = TEESMC_RETURN_OK;
+}
+
+static void entry_invoke_command(struct thread_smc_args *args,
+ struct teesmc32_arg *arg32, uint32_t num_params)
+{
+ struct tee_dispatch_invoke_command_in in;
+ struct tee_dispatch_invoke_command_out out;
+ struct teesmc32_param *params = TEESMC32_GET_PARAMS(arg32);
+
+ if (!copy_in_params(params, num_params,
+ &in.param_types, in.param_attr, in.params)) {
+ arg32->ret = TEE_ERROR_BAD_PARAMETERS;
+ arg32->ret_origin = TEE_ORIGIN_TEE;
+ args->a0 = TEESMC_RETURN_OK;
+ return;
+ }
+
+ in.sess = (TEE_Session *)arg32->session;
+ in.cmd = arg32->ta_func;
+ (void)tee_dispatch_invoke_command(&in, &out);
+ if (out.msg.res == TEE_STE_ERROR_SYSTEM_BUSY) {
+ args->a0 = TEESMC_RETURN_EBUSY;
+ return;
+ }
+
+ copy_out_param(out.params, in.param_types, num_params, params);
+
+ arg32->ret = out.msg.res;
+ arg32->ret_origin = out.msg.err;
+ args->a0 = TEESMC_RETURN_OK;
+}
+
+static void entry_cancel(struct thread_smc_args *args,
+ struct teesmc32_arg *arg32, uint32_t num_params)
+{
+
+ if (num_params == 0) {
+ struct tee_dispatch_cancel_command_in in;
+ struct tee_dispatch_cancel_command_out out;
+
+ in.sess = (TEE_Session *)arg32->session;
+ (void)tee_dispatch_cancel_command(&in, &out);
+
+ if (out.msg.res == TEE_STE_ERROR_SYSTEM_BUSY) {
+ args->a0 = TEESMC_RETURN_EBUSY;
+ return;
+ }
+
+ arg32->ret = out.msg.res;
+ arg32->ret_origin = out.msg.err;
+ } else {
+ arg32->ret = TEE_ERROR_BAD_PARAMETERS;
+ arg32->ret_origin = TEE_ORIGIN_TEE;
+ }
+
+ args->a0 = TEESMC_RETURN_OK;
+}
+
+
+
+static void tee_entry_call_with_arg(struct thread_smc_args *args)
+{
+ struct teesmc32_arg *arg32;
+ uint32_t num_params;
+
+ if (args->a0 != TEESMC32_CALL_WITH_ARG &&
+ args->a0 != TEESMC32_FASTCALL_WITH_ARG) {
+ EMSG("Unknown SMC 0x%x\n", args->a0);
+ DMSG("Expected 0x%x or 0x%x\n",
+ TEESMC32_CALL_WITH_ARG, TEESMC32_FASTCALL_WITH_ARG);
+ args->a0 = TEESMC_RETURN_UNKNOWN_FUNCTION;
+ return;
+ }
+
+ if (args->a0 == TEESMC32_CALL_WITH_ARG)
+ thread_set_irq(true); /* Enable IRQ for STD calls */
+
+ if (!tee_pbuf_is_non_sec(args->a1, sizeof(struct teesmc32_arg)) ||
+ !TEE_ALIGNMENT_IS_OK(args->a1, struct teesmc32_arg) ||
+ core_pa2va(args->a1, (void *)&arg32)) {
+ EMSG("Bad arg address 0x%x\n", args->a1);
+ args->a0 = TEESMC_RETURN_EBADADDR;
+ return;
+ }
+
+ num_params = arg32->num_params;
+ if (!tee_pbuf_is_non_sec(args->a1, TEESMC32_GET_ARG_SIZE(num_params))) {
+ EMSG("Bad arg address 0x%x\n", args->a1);
+ args->a0 = TEESMC_RETURN_EBADADDR;
+ return;
+ }
+
+ if (args->a0 == TEESMC32_CALL_WITH_ARG) {
+ switch (arg32->cmd) {
+ case TEESMC_CMD_OPEN_SESSION:
+ entry_open_session(args, arg32, num_params);
+ break;
+ case TEESMC_CMD_CLOSE_SESSION:
+ entry_close_session(args, arg32, num_params);
+ break;
+ case TEESMC_CMD_INVOKE_COMMAND:
+ entry_invoke_command(args, arg32, num_params);
+ break;
+ case TEESMC_CMD_CANCEL:
+ entry_cancel(args, arg32, num_params);
+ break;
+ default:
+ EMSG("Unknown cmd 0x%x\n", arg32->cmd);
+ args->a0 = TEESMC_RETURN_EBADCMD;
+ }
+ } else {
+ EMSG("Unknown fastcall cmd 0x%x\n", arg32->cmd);
+ args->a0 = TEESMC_RETURN_EBADCMD;
+ }
+}
+
+void tee_entry(struct thread_smc_args *args)
+{
+ switch (args->a0) {
+ case TEESMC32_CALLS_COUNT:
+ tee_entry_get_api_call_count(args);
+ break;
+ case TEESMC32_CALLS_UID:
+ tee_entry_get_api_uuid(args);
+ break;
+ case TEESMC32_CALLS_REVISION:
+ tee_entry_get_api_revision(args);
+ break;
+ case TEESMC32_CALL_GET_OS_UUID:
+ tee_entry_get_os_uuid(args);
+ break;
+ case TEESMC32_CALL_GET_OS_REVISION:
+ tee_entry_get_os_revision(args);
+ break;
+ case TEESMC32_CALL_WITH_ARG:
+ case TEESMC64_CALL_WITH_ARG:
+ tee_entry_call_with_arg(args);
+ break;
+ default:
+ args->a0 = TEESMC_RETURN_UNKNOWN_FUNCTION;
+ break;
+ }
+}
+
+size_t tee_entry_generic_get_api_call_count(void)
+{
+ /*
+ * All the differnt calls handled in this file. If the specific
+ * target has additional calls it will call this function and
+ * add the number of calls the target has added.
+ */
+ return 7;
+}
+
+void __attribute__((weak)) tee_entry_get_api_call_count(
+ struct thread_smc_args *args)
+{
+ args->a0 = tee_entry_generic_get_api_call_count();
+}
+
+void __attribute__((weak)) tee_entry_get_api_uuid(struct thread_smc_args *args)
+{
+ args->a0 = TEESMC_UID_R0;
+ args->a1 = TEESMC_UID_R1;
+ args->a2 = TEESMC_UID_R2;
+ args->a3 = TEESMC_UID32_R3;
+}
+
+void __attribute__((weak)) tee_entry_get_api_revision(
+ struct thread_smc_args *args)
+{
+ args->a0 = TEESMC_REVISION_MAJOR;
+ args->a1 = TEESMC_REVISION_MINOR;
+}
+
+void __attribute__((weak)) tee_entry_get_os_uuid(struct thread_smc_args *args)
+{
+ /* Not implemented */
+ args->a0 = TEESMC_RETURN_UNKNOWN_FUNCTION;
+}
+
+void __attribute__((weak)) tee_entry_get_os_revision(
+ struct thread_smc_args *args)
+{
+ /* Not implemented */
+ args->a0 = TEESMC_RETURN_UNKNOWN_FUNCTION;
+}
diff --git a/core/arch/arm32/tee/sub.mk b/core/arch/arm32/tee/sub.mk
new file mode 100644
index 0000000..9b9b940
--- /dev/null
+++ b/core/arch/arm32/tee/sub.mk
@@ -0,0 +1,2 @@
+srcs-y += tee_svc_asm.S
+srcs-y += entry.c
diff --git a/core/arch/arm32/tee/tee_svc_asm.S b/core/arch/arm32/tee/tee_svc_asm.S
new file mode 100644
index 0000000..a4156d4
--- /dev/null
+++ b/core/arch/arm32/tee/tee_svc_asm.S
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2014, STMicroelectronics International N.V.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "tee_syscall_numbers.h"
+
+.global tee_svc_enter_user_mode
+.global tee_svc_sys_return
+.global tee_svc_syscall
+
+.set SPSR_T_BIT, (1 << 5)
+.set SPSR_IT_MASK, 0x0600FC00
+.set SPSR_IT_MASK1, 0x06000000
+.set SPSR_IT_MASK2, 0x0000FC00
+
+.section .text
+.balign 4
+.code 32
+
+/*
+ * Function called from the vector table when a svc exception is received.
+ * This function handles entry and exit from a system call.
+ */
+.func tee_svc_syscall
+tee_svc_syscall:
+ push {r4 - r12, lr}
+ mov r8, sp
+
+ /* Restore IRQ which are disabled on exception entry */
+ push {r0-r3}
+ blx thread_restore_irq
+ pop {r0-r3}
+
+ /*
+ * Copy eventual arguments passed on the user stack.
+ *
+ * r5 holds the address of the first word
+ * r6 holds the number of words
+ *
+ * TODO figure out how to avoid stack overflow because of too much data
+ * passed on the stack.
+ */
+ sub sp, sp, r6, lsl #2
+ cmp r6, #0
+ beq .Lno_args
+ push {r0}
+ push {r1-r3}
+ mov r0, #0
+ mov r2, r5
+ add r1, sp, #(4 * 4)
+ mov r3, r6, lsl #2
+ ldr lr, =tee_svc_copy_from_user
+ blx lr
+
+ /* If copy failed return the error */
+ cmp r0, #0
+ pop {r1-r3}
+ addne sp, sp, #4
+ popeq {r0}
+ bne .Lret
+.Lno_args:
+
+ /*
+ * Find the system call and call the function.
+ *
+ * System call number is passed in r7.
+ */
+ ldr r12, =tee_svc_syscall_table
+ cmp r7, #TEE_SCN_MAX
+ /* Either syscall function should return to cleanup (.Lret) */
+ ldr lr, =.Lret
+ ldrls pc, [r12, r7, lsl #2] /* if valid syscall number */
+ ldr pc, =tee_svc_sys_nocall /* if invalid syscall number */
+.Lret:
+ mov sp, r8
+ pop {r4 - r12, lr}
+ movs pc, lr
+.endfunc
+
+
+
+@ TEE_Result tee_svc_enter_user_mode(
+@ uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3,
+@ tee_uaddr_t sp, tee_uaddr_t user_func,
+@ uint32_t *panicked, uint32_t *panic_code);
+.func tee_svc_enter_user_mode
+tee_svc_enter_user_mode:
+ /*
+ * Save all registers to allow tee_svc_sys_return() to
+ * resume execution as if this function would have returned.
+ * This is also used in tee_svc_sys_panic().
+ *
+ * If stack usage of this function is changed tee_svc_sys_return()
+ * and tee_svc_sys_panic() has to be updated.
+ */
+ push {r4-r12,lr}
+
+ ldr r4, [sp, #(10 * 0x4)] /* user stack pointer */
+ ldr r5, [sp, #(11 * 0x4)] /* user function */
+
+ /* Save user sp */
+ stmfd sp, {sp}^ /* store r13 user mode */
+ nop
+ sub sp, sp, #4 /* update stack pointer */
+
+ /* Switch from Supervisor mode to System mode */
+ mrs r6, cpsr
+ mrs r7, cpsr
+ orr r6, #0xF
+ msr cpsr, r6
+
+ /* Setup user stack */
+ mov sp, r4
+
+ /* Switch back to Supervisor mode to have a spsr to modify */
+ msr cpsr, r7
+
+ /*
+ * Set the saved Processors Status Register to user mode to allow entry
+ * of user mode through movs below. Also update thumbstate since movs
+ * doesn't do that automatically.
+ */
+ bic r6, #0xF
+ tst r5, #1 /* If it's odd we should switch to thumb mode */
+ orrne r6, #SPSR_T_BIT /* Enable thumb mode */
+ biceq r6, #SPSR_T_BIT /* Disable thumb mode */
+ bicne r6, #SPSR_IT_MASK1 /* Clear IT state for thumb mode */
+ bicne r6, #SPSR_IT_MASK2 /* Clear IT state for thumb mode */
+ msr spsr_cxsf, r6
+
+ /*
+ * Don't allow return from this function, return is done through
+ * tee_svc_sys_return() below.
+ */
+ mov lr, #0
+ /* Call the user function with its arguments */
+ movs pc, r5
+.endfunc
+
+@ tee_svc_sys_return(uint32_t ret, uint32_t param_types, void *params);
+.func tee_svc_sys_return
+tee_svc_sys_return:
+ mov sp, r8 /* Restore sp in case extra parameters was passed */
+ pop {r4-r12,lr} /* Match the push in tee_svc_syscall() */
+
+ /* Restore user sp */
+ ldmfd sp, {sp}^ /* store r13 user mode */
+ nop
+ add sp, sp, #4 /* update stack pointer */
+
+ pop {r4-r12,pc} /* Match the push in tee_svc_enter_user_mode() */
+.endfunc
+
+@ void tee_svc_sys_panic(uint32_t code);
+.func tee_svc_sys_panic
+tee_svc_sys_panic:
+ mov sp, r8 /* Restore sp in case extra parameters was passed */
+ pop {r4-r12,lr} /* Match the push in tee_svc_syscall() */
+
+.global tee_svc_user_ta_panic_from_pager
+tee_svc_user_ta_panic_from_pager:
+ ldr r1, [sp, #(13 * 0x4)] /* &session->panicked */
+ mov r2, #1 /* true */
+ str r2, [r1] /* update session->panicked */
+
+ ldr r1, [sp, #(14 * 0x4)] /* &session->panic_code */
+ str r0, [r1] /* update session->panic_code */
+
+ /* Restore user sp */
+ ldmfd sp, {sp}^ /* store r13 user mode */
+ nop
+ add sp, sp, #4 /* update stack pointer */
+
+ pop {r4-r12,pc} /* Match the push in tee_svc_enter_user_mode() */
+.endfunc
+
+
+ .section .rodata
+tee_svc_syscall_table:
+.word tee_svc_sys_return
+.word tee_svc_sys_log
+.word tee_svc_sys_panic
+.word tee_svc_sys_dummy
+.word tee_svc_sys_dummy_7args
+.word tee_svc_sys_get_property
+.word tee_svc_open_ta_session
+.word tee_svc_close_ta_session
+.word tee_svc_invoke_ta_command
+.word tee_svc_check_access_rights
+.word tee_svc_get_cancellation_flag
+.word tee_svc_unmask_cancellation
+.word tee_svc_mask_cancellation
+.word tee_svc_wait
+.word tee_svc_get_time
+.word tee_svc_set_ta_time
+.word tee_svc_cryp_state_alloc
+.word tee_svc_cryp_state_copy
+.word tee_svc_cryp_state_free
+.word tee_svc_hash_init
+.word tee_svc_hash_update
+.word tee_svc_hash_final
+.word tee_svc_cipher_init
+.word tee_svc_cipher_update
+.word tee_svc_cipher_final
+.word tee_svc_cryp_obj_get_info
+.word tee_svc_cryp_obj_restrict_usage
+.word tee_svc_cryp_obj_get_attr
+.word tee_svc_cryp_obj_alloc
+.word tee_svc_cryp_obj_close
+.word tee_svc_cryp_obj_reset
+.word tee_svc_cryp_obj_populate
+.word tee_svc_cryp_obj_copy
+.word tee_svc_cryp_derive_key
+.word tee_svc_cryp_random_number_generate
+.word tee_svc_authenc_init
+.word tee_svc_authenc_update_aad
+.word tee_svc_authenc_update_payload
+.word tee_svc_authenc_enc_final
+.word tee_svc_authenc_dec_final
+.word tee_svc_asymm_operate
+.word tee_svc_asymm_verify
+.word tee_svc_storage_obj_open
+.word tee_svc_storage_obj_create
+.word tee_svc_storage_obj_del
+.word tee_svc_storage_obj_rename
+.word tee_svc_storage_alloc_enum
+.word tee_svc_storage_free_enum
+.word tee_svc_storage_reset_enum
+.word tee_svc_storage_start_enum
+.word tee_svc_storage_next_enum
+.word tee_svc_storage_obj_read
+.word tee_svc_storage_obj_write
+.word tee_svc_storage_obj_trunc
+.word tee_svc_storage_obj_seek
+.word tee_svc_obj_generate_key