xref: /optee_os/core/kernel/ts_manager.c (revision 053593356df20f185a674a23e3cc34d67675636e)
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