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, ®s->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