2 * Copyright (c) 2014, STMicroelectronics International N.V.
3 * Copyright (c) 2015, Linaro Limited
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
29 #include <kernel/panic.h>
30 #include <kernel/pseudo_ta.h>
31 #include <kernel/tee_ta_manager.h>
32 #include <mm/core_memprot.h>
34 #include <sm/tee_mon.h>
38 #include <types_ext.h>
40 #ifdef CFG_SECURE_DATA_PATH
41 static bool client_is_secure(struct tee_ta_session *s)
43 /* rely on core entry to have constrained client IDs */
44 if (s->clnt_id.login == TEE_LOGIN_TRUSTED_APP)
50 static bool validate_in_param(struct tee_ta_session *s, struct mobj *mobj)
52 /* for secure clients, core entry always holds valid memref objects */
53 if (client_is_secure(s))
56 /* all non-secure memory references are hanlded by pTAs */
57 if (mobj_is_nonsec(mobj))
63 static bool validate_in_param(struct tee_ta_session *s __unused,
64 struct mobj *mobj __unused)
66 /* At this point, core has filled only valid accessible memref mobj */
71 /* Maps static TA params */
72 static TEE_Result copy_in_param(struct tee_ta_session *s __maybe_unused,
73 struct tee_ta_param *param,
74 TEE_Param tee_param[TEE_NUM_PARAMS])
79 for (n = 0; n < TEE_NUM_PARAMS; n++) {
80 switch (TEE_PARAM_TYPE_GET(param->types, n)) {
81 case TEE_PARAM_TYPE_VALUE_INPUT:
82 case TEE_PARAM_TYPE_VALUE_OUTPUT:
83 case TEE_PARAM_TYPE_VALUE_INOUT:
84 tee_param[n].value.a = param->u[n].val.a;
85 tee_param[n].value.b = param->u[n].val.b;
87 case TEE_PARAM_TYPE_MEMREF_INPUT:
88 case TEE_PARAM_TYPE_MEMREF_OUTPUT:
89 case TEE_PARAM_TYPE_MEMREF_INOUT:
90 if (!validate_in_param(s, param->u[n].mem.mobj))
91 return TEE_ERROR_BAD_PARAMETERS;
93 va = mobj_get_va(param->u[n].mem.mobj,
94 param->u[n].mem.offs);
96 return TEE_ERROR_BAD_PARAMETERS;
97 tee_param[n].memref.buffer = va;
98 tee_param[n].memref.size = param->u[n].mem.size;
101 memset(tee_param + n, 0, sizeof(TEE_Param));
109 static void update_out_param(TEE_Param tee_param[TEE_NUM_PARAMS],
110 struct tee_ta_param *param)
114 for (n = 0; n < TEE_NUM_PARAMS; n++) {
115 switch (TEE_PARAM_TYPE_GET(param->types, n)) {
116 case TEE_PARAM_TYPE_VALUE_OUTPUT:
117 case TEE_PARAM_TYPE_VALUE_INOUT:
118 param->u[n].val.a = tee_param[n].value.a;
119 param->u[n].val.b = tee_param[n].value.b;
121 case TEE_PARAM_TYPE_MEMREF_OUTPUT:
122 case TEE_PARAM_TYPE_MEMREF_INOUT:
123 param->u[n].mem.size = tee_param[n].memref.size;
131 static TEE_Result pseudo_ta_enter_open_session(struct tee_ta_session *s,
132 struct tee_ta_param *param, TEE_ErrorOrigin *eo)
134 TEE_Result res = TEE_SUCCESS;
135 struct pseudo_ta_ctx *stc = to_pseudo_ta_ctx(s->ctx);
136 TEE_Param tee_param[TEE_NUM_PARAMS];
138 tee_ta_push_current_session(s);
139 *eo = TEE_ORIGIN_TRUSTED_APP;
141 if ((s->ctx->ref_count == 1) && stc->pseudo_ta->create_entry_point) {
142 res = stc->pseudo_ta->create_entry_point();
143 if (res != TEE_SUCCESS)
147 if (stc->pseudo_ta->open_session_entry_point) {
148 res = copy_in_param(s, param, tee_param);
149 if (res != TEE_SUCCESS) {
150 *eo = TEE_ORIGIN_TEE;
154 res = stc->pseudo_ta->open_session_entry_point(param->types,
157 update_out_param(tee_param, param);
161 tee_ta_pop_current_session();
165 static TEE_Result pseudo_ta_enter_invoke_cmd(struct tee_ta_session *s,
166 uint32_t cmd, struct tee_ta_param *param,
170 struct pseudo_ta_ctx *stc = to_pseudo_ta_ctx(s->ctx);
171 TEE_Param tee_param[TEE_NUM_PARAMS];
173 tee_ta_push_current_session(s);
174 res = copy_in_param(s, param, tee_param);
175 if (res != TEE_SUCCESS) {
176 *eo = TEE_ORIGIN_TEE;
180 *eo = TEE_ORIGIN_TRUSTED_APP;
181 res = stc->pseudo_ta->invoke_command_entry_point(s->user_ctx, cmd,
184 update_out_param(tee_param, param);
186 tee_ta_pop_current_session();
190 static void pseudo_ta_enter_close_session(struct tee_ta_session *s)
192 struct pseudo_ta_ctx *stc = to_pseudo_ta_ctx(s->ctx);
194 tee_ta_push_current_session(s);
196 if (stc->pseudo_ta->close_session_entry_point)
197 stc->pseudo_ta->close_session_entry_point(s->user_ctx);
199 if ((s->ctx->ref_count == 1) && stc->pseudo_ta->destroy_entry_point)
200 stc->pseudo_ta->destroy_entry_point();
202 tee_ta_pop_current_session();
205 static void pseudo_ta_destroy(struct tee_ta_ctx *ctx)
207 free(to_pseudo_ta_ctx(ctx));
210 static const struct tee_ta_ops pseudo_ta_ops = {
211 .enter_open_session = pseudo_ta_enter_open_session,
212 .enter_invoke_cmd = pseudo_ta_enter_invoke_cmd,
213 .enter_close_session = pseudo_ta_enter_close_session,
214 .destroy = pseudo_ta_destroy,
218 /* Defined in link script */
219 extern const struct pseudo_ta_head __start_ta_head_section;
220 extern const struct pseudo_ta_head __stop_ta_head_section;
222 /* Insures declared pseudo TAs conforms with core expectations */
223 static TEE_Result verify_pseudo_tas_conformance(void)
225 const struct pseudo_ta_head *start = &__start_ta_head_section;
226 const struct pseudo_ta_head *end = &__stop_ta_head_section;
227 const struct pseudo_ta_head *pta;
229 for (pta = start; pta < end; pta++) {
230 const struct pseudo_ta_head *pta2;
232 /* PTAs must all have a specific UUID */
233 for (pta2 = pta + 1; pta2 < end; pta2++)
234 if (!memcmp(&pta->uuid, &pta2->uuid, sizeof(TEE_UUID)))
238 (pta->flags & PTA_MANDATORY_FLAGS) != PTA_MANDATORY_FLAGS ||
239 pta->flags & ~PTA_ALLOWED_FLAGS ||
240 !pta->invoke_command_entry_point)
245 DMSG("pseudo TA error at %p", (void *)pta);
249 service_init(verify_pseudo_tas_conformance);
251 /*-----------------------------------------------------------------------------
252 * Initialises a session based on the UUID or ptr to the ta
253 * Returns ptr to the session (ta_session) and a TEE_Result
254 *---------------------------------------------------------------------------*/
255 TEE_Result tee_ta_init_pseudo_ta_session(const TEE_UUID *uuid,
256 struct tee_ta_session *s)
258 struct pseudo_ta_ctx *stc = NULL;
259 struct tee_ta_ctx *ctx;
260 const struct pseudo_ta_head *ta;
262 DMSG(" Lookup for pseudo TA %pUl", (void *)uuid);
264 ta = &__start_ta_head_section;
266 if (ta >= &__stop_ta_head_section)
267 return TEE_ERROR_ITEM_NOT_FOUND;
268 if (memcmp(&ta->uuid, uuid, sizeof(TEE_UUID)) == 0)
273 /* Load a new TA and create a session */
274 DMSG(" Open %s", ta->name);
275 stc = calloc(1, sizeof(struct pseudo_ta_ctx));
277 return TEE_ERROR_OUT_OF_MEMORY;
282 ctx->flags = ta->flags;
284 ctx->uuid = ta->uuid;
285 ctx->ops = &pseudo_ta_ops;
286 TAILQ_INSERT_TAIL(&tee_ctxes, ctx, link);
288 DMSG(" %s : %pUl", stc->pseudo_ta->name, (void *)&ctx->uuid);