1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2014, STMicroelectronics International N.V.
4 * Copyright (c) 2020, Linaro Limited
5 */
6
7 #include <kernel/panic.h>
8 #include <kernel/pseudo_ta.h>
9 #include <kernel/tee_ta_manager.h>
10 #include <kernel/thread.h>
11 #include <kernel/ts_manager.h>
12 #include <kernel/user_mode_ctx.h>
13 #include <mm/core_mmu.h>
14 #include <mm/vm.h>
15
update_current_ctx(struct thread_specific_data * tsd)16 static void update_current_ctx(struct thread_specific_data *tsd)
17 {
18 struct ts_ctx *ctx = NULL;
19 struct ts_session *s = TAILQ_FIRST(&tsd->sess_stack);
20
21 if (s) {
22 if (is_pseudo_ta_ctx(s->ctx))
23 s = TAILQ_NEXT(s, link_tsd);
24
25 if (s)
26 ctx = s->ctx;
27 }
28
29 if (tsd->ctx != ctx)
30 vm_set_ctx(ctx);
31 /*
32 * If current context is of user mode, then it has to be active too.
33 */
34 if (is_user_mode_ctx(ctx) != core_mmu_user_mapping_is_active())
35 panic("unexpected active mapping");
36 }
37
swap_fbuf(struct ts_session * s __maybe_unused,void * fbuf __maybe_unused)38 static void *swap_fbuf(struct ts_session *s __maybe_unused,
39 void *fbuf __maybe_unused)
40 {
41 void *ret = NULL;
42
43 #if defined(CFG_FTRACE_SUPPORT)
44 ret = s->fbuf;
45 s->fbuf = fbuf;
46 #endif
47
48 return ret;
49 }
50
ts_push_current_session(struct ts_session * s)51 void ts_push_current_session(struct ts_session *s)
52 {
53 struct thread_specific_data *tsd = thread_get_tsd();
54 uint32_t state = 0;
55 void *fbuf = NULL;
56
57 /*
58 * If ftrace is enabled we may access the session list and the fbuf
59 * field in the current (first) session when processing a foreign
60 * interrupt when saving the state of the thread. Mask foreign
61 * interrupts temporarily to make sure that we present a consistent
62 * state.
63 *
64 * We disable the fbuf temporarily while switching mapped TS to
65 * since this isn't an atomic operation, that is, the mappings are
66 * replaced entry by entry so it's not clear what is mapped during
67 * the call to update_current_ctx().
68 */
69
70 if (IS_ENABLED(CFG_FTRACE_SUPPORT)) {
71 state = thread_mask_exceptions(THREAD_EXCP_FOREIGN_INTR);
72 fbuf = swap_fbuf(s, NULL);
73 }
74
75 TAILQ_INSERT_HEAD(&tsd->sess_stack, s, link_tsd);
76
77 if (IS_ENABLED(CFG_FTRACE_SUPPORT))
78 thread_unmask_exceptions(state);
79
80 update_current_ctx(tsd);
81
82 if (IS_ENABLED(CFG_FTRACE_SUPPORT) && fbuf) {
83 state = thread_mask_exceptions(THREAD_EXCP_FOREIGN_INTR);
84 swap_fbuf(s, fbuf);
85 thread_unmask_exceptions(state);
86 }
87 }
88
ts_pop_current_session(void)89 struct ts_session *ts_pop_current_session(void)
90 {
91 struct thread_specific_data *tsd = thread_get_tsd();
92 struct ts_session *s = TAILQ_FIRST(&tsd->sess_stack);
93 struct ts_session *s2 = NULL;
94 uint32_t state = 0;
95 void *fbuf = NULL;
96
97 if (!s)
98 return NULL;
99
100 /* See comment in ts_push_current_session() above for ftrace support */
101
102 if (IS_ENABLED(CFG_FTRACE_SUPPORT)) {
103 s2 = TAILQ_NEXT(s, link_tsd);
104 if (s2)
105 fbuf = swap_fbuf(s2, NULL);
106 state = thread_mask_exceptions(THREAD_EXCP_FOREIGN_INTR);
107 }
108
109 TAILQ_REMOVE(&tsd->sess_stack, s, link_tsd);
110
111 if (IS_ENABLED(CFG_FTRACE_SUPPORT))
112 thread_unmask_exceptions(state);
113
114 update_current_ctx(tsd);
115
116 if (IS_ENABLED(CFG_FTRACE_SUPPORT) && fbuf) {
117 state = thread_mask_exceptions(THREAD_EXCP_FOREIGN_INTR);
118 swap_fbuf(s2, fbuf);
119 thread_unmask_exceptions(state);
120 }
121
122 return s;
123 }
124
ts_get_calling_session(void)125 struct ts_session *ts_get_calling_session(void)
126 {
127 return TAILQ_NEXT(ts_get_current_session(), link_tsd);
128 }
129
ts_get_current_session_may_fail(void)130 struct ts_session *ts_get_current_session_may_fail(void)
131 {
132 return TAILQ_FIRST(&thread_get_tsd()->sess_stack);
133 }
134
ts_get_current_session(void)135 struct ts_session *ts_get_current_session(void)
136 {
137 struct ts_session *s = ts_get_current_session_may_fail();
138
139 if (!s)
140 panic();
141 return s;
142 }
143