xref: /optee_os/core/arch/arm/kernel/secure_partition.c (revision 82d5d8cc2e491a5af963238148e8124e2bceae63)
1dea46be3SJelle Sels // SPDX-License-Identifier: BSD-2-Clause
2dea46be3SJelle Sels /*
3655625e0SImre Kis  * Copyright (c) 2020-2024, Arm Limited.
4dea46be3SJelle Sels  */
5dea46be3SJelle Sels #include <crypto/crypto.h>
6dea46be3SJelle Sels #include <initcall.h>
78d2d14e5SBalint Dobszay #include <kernel/boot.h>
8dea46be3SJelle Sels #include <kernel/embedded_ts.h>
9c185655eSJelle Sels #include <kernel/ldelf_loader.h>
10c185655eSJelle Sels #include <kernel/secure_partition.h>
11ae6b3380SJelle Sels #include <kernel/spinlock.h>
12ae6b3380SJelle Sels #include <kernel/spmc_sp_handler.h>
137e399f9bSJens Wiklander #include <kernel/thread_private.h>
14c185655eSJelle Sels #include <kernel/thread_spmc.h>
15145035ffSImre Kis #include <kernel/tpm.h>
16dea46be3SJelle Sels #include <kernel/ts_store.h>
17c185655eSJelle Sels #include <ldelf.h>
1828710257SJelle Sels #include <libfdt.h>
19c185655eSJelle Sels #include <mm/core_mmu.h>
20c185655eSJelle Sels #include <mm/fobj.h>
21c185655eSJelle Sels #include <mm/mobj.h>
22de19cacbSJens Wiklander #include <mm/phys_mem.h>
23c185655eSJelle Sels #include <mm/vm.h>
24c185655eSJelle Sels #include <optee_ffa.h>
25dea46be3SJelle Sels #include <stdio.h>
26dea46be3SJelle Sels #include <string.h>
2728710257SJelle Sels #include <tee/uuid.h>
28de19cacbSJens Wiklander #include <tee_api_types.h>
29dea46be3SJelle Sels #include <trace.h>
30c185655eSJelle Sels #include <types_ext.h>
31dea46be3SJelle Sels #include <utee_defines.h>
32dea46be3SJelle Sels #include <util.h>
33dea46be3SJelle Sels #include <zlib.h>
34dea46be3SJelle Sels 
355f1edb13SBalint Dobszay #define BOUNCE_BUFFER_SIZE		4096
365f1edb13SBalint Dobszay 
379d58f55eSGyorgy Szing #define UNDEFINED_BOOT_ORDER_VALUE	UINT32_MAX
389d58f55eSGyorgy Szing 
396d618ba1SJelle Sels #define SP_MANIFEST_ATTR_READ		BIT(0)
406d618ba1SJelle Sels #define SP_MANIFEST_ATTR_WRITE		BIT(1)
416d618ba1SJelle Sels #define SP_MANIFEST_ATTR_EXEC		BIT(2)
426d618ba1SJelle Sels #define SP_MANIFEST_ATTR_NSEC		BIT(3)
439363481eSGabor Toth #define SP_MANIFEST_ATTR_GP		BIT(4)
446d618ba1SJelle Sels 
453da1a076SBalint Dobszay #define SP_MANIFEST_ATTR_RO		(SP_MANIFEST_ATTR_READ)
463da1a076SBalint Dobszay #define SP_MANIFEST_ATTR_RW		(SP_MANIFEST_ATTR_READ | \
473da1a076SBalint Dobszay 					 SP_MANIFEST_ATTR_WRITE)
483da1a076SBalint Dobszay #define SP_MANIFEST_ATTR_RX		(SP_MANIFEST_ATTR_READ | \
493da1a076SBalint Dobszay 					 SP_MANIFEST_ATTR_EXEC)
503da1a076SBalint Dobszay #define SP_MANIFEST_ATTR_RWX		(SP_MANIFEST_ATTR_READ  | \
513da1a076SBalint Dobszay 					 SP_MANIFEST_ATTR_WRITE | \
523da1a076SBalint Dobszay 					 SP_MANIFEST_ATTR_EXEC)
533da1a076SBalint Dobszay 
5409b678f1SImre Kis #define SP_MANIFEST_FLAG_NOBITS	BIT(0)
5509b678f1SImre Kis 
569cc3a2ffSImre Kis #define SP_MANIFEST_NS_INT_QUEUED	(0x0)
579cc3a2ffSImre Kis #define SP_MANIFEST_NS_INT_MANAGED_EXIT	(0x1)
589cc3a2ffSImre Kis #define SP_MANIFEST_NS_INT_SIGNALED	(0x2)
599cc3a2ffSImre Kis 
60cc04f76fSBalint Dobszay #define SP_MANIFEST_EXEC_STATE_AARCH64	(0x0)
61cc04f76fSBalint Dobszay #define SP_MANIFEST_EXEC_STATE_AARCH32	(0x1)
62cc04f76fSBalint Dobszay 
63cc04f76fSBalint Dobszay #define SP_MANIFEST_DIRECT_REQ_RECEIVE	BIT(0)
64cc04f76fSBalint Dobszay #define SP_MANIFEST_DIRECT_REQ_SEND	BIT(1)
65cc04f76fSBalint Dobszay #define SP_MANIFEST_INDIRECT_REQ	BIT(2)
66cc04f76fSBalint Dobszay 
678dde314bSBalint Dobszay #define SP_MANIFEST_VM_CREATED_MSG	BIT(0)
688dde314bSBalint Dobszay #define SP_MANIFEST_VM_DESTROYED_MSG	BIT(1)
698dde314bSBalint Dobszay 
708d2d14e5SBalint Dobszay #define SP_PKG_HEADER_MAGIC (0x474b5053)
7163a75748SImre Kis #define SP_PKG_HEADER_VERSION_V1 (0x1)
7263a75748SImre Kis #define SP_PKG_HEADER_VERSION_V2 (0x2)
738d2d14e5SBalint Dobszay 
748d2d14e5SBalint Dobszay struct sp_pkg_header {
758d2d14e5SBalint Dobszay 	uint32_t magic;
768d2d14e5SBalint Dobszay 	uint32_t version;
778d2d14e5SBalint Dobszay 	uint32_t pm_offset;
788d2d14e5SBalint Dobszay 	uint32_t pm_size;
798d2d14e5SBalint Dobszay 	uint32_t img_offset;
808d2d14e5SBalint Dobszay 	uint32_t img_size;
818d2d14e5SBalint Dobszay };
828d2d14e5SBalint Dobszay 
838d2d14e5SBalint Dobszay struct fip_sp_head fip_sp_list = STAILQ_HEAD_INITIALIZER(fip_sp_list);
848d2d14e5SBalint Dobszay 
85593b94eeSJens Wiklander static const struct ts_ops sp_ops;
86c185655eSJelle Sels 
87c185655eSJelle Sels /* List that holds all of the loaded SP's */
88c185655eSJelle Sels static struct sp_sessions_head open_sp_sessions =
89c185655eSJelle Sels 	TAILQ_HEAD_INITIALIZER(open_sp_sessions);
90c185655eSJelle Sels 
find_secure_partition(const TEE_UUID * uuid)91dea46be3SJelle Sels static const struct embedded_ts *find_secure_partition(const TEE_UUID *uuid)
92dea46be3SJelle Sels {
93e23cd783SJelle Sels 	const struct sp_image *sp = NULL;
948d2d14e5SBalint Dobszay 	const struct fip_sp *fip_sp = NULL;
95dea46be3SJelle Sels 
96c185655eSJelle Sels 	for_each_secure_partition(sp) {
97e23cd783SJelle Sels 		if (!memcmp(&sp->image.uuid, uuid, sizeof(*uuid)))
98e23cd783SJelle Sels 			return &sp->image;
99c185655eSJelle Sels 	}
1008d2d14e5SBalint Dobszay 
1018d2d14e5SBalint Dobszay 	for_each_fip_sp(fip_sp) {
1028d2d14e5SBalint Dobszay 		if (!memcmp(&fip_sp->sp_img.image.uuid, uuid, sizeof(*uuid)))
1038d2d14e5SBalint Dobszay 			return &fip_sp->sp_img.image;
1048d2d14e5SBalint Dobszay 	}
1058d2d14e5SBalint Dobszay 
106c185655eSJelle Sels 	return NULL;
107c185655eSJelle Sels }
108c185655eSJelle Sels 
is_sp_ctx(struct ts_ctx * ctx)109c185655eSJelle Sels bool is_sp_ctx(struct ts_ctx *ctx)
110c185655eSJelle Sels {
1117213740bSJens Wiklander 	return ctx && (ctx->ops == &sp_ops);
112c185655eSJelle Sels }
113c185655eSJelle Sels 
set_sp_ctx_ops(struct ts_ctx * ctx)114c185655eSJelle Sels static void set_sp_ctx_ops(struct ts_ctx *ctx)
115c185655eSJelle Sels {
1167213740bSJens Wiklander 	ctx->ops = &sp_ops;
117c185655eSJelle Sels }
118c185655eSJelle Sels 
sp_get_session(uint32_t session_id)119c185655eSJelle Sels struct sp_session *sp_get_session(uint32_t session_id)
120c185655eSJelle Sels {
121c185655eSJelle Sels 	struct sp_session *s = NULL;
122c185655eSJelle Sels 
123c185655eSJelle Sels 	TAILQ_FOREACH(s, &open_sp_sessions, link) {
124c185655eSJelle Sels 		if (s->endpoint_id == session_id)
125c185655eSJelle Sels 			return s;
126c185655eSJelle Sels 	}
127dea46be3SJelle Sels 
128dea46be3SJelle Sels 	return NULL;
129dea46be3SJelle Sels }
130dea46be3SJelle Sels 
sp_partition_info_get(uint32_t ffa_vers,void * buf,size_t buf_size,const uint32_t ffa_uuid_words[4],size_t * elem_count,bool count_only)131a1c53023SJens Wiklander TEE_Result sp_partition_info_get(uint32_t ffa_vers, void *buf, size_t buf_size,
1325c85c87eSJens Wiklander 				 const uint32_t ffa_uuid_words[4],
1335c85c87eSJens Wiklander 				 size_t *elem_count, bool count_only)
1343a7bfc34SJelle Sels {
135a1c53023SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
1363a7bfc34SJelle Sels 	struct sp_session *s = NULL;
1375c85c87eSJens Wiklander 	TEE_UUID uuid = { };
1385c85c87eSJens Wiklander 	TEE_UUID *ffa_uuid = NULL;
139*82d5d8ccSJens Wiklander 	enum sp_status st = sp_idle;
1405c85c87eSJens Wiklander 
1415c85c87eSJens Wiklander 	if (ffa_uuid_words) {
1425c85c87eSJens Wiklander 		tee_uuid_from_octets(&uuid, (void *)ffa_uuid_words);
1435c85c87eSJens Wiklander 		ffa_uuid = &uuid;
1445c85c87eSJens Wiklander 	}
1453a7bfc34SJelle Sels 
1463a7bfc34SJelle Sels 	TAILQ_FOREACH(s, &open_sp_sessions, link) {
147552d5e40SJelle Sels 		if (ffa_uuid &&
148552d5e40SJelle Sels 		    memcmp(&s->ffa_uuid, ffa_uuid, sizeof(*ffa_uuid)))
149552d5e40SJelle Sels 			continue;
150552d5e40SJelle Sels 
151*82d5d8ccSJens Wiklander 		cpu_spin_lock(&s->spinlock);
152*82d5d8ccSJens Wiklander 		st = s->state;
153*82d5d8ccSJens Wiklander 		cpu_spin_unlock(&s->spinlock);
154*82d5d8ccSJens Wiklander 		if (st == sp_dead)
1553a7bfc34SJelle Sels 			continue;
156*82d5d8ccSJens Wiklander 
157a1c53023SJens Wiklander 		if (!count_only && !res) {
158a1c53023SJens Wiklander 			uint32_t uuid_words[4] = { 0 };
159a1c53023SJens Wiklander 
160a1c53023SJens Wiklander 			tee_uuid_to_octets((uint8_t *)uuid_words, &s->ffa_uuid);
161a1c53023SJens Wiklander 			res = spmc_fill_partition_entry(ffa_vers, buf, buf_size,
162a1c53023SJens Wiklander 							*elem_count,
163a1c53023SJens Wiklander 							s->endpoint_id, 1,
164cc04f76fSBalint Dobszay 							s->props, uuid_words);
1653a7bfc34SJelle Sels 		}
166a1c53023SJens Wiklander 		*elem_count += 1;
1673a7bfc34SJelle Sels 	}
1683a7bfc34SJelle Sels 
169a1c53023SJens Wiklander 	return res;
1703a7bfc34SJelle Sels }
1713a7bfc34SJelle Sels 
sp_has_exclusive_access(struct sp_mem_map_region * mem,struct user_mode_ctx * uctx)17272ede99eSJelle Sels bool sp_has_exclusive_access(struct sp_mem_map_region *mem,
17372ede99eSJelle Sels 			     struct user_mode_ctx *uctx)
17472ede99eSJelle Sels {
17572ede99eSJelle Sels 	/*
17672ede99eSJelle Sels 	 * Check that we have access to the region if it is supposed to be
17772ede99eSJelle Sels 	 * mapped to the current context.
17872ede99eSJelle Sels 	 */
17972ede99eSJelle Sels 	if (uctx) {
18072ede99eSJelle Sels 		struct vm_region *region = NULL;
18172ede99eSJelle Sels 
18272ede99eSJelle Sels 		/* Make sure that each mobj belongs to the SP */
18372ede99eSJelle Sels 		TAILQ_FOREACH(region, &uctx->vm_info.regions, link) {
18472ede99eSJelle Sels 			if (region->mobj == mem->mobj)
18572ede99eSJelle Sels 				break;
18672ede99eSJelle Sels 		}
18772ede99eSJelle Sels 
18872ede99eSJelle Sels 		if (!region)
18972ede99eSJelle Sels 			return false;
19072ede99eSJelle Sels 	}
19172ede99eSJelle Sels 
19272ede99eSJelle Sels 	/* Check that it is not shared with another SP */
19372ede99eSJelle Sels 	return !sp_mem_is_shared(mem);
19472ede99eSJelle Sels }
19572ede99eSJelle Sels 
endpoint_id_is_valid(uint32_t id)19619ad526cSBalint Dobszay static bool endpoint_id_is_valid(uint32_t id)
19719ad526cSBalint Dobszay {
19819ad526cSBalint Dobszay 	/*
19919ad526cSBalint Dobszay 	 * These IDs are assigned at the SPMC init so already have valid values
20019ad526cSBalint Dobszay 	 * by the time this function gets first called
20119ad526cSBalint Dobszay 	 */
202ecf08061SJens Wiklander 	return !spmc_is_reserved_id(id) && !spmc_find_lsp_by_sp_id(id) &&
20319ad526cSBalint Dobszay 	       id >= FFA_SWD_ID_MIN && id <= FFA_SWD_ID_MAX;
20419ad526cSBalint Dobszay }
20519ad526cSBalint Dobszay 
new_session_id(uint16_t * endpoint_id)206d10a438bSGabor Ambrus static TEE_Result new_session_id(uint16_t *endpoint_id)
207c185655eSJelle Sels {
20819ad526cSBalint Dobszay 	uint32_t id = 0;
209c185655eSJelle Sels 
210d10a438bSGabor Ambrus 	/* Find the first available endpoint id */
21119ad526cSBalint Dobszay 	for (id = FFA_SWD_ID_MIN; id <= FFA_SWD_ID_MAX; id++) {
21219ad526cSBalint Dobszay 		if (endpoint_id_is_valid(id) && !sp_get_session(id)) {
21319ad526cSBalint Dobszay 			*endpoint_id = id;
214d10a438bSGabor Ambrus 			return TEE_SUCCESS;
215c185655eSJelle Sels 		}
21619ad526cSBalint Dobszay 	}
21719ad526cSBalint Dobszay 
21819ad526cSBalint Dobszay 	return TEE_ERROR_BAD_FORMAT;
21919ad526cSBalint Dobszay }
220c185655eSJelle Sels 
sp_create_ctx(const TEE_UUID * bin_uuid,struct sp_session * s)221552d5e40SJelle Sels static TEE_Result sp_create_ctx(const TEE_UUID *bin_uuid, struct sp_session *s)
222c185655eSJelle Sels {
223c185655eSJelle Sels 	TEE_Result res = TEE_SUCCESS;
224c185655eSJelle Sels 	struct sp_ctx *spc = NULL;
225c185655eSJelle Sels 
226c185655eSJelle Sels 	/* Register context */
227c185655eSJelle Sels 	spc = calloc(1, sizeof(struct sp_ctx));
228c185655eSJelle Sels 	if (!spc)
229c185655eSJelle Sels 		return TEE_ERROR_OUT_OF_MEMORY;
230c185655eSJelle Sels 
231c185655eSJelle Sels 	spc->open_session = s;
232c185655eSJelle Sels 	s->ts_sess.ctx = &spc->ts_ctx;
233552d5e40SJelle Sels 	spc->ts_ctx.uuid = *bin_uuid;
234c185655eSJelle Sels 
23560d3fc69SJens Wiklander 	res = vm_info_init(&spc->uctx, &spc->ts_ctx);
236c185655eSJelle Sels 	if (res)
237c185655eSJelle Sels 		goto err;
238c185655eSJelle Sels 
239c185655eSJelle Sels 	set_sp_ctx_ops(&spc->ts_ctx);
240c185655eSJelle Sels 
241d19343acSGabor Toth #ifdef CFG_TA_PAUTH
242d19343acSGabor Toth 	crypto_rng_read(&spc->uctx.keys, sizeof(spc->uctx.keys));
243d19343acSGabor Toth #endif
244d19343acSGabor Toth 
245c185655eSJelle Sels 	return TEE_SUCCESS;
246c185655eSJelle Sels 
247c185655eSJelle Sels err:
248c185655eSJelle Sels 	free(spc);
249c185655eSJelle Sels 	return res;
250c185655eSJelle Sels }
251c185655eSJelle Sels 
252d10a438bSGabor Ambrus /*
253d10a438bSGabor Ambrus  * Insert a new sp_session to the sessions list, so that it is ordered
254d10a438bSGabor Ambrus  * by boot_order.
255d10a438bSGabor Ambrus  */
insert_session_ordered(struct sp_sessions_head * open_sessions,struct sp_session * session)256d10a438bSGabor Ambrus static void insert_session_ordered(struct sp_sessions_head *open_sessions,
257d10a438bSGabor Ambrus 				   struct sp_session *session)
258d10a438bSGabor Ambrus {
259d10a438bSGabor Ambrus 	struct sp_session *s = NULL;
260d10a438bSGabor Ambrus 
261d10a438bSGabor Ambrus 	if (!open_sessions || !session)
262d10a438bSGabor Ambrus 		return;
263d10a438bSGabor Ambrus 
264d10a438bSGabor Ambrus 	TAILQ_FOREACH(s, &open_sp_sessions, link) {
265d10a438bSGabor Ambrus 		if (s->boot_order > session->boot_order)
266d10a438bSGabor Ambrus 			break;
267d10a438bSGabor Ambrus 	}
268d10a438bSGabor Ambrus 
269d10a438bSGabor Ambrus 	if (!s)
270d10a438bSGabor Ambrus 		TAILQ_INSERT_TAIL(open_sessions, session, link);
271d10a438bSGabor Ambrus 	else
272d10a438bSGabor Ambrus 		TAILQ_INSERT_BEFORE(s, session, link);
273d10a438bSGabor Ambrus }
274d10a438bSGabor Ambrus 
sp_create_session(struct sp_sessions_head * open_sessions,const TEE_UUID * bin_uuid,const uint32_t boot_order,struct sp_session ** sess)275c185655eSJelle Sels static TEE_Result sp_create_session(struct sp_sessions_head *open_sessions,
276552d5e40SJelle Sels 				    const TEE_UUID *bin_uuid,
277d10a438bSGabor Ambrus 				    const uint32_t boot_order,
278c185655eSJelle Sels 				    struct sp_session **sess)
279c185655eSJelle Sels {
280c185655eSJelle Sels 	TEE_Result res = TEE_SUCCESS;
281c185655eSJelle Sels 	struct sp_session *s = calloc(1, sizeof(struct sp_session));
282c185655eSJelle Sels 
283c185655eSJelle Sels 	if (!s)
284c185655eSJelle Sels 		return TEE_ERROR_OUT_OF_MEMORY;
285c185655eSJelle Sels 
286d10a438bSGabor Ambrus 	s->boot_order = boot_order;
287d10a438bSGabor Ambrus 
288cc04f76fSBalint Dobszay 	/* Other properties are filled later, based on the SP's manifest */
289cc04f76fSBalint Dobszay 	s->props = FFA_PART_PROP_IS_PE_ID;
290cc04f76fSBalint Dobszay 
291d10a438bSGabor Ambrus 	res = new_session_id(&s->endpoint_id);
292d10a438bSGabor Ambrus 	if (res)
293c185655eSJelle Sels 		goto err;
294c185655eSJelle Sels 
295552d5e40SJelle Sels 	DMSG("Loading Secure Partition %pUl", (void *)bin_uuid);
296552d5e40SJelle Sels 	res = sp_create_ctx(bin_uuid, s);
297c185655eSJelle Sels 	if (res)
298c185655eSJelle Sels 		goto err;
299c185655eSJelle Sels 
300d10a438bSGabor Ambrus 	insert_session_ordered(open_sessions, s);
301c185655eSJelle Sels 	*sess = s;
302c185655eSJelle Sels 	return TEE_SUCCESS;
303c185655eSJelle Sels 
304c185655eSJelle Sels err:
305c185655eSJelle Sels 	free(s);
306c185655eSJelle Sels 	return res;
307c185655eSJelle Sels }
308c185655eSJelle Sels 
sp_init_set_registers(struct sp_ctx * ctx)309c185655eSJelle Sels static TEE_Result sp_init_set_registers(struct sp_ctx *ctx)
310c185655eSJelle Sels {
311c185655eSJelle Sels 	struct thread_ctx_regs *sp_regs = &ctx->sp_regs;
312c185655eSJelle Sels 
313c185655eSJelle Sels 	memset(sp_regs, 0, sizeof(*sp_regs));
314c185655eSJelle Sels 	sp_regs->sp = ctx->uctx.stack_ptr;
315c185655eSJelle Sels 	sp_regs->pc = ctx->uctx.entry_func;
316c185655eSJelle Sels 
317c185655eSJelle Sels 	return TEE_SUCCESS;
318c185655eSJelle Sels }
319c185655eSJelle Sels 
sp_map_shared(struct sp_session * s,struct sp_mem_receiver * receiver,struct sp_mem * smem,uint64_t * va)320de66193dSJelle Sels TEE_Result sp_map_shared(struct sp_session *s,
321de66193dSJelle Sels 			 struct sp_mem_receiver *receiver,
322de66193dSJelle Sels 			 struct sp_mem *smem,
323de66193dSJelle Sels 			 uint64_t *va)
324de66193dSJelle Sels {
325de66193dSJelle Sels 	TEE_Result res = TEE_SUCCESS;
326de66193dSJelle Sels 	struct sp_ctx *ctx = NULL;
327de66193dSJelle Sels 	uint32_t perm = TEE_MATTR_UR;
328de66193dSJelle Sels 	struct sp_mem_map_region *reg = NULL;
329de66193dSJelle Sels 
330de66193dSJelle Sels 	ctx = to_sp_ctx(s->ts_sess.ctx);
331de66193dSJelle Sels 
332de66193dSJelle Sels 	/* Get the permission */
333de66193dSJelle Sels 	if (receiver->perm.perm & FFA_MEM_ACC_EXE)
334de66193dSJelle Sels 		perm |= TEE_MATTR_UX;
335de66193dSJelle Sels 
336de66193dSJelle Sels 	if (receiver->perm.perm & FFA_MEM_ACC_RW) {
337de66193dSJelle Sels 		if (receiver->perm.perm & FFA_MEM_ACC_EXE)
338de66193dSJelle Sels 			return TEE_ERROR_ACCESS_CONFLICT;
339de66193dSJelle Sels 
340de66193dSJelle Sels 		perm |= TEE_MATTR_UW;
341de66193dSJelle Sels 	}
342de66193dSJelle Sels 	/*
343de66193dSJelle Sels 	 * Currently we don't support passing a va. We can't guarantee that the
344de66193dSJelle Sels 	 * full region will be mapped in a contiguous region. A smem->region can
345de66193dSJelle Sels 	 * have multiple mobj for one share. Currently there doesn't seem to be
346de66193dSJelle Sels 	 * an option to guarantee that these will be mapped in a contiguous va
347de66193dSJelle Sels 	 * space.
348de66193dSJelle Sels 	 */
349de66193dSJelle Sels 	if (*va)
350de66193dSJelle Sels 		return TEE_ERROR_NOT_SUPPORTED;
351de66193dSJelle Sels 
352de66193dSJelle Sels 	SLIST_FOREACH(reg, &smem->regions, link) {
353de66193dSJelle Sels 		res = vm_map(&ctx->uctx, va, reg->page_count * SMALL_PAGE_SIZE,
354de66193dSJelle Sels 			     perm, 0, reg->mobj, reg->page_offset);
355de66193dSJelle Sels 
356de66193dSJelle Sels 		if (res != TEE_SUCCESS) {
357de66193dSJelle Sels 			EMSG("Failed to map memory region %#"PRIx32, res);
358de66193dSJelle Sels 			return res;
359de66193dSJelle Sels 		}
360de66193dSJelle Sels 	}
361de66193dSJelle Sels 	return TEE_SUCCESS;
362de66193dSJelle Sels }
363de66193dSJelle Sels 
sp_unmap_ffa_regions(struct sp_session * s,struct sp_mem * smem)364c1aadcc7SJelle Sels TEE_Result sp_unmap_ffa_regions(struct sp_session *s, struct sp_mem *smem)
365c1aadcc7SJelle Sels {
366c1aadcc7SJelle Sels 	TEE_Result res = TEE_SUCCESS;
367c1aadcc7SJelle Sels 	vaddr_t vaddr = 0;
368c1aadcc7SJelle Sels 	size_t len = 0;
369c1aadcc7SJelle Sels 	struct sp_ctx *ctx = to_sp_ctx(s->ts_sess.ctx);
370c1aadcc7SJelle Sels 	struct sp_mem_map_region *reg = NULL;
371c1aadcc7SJelle Sels 
372c1aadcc7SJelle Sels 	SLIST_FOREACH(reg, &smem->regions, link) {
373c1aadcc7SJelle Sels 		vaddr = (vaddr_t)sp_mem_get_va(&ctx->uctx, reg->page_offset,
374c1aadcc7SJelle Sels 					       reg->mobj);
375c1aadcc7SJelle Sels 		len = reg->page_count * SMALL_PAGE_SIZE;
376c1aadcc7SJelle Sels 
377c1aadcc7SJelle Sels 		res = vm_unmap(&ctx->uctx, vaddr, len);
378c1aadcc7SJelle Sels 		if (res != TEE_SUCCESS)
379c1aadcc7SJelle Sels 			return res;
380c1aadcc7SJelle Sels 	}
381c1aadcc7SJelle Sels 
382c1aadcc7SJelle Sels 	return TEE_SUCCESS;
383c1aadcc7SJelle Sels }
384c1aadcc7SJelle Sels 
sp_dt_get_u64(const void * fdt,int node,const char * property,uint64_t * value)3856d618ba1SJelle Sels static TEE_Result sp_dt_get_u64(const void *fdt, int node, const char *property,
3866d618ba1SJelle Sels 				uint64_t *value)
3876d618ba1SJelle Sels {
3886d618ba1SJelle Sels 	const fdt64_t *p = NULL;
3896d618ba1SJelle Sels 	int len = 0;
3906d618ba1SJelle Sels 
3916d618ba1SJelle Sels 	p = fdt_getprop(fdt, node, property, &len);
3922fe8f2a0SImre Kis 	if (!p)
3936d618ba1SJelle Sels 		return TEE_ERROR_ITEM_NOT_FOUND;
3946d618ba1SJelle Sels 
3952fe8f2a0SImre Kis 	if (len != sizeof(*p))
3962fe8f2a0SImre Kis 		return TEE_ERROR_BAD_FORMAT;
3972fe8f2a0SImre Kis 
398c9dad419SBalint Dobszay 	*value = fdt64_ld(p);
3996d618ba1SJelle Sels 
4006d618ba1SJelle Sels 	return TEE_SUCCESS;
4016d618ba1SJelle Sels }
4026d618ba1SJelle Sels 
sp_dt_get_u32(const void * fdt,int node,const char * property,uint32_t * value)4036d618ba1SJelle Sels static TEE_Result sp_dt_get_u32(const void *fdt, int node, const char *property,
4046d618ba1SJelle Sels 				uint32_t *value)
4056d618ba1SJelle Sels {
4066d618ba1SJelle Sels 	const fdt32_t *p = NULL;
4076d618ba1SJelle Sels 	int len = 0;
4086d618ba1SJelle Sels 
4096d618ba1SJelle Sels 	p = fdt_getprop(fdt, node, property, &len);
4102fe8f2a0SImre Kis 	if (!p)
4116d618ba1SJelle Sels 		return TEE_ERROR_ITEM_NOT_FOUND;
4126d618ba1SJelle Sels 
4132fe8f2a0SImre Kis 	if (len != sizeof(*p))
4142fe8f2a0SImre Kis 		return TEE_ERROR_BAD_FORMAT;
4152fe8f2a0SImre Kis 
4166d618ba1SJelle Sels 	*value = fdt32_to_cpu(*p);
4176d618ba1SJelle Sels 
4186d618ba1SJelle Sels 	return TEE_SUCCESS;
4196d618ba1SJelle Sels }
4206d618ba1SJelle Sels 
sp_dt_get_u16(const void * fdt,int node,const char * property,uint16_t * value)421d10a438bSGabor Ambrus static TEE_Result sp_dt_get_u16(const void *fdt, int node, const char *property,
422d10a438bSGabor Ambrus 				uint16_t *value)
423d10a438bSGabor Ambrus {
424d10a438bSGabor Ambrus 	const fdt16_t *p = NULL;
425d10a438bSGabor Ambrus 	int len = 0;
426d10a438bSGabor Ambrus 
427d10a438bSGabor Ambrus 	p = fdt_getprop(fdt, node, property, &len);
428d10a438bSGabor Ambrus 	if (!p)
429d10a438bSGabor Ambrus 		return TEE_ERROR_ITEM_NOT_FOUND;
430d10a438bSGabor Ambrus 
431d10a438bSGabor Ambrus 	if (len != sizeof(*p))
432d10a438bSGabor Ambrus 		return TEE_ERROR_BAD_FORMAT;
433d10a438bSGabor Ambrus 
434d10a438bSGabor Ambrus 	*value = fdt16_to_cpu(*p);
435d10a438bSGabor Ambrus 
436d10a438bSGabor Ambrus 	return TEE_SUCCESS;
437d10a438bSGabor Ambrus }
438d10a438bSGabor Ambrus 
sp_dt_get_uuid(const void * fdt,int node,const char * property,TEE_UUID * uuid)4397eda852fSBalint Dobszay static TEE_Result sp_dt_get_uuid(const void *fdt, int node,
4407eda852fSBalint Dobszay 				 const char *property, TEE_UUID *uuid)
4417eda852fSBalint Dobszay {
4427eda852fSBalint Dobszay 	uint32_t uuid_array[4] = { 0 };
4437eda852fSBalint Dobszay 	const fdt32_t *p = NULL;
4447eda852fSBalint Dobszay 	int len = 0;
4457eda852fSBalint Dobszay 	int i = 0;
4467eda852fSBalint Dobszay 
4477eda852fSBalint Dobszay 	p = fdt_getprop(fdt, node, property, &len);
4482fe8f2a0SImre Kis 	if (!p)
4497eda852fSBalint Dobszay 		return TEE_ERROR_ITEM_NOT_FOUND;
4507eda852fSBalint Dobszay 
4512fe8f2a0SImre Kis 	if (len != sizeof(TEE_UUID))
4522fe8f2a0SImre Kis 		return TEE_ERROR_BAD_FORMAT;
4532fe8f2a0SImre Kis 
4547eda852fSBalint Dobszay 	for (i = 0; i < 4; i++)
4557eda852fSBalint Dobszay 		uuid_array[i] = fdt32_to_cpu(p[i]);
4567eda852fSBalint Dobszay 
4577eda852fSBalint Dobszay 	tee_uuid_from_octets(uuid, (uint8_t *)uuid_array);
4587eda852fSBalint Dobszay 
4597eda852fSBalint Dobszay 	return TEE_SUCCESS;
4607eda852fSBalint Dobszay }
4617eda852fSBalint Dobszay 
sp_is_elf_format(const void * fdt,int sp_node,bool * is_elf_format)4623a735b93SImre Kis static TEE_Result sp_is_elf_format(const void *fdt, int sp_node,
4633a735b93SImre Kis 				   bool *is_elf_format)
4643a735b93SImre Kis {
4653a735b93SImre Kis 	TEE_Result res = TEE_SUCCESS;
4663a735b93SImre Kis 	uint32_t elf_format = 0;
4673a735b93SImre Kis 
4683a735b93SImre Kis 	res = sp_dt_get_u32(fdt, sp_node, "elf-format", &elf_format);
4693a735b93SImre Kis 	if (res != TEE_SUCCESS && res != TEE_ERROR_ITEM_NOT_FOUND)
4703a735b93SImre Kis 		return res;
4713a735b93SImre Kis 
4723a735b93SImre Kis 	*is_elf_format = (elf_format != 0);
4733a735b93SImre Kis 
4743a735b93SImre Kis 	return TEE_SUCCESS;
4753a735b93SImre Kis }
4763a735b93SImre Kis 
sp_binary_open(const TEE_UUID * uuid,const struct ts_store_ops ** ops,struct ts_store_handle ** handle)4773a735b93SImre Kis static TEE_Result sp_binary_open(const TEE_UUID *uuid,
4783a735b93SImre Kis 				 const struct ts_store_ops **ops,
4793a735b93SImre Kis 				 struct ts_store_handle **handle)
4803a735b93SImre Kis {
4813a735b93SImre Kis 	TEE_Result res = TEE_ERROR_ITEM_NOT_FOUND;
4823a735b93SImre Kis 
4833a735b93SImre Kis 	SCATTERED_ARRAY_FOREACH(*ops, sp_stores, struct ts_store_ops) {
4843a735b93SImre Kis 		res = (*ops)->open(uuid, handle);
4853a735b93SImre Kis 		if (res != TEE_ERROR_ITEM_NOT_FOUND &&
4863a735b93SImre Kis 		    res != TEE_ERROR_STORAGE_NOT_AVAILABLE)
4873a735b93SImre Kis 			break;
4883a735b93SImre Kis 	}
4893a735b93SImre Kis 
4903a735b93SImre Kis 	return res;
4913a735b93SImre Kis }
4923a735b93SImre Kis 
load_binary_sp(struct ts_session * s,struct user_mode_ctx * uctx)4933a735b93SImre Kis static TEE_Result load_binary_sp(struct ts_session *s,
4943a735b93SImre Kis 				 struct user_mode_ctx *uctx)
4953a735b93SImre Kis {
4963a735b93SImre Kis 	size_t bin_size = 0, bin_size_rounded = 0, bin_page_count = 0;
4975f1edb13SBalint Dobszay 	size_t bb_size = ROUNDUP(BOUNCE_BUFFER_SIZE, SMALL_PAGE_SIZE);
4985f1edb13SBalint Dobszay 	size_t bb_num_pages = bb_size / SMALL_PAGE_SIZE;
4993a735b93SImre Kis 	const struct ts_store_ops *store_ops = NULL;
5003a735b93SImre Kis 	struct ts_store_handle *handle = NULL;
5013a735b93SImre Kis 	TEE_Result res = TEE_SUCCESS;
5023a735b93SImre Kis 	tee_mm_entry_t *mm = NULL;
5035f1edb13SBalint Dobszay 	struct fobj *fobj = NULL;
5043a735b93SImre Kis 	struct mobj *mobj = NULL;
5053a735b93SImre Kis 	uaddr_t base_addr = 0;
5063a735b93SImre Kis 	uint32_t vm_flags = 0;
5073a735b93SImre Kis 	unsigned int idx = 0;
5083a735b93SImre Kis 	vaddr_t va = 0;
5093a735b93SImre Kis 
5103a735b93SImre Kis 	if (!s || !uctx)
5113a735b93SImre Kis 		return TEE_ERROR_BAD_PARAMETERS;
5123a735b93SImre Kis 
5133a735b93SImre Kis 	DMSG("Loading raw binary format SP %pUl", &uctx->ts_ctx->uuid);
5143a735b93SImre Kis 
5155f1edb13SBalint Dobszay 	/* Initialize the bounce buffer */
5165f1edb13SBalint Dobszay 	fobj = fobj_sec_mem_alloc(bb_num_pages);
5175f1edb13SBalint Dobszay 	mobj = mobj_with_fobj_alloc(fobj, NULL, TEE_MATTR_MEM_TYPE_TAGGED);
5185f1edb13SBalint Dobszay 	fobj_put(fobj);
5195f1edb13SBalint Dobszay 	if (!mobj)
5205f1edb13SBalint Dobszay 		return TEE_ERROR_OUT_OF_MEMORY;
5215f1edb13SBalint Dobszay 
5225f1edb13SBalint Dobszay 	res = vm_map(uctx, &va, bb_size, TEE_MATTR_PRW, 0, mobj, 0);
5235f1edb13SBalint Dobszay 	mobj_put(mobj);
5245f1edb13SBalint Dobszay 	if (res)
5255f1edb13SBalint Dobszay 		return res;
5265f1edb13SBalint Dobszay 
5275f1edb13SBalint Dobszay 	uctx->bbuf = (uint8_t *)va;
5285f1edb13SBalint Dobszay 	uctx->bbuf_size = BOUNCE_BUFFER_SIZE;
5295f1edb13SBalint Dobszay 
5303a735b93SImre Kis 	vm_set_ctx(uctx->ts_ctx);
5313a735b93SImre Kis 
5323a735b93SImre Kis 	/* Find TS store and open SP binary */
5333a735b93SImre Kis 	res = sp_binary_open(&uctx->ts_ctx->uuid, &store_ops, &handle);
5343a735b93SImre Kis 	if (res != TEE_SUCCESS) {
5353a735b93SImre Kis 		EMSG("Failed to open SP binary");
5363a735b93SImre Kis 		return res;
5373a735b93SImre Kis 	}
5383a735b93SImre Kis 
5393a735b93SImre Kis 	/* Query binary size and calculate page count */
5403a735b93SImre Kis 	res = store_ops->get_size(handle, &bin_size);
5413a735b93SImre Kis 	if (res != TEE_SUCCESS)
5423a735b93SImre Kis 		goto err;
5433a735b93SImre Kis 
5443a735b93SImre Kis 	if (ROUNDUP_OVERFLOW(bin_size, SMALL_PAGE_SIZE, &bin_size_rounded)) {
5453a735b93SImre Kis 		res = TEE_ERROR_OVERFLOW;
5463a735b93SImre Kis 		goto err;
5473a735b93SImre Kis 	}
5483a735b93SImre Kis 
5493a735b93SImre Kis 	bin_page_count = bin_size_rounded / SMALL_PAGE_SIZE;
5503a735b93SImre Kis 
5513a735b93SImre Kis 	/* Allocate memory */
552de19cacbSJens Wiklander 	mm = phys_mem_ta_alloc(bin_size_rounded);
5533a735b93SImre Kis 	if (!mm) {
5543a735b93SImre Kis 		res = TEE_ERROR_OUT_OF_MEMORY;
5553a735b93SImre Kis 		goto err;
5563a735b93SImre Kis 	}
5573a735b93SImre Kis 
5583a735b93SImre Kis 	base_addr = tee_mm_get_smem(mm);
5593a735b93SImre Kis 
5603a735b93SImre Kis 	/* Create mobj */
5613a735b93SImre Kis 	mobj = sp_mem_new_mobj(bin_page_count, TEE_MATTR_MEM_TYPE_CACHED, true);
5623a735b93SImre Kis 	if (!mobj) {
5633a735b93SImre Kis 		res = TEE_ERROR_OUT_OF_MEMORY;
5643a735b93SImre Kis 		goto err_free_tee_mm;
5653a735b93SImre Kis 	}
5663a735b93SImre Kis 
5673a735b93SImre Kis 	res = sp_mem_add_pages(mobj, &idx, base_addr, bin_page_count);
5683a735b93SImre Kis 	if (res)
5693a735b93SImre Kis 		goto err_free_mobj;
5703a735b93SImre Kis 
5713a735b93SImre Kis 	/* Map memory area for the SP binary */
5725f1edb13SBalint Dobszay 	va = 0;
5733a735b93SImre Kis 	res = vm_map(uctx, &va, bin_size_rounded, TEE_MATTR_URWX,
5743a735b93SImre Kis 		     vm_flags, mobj, 0);
5753a735b93SImre Kis 	if (res)
5763a735b93SImre Kis 		goto err_free_mobj;
5773a735b93SImre Kis 
5783a735b93SImre Kis 	/* Read SP binary into the previously mapped memory area */
579ef44161fSJens Wiklander 	res = store_ops->read(handle, NULL, (void *)va, bin_size);
5803a735b93SImre Kis 	if (res)
5813a735b93SImre Kis 		goto err_unmap;
5823a735b93SImre Kis 
5833a735b93SImre Kis 	/* Set memory protection to allow execution */
5843a735b93SImre Kis 	res = vm_set_prot(uctx, va, bin_size_rounded, TEE_MATTR_UX);
5853a735b93SImre Kis 	if (res)
5863a735b93SImre Kis 		goto err_unmap;
5873a735b93SImre Kis 
5883a735b93SImre Kis 	mobj_put(mobj);
5893a735b93SImre Kis 	store_ops->close(handle);
5903a735b93SImre Kis 
5913a735b93SImre Kis 	/* The entry point must be at the beginning of the SP binary. */
5923a735b93SImre Kis 	uctx->entry_func = va;
5933a735b93SImre Kis 	uctx->load_addr = va;
5943a735b93SImre Kis 	uctx->is_32bit = false;
5953a735b93SImre Kis 
5963a735b93SImre Kis 	s->handle_scall = s->ctx->ops->handle_scall;
5973a735b93SImre Kis 
5983a735b93SImre Kis 	return TEE_SUCCESS;
5993a735b93SImre Kis 
6003a735b93SImre Kis err_unmap:
6013a735b93SImre Kis 	vm_unmap(uctx, va, bin_size_rounded);
6023a735b93SImre Kis 
6033a735b93SImre Kis err_free_mobj:
6043a735b93SImre Kis 	mobj_put(mobj);
6053a735b93SImre Kis 
6063a735b93SImre Kis err_free_tee_mm:
6073a735b93SImre Kis 	tee_mm_free(mm);
6083a735b93SImre Kis 
6093a735b93SImre Kis err:
6103a735b93SImre Kis 	store_ops->close(handle);
6113a735b93SImre Kis 
6123a735b93SImre Kis 	return res;
6133a735b93SImre Kis }
6143a735b93SImre Kis 
sp_open_session(struct sp_session ** sess,struct sp_sessions_head * open_sessions,const TEE_UUID * ffa_uuid,const TEE_UUID * bin_uuid,const uint32_t boot_order,const void * fdt)6153a735b93SImre Kis static TEE_Result sp_open_session(struct sp_session **sess,
6163a735b93SImre Kis 				  struct sp_sessions_head *open_sessions,
617552d5e40SJelle Sels 				  const TEE_UUID *ffa_uuid,
618552d5e40SJelle Sels 				  const TEE_UUID *bin_uuid,
619d10a438bSGabor Ambrus 				  const uint32_t boot_order,
6203a735b93SImre Kis 				  const void *fdt)
6213a735b93SImre Kis {
6223a735b93SImre Kis 	TEE_Result res = TEE_SUCCESS;
6233a735b93SImre Kis 	struct sp_session *s = NULL;
6243a735b93SImre Kis 	struct sp_ctx *ctx = NULL;
6253a735b93SImre Kis 	bool is_elf_format = false;
6263a735b93SImre Kis 
627552d5e40SJelle Sels 	if (!find_secure_partition(bin_uuid))
6283a735b93SImre Kis 		return TEE_ERROR_ITEM_NOT_FOUND;
6293a735b93SImre Kis 
630d10a438bSGabor Ambrus 	res = sp_create_session(open_sessions, bin_uuid, boot_order, &s);
6313a735b93SImre Kis 	if (res != TEE_SUCCESS) {
6323a735b93SImre Kis 		DMSG("sp_create_session failed %#"PRIx32, res);
6333a735b93SImre Kis 		return res;
6343a735b93SImre Kis 	}
6353a735b93SImre Kis 
6363a735b93SImre Kis 	ctx = to_sp_ctx(s->ts_sess.ctx);
6373a735b93SImre Kis 	assert(ctx);
6383a735b93SImre Kis 	if (!ctx)
6393a735b93SImre Kis 		return TEE_ERROR_TARGET_DEAD;
6403a735b93SImre Kis 	*sess = s;
6413a735b93SImre Kis 
6423a735b93SImre Kis 	ts_push_current_session(&s->ts_sess);
6433a735b93SImre Kis 
6443a735b93SImre Kis 	res = sp_is_elf_format(fdt, 0, &is_elf_format);
6453a735b93SImre Kis 	if (res == TEE_SUCCESS) {
6463a735b93SImre Kis 		if (is_elf_format) {
6473a735b93SImre Kis 			/* Load the SP using ldelf. */
6483a735b93SImre Kis 			ldelf_load_ldelf(&ctx->uctx);
6493a735b93SImre Kis 			res = ldelf_init_with_ldelf(&s->ts_sess, &ctx->uctx);
6503a735b93SImre Kis 		} else {
6513a735b93SImre Kis 			/* Raw binary format SP */
6523a735b93SImre Kis 			res = load_binary_sp(&s->ts_sess, &ctx->uctx);
6533a735b93SImre Kis 		}
6543a735b93SImre Kis 	} else {
6553a735b93SImre Kis 		EMSG("Failed to detect SP format");
6563a735b93SImre Kis 	}
6573a735b93SImre Kis 
6583a735b93SImre Kis 	if (res != TEE_SUCCESS) {
6593a735b93SImre Kis 		EMSG("Failed loading SP  %#"PRIx32, res);
6603a735b93SImre Kis 		ts_pop_current_session();
6613a735b93SImre Kis 		return TEE_ERROR_TARGET_DEAD;
6623a735b93SImre Kis 	}
6633a735b93SImre Kis 
66445afee9aSImre Kis 	/*
66545afee9aSImre Kis 	 * Make the SP ready for its first run.
66645afee9aSImre Kis 	 * Set state to busy to prevent other endpoints from sending messages to
66745afee9aSImre Kis 	 * the SP before its boot phase is done.
66845afee9aSImre Kis 	 */
66945afee9aSImre Kis 	s->state = sp_busy;
6703a735b93SImre Kis 	s->caller_id = 0;
6713a735b93SImre Kis 	sp_init_set_registers(ctx);
672552d5e40SJelle Sels 	memcpy(&s->ffa_uuid, ffa_uuid, sizeof(*ffa_uuid));
6733a735b93SImre Kis 	ts_pop_current_session();
6743a735b93SImre Kis 
6753a735b93SImre Kis 	return TEE_SUCCESS;
6763a735b93SImre Kis }
6773a735b93SImre Kis 
fdt_get_uuid(const void * const fdt,TEE_UUID * uuid)678552d5e40SJelle Sels static TEE_Result fdt_get_uuid(const void * const fdt, TEE_UUID *uuid)
67965ef988fSBalint Dobszay {
68065ef988fSBalint Dobszay 	const struct fdt_property *description = NULL;
68165ef988fSBalint Dobszay 	int description_name_len = 0;
68265ef988fSBalint Dobszay 
68365ef988fSBalint Dobszay 	if (fdt_node_check_compatible(fdt, 0, "arm,ffa-manifest-1.0")) {
68465ef988fSBalint Dobszay 		EMSG("Failed loading SP, manifest not found");
68565ef988fSBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
68665ef988fSBalint Dobszay 	}
68765ef988fSBalint Dobszay 
68865ef988fSBalint Dobszay 	description = fdt_get_property(fdt, 0, "description",
68965ef988fSBalint Dobszay 				       &description_name_len);
69065ef988fSBalint Dobszay 	if (description)
69165ef988fSBalint Dobszay 		DMSG("Loading SP: %s", description->data);
69265ef988fSBalint Dobszay 
693552d5e40SJelle Sels 	if (sp_dt_get_uuid(fdt, 0, "uuid", uuid)) {
69465ef988fSBalint Dobszay 		EMSG("Missing or invalid UUID in SP manifest");
69565ef988fSBalint Dobszay 		return TEE_ERROR_BAD_FORMAT;
69665ef988fSBalint Dobszay 	}
69765ef988fSBalint Dobszay 
69865ef988fSBalint Dobszay 	return TEE_SUCCESS;
69965ef988fSBalint Dobszay }
70065ef988fSBalint Dobszay 
copy_and_map_fdt(struct sp_ctx * ctx,const void * const fdt,void ** fdt_copy,size_t * mapped_size)7017bb22ad3SBalint Dobszay static TEE_Result copy_and_map_fdt(struct sp_ctx *ctx, const void * const fdt,
7027bb22ad3SBalint Dobszay 				   void **fdt_copy, size_t *mapped_size)
70365ef988fSBalint Dobszay {
7047bb22ad3SBalint Dobszay 	size_t total_size = ROUNDUP(fdt_totalsize(fdt), SMALL_PAGE_SIZE);
7057bb22ad3SBalint Dobszay 	size_t num_pages = total_size / SMALL_PAGE_SIZE;
7067bb22ad3SBalint Dobszay 	uint32_t perm = TEE_MATTR_UR | TEE_MATTR_PRW;
70765ef988fSBalint Dobszay 	TEE_Result res = TEE_SUCCESS;
70865ef988fSBalint Dobszay 	struct mobj *m = NULL;
7097bb22ad3SBalint Dobszay 	struct fobj *f = NULL;
7107bb22ad3SBalint Dobszay 	vaddr_t va = 0;
7117bb22ad3SBalint Dobszay 
7127bb22ad3SBalint Dobszay 	f = fobj_sec_mem_alloc(num_pages);
7137bb22ad3SBalint Dobszay 	m = mobj_with_fobj_alloc(f, NULL, TEE_MATTR_MEM_TYPE_TAGGED);
7147bb22ad3SBalint Dobszay 	fobj_put(f);
7157bb22ad3SBalint Dobszay 	if (!m)
7167bb22ad3SBalint Dobszay 		return TEE_ERROR_OUT_OF_MEMORY;
7177bb22ad3SBalint Dobszay 
7187bb22ad3SBalint Dobszay 	res = vm_map(&ctx->uctx, &va, total_size, perm, 0, m, 0);
7197bb22ad3SBalint Dobszay 	mobj_put(m);
7207bb22ad3SBalint Dobszay 	if (res)
7217bb22ad3SBalint Dobszay 		return res;
7227bb22ad3SBalint Dobszay 
7237bb22ad3SBalint Dobszay 	if (fdt_open_into(fdt, (void *)va, total_size))
7247bb22ad3SBalint Dobszay 		return TEE_ERROR_GENERIC;
7257bb22ad3SBalint Dobszay 
7267bb22ad3SBalint Dobszay 	*fdt_copy = (void *)va;
7277bb22ad3SBalint Dobszay 	*mapped_size = total_size;
7287bb22ad3SBalint Dobszay 
7297bb22ad3SBalint Dobszay 	return res;
7307bb22ad3SBalint Dobszay }
7317bb22ad3SBalint Dobszay 
fill_boot_info_1_0(vaddr_t buf,const void * fdt)7327bb22ad3SBalint Dobszay static void fill_boot_info_1_0(vaddr_t buf, const void *fdt)
7337bb22ad3SBalint Dobszay {
7347bb22ad3SBalint Dobszay 	struct ffa_boot_info_1_0 *info = (struct ffa_boot_info_1_0 *)buf;
73565ef988fSBalint Dobszay 	static const char fdt_name[16] = "TYPE_DT\0\0\0\0\0\0\0\0";
73665ef988fSBalint Dobszay 
7377bb22ad3SBalint Dobszay 	memcpy(&info->magic, "FF-A", 4);
7387bb22ad3SBalint Dobszay 	info->count = 1;
73965ef988fSBalint Dobszay 
7407bb22ad3SBalint Dobszay 	COMPILE_TIME_ASSERT(sizeof(info->nvp[0].name) == sizeof(fdt_name));
7417bb22ad3SBalint Dobszay 	memcpy(info->nvp[0].name, fdt_name, sizeof(fdt_name));
7427bb22ad3SBalint Dobszay 	info->nvp[0].value = (uintptr_t)fdt;
7437bb22ad3SBalint Dobszay 	info->nvp[0].size = fdt_totalsize(fdt);
7447bb22ad3SBalint Dobszay }
7457bb22ad3SBalint Dobszay 
fill_boot_info_1_1(vaddr_t buf,const void * fdt,uint32_t vers)746bef959c8SJens Wiklander static void fill_boot_info_1_1(vaddr_t buf, const void *fdt, uint32_t vers)
7477bb22ad3SBalint Dobszay {
7487bb22ad3SBalint Dobszay 	size_t desc_offs = ROUNDUP(sizeof(struct ffa_boot_info_header_1_1), 8);
7497bb22ad3SBalint Dobszay 	struct ffa_boot_info_header_1_1 *header =
7507bb22ad3SBalint Dobszay 		(struct ffa_boot_info_header_1_1 *)buf;
7517bb22ad3SBalint Dobszay 	struct ffa_boot_info_1_1 *desc =
7527bb22ad3SBalint Dobszay 		(struct ffa_boot_info_1_1 *)(buf + desc_offs);
7537bb22ad3SBalint Dobszay 
7547bb22ad3SBalint Dobszay 	header->signature = FFA_BOOT_INFO_SIGNATURE;
755bef959c8SJens Wiklander 	header->version = vers;
7567bb22ad3SBalint Dobszay 	header->blob_size = desc_offs + sizeof(struct ffa_boot_info_1_1);
7577bb22ad3SBalint Dobszay 	header->desc_size = sizeof(struct ffa_boot_info_1_1);
7587bb22ad3SBalint Dobszay 	header->desc_count = 1;
7597bb22ad3SBalint Dobszay 	header->desc_offset = desc_offs;
7607bb22ad3SBalint Dobszay 
7617bb22ad3SBalint Dobszay 	memset(&desc[0].name, 0, sizeof(desc[0].name));
7627bb22ad3SBalint Dobszay 	/* Type: Standard boot info (bit[7] == 0), FDT type */
7637bb22ad3SBalint Dobszay 	desc[0].type = FFA_BOOT_INFO_TYPE_ID_FDT;
7647bb22ad3SBalint Dobszay 	/* Flags: Contents field contains an address */
7657bb22ad3SBalint Dobszay 	desc[0].flags = FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_ADDR <<
7667bb22ad3SBalint Dobszay 			FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_SHIFT;
7677bb22ad3SBalint Dobszay 	desc[0].size = fdt_totalsize(fdt);
7687bb22ad3SBalint Dobszay 	desc[0].contents = (uintptr_t)fdt;
7697bb22ad3SBalint Dobszay }
7707bb22ad3SBalint Dobszay 
create_and_map_boot_info(struct sp_ctx * ctx,const void * fdt,struct thread_smc_1_2_regs * args,vaddr_t * va,size_t * mapped_size,uint32_t sp_ffa_version)7717bb22ad3SBalint Dobszay static TEE_Result create_and_map_boot_info(struct sp_ctx *ctx, const void *fdt,
772d17db2afSJens Wiklander 					   struct thread_smc_1_2_regs *args,
773655625e0SImre Kis 					   vaddr_t *va, size_t *mapped_size,
774655625e0SImre Kis 					   uint32_t sp_ffa_version)
7757bb22ad3SBalint Dobszay {
7767bb22ad3SBalint Dobszay 	size_t total_size = ROUNDUP(CFG_SP_INIT_INFO_MAX_SIZE, SMALL_PAGE_SIZE);
7777bb22ad3SBalint Dobszay 	size_t num_pages = total_size / SMALL_PAGE_SIZE;
7787bb22ad3SBalint Dobszay 	uint32_t perm = TEE_MATTR_UR | TEE_MATTR_PRW;
7797bb22ad3SBalint Dobszay 	TEE_Result res = TEE_SUCCESS;
7807bb22ad3SBalint Dobszay 	struct fobj *f = NULL;
7817bb22ad3SBalint Dobszay 	struct mobj *m = NULL;
7827bb22ad3SBalint Dobszay 	uint32_t info_reg = 0;
7837bb22ad3SBalint Dobszay 
7847bb22ad3SBalint Dobszay 	f = fobj_sec_mem_alloc(num_pages);
7857bb22ad3SBalint Dobszay 	m = mobj_with_fobj_alloc(f, NULL, TEE_MATTR_MEM_TYPE_TAGGED);
78665ef988fSBalint Dobszay 	fobj_put(f);
78765ef988fSBalint Dobszay 	if (!m)
78865ef988fSBalint Dobszay 		return TEE_ERROR_OUT_OF_MEMORY;
78965ef988fSBalint Dobszay 
790c36d2192SBalint Dobszay 	res = vm_map(&ctx->uctx, va, total_size, perm, 0, m, 0);
79165ef988fSBalint Dobszay 	mobj_put(m);
79265ef988fSBalint Dobszay 	if (res)
79365ef988fSBalint Dobszay 		return res;
79465ef988fSBalint Dobszay 
7957bb22ad3SBalint Dobszay 	*mapped_size = total_size;
7968e42ac92SBalint Dobszay 
7977bb22ad3SBalint Dobszay 	switch (sp_ffa_version) {
7987bb22ad3SBalint Dobszay 	case MAKE_FFA_VERSION(1, 0):
7997bb22ad3SBalint Dobszay 		fill_boot_info_1_0(*va, fdt);
8007bb22ad3SBalint Dobszay 		break;
8017bb22ad3SBalint Dobszay 	case MAKE_FFA_VERSION(1, 1):
802bef959c8SJens Wiklander 	case MAKE_FFA_VERSION(1, 2):
803bef959c8SJens Wiklander 		fill_boot_info_1_1(*va, fdt, sp_ffa_version);
8047bb22ad3SBalint Dobszay 		break;
8057bb22ad3SBalint Dobszay 	default:
8067bb22ad3SBalint Dobszay 		EMSG("Unknown FF-A version: %#"PRIx32, sp_ffa_version);
8077bb22ad3SBalint Dobszay 		return TEE_ERROR_NOT_SUPPORTED;
8087bb22ad3SBalint Dobszay 	}
80965ef988fSBalint Dobszay 
8107bb22ad3SBalint Dobszay 	res = sp_dt_get_u32(fdt, 0, "gp-register-num", &info_reg);
8117bb22ad3SBalint Dobszay 	if (res) {
8127bb22ad3SBalint Dobszay 		if (res == TEE_ERROR_ITEM_NOT_FOUND) {
8137bb22ad3SBalint Dobszay 			/* If the property is not present, set default to x0 */
8147bb22ad3SBalint Dobszay 			info_reg = 0;
8157bb22ad3SBalint Dobszay 		} else {
8167bb22ad3SBalint Dobszay 			return TEE_ERROR_BAD_FORMAT;
8177bb22ad3SBalint Dobszay 		}
8187bb22ad3SBalint Dobszay 	}
81965ef988fSBalint Dobszay 
8207bb22ad3SBalint Dobszay 	switch (info_reg) {
8217bb22ad3SBalint Dobszay 	case 0:
8227bb22ad3SBalint Dobszay 		args->a0 = *va;
8237bb22ad3SBalint Dobszay 		break;
8247bb22ad3SBalint Dobszay 	case 1:
8257bb22ad3SBalint Dobszay 		args->a1 = *va;
8267bb22ad3SBalint Dobszay 		break;
8277bb22ad3SBalint Dobszay 	case 2:
8287bb22ad3SBalint Dobszay 		args->a2 = *va;
8297bb22ad3SBalint Dobszay 		break;
8307bb22ad3SBalint Dobszay 	case 3:
8317bb22ad3SBalint Dobszay 		args->a3 = *va;
8327bb22ad3SBalint Dobszay 		break;
8337bb22ad3SBalint Dobszay 	default:
8347bb22ad3SBalint Dobszay 		EMSG("Invalid register selected for passing boot info");
8357bb22ad3SBalint Dobszay 		return TEE_ERROR_BAD_FORMAT;
8367bb22ad3SBalint Dobszay 	}
837c36d2192SBalint Dobszay 
83865ef988fSBalint Dobszay 	return TEE_SUCCESS;
83965ef988fSBalint Dobszay }
84065ef988fSBalint Dobszay 
handle_fdt_load_relative_mem_regions(struct sp_ctx * ctx,const void * fdt)84109b678f1SImre Kis static TEE_Result handle_fdt_load_relative_mem_regions(struct sp_ctx *ctx,
84209b678f1SImre Kis 						       const void *fdt)
84309b678f1SImre Kis {
84409b678f1SImre Kis 	int node = 0;
84509b678f1SImre Kis 	int subnode = 0;
84609b678f1SImre Kis 	tee_mm_entry_t *mm = NULL;
84709b678f1SImre Kis 	TEE_Result res = TEE_SUCCESS;
84809b678f1SImre Kis 
84909b678f1SImre Kis 	/*
85009b678f1SImre Kis 	 * Memory regions are optional in the SP manifest, it's not an error if
85109b678f1SImre Kis 	 * we don't find any.
85209b678f1SImre Kis 	 */
85309b678f1SImre Kis 	node = fdt_node_offset_by_compatible(fdt, 0,
85409b678f1SImre Kis 					     "arm,ffa-manifest-memory-regions");
85509b678f1SImre Kis 	if (node < 0)
85609b678f1SImre Kis 		return TEE_SUCCESS;
85709b678f1SImre Kis 
85809b678f1SImre Kis 	fdt_for_each_subnode(subnode, fdt, node) {
85909b678f1SImre Kis 		uint64_t load_rel_offset = 0;
86009b678f1SImre Kis 		uint32_t attributes = 0;
86109b678f1SImre Kis 		uint64_t base_addr = 0;
86209b678f1SImre Kis 		uint32_t pages_cnt = 0;
86309b678f1SImre Kis 		uint32_t flags = 0;
86409b678f1SImre Kis 		uint32_t perm = 0;
86509b678f1SImre Kis 		size_t size = 0;
86609b678f1SImre Kis 		vaddr_t va = 0;
86709b678f1SImre Kis 
86809b678f1SImre Kis 		mm = NULL;
86909b678f1SImre Kis 
87009b678f1SImre Kis 		/* Load address relative offset of a memory region */
87109b678f1SImre Kis 		if (!sp_dt_get_u64(fdt, subnode, "load-address-relative-offset",
87209b678f1SImre Kis 				   &load_rel_offset)) {
87309b678f1SImre Kis 			va = ctx->uctx.load_addr + load_rel_offset;
87409b678f1SImre Kis 		} else {
87509b678f1SImre Kis 			/* Skip non load address relative memory regions */
87609b678f1SImre Kis 			continue;
87709b678f1SImre Kis 		}
87809b678f1SImre Kis 
87909b678f1SImre Kis 		if (!sp_dt_get_u64(fdt, subnode, "base-address", &base_addr)) {
88009b678f1SImre Kis 			EMSG("Both base-address and load-address-relative-offset fields are set");
88109b678f1SImre Kis 			return TEE_ERROR_BAD_FORMAT;
88209b678f1SImre Kis 		}
88309b678f1SImre Kis 
88409b678f1SImre Kis 		/* Size of memory region as count of 4K pages */
88509b678f1SImre Kis 		if (sp_dt_get_u32(fdt, subnode, "pages-count", &pages_cnt)) {
88609b678f1SImre Kis 			EMSG("Mandatory field is missing: pages-count");
88709b678f1SImre Kis 			return TEE_ERROR_BAD_FORMAT;
88809b678f1SImre Kis 		}
88909b678f1SImre Kis 
89009b678f1SImre Kis 		if (MUL_OVERFLOW(pages_cnt, SMALL_PAGE_SIZE, &size))
89109b678f1SImre Kis 			return TEE_ERROR_OVERFLOW;
89209b678f1SImre Kis 
89309b678f1SImre Kis 		/* Memory region attributes  */
89409b678f1SImre Kis 		if (sp_dt_get_u32(fdt, subnode, "attributes", &attributes)) {
89509b678f1SImre Kis 			EMSG("Mandatory field is missing: attributes");
89609b678f1SImre Kis 			return TEE_ERROR_BAD_FORMAT;
89709b678f1SImre Kis 		}
89809b678f1SImre Kis 
89909b678f1SImre Kis 		/* Check instruction and data access permissions */
90009b678f1SImre Kis 		switch (attributes & SP_MANIFEST_ATTR_RWX) {
90109b678f1SImre Kis 		case SP_MANIFEST_ATTR_RO:
90209b678f1SImre Kis 			perm = TEE_MATTR_UR;
90309b678f1SImre Kis 			break;
90409b678f1SImre Kis 		case SP_MANIFEST_ATTR_RW:
90509b678f1SImre Kis 			perm = TEE_MATTR_URW;
90609b678f1SImre Kis 			break;
90709b678f1SImre Kis 		case SP_MANIFEST_ATTR_RX:
90809b678f1SImre Kis 			perm = TEE_MATTR_URX;
90909b678f1SImre Kis 			break;
91009b678f1SImre Kis 		default:
91109b678f1SImre Kis 			EMSG("Invalid memory access permissions");
91209b678f1SImre Kis 			return TEE_ERROR_BAD_FORMAT;
91309b678f1SImre Kis 		}
91409b678f1SImre Kis 
9159363481eSGabor Toth 		if (IS_ENABLED(CFG_TA_BTI) &&
9169363481eSGabor Toth 		    attributes & SP_MANIFEST_ATTR_GP) {
9179363481eSGabor Toth 			if (!(attributes & SP_MANIFEST_ATTR_RX)) {
9189363481eSGabor Toth 				EMSG("Guard only executable region");
9199363481eSGabor Toth 				return TEE_ERROR_BAD_FORMAT;
9209363481eSGabor Toth 			}
9219363481eSGabor Toth 			perm |= TEE_MATTR_GUARDED;
9229363481eSGabor Toth 		}
9239363481eSGabor Toth 
92409b678f1SImre Kis 		res = sp_dt_get_u32(fdt, subnode, "load-flags", &flags);
92509b678f1SImre Kis 		if (res != TEE_SUCCESS && res != TEE_ERROR_ITEM_NOT_FOUND) {
92609b678f1SImre Kis 			EMSG("Optional field with invalid value: flags");
92709b678f1SImre Kis 			return TEE_ERROR_BAD_FORMAT;
92809b678f1SImre Kis 		}
92909b678f1SImre Kis 
93009b678f1SImre Kis 		/* Load relative regions must be secure */
93109b678f1SImre Kis 		if (attributes & SP_MANIFEST_ATTR_NSEC) {
93209b678f1SImre Kis 			EMSG("Invalid memory security attribute");
93309b678f1SImre Kis 			return TEE_ERROR_BAD_FORMAT;
93409b678f1SImre Kis 		}
93509b678f1SImre Kis 
93609b678f1SImre Kis 		if (flags & SP_MANIFEST_FLAG_NOBITS) {
93709b678f1SImre Kis 			/*
93809b678f1SImre Kis 			 * NOBITS flag is set, which means that loaded binary
93909b678f1SImre Kis 			 * doesn't contain this area, so it's need to be
94009b678f1SImre Kis 			 * allocated.
94109b678f1SImre Kis 			 */
94209b678f1SImre Kis 			struct mobj *m = NULL;
94309b678f1SImre Kis 			unsigned int idx = 0;
94409b678f1SImre Kis 
945de19cacbSJens Wiklander 			mm = phys_mem_ta_alloc(size);
94609b678f1SImre Kis 			if (!mm)
94709b678f1SImre Kis 				return TEE_ERROR_OUT_OF_MEMORY;
94809b678f1SImre Kis 
94909b678f1SImre Kis 			base_addr = tee_mm_get_smem(mm);
95009b678f1SImre Kis 
95109b678f1SImre Kis 			m = sp_mem_new_mobj(pages_cnt,
95209b678f1SImre Kis 					    TEE_MATTR_MEM_TYPE_CACHED, true);
95309b678f1SImre Kis 			if (!m) {
95409b678f1SImre Kis 				res = TEE_ERROR_OUT_OF_MEMORY;
95509b678f1SImre Kis 				goto err_mm_free;
95609b678f1SImre Kis 			}
95709b678f1SImre Kis 
95809b678f1SImre Kis 			res = sp_mem_add_pages(m, &idx, base_addr, pages_cnt);
95909b678f1SImre Kis 			if (res) {
96009b678f1SImre Kis 				mobj_put(m);
96109b678f1SImre Kis 				goto err_mm_free;
96209b678f1SImre Kis 			}
96309b678f1SImre Kis 
96409b678f1SImre Kis 			res = vm_map(&ctx->uctx, &va, size, perm, 0, m, 0);
96509b678f1SImre Kis 			mobj_put(m);
96609b678f1SImre Kis 			if (res)
96709b678f1SImre Kis 				goto err_mm_free;
96809b678f1SImre Kis 		} else {
96909b678f1SImre Kis 			/*
97009b678f1SImre Kis 			 * If NOBITS is not present the memory area is already
97109b678f1SImre Kis 			 * mapped and only need to set the correct permissions.
97209b678f1SImre Kis 			 */
97309b678f1SImre Kis 			res = vm_set_prot(&ctx->uctx, va, size, perm);
97409b678f1SImre Kis 			if (res)
97509b678f1SImre Kis 				return res;
97609b678f1SImre Kis 		}
97709b678f1SImre Kis 	}
97809b678f1SImre Kis 
97909b678f1SImre Kis 	return TEE_SUCCESS;
98009b678f1SImre Kis 
98109b678f1SImre Kis err_mm_free:
98209b678f1SImre Kis 	tee_mm_free(mm);
98309b678f1SImre Kis 	return res;
98409b678f1SImre Kis }
98509b678f1SImre Kis 
handle_fdt_dev_regions(struct sp_ctx * ctx,void * fdt)9866d618ba1SJelle Sels static TEE_Result handle_fdt_dev_regions(struct sp_ctx *ctx, void *fdt)
9876d618ba1SJelle Sels {
9886d618ba1SJelle Sels 	int node = 0;
9896d618ba1SJelle Sels 	int subnode = 0;
9906d618ba1SJelle Sels 	TEE_Result res = TEE_SUCCESS;
9916d618ba1SJelle Sels 	const char *dt_device_match_table = {
9926d618ba1SJelle Sels 		"arm,ffa-manifest-device-regions",
9936d618ba1SJelle Sels 	};
9946d618ba1SJelle Sels 
9956d618ba1SJelle Sels 	/*
9966d618ba1SJelle Sels 	 * Device regions are optional in the SP manifest, it's not an error if
9976d618ba1SJelle Sels 	 * we don't find any
9986d618ba1SJelle Sels 	 */
9996d618ba1SJelle Sels 	node = fdt_node_offset_by_compatible(fdt, 0, dt_device_match_table);
10006d618ba1SJelle Sels 	if (node < 0)
10016d618ba1SJelle Sels 		return TEE_SUCCESS;
10026d618ba1SJelle Sels 
10036d618ba1SJelle Sels 	fdt_for_each_subnode(subnode, fdt, node) {
10046d618ba1SJelle Sels 		uint64_t base_addr = 0;
10056d618ba1SJelle Sels 		uint32_t pages_cnt = 0;
10066d618ba1SJelle Sels 		uint32_t attributes = 0;
10076d618ba1SJelle Sels 		struct mobj *m = NULL;
10086d618ba1SJelle Sels 		bool is_secure = true;
10096d618ba1SJelle Sels 		uint32_t perm = 0;
10106d618ba1SJelle Sels 		vaddr_t va = 0;
10116d618ba1SJelle Sels 		unsigned int idx = 0;
10126d618ba1SJelle Sels 
10136d618ba1SJelle Sels 		/*
10146d618ba1SJelle Sels 		 * Physical base address of a device MMIO region.
10156d618ba1SJelle Sels 		 * Currently only physically contiguous region is supported.
10166d618ba1SJelle Sels 		 */
10176d618ba1SJelle Sels 		if (sp_dt_get_u64(fdt, subnode, "base-address", &base_addr)) {
10186d618ba1SJelle Sels 			EMSG("Mandatory field is missing: base-address");
10196d618ba1SJelle Sels 			return TEE_ERROR_BAD_FORMAT;
10206d618ba1SJelle Sels 		}
10216d618ba1SJelle Sels 
10226d618ba1SJelle Sels 		/* Total size of MMIO region as count of 4K pages */
10236d618ba1SJelle Sels 		if (sp_dt_get_u32(fdt, subnode, "pages-count", &pages_cnt)) {
10246d618ba1SJelle Sels 			EMSG("Mandatory field is missing: pages-count");
10256d618ba1SJelle Sels 			return TEE_ERROR_BAD_FORMAT;
10266d618ba1SJelle Sels 		}
10276d618ba1SJelle Sels 
10286d618ba1SJelle Sels 		/* Data access, instruction access and security attributes */
10296d618ba1SJelle Sels 		if (sp_dt_get_u32(fdt, subnode, "attributes", &attributes)) {
10306d618ba1SJelle Sels 			EMSG("Mandatory field is missing: attributes");
10316d618ba1SJelle Sels 			return TEE_ERROR_BAD_FORMAT;
10326d618ba1SJelle Sels 		}
10336d618ba1SJelle Sels 
10343da1a076SBalint Dobszay 		/* Check instruction and data access permissions */
10353da1a076SBalint Dobszay 		switch (attributes & SP_MANIFEST_ATTR_RWX) {
10363da1a076SBalint Dobszay 		case SP_MANIFEST_ATTR_RO:
10376d618ba1SJelle Sels 			perm = TEE_MATTR_UR;
10383da1a076SBalint Dobszay 			break;
10393da1a076SBalint Dobszay 		case SP_MANIFEST_ATTR_RW:
10403da1a076SBalint Dobszay 			perm = TEE_MATTR_URW;
10413da1a076SBalint Dobszay 			break;
10423da1a076SBalint Dobszay 		default:
10433da1a076SBalint Dobszay 			EMSG("Invalid memory access permissions");
10446d618ba1SJelle Sels 			return TEE_ERROR_BAD_FORMAT;
10456d618ba1SJelle Sels 		}
10466d618ba1SJelle Sels 
10476d618ba1SJelle Sels 		/*
10486d618ba1SJelle Sels 		 * The SP is a secure endpoint, security attribute can be
10496d618ba1SJelle Sels 		 * secure or non-secure
10506d618ba1SJelle Sels 		 */
10516d618ba1SJelle Sels 		if (attributes & SP_MANIFEST_ATTR_NSEC)
10526d618ba1SJelle Sels 			is_secure = false;
10536d618ba1SJelle Sels 
10546d618ba1SJelle Sels 		/* Memory attributes must be Device-nGnRnE */
10556d618ba1SJelle Sels 		m = sp_mem_new_mobj(pages_cnt, TEE_MATTR_MEM_TYPE_STRONGLY_O,
10566d618ba1SJelle Sels 				    is_secure);
10576d618ba1SJelle Sels 		if (!m)
10586d618ba1SJelle Sels 			return TEE_ERROR_OUT_OF_MEMORY;
10596d618ba1SJelle Sels 
10606d618ba1SJelle Sels 		res = sp_mem_add_pages(m, &idx, (paddr_t)base_addr, pages_cnt);
10616d618ba1SJelle Sels 		if (res) {
10626d618ba1SJelle Sels 			mobj_put(m);
10636d618ba1SJelle Sels 			return res;
10646d618ba1SJelle Sels 		}
10656d618ba1SJelle Sels 
10666d618ba1SJelle Sels 		res = vm_map(&ctx->uctx, &va, pages_cnt * SMALL_PAGE_SIZE,
10676d618ba1SJelle Sels 			     perm, 0, m, 0);
10686d618ba1SJelle Sels 		mobj_put(m);
10696d618ba1SJelle Sels 		if (res)
10706d618ba1SJelle Sels 			return res;
10716d618ba1SJelle Sels 
10726d618ba1SJelle Sels 		/*
10736d618ba1SJelle Sels 		 * Overwrite the device region's PA in the fdt with the VA. This
10746d618ba1SJelle Sels 		 * fdt will be passed to the SP.
10756d618ba1SJelle Sels 		 */
10766d618ba1SJelle Sels 		res = fdt_setprop_u64(fdt, subnode, "base-address", va);
10776d618ba1SJelle Sels 
10786d618ba1SJelle Sels 		/*
10796d618ba1SJelle Sels 		 * Unmap the region if the overwrite failed since the SP won't
10806d618ba1SJelle Sels 		 * be able to access it without knowing the VA.
10816d618ba1SJelle Sels 		 */
10826d618ba1SJelle Sels 		if (res) {
10836d618ba1SJelle Sels 			vm_unmap(&ctx->uctx, va, pages_cnt * SMALL_PAGE_SIZE);
10846d618ba1SJelle Sels 			return res;
10856d618ba1SJelle Sels 		}
10866d618ba1SJelle Sels 	}
10876d618ba1SJelle Sels 
10886d618ba1SJelle Sels 	return TEE_SUCCESS;
10896d618ba1SJelle Sels }
10906d618ba1SJelle Sels 
swap_sp_endpoints(uint32_t endpoint_id,uint32_t new_endpoint_id)109124fe8824SJelle Sels static TEE_Result swap_sp_endpoints(uint32_t endpoint_id,
109224fe8824SJelle Sels 				    uint32_t new_endpoint_id)
109324fe8824SJelle Sels {
109424fe8824SJelle Sels 	struct sp_session *session = sp_get_session(endpoint_id);
109524fe8824SJelle Sels 	uint32_t manifest_endpoint_id = 0;
109624fe8824SJelle Sels 
109724fe8824SJelle Sels 	/*
109824fe8824SJelle Sels 	 * We don't know in which order the SPs are loaded. The endpoint ID
109924fe8824SJelle Sels 	 * defined in the manifest could already be generated by
110024fe8824SJelle Sels 	 * new_session_id() and used by another SP. If this is the case, we swap
110124fe8824SJelle Sels 	 * the ID's of the two SPs. We also have to make sure that the ID's are
110224fe8824SJelle Sels 	 * not defined twice in the manifest.
110324fe8824SJelle Sels 	 */
110424fe8824SJelle Sels 
110524fe8824SJelle Sels 	/* The endpoint ID was not assigned yet */
110624fe8824SJelle Sels 	if (!session)
110724fe8824SJelle Sels 		return TEE_SUCCESS;
110824fe8824SJelle Sels 
110924fe8824SJelle Sels 	/*
111024fe8824SJelle Sels 	 * Read the manifest file from the SP who originally had the endpoint.
111124fe8824SJelle Sels 	 * We can safely swap the endpoint ID's if the manifest file doesn't
111224fe8824SJelle Sels 	 * have an endpoint ID defined.
111324fe8824SJelle Sels 	 */
111424fe8824SJelle Sels 	if (!sp_dt_get_u32(session->fdt, 0, "id", &manifest_endpoint_id)) {
111524fe8824SJelle Sels 		assert(manifest_endpoint_id == endpoint_id);
111624fe8824SJelle Sels 		EMSG("SP: Found duplicated endpoint ID %#"PRIx32, endpoint_id);
111724fe8824SJelle Sels 		return TEE_ERROR_ACCESS_CONFLICT;
111824fe8824SJelle Sels 	}
111924fe8824SJelle Sels 
112024fe8824SJelle Sels 	session->endpoint_id = new_endpoint_id;
112124fe8824SJelle Sels 
112224fe8824SJelle Sels 	return TEE_SUCCESS;
112324fe8824SJelle Sels }
112424fe8824SJelle Sels 
read_manifest_endpoint_id(struct sp_session * s)112524fe8824SJelle Sels static TEE_Result read_manifest_endpoint_id(struct sp_session *s)
112624fe8824SJelle Sels {
112724fe8824SJelle Sels 	uint32_t endpoint_id = 0;
112824fe8824SJelle Sels 
112924fe8824SJelle Sels 	/*
113024fe8824SJelle Sels 	 * The endpoint ID can be optionally defined in the manifest file. We
113124fe8824SJelle Sels 	 * have to map the ID inside the manifest to the SP if it's defined.
113224fe8824SJelle Sels 	 * If not, the endpoint ID generated inside new_session_id() will be
113324fe8824SJelle Sels 	 * used.
113424fe8824SJelle Sels 	 */
113524fe8824SJelle Sels 	if (!sp_dt_get_u32(s->fdt, 0, "id", &endpoint_id)) {
113624fe8824SJelle Sels 		TEE_Result res = TEE_ERROR_GENERIC;
113724fe8824SJelle Sels 
113819ad526cSBalint Dobszay 		if (!endpoint_id_is_valid(endpoint_id)) {
113919ad526cSBalint Dobszay 			EMSG("Invalid endpoint ID 0x%"PRIx32, endpoint_id);
114024fe8824SJelle Sels 			return TEE_ERROR_BAD_FORMAT;
114119ad526cSBalint Dobszay 		}
114224fe8824SJelle Sels 
114324fe8824SJelle Sels 		res = swap_sp_endpoints(endpoint_id, s->endpoint_id);
114424fe8824SJelle Sels 		if (res)
114524fe8824SJelle Sels 			return res;
114624fe8824SJelle Sels 
114724fe8824SJelle Sels 		DMSG("SP: endpoint ID (0x%"PRIx32") found in manifest",
114824fe8824SJelle Sels 		     endpoint_id);
114924fe8824SJelle Sels 		/* Assign the endpoint ID to the current SP */
115024fe8824SJelle Sels 		s->endpoint_id = endpoint_id;
115124fe8824SJelle Sels 	}
115224fe8824SJelle Sels 	return TEE_SUCCESS;
115324fe8824SJelle Sels }
115424fe8824SJelle Sels 
handle_fdt_mem_regions(struct sp_ctx * ctx,void * fdt)11555a923b99SBalint Dobszay static TEE_Result handle_fdt_mem_regions(struct sp_ctx *ctx, void *fdt)
11565a923b99SBalint Dobszay {
11575a923b99SBalint Dobszay 	int node = 0;
11585a923b99SBalint Dobszay 	int subnode = 0;
1159c36d2192SBalint Dobszay 	tee_mm_entry_t *mm = NULL;
11605a923b99SBalint Dobszay 	TEE_Result res = TEE_SUCCESS;
11615a923b99SBalint Dobszay 
11625a923b99SBalint Dobszay 	/*
11635a923b99SBalint Dobszay 	 * Memory regions are optional in the SP manifest, it's not an error if
11645a923b99SBalint Dobszay 	 * we don't find any.
11655a923b99SBalint Dobszay 	 */
11665a923b99SBalint Dobszay 	node = fdt_node_offset_by_compatible(fdt, 0,
11675a923b99SBalint Dobszay 					     "arm,ffa-manifest-memory-regions");
11685a923b99SBalint Dobszay 	if (node < 0)
11695a923b99SBalint Dobszay 		return TEE_SUCCESS;
11705a923b99SBalint Dobszay 
11715a923b99SBalint Dobszay 	fdt_for_each_subnode(subnode, fdt, node) {
117209b678f1SImre Kis 		uint64_t load_rel_offset = 0;
1173c36d2192SBalint Dobszay 		bool alloc_needed = false;
11745a923b99SBalint Dobszay 		uint32_t attributes = 0;
11755a923b99SBalint Dobszay 		uint64_t base_addr = 0;
11765a923b99SBalint Dobszay 		uint32_t pages_cnt = 0;
11775a923b99SBalint Dobszay 		bool is_secure = true;
11785a923b99SBalint Dobszay 		struct mobj *m = NULL;
11795a923b99SBalint Dobszay 		unsigned int idx = 0;
11805a923b99SBalint Dobszay 		uint32_t perm = 0;
11815a923b99SBalint Dobszay 		size_t size = 0;
11825a923b99SBalint Dobszay 		vaddr_t va = 0;
11835a923b99SBalint Dobszay 
1184c36d2192SBalint Dobszay 		mm = NULL;
1185c36d2192SBalint Dobszay 
118609b678f1SImre Kis 		/* Load address relative offset of a memory region */
118709b678f1SImre Kis 		if (!sp_dt_get_u64(fdt, subnode, "load-address-relative-offset",
118809b678f1SImre Kis 				   &load_rel_offset)) {
118909b678f1SImre Kis 			/*
119009b678f1SImre Kis 			 * At this point the memory region is already mapped by
119109b678f1SImre Kis 			 * handle_fdt_load_relative_mem_regions.
119209b678f1SImre Kis 			 * Only need to set the base-address in the manifest and
119309b678f1SImre Kis 			 * then skip the rest of the mapping process.
119409b678f1SImre Kis 			 */
119509b678f1SImre Kis 			va = ctx->uctx.load_addr + load_rel_offset;
119609b678f1SImre Kis 			res = fdt_setprop_u64(fdt, subnode, "base-address", va);
119709b678f1SImre Kis 			if (res)
119809b678f1SImre Kis 				return res;
119909b678f1SImre Kis 
120009b678f1SImre Kis 			continue;
120109b678f1SImre Kis 		}
120209b678f1SImre Kis 
12035a923b99SBalint Dobszay 		/*
12045a923b99SBalint Dobszay 		 * Base address of a memory region.
1205c36d2192SBalint Dobszay 		 * If not present, we have to allocate the specified memory.
12065a923b99SBalint Dobszay 		 * If present, this field could specify a PA or VA. Currently
12075a923b99SBalint Dobszay 		 * only a PA is supported.
12085a923b99SBalint Dobszay 		 */
1209c36d2192SBalint Dobszay 		if (sp_dt_get_u64(fdt, subnode, "base-address", &base_addr))
1210c36d2192SBalint Dobszay 			alloc_needed = true;
12115a923b99SBalint Dobszay 
12125a923b99SBalint Dobszay 		/* Size of memory region as count of 4K pages */
12135a923b99SBalint Dobszay 		if (sp_dt_get_u32(fdt, subnode, "pages-count", &pages_cnt)) {
12145a923b99SBalint Dobszay 			EMSG("Mandatory field is missing: pages-count");
12155a923b99SBalint Dobszay 			return TEE_ERROR_BAD_FORMAT;
12165a923b99SBalint Dobszay 		}
12175a923b99SBalint Dobszay 
12185a923b99SBalint Dobszay 		if (MUL_OVERFLOW(pages_cnt, SMALL_PAGE_SIZE, &size))
12195a923b99SBalint Dobszay 			return TEE_ERROR_OVERFLOW;
12205a923b99SBalint Dobszay 
12215a923b99SBalint Dobszay 		/*
12225a923b99SBalint Dobszay 		 * Memory region attributes:
12235a923b99SBalint Dobszay 		 * - Instruction/data access permissions
12245a923b99SBalint Dobszay 		 * - Cacheability/shareability attributes
12255a923b99SBalint Dobszay 		 * - Security attributes
12265a923b99SBalint Dobszay 		 *
12275a923b99SBalint Dobszay 		 * Cacheability/shareability attributes can be ignored for now.
12285a923b99SBalint Dobszay 		 * OP-TEE only supports a single type for normal cached memory
12295a923b99SBalint Dobszay 		 * and currently there is no use case that would require to
12305a923b99SBalint Dobszay 		 * change this.
12315a923b99SBalint Dobszay 		 */
12325a923b99SBalint Dobszay 		if (sp_dt_get_u32(fdt, subnode, "attributes", &attributes)) {
12335a923b99SBalint Dobszay 			EMSG("Mandatory field is missing: attributes");
12345a923b99SBalint Dobszay 			return TEE_ERROR_BAD_FORMAT;
12355a923b99SBalint Dobszay 		}
12365a923b99SBalint Dobszay 
12375a923b99SBalint Dobszay 		/* Check instruction and data access permissions */
12385a923b99SBalint Dobszay 		switch (attributes & SP_MANIFEST_ATTR_RWX) {
12395a923b99SBalint Dobszay 		case SP_MANIFEST_ATTR_RO:
12405a923b99SBalint Dobszay 			perm = TEE_MATTR_UR;
12415a923b99SBalint Dobszay 			break;
12425a923b99SBalint Dobszay 		case SP_MANIFEST_ATTR_RW:
12435a923b99SBalint Dobszay 			perm = TEE_MATTR_URW;
12445a923b99SBalint Dobszay 			break;
12455a923b99SBalint Dobszay 		case SP_MANIFEST_ATTR_RX:
12465a923b99SBalint Dobszay 			perm = TEE_MATTR_URX;
12475a923b99SBalint Dobszay 			break;
12485a923b99SBalint Dobszay 		default:
12495a923b99SBalint Dobszay 			EMSG("Invalid memory access permissions");
12505a923b99SBalint Dobszay 			return TEE_ERROR_BAD_FORMAT;
12515a923b99SBalint Dobszay 		}
12525a923b99SBalint Dobszay 
12539363481eSGabor Toth 		if (IS_ENABLED(CFG_TA_BTI) &&
12549363481eSGabor Toth 		    attributes & SP_MANIFEST_ATTR_GP) {
12559363481eSGabor Toth 			if (!(attributes & SP_MANIFEST_ATTR_RX)) {
12569363481eSGabor Toth 				EMSG("Guard only executable region");
12579363481eSGabor Toth 				return TEE_ERROR_BAD_FORMAT;
12589363481eSGabor Toth 			}
12599363481eSGabor Toth 			perm |= TEE_MATTR_GUARDED;
12609363481eSGabor Toth 		}
12619363481eSGabor Toth 
12625a923b99SBalint Dobszay 		/*
12635a923b99SBalint Dobszay 		 * The SP is a secure endpoint, security attribute can be
12645a923b99SBalint Dobszay 		 * secure or non-secure.
1265c36d2192SBalint Dobszay 		 * The SPMC cannot allocate non-secure memory, i.e. if the base
1266c36d2192SBalint Dobszay 		 * address is missing this attribute must be secure.
12675a923b99SBalint Dobszay 		 */
1268c36d2192SBalint Dobszay 		if (attributes & SP_MANIFEST_ATTR_NSEC) {
1269c36d2192SBalint Dobszay 			if (alloc_needed) {
1270c36d2192SBalint Dobszay 				EMSG("Invalid memory security attribute");
1271c36d2192SBalint Dobszay 				return TEE_ERROR_BAD_FORMAT;
1272c36d2192SBalint Dobszay 			}
12735a923b99SBalint Dobszay 			is_secure = false;
1274c36d2192SBalint Dobszay 		}
1275c36d2192SBalint Dobszay 
1276c36d2192SBalint Dobszay 		if (alloc_needed) {
1277c36d2192SBalint Dobszay 			/* Base address is missing, we have to allocate */
1278de19cacbSJens Wiklander 			mm = phys_mem_ta_alloc(size);
1279c36d2192SBalint Dobszay 			if (!mm)
1280c36d2192SBalint Dobszay 				return TEE_ERROR_OUT_OF_MEMORY;
1281c36d2192SBalint Dobszay 
1282c36d2192SBalint Dobszay 			base_addr = tee_mm_get_smem(mm);
1283c36d2192SBalint Dobszay 		}
12845a923b99SBalint Dobszay 
12855a923b99SBalint Dobszay 		m = sp_mem_new_mobj(pages_cnt, TEE_MATTR_MEM_TYPE_CACHED,
12865a923b99SBalint Dobszay 				    is_secure);
1287c36d2192SBalint Dobszay 		if (!m) {
1288c36d2192SBalint Dobszay 			res = TEE_ERROR_OUT_OF_MEMORY;
1289c36d2192SBalint Dobszay 			goto err_mm_free;
1290c36d2192SBalint Dobszay 		}
12915a923b99SBalint Dobszay 
12925a923b99SBalint Dobszay 		res = sp_mem_add_pages(m, &idx, base_addr, pages_cnt);
12935a923b99SBalint Dobszay 		if (res) {
12945a923b99SBalint Dobszay 			mobj_put(m);
1295c36d2192SBalint Dobszay 			goto err_mm_free;
12965a923b99SBalint Dobszay 		}
12975a923b99SBalint Dobszay 
12985a923b99SBalint Dobszay 		res = vm_map(&ctx->uctx, &va, size, perm, 0, m, 0);
12995a923b99SBalint Dobszay 		mobj_put(m);
13005a923b99SBalint Dobszay 		if (res)
1301c36d2192SBalint Dobszay 			goto err_mm_free;
13025a923b99SBalint Dobszay 
13035a923b99SBalint Dobszay 		/*
13045a923b99SBalint Dobszay 		 * Overwrite the memory region's base address in the fdt with
13055a923b99SBalint Dobszay 		 * the VA. This fdt will be passed to the SP.
1306c36d2192SBalint Dobszay 		 * If the base-address field was not present in the original
1307c36d2192SBalint Dobszay 		 * fdt, this function will create it. This doesn't cause issues
1308c36d2192SBalint Dobszay 		 * since the necessary extra space has been allocated when
1309c36d2192SBalint Dobszay 		 * opening the fdt.
13105a923b99SBalint Dobszay 		 */
13115a923b99SBalint Dobszay 		res = fdt_setprop_u64(fdt, subnode, "base-address", va);
13125a923b99SBalint Dobszay 
13135a923b99SBalint Dobszay 		/*
13145a923b99SBalint Dobszay 		 * Unmap the region if the overwrite failed since the SP won't
13155a923b99SBalint Dobszay 		 * be able to access it without knowing the VA.
13165a923b99SBalint Dobszay 		 */
13175a923b99SBalint Dobszay 		if (res) {
13185a923b99SBalint Dobszay 			vm_unmap(&ctx->uctx, va, size);
1319c36d2192SBalint Dobszay 			goto err_mm_free;
13205a923b99SBalint Dobszay 		}
13215a923b99SBalint Dobszay 	}
13225a923b99SBalint Dobszay 
13235a923b99SBalint Dobszay 	return TEE_SUCCESS;
1324c36d2192SBalint Dobszay 
1325c36d2192SBalint Dobszay err_mm_free:
1326c36d2192SBalint Dobszay 	tee_mm_free(mm);
1327c36d2192SBalint Dobszay 	return res;
13285a923b99SBalint Dobszay }
13295a923b99SBalint Dobszay 
handle_tpm_event_log(struct sp_ctx * ctx,void * fdt)1330145035ffSImre Kis static TEE_Result handle_tpm_event_log(struct sp_ctx *ctx, void *fdt)
1331145035ffSImre Kis {
1332145035ffSImre Kis 	uint32_t perm = TEE_MATTR_URW | TEE_MATTR_PRW;
1333145035ffSImre Kis 	uint32_t dummy_size __maybe_unused = 0;
1334145035ffSImre Kis 	TEE_Result res = TEE_SUCCESS;
1335145035ffSImre Kis 	size_t page_count = 0;
1336145035ffSImre Kis 	struct fobj *f = NULL;
1337145035ffSImre Kis 	struct mobj *m = NULL;
1338145035ffSImre Kis 	vaddr_t log_addr = 0;
1339145035ffSImre Kis 	size_t log_size = 0;
1340145035ffSImre Kis 	int node = 0;
1341145035ffSImre Kis 
1342145035ffSImre Kis 	node = fdt_node_offset_by_compatible(fdt, 0, "arm,tpm_event_log");
1343145035ffSImre Kis 	if (node < 0)
1344145035ffSImre Kis 		return TEE_SUCCESS;
1345145035ffSImre Kis 
1346145035ffSImre Kis 	/* Checking the existence and size of the event log properties */
1347145035ffSImre Kis 	if (sp_dt_get_u64(fdt, node, "tpm_event_log_addr", &log_addr)) {
1348145035ffSImre Kis 		EMSG("tpm_event_log_addr not found or has invalid size");
1349145035ffSImre Kis 		return TEE_ERROR_BAD_FORMAT;
1350145035ffSImre Kis 	}
1351145035ffSImre Kis 
1352145035ffSImre Kis 	if (sp_dt_get_u32(fdt, node, "tpm_event_log_size", &dummy_size)) {
1353145035ffSImre Kis 		EMSG("tpm_event_log_size not found or has invalid size");
1354145035ffSImre Kis 		return TEE_ERROR_BAD_FORMAT;
1355145035ffSImre Kis 	}
1356145035ffSImre Kis 
1357145035ffSImre Kis 	/* Validating event log */
1358145035ffSImre Kis 	res = tpm_get_event_log_size(&log_size);
1359145035ffSImre Kis 	if (res)
1360145035ffSImre Kis 		return res;
1361145035ffSImre Kis 
1362145035ffSImre Kis 	if (!log_size) {
1363145035ffSImre Kis 		EMSG("Empty TPM event log was provided");
1364145035ffSImre Kis 		return TEE_ERROR_ITEM_NOT_FOUND;
1365145035ffSImre Kis 	}
1366145035ffSImre Kis 
1367145035ffSImre Kis 	/* Allocating memory area for the event log to share with the SP */
1368145035ffSImre Kis 	page_count = ROUNDUP_DIV(log_size, SMALL_PAGE_SIZE);
1369145035ffSImre Kis 
1370145035ffSImre Kis 	f = fobj_sec_mem_alloc(page_count);
13716105aa86SJens Wiklander 	m = mobj_with_fobj_alloc(f, NULL, TEE_MATTR_MEM_TYPE_TAGGED);
1372145035ffSImre Kis 	fobj_put(f);
1373145035ffSImre Kis 	if (!m)
1374145035ffSImre Kis 		return TEE_ERROR_OUT_OF_MEMORY;
1375145035ffSImre Kis 
1376145035ffSImre Kis 	res = vm_map(&ctx->uctx, &log_addr, log_size, perm, 0, m, 0);
1377145035ffSImre Kis 	mobj_put(m);
1378145035ffSImre Kis 	if (res)
1379145035ffSImre Kis 		return res;
1380145035ffSImre Kis 
1381145035ffSImre Kis 	/* Copy event log */
1382145035ffSImre Kis 	res = tpm_get_event_log((void *)log_addr, &log_size);
1383145035ffSImre Kis 	if (res)
1384145035ffSImre Kis 		goto err_unmap;
1385145035ffSImre Kis 
1386145035ffSImre Kis 	/* Setting event log details in the manifest */
1387145035ffSImre Kis 	res = fdt_setprop_u64(fdt, node, "tpm_event_log_addr", log_addr);
1388145035ffSImre Kis 	if (res)
1389145035ffSImre Kis 		goto err_unmap;
1390145035ffSImre Kis 
1391145035ffSImre Kis 	res = fdt_setprop_u32(fdt, node, "tpm_event_log_size", log_size);
1392145035ffSImre Kis 	if (res)
1393145035ffSImre Kis 		goto err_unmap;
1394145035ffSImre Kis 
1395145035ffSImre Kis 	return TEE_SUCCESS;
1396145035ffSImre Kis 
1397145035ffSImre Kis err_unmap:
1398145035ffSImre Kis 	vm_unmap(&ctx->uctx, log_addr, log_size);
1399145035ffSImre Kis 
1400145035ffSImre Kis 	return res;
1401145035ffSImre Kis }
1402145035ffSImre Kis 
1403acaba7aaSBalint Dobszay /*
1404acaba7aaSBalint Dobszay  * Note: this function is called only on the primary CPU. It assumes that the
1405acaba7aaSBalint Dobszay  * features present on the primary CPU are available on all of the secondary
1406acaba7aaSBalint Dobszay  * CPUs as well.
1407acaba7aaSBalint Dobszay  */
handle_hw_features(void * fdt)1408acaba7aaSBalint Dobszay static TEE_Result handle_hw_features(void *fdt)
1409acaba7aaSBalint Dobszay {
1410acaba7aaSBalint Dobszay 	uint32_t val __maybe_unused = 0;
1411acaba7aaSBalint Dobszay 	TEE_Result res = TEE_SUCCESS;
1412acaba7aaSBalint Dobszay 	int node = 0;
1413acaba7aaSBalint Dobszay 
1414acaba7aaSBalint Dobszay 	/*
1415acaba7aaSBalint Dobszay 	 * HW feature descriptions are optional in the SP manifest, it's not an
1416acaba7aaSBalint Dobszay 	 * error if we don't find any.
1417acaba7aaSBalint Dobszay 	 */
1418acaba7aaSBalint Dobszay 	node = fdt_node_offset_by_compatible(fdt, 0, "arm,hw-features");
1419acaba7aaSBalint Dobszay 	if (node < 0)
1420acaba7aaSBalint Dobszay 		return TEE_SUCCESS;
1421acaba7aaSBalint Dobszay 
1422acaba7aaSBalint Dobszay 	/* Modify the crc32 property only if it's already present */
1423acaba7aaSBalint Dobszay 	if (!sp_dt_get_u32(fdt, node, "crc32", &val)) {
1424acaba7aaSBalint Dobszay 		res = fdt_setprop_u32(fdt, node, "crc32",
1425acaba7aaSBalint Dobszay 				      feat_crc32_implemented());
1426acaba7aaSBalint Dobszay 		if (res)
1427acaba7aaSBalint Dobszay 			return res;
1428acaba7aaSBalint Dobszay 	}
1429acaba7aaSBalint Dobszay 
14309f32a1a2SGabor Toth 	/* Modify the property only if it's already present */
14319f32a1a2SGabor Toth 	if (!sp_dt_get_u32(fdt, node, "bti", &val)) {
14329f32a1a2SGabor Toth 		res = fdt_setprop_u32(fdt, node, "bti",
14339f32a1a2SGabor Toth 				      feat_bti_is_implemented());
14349f32a1a2SGabor Toth 		if (res)
14359f32a1a2SGabor Toth 			return res;
14369f32a1a2SGabor Toth 	}
14379f32a1a2SGabor Toth 
14389f32a1a2SGabor Toth 	/* Modify the property only if it's already present */
14399f32a1a2SGabor Toth 	if (!sp_dt_get_u32(fdt, node, "pauth", &val)) {
14409f32a1a2SGabor Toth 		res = fdt_setprop_u32(fdt, node, "pauth",
14419f32a1a2SGabor Toth 				      feat_pauth_is_implemented());
14429f32a1a2SGabor Toth 		if (res)
14439f32a1a2SGabor Toth 			return res;
14449f32a1a2SGabor Toth 	}
14459f32a1a2SGabor Toth 
1446acaba7aaSBalint Dobszay 	return TEE_SUCCESS;
1447acaba7aaSBalint Dobszay }
1448acaba7aaSBalint Dobszay 
read_ns_interrupts_action(const void * fdt,struct sp_session * s)14499cc3a2ffSImre Kis static TEE_Result read_ns_interrupts_action(const void *fdt,
14509cc3a2ffSImre Kis 					    struct sp_session *s)
14519cc3a2ffSImre Kis {
14529cc3a2ffSImre Kis 	TEE_Result res = TEE_ERROR_BAD_PARAMETERS;
14539cc3a2ffSImre Kis 
14549cc3a2ffSImre Kis 	res = sp_dt_get_u32(fdt, 0, "ns-interrupts-action", &s->ns_int_mode);
14559cc3a2ffSImre Kis 
14569cc3a2ffSImre Kis 	if (res) {
14579cc3a2ffSImre Kis 		EMSG("Mandatory property is missing: ns-interrupts-action");
14589cc3a2ffSImre Kis 		return res;
14599cc3a2ffSImre Kis 	}
14609cc3a2ffSImre Kis 
14619cc3a2ffSImre Kis 	switch (s->ns_int_mode) {
14629cc3a2ffSImre Kis 	case SP_MANIFEST_NS_INT_QUEUED:
14639cc3a2ffSImre Kis 	case SP_MANIFEST_NS_INT_SIGNALED:
14649cc3a2ffSImre Kis 		/* OK */
14659cc3a2ffSImre Kis 		break;
14669cc3a2ffSImre Kis 
14679cc3a2ffSImre Kis 	case SP_MANIFEST_NS_INT_MANAGED_EXIT:
14689cc3a2ffSImre Kis 		EMSG("Managed exit is not implemented");
14699cc3a2ffSImre Kis 		return TEE_ERROR_NOT_IMPLEMENTED;
14709cc3a2ffSImre Kis 
14719cc3a2ffSImre Kis 	default:
14729cc3a2ffSImre Kis 		EMSG("Invalid ns-interrupts-action value: %"PRIu32,
14739cc3a2ffSImre Kis 		     s->ns_int_mode);
14749cc3a2ffSImre Kis 		return TEE_ERROR_BAD_PARAMETERS;
14759cc3a2ffSImre Kis 	}
14769cc3a2ffSImre Kis 
14779cc3a2ffSImre Kis 	return TEE_SUCCESS;
14789cc3a2ffSImre Kis }
14799cc3a2ffSImre Kis 
read_ffa_version(const void * fdt,struct sp_session * s)1480655625e0SImre Kis static TEE_Result read_ffa_version(const void *fdt, struct sp_session *s)
1481655625e0SImre Kis {
1482655625e0SImre Kis 	TEE_Result res = TEE_ERROR_BAD_PARAMETERS;
1483655625e0SImre Kis 	uint32_t ffa_version = 0;
1484655625e0SImre Kis 
1485655625e0SImre Kis 	res = sp_dt_get_u32(fdt, 0, "ffa-version", &ffa_version);
1486655625e0SImre Kis 	if (res) {
1487655625e0SImre Kis 		EMSG("Mandatory property is missing: ffa-version");
1488655625e0SImre Kis 		return res;
1489655625e0SImre Kis 	}
1490655625e0SImre Kis 
1491655625e0SImre Kis 	if (ffa_version != FFA_VERSION_1_0 && ffa_version != FFA_VERSION_1_1) {
1492655625e0SImre Kis 		EMSG("Invalid FF-A version value: 0x%08"PRIx32, ffa_version);
1493655625e0SImre Kis 		return TEE_ERROR_BAD_PARAMETERS;
1494655625e0SImre Kis 	}
1495655625e0SImre Kis 
1496655625e0SImre Kis 	s->rxtx.ffa_vers = ffa_version;
1497655625e0SImre Kis 
1498655625e0SImre Kis 	return TEE_SUCCESS;
1499655625e0SImre Kis }
1500655625e0SImre Kis 
read_sp_exec_state(const void * fdt,struct sp_session * s)1501cc04f76fSBalint Dobszay static TEE_Result read_sp_exec_state(const void *fdt, struct sp_session *s)
1502cc04f76fSBalint Dobszay {
1503cc04f76fSBalint Dobszay 	TEE_Result res = TEE_ERROR_BAD_PARAMETERS;
1504cc04f76fSBalint Dobszay 	uint32_t exec_state = 0;
1505cc04f76fSBalint Dobszay 
1506cc04f76fSBalint Dobszay 	res = sp_dt_get_u32(fdt, 0, "execution-state", &exec_state);
1507cc04f76fSBalint Dobszay 	if (res) {
1508cc04f76fSBalint Dobszay 		EMSG("Mandatory property is missing: execution-state");
1509cc04f76fSBalint Dobszay 		return res;
1510cc04f76fSBalint Dobszay 	}
1511cc04f76fSBalint Dobszay 
1512cc04f76fSBalint Dobszay 	/* Currently only AArch64 SPs are supported */
1513cc04f76fSBalint Dobszay 	if (exec_state == SP_MANIFEST_EXEC_STATE_AARCH64) {
1514cc04f76fSBalint Dobszay 		s->props |= FFA_PART_PROP_AARCH64_STATE;
1515cc04f76fSBalint Dobszay 	} else {
1516cc04f76fSBalint Dobszay 		EMSG("Invalid execution-state value: %"PRIu32, exec_state);
1517cc04f76fSBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
1518cc04f76fSBalint Dobszay 	}
1519cc04f76fSBalint Dobszay 
1520cc04f76fSBalint Dobszay 	return TEE_SUCCESS;
1521cc04f76fSBalint Dobszay }
1522cc04f76fSBalint Dobszay 
read_sp_msg_types(const void * fdt,struct sp_session * s)1523cc04f76fSBalint Dobszay static TEE_Result read_sp_msg_types(const void *fdt, struct sp_session *s)
1524cc04f76fSBalint Dobszay {
1525cc04f76fSBalint Dobszay 	TEE_Result res = TEE_ERROR_BAD_PARAMETERS;
1526cc04f76fSBalint Dobszay 	uint32_t msg_method = 0;
1527cc04f76fSBalint Dobszay 
1528cc04f76fSBalint Dobszay 	res = sp_dt_get_u32(fdt, 0, "messaging-method", &msg_method);
1529cc04f76fSBalint Dobszay 	if (res) {
1530cc04f76fSBalint Dobszay 		EMSG("Mandatory property is missing: messaging-method");
1531cc04f76fSBalint Dobszay 		return res;
1532cc04f76fSBalint Dobszay 	}
1533cc04f76fSBalint Dobszay 
1534cc04f76fSBalint Dobszay 	if (msg_method & SP_MANIFEST_DIRECT_REQ_RECEIVE)
1535cc04f76fSBalint Dobszay 		s->props |= FFA_PART_PROP_DIRECT_REQ_RECV;
1536cc04f76fSBalint Dobszay 
1537cc04f76fSBalint Dobszay 	if (msg_method & SP_MANIFEST_DIRECT_REQ_SEND)
1538cc04f76fSBalint Dobszay 		s->props |= FFA_PART_PROP_DIRECT_REQ_SEND;
1539cc04f76fSBalint Dobszay 
1540cc04f76fSBalint Dobszay 	if (msg_method & SP_MANIFEST_INDIRECT_REQ)
1541cc04f76fSBalint Dobszay 		IMSG("Indirect messaging is not supported");
1542cc04f76fSBalint Dobszay 
1543cc04f76fSBalint Dobszay 	return TEE_SUCCESS;
1544cc04f76fSBalint Dobszay }
1545cc04f76fSBalint Dobszay 
read_vm_availability_msg(const void * fdt,struct sp_session * s)15468dde314bSBalint Dobszay static TEE_Result read_vm_availability_msg(const void *fdt,
15478dde314bSBalint Dobszay 					   struct sp_session *s)
15488dde314bSBalint Dobszay {
15498dde314bSBalint Dobszay 	TEE_Result res = TEE_ERROR_BAD_PARAMETERS;
15508dde314bSBalint Dobszay 	uint32_t v = 0;
15518dde314bSBalint Dobszay 
15528dde314bSBalint Dobszay 	res = sp_dt_get_u32(fdt, 0, "vm-availability-messages", &v);
15538dde314bSBalint Dobszay 
15548dde314bSBalint Dobszay 	/* This field in the manifest is optional */
15558dde314bSBalint Dobszay 	if (res == TEE_ERROR_ITEM_NOT_FOUND)
15568dde314bSBalint Dobszay 		return TEE_SUCCESS;
15578dde314bSBalint Dobszay 
15588dde314bSBalint Dobszay 	if (res)
15598dde314bSBalint Dobszay 		return res;
15608dde314bSBalint Dobszay 
15618dde314bSBalint Dobszay 	if (v & ~(SP_MANIFEST_VM_CREATED_MSG | SP_MANIFEST_VM_DESTROYED_MSG)) {
15628dde314bSBalint Dobszay 		EMSG("Invalid vm-availability-messages value: %"PRIu32, v);
15638dde314bSBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
15648dde314bSBalint Dobszay 	}
15658dde314bSBalint Dobszay 
15668dde314bSBalint Dobszay 	if (v & SP_MANIFEST_VM_CREATED_MSG)
15678dde314bSBalint Dobszay 		s->props |= FFA_PART_PROP_NOTIF_CREATED;
15688dde314bSBalint Dobszay 
15698dde314bSBalint Dobszay 	if (v & SP_MANIFEST_VM_DESTROYED_MSG)
15708dde314bSBalint Dobszay 		s->props |= FFA_PART_PROP_NOTIF_DESTROYED;
15718dde314bSBalint Dobszay 
15728dde314bSBalint Dobszay 	return TEE_SUCCESS;
15738dde314bSBalint Dobszay }
15748dde314bSBalint Dobszay 
get_boot_order(const void * fdt,uint32_t * boot_order)15759d58f55eSGyorgy Szing static TEE_Result get_boot_order(const void *fdt, uint32_t *boot_order)
15769d58f55eSGyorgy Szing {
15779d58f55eSGyorgy Szing 	TEE_Result res = TEE_SUCCESS;
15789d58f55eSGyorgy Szing 
15799d58f55eSGyorgy Szing 	res = sp_dt_get_u32(fdt, 0, "boot-order", boot_order);
15809d58f55eSGyorgy Szing 
15819d58f55eSGyorgy Szing 	if (res == TEE_SUCCESS) {
15829d58f55eSGyorgy Szing 		if (*boot_order > UINT16_MAX) {
15839d58f55eSGyorgy Szing 			EMSG("Value of boot-order property (%"PRIu32") is out of range",
15849d58f55eSGyorgy Szing 			     *boot_order);
15859d58f55eSGyorgy Szing 			res = TEE_ERROR_BAD_FORMAT;
15869d58f55eSGyorgy Szing 		}
15879d58f55eSGyorgy Szing 	} else if (res == TEE_ERROR_BAD_FORMAT) {
15889d58f55eSGyorgy Szing 		uint16_t boot_order_u16 = 0;
15899d58f55eSGyorgy Szing 
15909d58f55eSGyorgy Szing 		res = sp_dt_get_u16(fdt, 0, "boot-order", &boot_order_u16);
15919d58f55eSGyorgy Szing 		if (res == TEE_SUCCESS)
15929d58f55eSGyorgy Szing 			*boot_order = boot_order_u16;
15939d58f55eSGyorgy Szing 	}
15949d58f55eSGyorgy Szing 
15959d58f55eSGyorgy Szing 	if (res == TEE_ERROR_ITEM_NOT_FOUND)
15969d58f55eSGyorgy Szing 		*boot_order = UNDEFINED_BOOT_ORDER_VALUE;
15979d58f55eSGyorgy Szing 	else if (res != TEE_SUCCESS)
15989d58f55eSGyorgy Szing 		EMSG("Failed reading boot-order property err: %#"PRIx32, res);
15999d58f55eSGyorgy Szing 
16009d58f55eSGyorgy Szing 	return res;
16019d58f55eSGyorgy Szing }
16029d58f55eSGyorgy Szing 
sp_init_uuid(const TEE_UUID * bin_uuid,const void * const fdt)1603552d5e40SJelle Sels static TEE_Result sp_init_uuid(const TEE_UUID *bin_uuid, const void * const fdt)
1604c185655eSJelle Sels {
1605c185655eSJelle Sels 	TEE_Result res = TEE_SUCCESS;
1606c185655eSJelle Sels 	struct sp_session *sess = NULL;
1607552d5e40SJelle Sels 	TEE_UUID ffa_uuid = {};
16089d58f55eSGyorgy Szing 	uint32_t boot_order = 0;
160928710257SJelle Sels 
1610552d5e40SJelle Sels 	res = fdt_get_uuid(fdt, &ffa_uuid);
1611c185655eSJelle Sels 	if (res)
1612c185655eSJelle Sels 		return res;
1613c185655eSJelle Sels 
16149d58f55eSGyorgy Szing 	res = get_boot_order(fdt, &boot_order);
16159d58f55eSGyorgy Szing 	if (res)
1616d10a438bSGabor Ambrus 		return res;
1617d10a438bSGabor Ambrus 
1618552d5e40SJelle Sels 	res = sp_open_session(&sess,
1619552d5e40SJelle Sels 			      &open_sp_sessions,
16209d58f55eSGyorgy Szing 			      &ffa_uuid, bin_uuid, boot_order, fdt);
16217e8d05e4SJelle Sels 	if (res)
16227e8d05e4SJelle Sels 		return res;
1623ae6b3380SJelle Sels 
162424fe8824SJelle Sels 	sess->fdt = fdt;
1625d10a438bSGabor Ambrus 
162624fe8824SJelle Sels 	res = read_manifest_endpoint_id(sess);
162724fe8824SJelle Sels 	if (res)
162824fe8824SJelle Sels 		return res;
162924fe8824SJelle Sels 	DMSG("endpoint is 0x%"PRIx16, sess->endpoint_id);
163024fe8824SJelle Sels 
16319cc3a2ffSImre Kis 	res = read_ns_interrupts_action(fdt, sess);
16329cc3a2ffSImre Kis 	if (res)
16339cc3a2ffSImre Kis 		return res;
16349cc3a2ffSImre Kis 
1635655625e0SImre Kis 	res = read_ffa_version(fdt, sess);
1636655625e0SImre Kis 	if (res)
1637655625e0SImre Kis 		return res;
1638655625e0SImre Kis 
1639cc04f76fSBalint Dobszay 	res = read_sp_exec_state(fdt, sess);
1640cc04f76fSBalint Dobszay 	if (res)
1641cc04f76fSBalint Dobszay 		return res;
1642cc04f76fSBalint Dobszay 
1643cc04f76fSBalint Dobszay 	res = read_sp_msg_types(fdt, sess);
1644cc04f76fSBalint Dobszay 	if (res)
1645cc04f76fSBalint Dobszay 		return res;
1646cc04f76fSBalint Dobszay 
16478dde314bSBalint Dobszay 	res = read_vm_availability_msg(fdt, sess);
16488dde314bSBalint Dobszay 	if (res)
16498dde314bSBalint Dobszay 		return res;
16508dde314bSBalint Dobszay 
165124fe8824SJelle Sels 	return TEE_SUCCESS;
165224fe8824SJelle Sels }
165324fe8824SJelle Sels 
sp_first_run(struct sp_session * sess)165424fe8824SJelle Sels static TEE_Result sp_first_run(struct sp_session *sess)
165524fe8824SJelle Sels {
165624fe8824SJelle Sels 	TEE_Result res = TEE_SUCCESS;
1657d17db2afSJens Wiklander 	struct thread_smc_1_2_regs args = { };
165824fe8824SJelle Sels 	struct sp_ctx *ctx = NULL;
16597bb22ad3SBalint Dobszay 	vaddr_t boot_info_va = 0;
16607bb22ad3SBalint Dobszay 	size_t boot_info_size = 0;
166124fe8824SJelle Sels 	void *fdt_copy = NULL;
16627bb22ad3SBalint Dobszay 	size_t fdt_size = 0;
166324fe8824SJelle Sels 
16646d618ba1SJelle Sels 	ctx = to_sp_ctx(sess->ts_sess.ctx);
16656d618ba1SJelle Sels 	ts_push_current_session(&sess->ts_sess);
1666d2a2d362SBalint Dobszay 	sess->is_initialized = false;
16676d618ba1SJelle Sels 
166809b678f1SImre Kis 	/*
166909b678f1SImre Kis 	 * Load relative memory regions must be handled before doing any other
167009b678f1SImre Kis 	 * mapping to prevent conflicts in the VA space.
167109b678f1SImre Kis 	 */
167209b678f1SImre Kis 	res = handle_fdt_load_relative_mem_regions(ctx, sess->fdt);
167309b678f1SImre Kis 	if (res) {
167409b678f1SImre Kis 		ts_pop_current_session();
167509b678f1SImre Kis 		return res;
167609b678f1SImre Kis 	}
167709b678f1SImre Kis 
16787bb22ad3SBalint Dobszay 	res = copy_and_map_fdt(ctx, sess->fdt, &fdt_copy, &fdt_size);
16796d618ba1SJelle Sels 	if (res)
16806d618ba1SJelle Sels 		goto out;
16816d618ba1SJelle Sels 
16826d618ba1SJelle Sels 	res = handle_fdt_dev_regions(ctx, fdt_copy);
16836d618ba1SJelle Sels 	if (res)
16846d618ba1SJelle Sels 		goto out;
16856d618ba1SJelle Sels 
16865a923b99SBalint Dobszay 	res = handle_fdt_mem_regions(ctx, fdt_copy);
16875a923b99SBalint Dobszay 	if (res)
16885a923b99SBalint Dobszay 		goto out;
16895a923b99SBalint Dobszay 
1690145035ffSImre Kis 	if (IS_ENABLED(CFG_CORE_TPM_EVENT_LOG)) {
1691145035ffSImre Kis 		res = handle_tpm_event_log(ctx, fdt_copy);
1692145035ffSImre Kis 		if (res)
1693145035ffSImre Kis 			goto out;
1694145035ffSImre Kis 	}
1695145035ffSImre Kis 
1696acaba7aaSBalint Dobszay 	res = handle_hw_features(fdt_copy);
1697acaba7aaSBalint Dobszay 	if (res)
1698acaba7aaSBalint Dobszay 		goto out;
1699acaba7aaSBalint Dobszay 
17007bb22ad3SBalint Dobszay 	res = create_and_map_boot_info(ctx, fdt_copy, &args, &boot_info_va,
1701655625e0SImre Kis 				       &boot_info_size, sess->rxtx.ffa_vers);
17027bb22ad3SBalint Dobszay 	if (res)
17037bb22ad3SBalint Dobszay 		goto out;
17047bb22ad3SBalint Dobszay 
17056d618ba1SJelle Sels 	ts_pop_current_session();
17066d618ba1SJelle Sels 
1707d2a2d362SBalint Dobszay 	res = sp_enter(&args, sess);
1708d2a2d362SBalint Dobszay 	if (res) {
1709d2a2d362SBalint Dobszay 		ts_push_current_session(&sess->ts_sess);
1710d2a2d362SBalint Dobszay 		goto out;
17116d618ba1SJelle Sels 	}
1712ae6b3380SJelle Sels 
1713ae6b3380SJelle Sels 	spmc_sp_msg_handler(&args, sess);
1714ae6b3380SJelle Sels 
1715d2a2d362SBalint Dobszay 	ts_push_current_session(&sess->ts_sess);
1716438f0055SJelle Sels 	sess->is_initialized = true;
1717438f0055SJelle Sels 
17186d618ba1SJelle Sels out:
17196d618ba1SJelle Sels 	/* Free the boot info page from the SP memory */
17207bb22ad3SBalint Dobszay 	vm_unmap(&ctx->uctx, boot_info_va, boot_info_size);
17217bb22ad3SBalint Dobszay 	vm_unmap(&ctx->uctx, (vaddr_t)fdt_copy, fdt_size);
17227e8d05e4SJelle Sels 	ts_pop_current_session();
17237e8d05e4SJelle Sels 
17247e8d05e4SJelle Sels 	return res;
1725ae6b3380SJelle Sels }
1726ae6b3380SJelle Sels 
sp_enter(struct thread_smc_1_2_regs * args,struct sp_session * sp)1727d17db2afSJens Wiklander TEE_Result sp_enter(struct thread_smc_1_2_regs *args, struct sp_session *sp)
1728ae6b3380SJelle Sels {
1729d2a2d362SBalint Dobszay 	TEE_Result res = TEE_SUCCESS;
1730ae6b3380SJelle Sels 	struct sp_ctx *ctx = to_sp_ctx(sp->ts_sess.ctx);
1731ae6b3380SJelle Sels 
1732ae6b3380SJelle Sels 	ctx->sp_regs.x[0] = args->a0;
1733ae6b3380SJelle Sels 	ctx->sp_regs.x[1] = args->a1;
1734ae6b3380SJelle Sels 	ctx->sp_regs.x[2] = args->a2;
1735ae6b3380SJelle Sels 	ctx->sp_regs.x[3] = args->a3;
1736ae6b3380SJelle Sels 	ctx->sp_regs.x[4] = args->a4;
1737ae6b3380SJelle Sels 	ctx->sp_regs.x[5] = args->a5;
1738ae6b3380SJelle Sels 	ctx->sp_regs.x[6] = args->a6;
1739ae6b3380SJelle Sels 	ctx->sp_regs.x[7] = args->a7;
1740d19343acSGabor Toth #ifdef CFG_TA_PAUTH
1741d19343acSGabor Toth 	ctx->sp_regs.apiakey_hi = ctx->uctx.keys.apia_hi;
1742d19343acSGabor Toth 	ctx->sp_regs.apiakey_lo = ctx->uctx.keys.apia_lo;
1743d19343acSGabor Toth #endif
1744ae6b3380SJelle Sels 
1745ae6b3380SJelle Sels 	res = sp->ts_sess.ctx->ops->enter_invoke_cmd(&sp->ts_sess, 0);
1746ae6b3380SJelle Sels 
1747ae6b3380SJelle Sels 	args->a0 = ctx->sp_regs.x[0];
1748ae6b3380SJelle Sels 	args->a1 = ctx->sp_regs.x[1];
1749ae6b3380SJelle Sels 	args->a2 = ctx->sp_regs.x[2];
1750ae6b3380SJelle Sels 	args->a3 = ctx->sp_regs.x[3];
1751ae6b3380SJelle Sels 	args->a4 = ctx->sp_regs.x[4];
1752ae6b3380SJelle Sels 	args->a5 = ctx->sp_regs.x[5];
1753ae6b3380SJelle Sels 	args->a6 = ctx->sp_regs.x[6];
1754ae6b3380SJelle Sels 	args->a7 = ctx->sp_regs.x[7];
1755ae6b3380SJelle Sels 
1756c185655eSJelle Sels 	return res;
1757c185655eSJelle Sels }
1758c185655eSJelle Sels 
17599cc3a2ffSImre Kis /*
17609cc3a2ffSImre Kis  * According to FF-A v1.1 section 8.3.1.4 if a caller requires less permissive
17619cc3a2ffSImre Kis  * active on NS interrupt than the callee, the callee must inherit the caller's
17629cc3a2ffSImre Kis  * configuration.
17639cc3a2ffSImre Kis  * Each SP's own NS action setting is stored in ns_int_mode. The effective
17649cc3a2ffSImre Kis  * action will be MIN([self action], [caller's action]) which is stored in the
17659cc3a2ffSImre Kis  * ns_int_mode_inherited field.
17669cc3a2ffSImre Kis  */
sp_cpsr_configure_foreign_interrupts(struct sp_session * s,struct ts_session * caller,uint64_t * cpsr)17679cc3a2ffSImre Kis static void sp_cpsr_configure_foreign_interrupts(struct sp_session *s,
17689cc3a2ffSImre Kis 						 struct ts_session *caller,
17699cc3a2ffSImre Kis 						 uint64_t *cpsr)
17709cc3a2ffSImre Kis {
17719cc3a2ffSImre Kis 	if (caller) {
17729cc3a2ffSImre Kis 		struct sp_session *caller_sp = to_sp_session(caller);
17739cc3a2ffSImre Kis 
17749cc3a2ffSImre Kis 		s->ns_int_mode_inherited = MIN(caller_sp->ns_int_mode_inherited,
17759cc3a2ffSImre Kis 					       s->ns_int_mode);
17769cc3a2ffSImre Kis 	} else {
17779cc3a2ffSImre Kis 		s->ns_int_mode_inherited = s->ns_int_mode;
17789cc3a2ffSImre Kis 	}
17799cc3a2ffSImre Kis 
17809cc3a2ffSImre Kis 	if (s->ns_int_mode_inherited == SP_MANIFEST_NS_INT_QUEUED)
17819cc3a2ffSImre Kis 		*cpsr |= SHIFT_U32(THREAD_EXCP_FOREIGN_INTR,
17829cc3a2ffSImre Kis 				   ARM32_CPSR_F_SHIFT);
17839cc3a2ffSImre Kis 	else
17849cc3a2ffSImre Kis 		*cpsr &= ~SHIFT_U32(THREAD_EXCP_FOREIGN_INTR,
17859cc3a2ffSImre Kis 				    ARM32_CPSR_F_SHIFT);
17869cc3a2ffSImre Kis }
17879cc3a2ffSImre Kis 
sp_enter_invoke_cmd(struct ts_session * s,uint32_t cmd __unused)1788ae6b3380SJelle Sels static TEE_Result sp_enter_invoke_cmd(struct ts_session *s,
1789ae6b3380SJelle Sels 				      uint32_t cmd __unused)
1790ae6b3380SJelle Sels {
1791ae6b3380SJelle Sels 	struct sp_ctx *ctx = to_sp_ctx(s->ctx);
1792ae6b3380SJelle Sels 	TEE_Result res = TEE_SUCCESS;
1793ae6b3380SJelle Sels 	uint32_t exceptions = 0;
1794ae6b3380SJelle Sels 	struct sp_session *sp_s = to_sp_session(s);
1795ae6b3380SJelle Sels 	struct ts_session *sess = NULL;
1796ae6b3380SJelle Sels 	struct thread_ctx_regs *sp_regs = NULL;
17979cc3a2ffSImre Kis 	struct ts_session *caller = NULL;
17984d028847SImre Kis 	uint32_t rpc_target_info = 0;
1799ae6b3380SJelle Sels 	uint32_t panicked = false;
1800ae6b3380SJelle Sels 	uint32_t panic_code = 0;
1801ae6b3380SJelle Sels 
1802ae6b3380SJelle Sels 	sp_regs = &ctx->sp_regs;
1803ae6b3380SJelle Sels 	ts_push_current_session(s);
1804ae6b3380SJelle Sels 
1805ae6b3380SJelle Sels 	exceptions = thread_mask_exceptions(THREAD_EXCP_ALL);
18064d028847SImre Kis 
18079cc3a2ffSImre Kis 	/* Enable/disable foreign interrupts in CPSR/SPSR */
18089cc3a2ffSImre Kis 	caller = ts_get_calling_session();
18099cc3a2ffSImre Kis 	sp_cpsr_configure_foreign_interrupts(sp_s, caller, &sp_regs->cpsr);
18109cc3a2ffSImre Kis 
18114d028847SImre Kis 	/*
18124d028847SImre Kis 	 * Store endpoint ID and thread ID in rpc_target_info. This will be used
18134d028847SImre Kis 	 * as w1 in FFA_INTERRUPT in case of a foreign interrupt.
18144d028847SImre Kis 	 */
18154d028847SImre Kis 	rpc_target_info = thread_get_tsd()->rpc_target_info;
18168c8f3baeSJens Wiklander 	sp_s->thread_id = thread_get_id();
18174d028847SImre Kis 	thread_get_tsd()->rpc_target_info =
18188c8f3baeSJens Wiklander 		FFA_TARGET_INFO_SET(sp_s->endpoint_id, sp_s->thread_id);
18194d028847SImre Kis 
1820ae6b3380SJelle Sels 	__thread_enter_user_mode(sp_regs, &panicked, &panic_code);
18214d028847SImre Kis 
18228c8f3baeSJens Wiklander 	sp_s->thread_id = THREAD_ID_INVALID;
18238c8f3baeSJens Wiklander 
18244d028847SImre Kis 	/* Restore rpc_target_info */
18254d028847SImre Kis 	thread_get_tsd()->rpc_target_info = rpc_target_info;
18264d028847SImre Kis 
1827ae6b3380SJelle Sels 	thread_unmask_exceptions(exceptions);
1828ae6b3380SJelle Sels 
1829ae6b3380SJelle Sels 	thread_user_clear_vfp(&ctx->uctx);
1830ae6b3380SJelle Sels 
1831ae6b3380SJelle Sels 	if (panicked) {
1832ae6b3380SJelle Sels 		DMSG("SP panicked with code  %#"PRIx32, panic_code);
1833ae6b3380SJelle Sels 		abort_print_current_ts();
1834ae6b3380SJelle Sels 
1835ae6b3380SJelle Sels 		sess = ts_pop_current_session();
1836ae6b3380SJelle Sels 		cpu_spin_lock(&sp_s->spinlock);
1837ae6b3380SJelle Sels 		sp_s->state = sp_dead;
1838ae6b3380SJelle Sels 		cpu_spin_unlock(&sp_s->spinlock);
1839ae6b3380SJelle Sels 
1840ae6b3380SJelle Sels 		return TEE_ERROR_TARGET_DEAD;
1841ae6b3380SJelle Sels 	}
1842ae6b3380SJelle Sels 
1843ae6b3380SJelle Sels 	sess = ts_pop_current_session();
1844ae6b3380SJelle Sels 	assert(sess == s);
1845ae6b3380SJelle Sels 
1846ae6b3380SJelle Sels 	return res;
1847ae6b3380SJelle Sels }
1848ae6b3380SJelle Sels 
1849ae6b3380SJelle Sels /* We currently don't support 32 bits */
1850ae6b3380SJelle Sels #ifdef ARM64
sp_svc_store_registers(struct thread_scall_regs * regs,struct thread_ctx_regs * sp_regs)1851ab5363c6SJens Wiklander static void sp_svc_store_registers(struct thread_scall_regs *regs,
1852ae6b3380SJelle Sels 				   struct thread_ctx_regs *sp_regs)
1853ae6b3380SJelle Sels {
1854ae6b3380SJelle Sels 	COMPILE_TIME_ASSERT(sizeof(sp_regs->x[0]) == sizeof(regs->x0));
1855ae6b3380SJelle Sels 	memcpy(sp_regs->x, &regs->x0, 31 * sizeof(regs->x0));
1856ae6b3380SJelle Sels 	sp_regs->pc = regs->elr;
1857ae6b3380SJelle Sels 	sp_regs->sp = regs->sp_el0;
1858ae6b3380SJelle Sels }
1859ae6b3380SJelle Sels #endif
1860ae6b3380SJelle Sels 
sp_handle_scall(struct thread_scall_regs * regs)1861ab5363c6SJens Wiklander static bool sp_handle_scall(struct thread_scall_regs *regs)
1862ae6b3380SJelle Sels {
1863ae6b3380SJelle Sels 	struct ts_session *ts = ts_get_current_session();
1864ae6b3380SJelle Sels 	struct sp_ctx *uctx = to_sp_ctx(ts->ctx);
1865ae6b3380SJelle Sels 	struct sp_session *s = uctx->open_session;
1866ae6b3380SJelle Sels 
1867ae6b3380SJelle Sels 	assert(s);
1868ae6b3380SJelle Sels 
1869ae6b3380SJelle Sels 	sp_svc_store_registers(regs, &uctx->sp_regs);
1870ae6b3380SJelle Sels 
1871ae6b3380SJelle Sels 	regs->x0 = 0;
1872ae6b3380SJelle Sels 	regs->x1 = 0; /* panic */
1873ae6b3380SJelle Sels 	regs->x2 = 0; /* panic code */
1874ae6b3380SJelle Sels 
1875ae6b3380SJelle Sels 	/*
1876ae6b3380SJelle Sels 	 * All the registers of the SP are saved in the SP session by the SVC
1877ae6b3380SJelle Sels 	 * handler.
1878ae6b3380SJelle Sels 	 * We always return to S-El1 after handling the SVC. We will continue
1879ae6b3380SJelle Sels 	 * in sp_enter_invoke_cmd() (return from __thread_enter_user_mode).
1880ae6b3380SJelle Sels 	 * The sp_enter() function copies the FF-A parameters (a0-a7) from the
1881ae6b3380SJelle Sels 	 * saved registers to the thread_smc_args. The thread_smc_args object is
1882ae6b3380SJelle Sels 	 * afterward used by the spmc_sp_msg_handler() to handle the
1883ae6b3380SJelle Sels 	 * FF-A message send by the SP.
1884ae6b3380SJelle Sels 	 */
1885ae6b3380SJelle Sels 	return false;
1886ae6b3380SJelle Sels }
1887ae6b3380SJelle Sels 
sp_dump_state(struct ts_ctx * ctx)188893585c5cSJelle Sels static void sp_dump_state(struct ts_ctx *ctx)
188993585c5cSJelle Sels {
189093585c5cSJelle Sels 	struct sp_ctx *utc = to_sp_ctx(ctx);
189193585c5cSJelle Sels 
189293585c5cSJelle Sels 	if (utc->uctx.dump_entry_func) {
189393585c5cSJelle Sels 		TEE_Result res = ldelf_dump_state(&utc->uctx);
189493585c5cSJelle Sels 
189593585c5cSJelle Sels 		if (!res || res == TEE_ERROR_TARGET_DEAD)
189693585c5cSJelle Sels 			return;
189793585c5cSJelle Sels 	}
189893585c5cSJelle Sels 
189993585c5cSJelle Sels 	user_mode_ctx_print_mappings(&utc->uctx);
190093585c5cSJelle Sels }
190193585c5cSJelle Sels 
1902593b94eeSJens Wiklander static const struct ts_ops sp_ops = {
1903ae6b3380SJelle Sels 	.enter_invoke_cmd = sp_enter_invoke_cmd,
1904ab5363c6SJens Wiklander 	.handle_scall = sp_handle_scall,
190593585c5cSJelle Sels 	.dump_state = sp_dump_state,
1906ae6b3380SJelle Sels };
1907ae6b3380SJelle Sels 
process_sp_pkg(uint64_t sp_pkg_pa,TEE_UUID * sp_uuid)19088d2d14e5SBalint Dobszay static TEE_Result process_sp_pkg(uint64_t sp_pkg_pa, TEE_UUID *sp_uuid)
19098d2d14e5SBalint Dobszay {
19102f2f69dfSJens Wiklander 	enum teecore_memtypes mtype = MEM_AREA_SEC_RAM_OVERALL;
19118d2d14e5SBalint Dobszay 	struct sp_pkg_header *sp_pkg_hdr = NULL;
19128d2d14e5SBalint Dobszay 	struct fip_sp *sp = NULL;
19138d2d14e5SBalint Dobszay 	uint64_t sp_fdt_end = 0;
19148d2d14e5SBalint Dobszay 	size_t sp_pkg_size = 0;
19158d2d14e5SBalint Dobszay 	vaddr_t sp_pkg_va = 0;
19168d2d14e5SBalint Dobszay 
19176d7c8c3dSBalint Dobszay 	/* Process the first page which contains the SP package header */
19186d7c8c3dSBalint Dobszay 	sp_pkg_va = (vaddr_t)phys_to_virt(sp_pkg_pa, mtype, SMALL_PAGE_SIZE);
19196d7c8c3dSBalint Dobszay 	if (!sp_pkg_va) {
19206d7c8c3dSBalint Dobszay 		EMSG("Cannot find mapping for PA %#" PRIxPA, sp_pkg_pa);
19218d2d14e5SBalint Dobszay 		return TEE_ERROR_GENERIC;
19228d2d14e5SBalint Dobszay 	}
19238d2d14e5SBalint Dobszay 
19248d2d14e5SBalint Dobszay 	sp_pkg_hdr = (struct sp_pkg_header *)sp_pkg_va;
19258d2d14e5SBalint Dobszay 
19268d2d14e5SBalint Dobszay 	if (sp_pkg_hdr->magic != SP_PKG_HEADER_MAGIC) {
19278d2d14e5SBalint Dobszay 		EMSG("Invalid SP package magic");
19286d7c8c3dSBalint Dobszay 		return TEE_ERROR_BAD_FORMAT;
19298d2d14e5SBalint Dobszay 	}
19308d2d14e5SBalint Dobszay 
193163a75748SImre Kis 	if (sp_pkg_hdr->version != SP_PKG_HEADER_VERSION_V1 &&
193263a75748SImre Kis 	    sp_pkg_hdr->version != SP_PKG_HEADER_VERSION_V2) {
19338d2d14e5SBalint Dobszay 		EMSG("Invalid SP header version");
19346d7c8c3dSBalint Dobszay 		return TEE_ERROR_BAD_FORMAT;
19358d2d14e5SBalint Dobszay 	}
19368d2d14e5SBalint Dobszay 
19378d2d14e5SBalint Dobszay 	if (ADD_OVERFLOW(sp_pkg_hdr->img_offset, sp_pkg_hdr->img_size,
19388d2d14e5SBalint Dobszay 			 &sp_pkg_size)) {
19398d2d14e5SBalint Dobszay 		EMSG("Invalid SP package size");
19406d7c8c3dSBalint Dobszay 		return TEE_ERROR_BAD_FORMAT;
19418d2d14e5SBalint Dobszay 	}
19428d2d14e5SBalint Dobszay 
19438d2d14e5SBalint Dobszay 	if (ADD_OVERFLOW(sp_pkg_hdr->pm_offset, sp_pkg_hdr->pm_size,
19448d2d14e5SBalint Dobszay 			 &sp_fdt_end) || sp_fdt_end > sp_pkg_hdr->img_offset) {
19458d2d14e5SBalint Dobszay 		EMSG("Invalid SP manifest size");
19466d7c8c3dSBalint Dobszay 		return TEE_ERROR_BAD_FORMAT;
19478d2d14e5SBalint Dobszay 	}
19488d2d14e5SBalint Dobszay 
19496d7c8c3dSBalint Dobszay 	/* Process the whole SP package now that the size is known */
19506d7c8c3dSBalint Dobszay 	sp_pkg_va = (vaddr_t)phys_to_virt(sp_pkg_pa, mtype, sp_pkg_size);
19516d7c8c3dSBalint Dobszay 	if (!sp_pkg_va) {
19526d7c8c3dSBalint Dobszay 		EMSG("Cannot find mapping for PA %#" PRIxPA, sp_pkg_pa);
19538d2d14e5SBalint Dobszay 		return TEE_ERROR_GENERIC;
19548d2d14e5SBalint Dobszay 	}
19558d2d14e5SBalint Dobszay 
19566d7c8c3dSBalint Dobszay 	sp_pkg_hdr = (struct sp_pkg_header *)sp_pkg_va;
19578d2d14e5SBalint Dobszay 
19588d2d14e5SBalint Dobszay 	sp = calloc(1, sizeof(struct fip_sp));
19596d7c8c3dSBalint Dobszay 	if (!sp)
19606d7c8c3dSBalint Dobszay 		return TEE_ERROR_OUT_OF_MEMORY;
19618d2d14e5SBalint Dobszay 
19628d2d14e5SBalint Dobszay 	memcpy(&sp->sp_img.image.uuid, sp_uuid, sizeof(*sp_uuid));
19638d2d14e5SBalint Dobszay 	sp->sp_img.image.ts = (uint8_t *)(sp_pkg_va + sp_pkg_hdr->img_offset);
19648d2d14e5SBalint Dobszay 	sp->sp_img.image.size = sp_pkg_hdr->img_size;
19658d2d14e5SBalint Dobszay 	sp->sp_img.image.flags = 0;
19668d2d14e5SBalint Dobszay 	sp->sp_img.fdt = (uint8_t *)(sp_pkg_va + sp_pkg_hdr->pm_offset);
19678d2d14e5SBalint Dobszay 
19688d2d14e5SBalint Dobszay 	STAILQ_INSERT_TAIL(&fip_sp_list, sp, link);
19698d2d14e5SBalint Dobszay 
19708d2d14e5SBalint Dobszay 	return TEE_SUCCESS;
19718d2d14e5SBalint Dobszay }
19728d2d14e5SBalint Dobszay 
fip_sp_init_all(void)19736d7c8c3dSBalint Dobszay static TEE_Result fip_sp_init_all(void)
19748d2d14e5SBalint Dobszay {
19758d2d14e5SBalint Dobszay 	TEE_Result res = TEE_SUCCESS;
19768d2d14e5SBalint Dobszay 	uint64_t sp_pkg_addr = 0;
19778d2d14e5SBalint Dobszay 	const void *fdt = NULL;
19788d2d14e5SBalint Dobszay 	TEE_UUID sp_uuid = { };
19798d2d14e5SBalint Dobszay 	int sp_pkgs_node = 0;
19808d2d14e5SBalint Dobszay 	int subnode = 0;
19818d2d14e5SBalint Dobszay 	int root = 0;
19828d2d14e5SBalint Dobszay 
1983330e04efSJens Wiklander 	fdt = get_manifest_dt();
19848d2d14e5SBalint Dobszay 	if (!fdt) {
19858d2d14e5SBalint Dobszay 		EMSG("No SPMC manifest found");
19868d2d14e5SBalint Dobszay 		return TEE_ERROR_GENERIC;
19878d2d14e5SBalint Dobszay 	}
19888d2d14e5SBalint Dobszay 
19898d2d14e5SBalint Dobszay 	root = fdt_path_offset(fdt, "/");
19908d2d14e5SBalint Dobszay 	if (root < 0)
19918d2d14e5SBalint Dobszay 		return TEE_ERROR_BAD_FORMAT;
19928d2d14e5SBalint Dobszay 
19938d2d14e5SBalint Dobszay 	if (fdt_node_check_compatible(fdt, root, "arm,ffa-core-manifest-1.0"))
19948d2d14e5SBalint Dobszay 		return TEE_ERROR_BAD_FORMAT;
19958d2d14e5SBalint Dobszay 
19968d2d14e5SBalint Dobszay 	/* SP packages are optional, it's not an error if we don't find any */
19978d2d14e5SBalint Dobszay 	sp_pkgs_node = fdt_node_offset_by_compatible(fdt, root, "arm,sp_pkg");
19988d2d14e5SBalint Dobszay 	if (sp_pkgs_node < 0)
19998d2d14e5SBalint Dobszay 		return TEE_SUCCESS;
20008d2d14e5SBalint Dobszay 
20018d2d14e5SBalint Dobszay 	fdt_for_each_subnode(subnode, fdt, sp_pkgs_node) {
20028d2d14e5SBalint Dobszay 		res = sp_dt_get_u64(fdt, subnode, "load-address", &sp_pkg_addr);
20038d2d14e5SBalint Dobszay 		if (res) {
20048d2d14e5SBalint Dobszay 			EMSG("Invalid FIP SP load address");
20058d2d14e5SBalint Dobszay 			return res;
20068d2d14e5SBalint Dobszay 		}
20078d2d14e5SBalint Dobszay 
20088d2d14e5SBalint Dobszay 		res = sp_dt_get_uuid(fdt, subnode, "uuid", &sp_uuid);
20098d2d14e5SBalint Dobszay 		if (res) {
20108d2d14e5SBalint Dobszay 			EMSG("Invalid FIP SP uuid");
20118d2d14e5SBalint Dobszay 			return res;
20128d2d14e5SBalint Dobszay 		}
20138d2d14e5SBalint Dobszay 
20148d2d14e5SBalint Dobszay 		res = process_sp_pkg(sp_pkg_addr, &sp_uuid);
20158d2d14e5SBalint Dobszay 		if (res) {
20168d2d14e5SBalint Dobszay 			EMSG("Invalid FIP SP package");
20178d2d14e5SBalint Dobszay 			return res;
20188d2d14e5SBalint Dobszay 		}
20198d2d14e5SBalint Dobszay 	}
20208d2d14e5SBalint Dobszay 
20218d2d14e5SBalint Dobszay 	return TEE_SUCCESS;
20228d2d14e5SBalint Dobszay }
20238d2d14e5SBalint Dobszay 
fip_sp_deinit_all(void)20246d7c8c3dSBalint Dobszay static void fip_sp_deinit_all(void)
20258d2d14e5SBalint Dobszay {
20268d2d14e5SBalint Dobszay 	while (!STAILQ_EMPTY(&fip_sp_list)) {
20278d2d14e5SBalint Dobszay 		struct fip_sp *sp = STAILQ_FIRST(&fip_sp_list);
20288d2d14e5SBalint Dobszay 
20298d2d14e5SBalint Dobszay 		STAILQ_REMOVE_HEAD(&fip_sp_list, link);
20308d2d14e5SBalint Dobszay 		free(sp);
20318d2d14e5SBalint Dobszay 	}
20328d2d14e5SBalint Dobszay }
20338d2d14e5SBalint Dobszay 
sp_init_all(void)2034c185655eSJelle Sels static TEE_Result sp_init_all(void)
2035c185655eSJelle Sels {
2036c185655eSJelle Sels 	TEE_Result res = TEE_SUCCESS;
2037e23cd783SJelle Sels 	const struct sp_image *sp = NULL;
20388d2d14e5SBalint Dobszay 	const struct fip_sp *fip_sp = NULL;
2039c185655eSJelle Sels 	char __maybe_unused msg[60] = { '\0', };
204024fe8824SJelle Sels 	struct sp_session *s = NULL;
2041d10a438bSGabor Ambrus 	struct sp_session *prev_sp = NULL;
2042c185655eSJelle Sels 
2043c185655eSJelle Sels 	for_each_secure_partition(sp) {
2044e23cd783SJelle Sels 		if (sp->image.uncompressed_size)
2045c185655eSJelle Sels 			snprintf(msg, sizeof(msg),
2046c185655eSJelle Sels 				 " (compressed, uncompressed %u)",
2047e23cd783SJelle Sels 				 sp->image.uncompressed_size);
2048c185655eSJelle Sels 		else
2049c185655eSJelle Sels 			msg[0] = '\0';
2050e23cd783SJelle Sels 		DMSG("SP %pUl size %u%s", (void *)&sp->image.uuid,
2051e23cd783SJelle Sels 		     sp->image.size, msg);
2052c185655eSJelle Sels 
205328710257SJelle Sels 		res = sp_init_uuid(&sp->image.uuid, sp->fdt);
2054c185655eSJelle Sels 
2055c185655eSJelle Sels 		if (res != TEE_SUCCESS) {
2056c185655eSJelle Sels 			EMSG("Failed initializing SP(%pUl) err:%#"PRIx32,
2057e23cd783SJelle Sels 			     &sp->image.uuid, res);
2058c185655eSJelle Sels 			if (!IS_ENABLED(CFG_SP_SKIP_FAILED))
2059c185655eSJelle Sels 				panic();
2060c185655eSJelle Sels 		}
2061c185655eSJelle Sels 	}
2062c185655eSJelle Sels 
20636d7c8c3dSBalint Dobszay 	res = fip_sp_init_all();
20648d2d14e5SBalint Dobszay 	if (res)
20656d7c8c3dSBalint Dobszay 		panic("Failed initializing FIP SPs");
20668d2d14e5SBalint Dobszay 
20678d2d14e5SBalint Dobszay 	for_each_fip_sp(fip_sp) {
20688d2d14e5SBalint Dobszay 		sp = &fip_sp->sp_img;
20698d2d14e5SBalint Dobszay 
20708d2d14e5SBalint Dobszay 		DMSG("SP %pUl size %u", (void *)&sp->image.uuid,
20718d2d14e5SBalint Dobszay 		     sp->image.size);
20728d2d14e5SBalint Dobszay 
20738d2d14e5SBalint Dobszay 		res = sp_init_uuid(&sp->image.uuid, sp->fdt);
20748d2d14e5SBalint Dobszay 
20758d2d14e5SBalint Dobszay 		if (res != TEE_SUCCESS) {
20768d2d14e5SBalint Dobszay 			EMSG("Failed initializing SP(%pUl) err:%#"PRIx32,
20778d2d14e5SBalint Dobszay 			     &sp->image.uuid, res);
20788d2d14e5SBalint Dobszay 			if (!IS_ENABLED(CFG_SP_SKIP_FAILED))
20798d2d14e5SBalint Dobszay 				panic();
20808d2d14e5SBalint Dobszay 		}
20818d2d14e5SBalint Dobszay 	}
20828d2d14e5SBalint Dobszay 
2083abbe1d51SBalint Dobszay 	/*
2084abbe1d51SBalint Dobszay 	 * At this point all FIP SPs are loaded by ldelf or by the raw binary SP
2085abbe1d51SBalint Dobszay 	 * loader, so the original images (loaded by BL2) are not needed anymore
2086abbe1d51SBalint Dobszay 	 */
2087abbe1d51SBalint Dobszay 	fip_sp_deinit_all();
2088abbe1d51SBalint Dobszay 
2089d10a438bSGabor Ambrus 	/*
2090d10a438bSGabor Ambrus 	 * Now that all SPs are loaded, check through the boot order values,
2091d10a438bSGabor Ambrus 	 * and warn in case there is a non-unique value.
2092d10a438bSGabor Ambrus 	 */
2093d10a438bSGabor Ambrus 	TAILQ_FOREACH(s, &open_sp_sessions, link) {
20949d58f55eSGyorgy Szing 		/* Avoid warnings if multiple SP have undefined boot-order. */
20959d58f55eSGyorgy Szing 		if (s->boot_order == UNDEFINED_BOOT_ORDER_VALUE)
2096d10a438bSGabor Ambrus 			break;
2097d10a438bSGabor Ambrus 
2098d10a438bSGabor Ambrus 		if (prev_sp && prev_sp->boot_order == s->boot_order)
2099d10a438bSGabor Ambrus 			IMSG("WARNING: duplicated boot-order (%pUl vs %pUl)",
2100d10a438bSGabor Ambrus 			     &prev_sp->ts_sess.ctx->uuid,
2101d10a438bSGabor Ambrus 			     &s->ts_sess.ctx->uuid);
2102d10a438bSGabor Ambrus 
2103d10a438bSGabor Ambrus 		prev_sp = s;
2104d10a438bSGabor Ambrus 	}
2105d10a438bSGabor Ambrus 
210624fe8824SJelle Sels 	/* Continue the initialization and run the SP */
210724fe8824SJelle Sels 	TAILQ_FOREACH(s, &open_sp_sessions, link) {
2108d10a438bSGabor Ambrus 		DMSG("Starting SP: 0x%"PRIx16, s->endpoint_id);
2109d10a438bSGabor Ambrus 
211024fe8824SJelle Sels 		res = sp_first_run(s);
211124fe8824SJelle Sels 		if (res != TEE_SUCCESS) {
211224fe8824SJelle Sels 			EMSG("Failed starting SP(0x%"PRIx16") err:%#"PRIx32,
211324fe8824SJelle Sels 			     s->endpoint_id, res);
211424fe8824SJelle Sels 			if (!IS_ENABLED(CFG_SP_SKIP_FAILED))
211524fe8824SJelle Sels 				panic();
211624fe8824SJelle Sels 		}
211724fe8824SJelle Sels 	}
21186d7c8c3dSBalint Dobszay 
2119c185655eSJelle Sels 	return TEE_SUCCESS;
2120c185655eSJelle Sels }
2121c185655eSJelle Sels 
2122c185655eSJelle Sels boot_final(sp_init_all);
2123c185655eSJelle Sels 
secure_partition_open(const TEE_UUID * uuid,struct ts_store_handle ** h)2124dea46be3SJelle Sels static TEE_Result secure_partition_open(const TEE_UUID *uuid,
2125dea46be3SJelle Sels 					struct ts_store_handle **h)
2126dea46be3SJelle Sels {
2127dea46be3SJelle Sels 	return emb_ts_open(uuid, h, find_secure_partition);
2128dea46be3SJelle Sels }
2129dea46be3SJelle Sels 
2130dea46be3SJelle Sels REGISTER_SP_STORE(2) = {
2131dea46be3SJelle Sels 	.description = "SP store",
2132dea46be3SJelle Sels 	.open = secure_partition_open,
2133dea46be3SJelle Sels 	.get_size = emb_ts_get_size,
2134dea46be3SJelle Sels 	.get_tag = emb_ts_get_tag,
2135dea46be3SJelle Sels 	.read = emb_ts_read,
2136dea46be3SJelle Sels 	.close = emb_ts_close,
2137dea46be3SJelle Sels };
2138