1/* SPDX-License-Identifier: BSD-2-Clause */
2/*
3 * Copyright (c) 2014, STMicroelectronics International N.V.
4 */
5#include "tee_syscall_numbers.h"
6#include "trace_levels.h"
7#include <arm.h>
8#include <asm.S>
9#include <generated/asm-defines.h>
10#include <kernel/thread.h>
11#include <tee_api_defines.h>
12
13/*
14 * uint32_t tee_svc_do_call(struct thread_svc_regs *regs, tee_svc_func func);
15 *
16 * Called from user_ta_handle_svc()
17 */
18FUNC tee_svc_do_call , :
19UNWIND(	.cantunwind)
20	push	{r5-r9, lr}
21	mov	r7, sp
22	mov	r8, r0
23	mov	r9, r1
24	ldr	r5, [r8, #THREAD_SVC_REG_R5]
25	ldr	r6, [r8, #THREAD_SVC_REG_R6]
26
27	/*
28	 * Copy eventual arguments passed on the user stack.
29	 *
30	 * r5 holds the address of the first word
31	 * r6 holds the number of words
32	 *
33	 * user_ta_handle_svc() who calls this function has already checked
34	 * that we don't copy too much data.
35	 */
36	cmp     r6, #0
37	beq     .Lno_args
38	sub     sp, sp, r6, lsl #2
39	bic	sp, sp, #7	/* make sure it's a multiple of 8 */
40	mov     r0, sp
41	mov     r1, r5
42	mov     r2, r6, lsl #2
43	ldr     lr, =copy_from_user
44	blx     lr
45
46	/* If copy failed return the error */
47	cmp     r0, #0
48	bne     .Lret
49
50.Lno_args:
51	/* Load arguments to function */
52	add	lr, r8, #THREAD_SVC_REG_R0
53	ldm	lr, {r0-r3}
54	blx	r9
55.Lret:
56	mov	sp, r7
57	pop	{r5-r9, pc}
58END_FUNC tee_svc_do_call
59
60/*
61 * syscall_sys_return() and syscall_panic() are two special cases for syscalls
62 * in the way that they do not return to the TA, instead execution is resumed
63 * as if __thread_enter_user_mode() had returned to thread_enter_user_mode().
64 *
65 * In order to do this the functions need a way to get hold of a pointer to
66 * the struct thread_svc_regs provided by storing relevant registers on the
67 * stack in thread_svc_handler() and later load them into registers again
68 * when thread_svc_handler() is returning.
69 *
70 * tee_svc_do_call() is supplied the pointer to struct thread_svc_regs in
71 * r0. This pointer can later be retrieved from r8.
72 */
73
74/*
75 * User space sees this function as:
76 * void syscall_sys_return(uint32_t ret) __noreturn;
77 *
78 * But internally the function depends on being called from
79 * tee_svc_do_call() with pointer to the struct thread_svc_regs saved by
80 * thread_svc_handler() in r8.
81 *
82 * The argument ret is already in r0 so we don't touch that and let it
83 * propagate as return value of the called
84 * tee_svc_unwind_enter_user_mode().
85 */
86FUNC syscall_sys_return , :
87	mov	r1, #0	/* panic = false */
88	mov	r2, #0	/* panic_code = 0 */
89	mov	r3, r8	/* pointer to struct thread_svc_regs */
90	b	tee_svc_sys_return_helper
91END_FUNC syscall_sys_return
92
93/*
94 * User space sees this function as:
95 * void syscall_panic(uint32_t code) __noreturn;
96 *
97 * But internally the function depends on being called from
98 * tee_svc_do_call() with pointer to the struct thread_svc_regs saved by
99 * thread_svc_handler() in r8.
100 */
101FUNC syscall_panic , :
102	mov	r1, #1	/* panic = true */
103	mov	r2, r0	/* panic_code = 0 */
104	mov	r3, r8	/* pointer to struct thread_svc_regs */
105	ldr	r0, =TEE_ERROR_TARGET_DEAD
106	b	tee_svc_sys_return_helper
107END_FUNC syscall_panic
108