1f9cd31c5SJelle Sels // SPDX-License-Identifier: BSD-2-Clause
2f9cd31c5SJelle Sels /*
3f9cd31c5SJelle Sels * Copyright (c) 2019, Linaro Limited
4f9cd31c5SJelle Sels * Copyright (c) 2020, Arm Limited.
5f9cd31c5SJelle Sels */
6f9cd31c5SJelle Sels
7f9cd31c5SJelle Sels #include <crypto/crypto.h>
8aa6d7fc3SLevi Yun #include <efi/hob.h>
9f9cd31c5SJelle Sels #include <ffa.h>
10409c619bSEtienne Carriere #include <keep.h>
11f9cd31c5SJelle Sels #include <kernel/abort.h>
12f9cd31c5SJelle Sels #include <kernel/stmm_sp.h>
13956c2d50SEtienne Carriere #include <kernel/tee_ta_manager.h>
147e399f9bSJens Wiklander #include <kernel/thread_private.h>
15f9cd31c5SJelle Sels #include <kernel/user_mode_ctx.h>
16a951fe52SEtienne Carriere #include <mempool.h>
17f9cd31c5SJelle Sels #include <mm/fobj.h>
18f9cd31c5SJelle Sels #include <mm/mobj.h>
19f9cd31c5SJelle Sels #include <mm/vm.h>
20f9cd31c5SJelle Sels #include <pta_stmm.h>
21f9cd31c5SJelle Sels #include <tee_api_defines_extensions.h>
22f9cd31c5SJelle Sels #include <tee/tee_pobj.h>
23f9cd31c5SJelle Sels #include <tee/tee_svc.h>
24f9cd31c5SJelle Sels #include <tee/tee_svc_storage.h>
25f9cd31c5SJelle Sels #include <zlib.h>
26f9cd31c5SJelle Sels
27d9339333SEtienne Carriere #ifdef ARM64
28d9339333SEtienne Carriere #define SVC_REGS_A0(_regs) ((_regs)->x0)
29d9339333SEtienne Carriere #define SVC_REGS_A1(_regs) ((_regs)->x1)
30d9339333SEtienne Carriere #define SVC_REGS_A2(_regs) ((_regs)->x2)
31d9339333SEtienne Carriere #define SVC_REGS_A3(_regs) ((_regs)->x3)
32d9339333SEtienne Carriere #define SVC_REGS_A4(_regs) ((_regs)->x4)
33d9339333SEtienne Carriere #define SVC_REGS_A5(_regs) ((_regs)->x5)
34d9339333SEtienne Carriere #define SVC_REGS_A6(_regs) ((_regs)->x6)
35d9339333SEtienne Carriere #define SVC_REGS_A7(_regs) ((_regs)->x7)
36d9339333SEtienne Carriere #define __FFA_SVC_RPMB_READ FFA_SVC_RPMB_READ
37d9339333SEtienne Carriere #define __FFA_SVC_RPMB_WRITE FFA_SVC_RPMB_WRITE
38d9339333SEtienne Carriere #define __FFA_MSG_SEND_DIRECT_RESP FFA_MSG_SEND_DIRECT_RESP_64
39d9339333SEtienne Carriere #define __FFA_MSG_SEND_DIRECT_REQ FFA_MSG_SEND_DIRECT_REQ_64
40aa6d7fc3SLevi Yun #define __FFA_MEM_PERM_GET FFA_MEM_PERM_GET_64
41aa6d7fc3SLevi Yun #define __FFA_MEM_PERM_SET FFA_MEM_PERM_SET_64
42d9339333SEtienne Carriere #endif
43d9339333SEtienne Carriere #ifdef ARM32
44d9339333SEtienne Carriere #define SVC_REGS_A0(_regs) ((_regs)->r0)
45d9339333SEtienne Carriere #define SVC_REGS_A1(_regs) ((_regs)->r1)
46d9339333SEtienne Carriere #define SVC_REGS_A2(_regs) ((_regs)->r2)
47d9339333SEtienne Carriere #define SVC_REGS_A3(_regs) ((_regs)->r3)
48d9339333SEtienne Carriere #define SVC_REGS_A4(_regs) ((_regs)->r4)
49d9339333SEtienne Carriere #define SVC_REGS_A5(_regs) ((_regs)->r5)
50d9339333SEtienne Carriere #define SVC_REGS_A6(_regs) ((_regs)->r6)
51d9339333SEtienne Carriere #define SVC_REGS_A7(_regs) ((_regs)->r7)
52d9339333SEtienne Carriere #define __FFA_SVC_RPMB_READ FFA_SVC_RPMB_READ_32
53d9339333SEtienne Carriere #define __FFA_SVC_RPMB_WRITE FFA_SVC_RPMB_WRITE_32
54d9339333SEtienne Carriere #define __FFA_MSG_SEND_DIRECT_RESP FFA_MSG_SEND_DIRECT_RESP_32
55d9339333SEtienne Carriere #define __FFA_MSG_SEND_DIRECT_REQ FFA_MSG_SEND_DIRECT_REQ_32
56aa6d7fc3SLevi Yun #define __FFA_MEM_PERM_GET FFA_MEM_PERM_GET_32
57aa6d7fc3SLevi Yun #define __FFA_MEM_PERM_SET FFA_MEM_PERM_SET_32
58d9339333SEtienne Carriere #endif
59d9339333SEtienne Carriere
60f9cd31c5SJelle Sels static const TEE_UUID stmm_uuid = PTA_STMM_UUID;
61aa6d7fc3SLevi Yun static TEE_UUID ns_buf_guid = MM_NS_BUFFER_GUID;
62aa6d7fc3SLevi Yun static TEE_UUID mmram_resv_guid = MM_PEI_MMRAM_MEMORY_RESERVE_GUID;
63f9cd31c5SJelle Sels
64f9cd31c5SJelle Sels /*
65f9cd31c5SJelle Sels * Once a complete FFA spec is added, these will become discoverable.
66f9cd31c5SJelle Sels * Until then these are considered part of the internal ABI between
67f9cd31c5SJelle Sels * OP-TEE and StMM.
68f9cd31c5SJelle Sels */
69f9cd31c5SJelle Sels static const uint16_t stmm_id = 1U;
70f9cd31c5SJelle Sels static const uint16_t stmm_pta_id = 2U;
71f9cd31c5SJelle Sels static const uint16_t ffa_storage_id = 4U;
72f9cd31c5SJelle Sels
73aa6d7fc3SLevi Yun static const unsigned int stmm_heap_size = 402 * SMALL_PAGE_SIZE;
742452979fSIlias Apalodimas static const unsigned int stmm_sec_buf_size = 4 * SMALL_PAGE_SIZE;
752452979fSIlias Apalodimas static const unsigned int stmm_ns_comm_buf_size = 4 * SMALL_PAGE_SIZE;
76f9cd31c5SJelle Sels
77f9cd31c5SJelle Sels extern unsigned char stmm_image[];
78f9cd31c5SJelle Sels extern const unsigned int stmm_image_size;
79f9cd31c5SJelle Sels extern const unsigned int stmm_image_uncompressed_size;
80f9cd31c5SJelle Sels
81aa6d7fc3SLevi Yun static vaddr_t stmm_image_addr;
82aa6d7fc3SLevi Yun static vaddr_t stmm_heap_addr;
83aa6d7fc3SLevi Yun static vaddr_t stmm_ns_comm_buf_addr;
84aa6d7fc3SLevi Yun static vaddr_t stmm_sec_buf_addr;
85aa6d7fc3SLevi Yun
stmm_get_uuid(void)868f31ccb0SJens Wiklander const TEE_UUID *stmm_get_uuid(void)
878f31ccb0SJens Wiklander {
888f31ccb0SJens Wiklander return &stmm_uuid;
898f31ccb0SJens Wiklander }
908f31ccb0SJens Wiklander
stmm_alloc_ctx(const TEE_UUID * uuid)91f9cd31c5SJelle Sels static struct stmm_ctx *stmm_alloc_ctx(const TEE_UUID *uuid)
92f9cd31c5SJelle Sels {
93aa6d7fc3SLevi Yun TEE_Result res = TEE_ERROR_GENERIC;
94f9cd31c5SJelle Sels struct stmm_ctx *spc = NULL;
95f9cd31c5SJelle Sels
96f9cd31c5SJelle Sels spc = calloc(1, sizeof(*spc));
97f9cd31c5SJelle Sels if (!spc)
98f9cd31c5SJelle Sels return NULL;
99f9cd31c5SJelle Sels
100f9cd31c5SJelle Sels spc->ta_ctx.ts_ctx.ops = &stmm_sp_ops;
101f9cd31c5SJelle Sels spc->ta_ctx.ts_ctx.uuid = *uuid;
102f9cd31c5SJelle Sels spc->ta_ctx.flags = TA_FLAG_SINGLE_INSTANCE |
103f9cd31c5SJelle Sels TA_FLAG_INSTANCE_KEEP_ALIVE;
104f9cd31c5SJelle Sels
10560d3fc69SJens Wiklander res = vm_info_init(&spc->uctx, &spc->ta_ctx.ts_ctx);
106f9cd31c5SJelle Sels if (res) {
107f9cd31c5SJelle Sels free(spc);
108f9cd31c5SJelle Sels return NULL;
109f9cd31c5SJelle Sels }
110f9cd31c5SJelle Sels
111f9cd31c5SJelle Sels spc->ta_ctx.ref_count = 1;
112f9cd31c5SJelle Sels condvar_init(&spc->ta_ctx.busy_cv);
113f9cd31c5SJelle Sels
114f9cd31c5SJelle Sels return spc;
115f9cd31c5SJelle Sels }
116f9cd31c5SJelle Sels
stmm_enter_user_mode(struct stmm_ctx * spc)117f9cd31c5SJelle Sels static TEE_Result stmm_enter_user_mode(struct stmm_ctx *spc)
118f9cd31c5SJelle Sels {
119f9cd31c5SJelle Sels uint32_t exceptions = 0;
120f9cd31c5SJelle Sels uint32_t panic_code = 0;
121f9cd31c5SJelle Sels uint32_t panicked = 0;
122f9cd31c5SJelle Sels uint64_t cntkctl = 0;
123f9cd31c5SJelle Sels
124f9cd31c5SJelle Sels exceptions = thread_mask_exceptions(THREAD_EXCP_ALL);
125f9cd31c5SJelle Sels cntkctl = read_cntkctl();
126f9cd31c5SJelle Sels write_cntkctl(cntkctl | CNTKCTL_PL0PCTEN);
12727c1358cSEtienne Carriere
12827c1358cSEtienne Carriere #ifdef ARM32
12927c1358cSEtienne Carriere /* Handle usr_lr in place of __thread_enter_user_mode() */
13027c1358cSEtienne Carriere thread_set_usr_lr(spc->regs.usr_lr);
13127c1358cSEtienne Carriere #endif
13227c1358cSEtienne Carriere
133f9cd31c5SJelle Sels __thread_enter_user_mode(&spc->regs, &panicked, &panic_code);
13427c1358cSEtienne Carriere
13527c1358cSEtienne Carriere #ifdef ARM32
13627c1358cSEtienne Carriere spc->regs.usr_lr = thread_get_usr_lr();
13727c1358cSEtienne Carriere #endif
13827c1358cSEtienne Carriere
139f9cd31c5SJelle Sels write_cntkctl(cntkctl);
140f9cd31c5SJelle Sels thread_unmask_exceptions(exceptions);
141f9cd31c5SJelle Sels
142b351c689SBalint Dobszay thread_user_clear_vfp(&spc->uctx);
143f9cd31c5SJelle Sels
144f9cd31c5SJelle Sels if (panicked) {
1454e994fd8SJelle Sels abort_print_current_ts();
146f9cd31c5SJelle Sels DMSG("stmm panicked with code %#"PRIx32, panic_code);
147f9cd31c5SJelle Sels return TEE_ERROR_TARGET_DEAD;
148f9cd31c5SJelle Sels }
149f9cd31c5SJelle Sels
150f9cd31c5SJelle Sels return TEE_SUCCESS;
151f9cd31c5SJelle Sels }
152f9cd31c5SJelle Sels
153d9339333SEtienne Carriere #ifdef ARM64
init_stmm_regs(struct stmm_ctx * spc,unsigned long a0,unsigned long a1,unsigned long a2,unsigned long a3,unsigned long pc)154f9cd31c5SJelle Sels static void init_stmm_regs(struct stmm_ctx *spc, unsigned long a0,
155aa6d7fc3SLevi Yun unsigned long a1, unsigned long a2, unsigned long a3,
156aa6d7fc3SLevi Yun unsigned long pc)
157f9cd31c5SJelle Sels {
158f9cd31c5SJelle Sels spc->regs.x[0] = a0;
159f9cd31c5SJelle Sels spc->regs.x[1] = a1;
160aa6d7fc3SLevi Yun spc->regs.x[2] = a2;
161aa6d7fc3SLevi Yun spc->regs.x[3] = a3;
162f9cd31c5SJelle Sels spc->regs.pc = pc;
163f9cd31c5SJelle Sels }
164d9339333SEtienne Carriere #endif
165d9339333SEtienne Carriere
166d9339333SEtienne Carriere #ifdef ARM32
get_spsr(void)167d9339333SEtienne Carriere static uint32_t __maybe_unused get_spsr(void)
168d9339333SEtienne Carriere {
169d9339333SEtienne Carriere uint32_t s = 0;
170d9339333SEtienne Carriere
171d9339333SEtienne Carriere s = read_cpsr();
172d9339333SEtienne Carriere s &= ~(CPSR_MODE_MASK | CPSR_T | ARM32_CPSR_IT_MASK);
173d9339333SEtienne Carriere s |= CPSR_MODE_USR;
174d9339333SEtienne Carriere
175d9339333SEtienne Carriere return s;
176d9339333SEtienne Carriere }
177d9339333SEtienne Carriere
init_stmm_regs(struct stmm_ctx * spc,unsigned long a0,unsigned long a1,unsigned long a2,unsigned long a3,unsigned long pc)178d9339333SEtienne Carriere static void init_stmm_regs(struct stmm_ctx *spc, unsigned long a0,
179aa6d7fc3SLevi Yun unsigned long a1, unsigned long a2, unsigned long a3,
180aa6d7fc3SLevi Yun unsigned long pc)
181d9339333SEtienne Carriere {
182d9339333SEtienne Carriere spc->regs.r0 = a0;
183d9339333SEtienne Carriere spc->regs.r1 = a1;
184aa6d7fc3SLevi Yun spc->regs.r2 = a2;
185aa6d7fc3SLevi Yun spc->regs.r3 = a3;
186d9339333SEtienne Carriere spc->regs.cpsr = get_spsr();
187d9339333SEtienne Carriere spc->regs.pc = pc;
188d9339333SEtienne Carriere }
189d9339333SEtienne Carriere #endif
190f9cd31c5SJelle Sels
alloc_and_map_sp_fobj(struct stmm_ctx * spc,size_t sz,uint32_t prot,vaddr_t * va)191f9cd31c5SJelle Sels static TEE_Result alloc_and_map_sp_fobj(struct stmm_ctx *spc, size_t sz,
192f9cd31c5SJelle Sels uint32_t prot, vaddr_t *va)
193f9cd31c5SJelle Sels {
19404e46975SEtienne Carriere size_t num_pgs = ROUNDUP_DIV(sz, SMALL_PAGE_SIZE);
195f9cd31c5SJelle Sels struct fobj *fobj = fobj_ta_mem_alloc(num_pgs);
196f9cd31c5SJelle Sels TEE_Result res = TEE_SUCCESS;
1976105aa86SJens Wiklander struct mobj *mobj = NULL;
198f9cd31c5SJelle Sels
1996105aa86SJens Wiklander mobj = mobj_with_fobj_alloc(fobj, NULL, TEE_MATTR_MEM_TYPE_TAGGED);
200f9cd31c5SJelle Sels fobj_put(fobj);
201f9cd31c5SJelle Sels if (!mobj)
202f9cd31c5SJelle Sels return TEE_ERROR_OUT_OF_MEMORY;
203f9cd31c5SJelle Sels
204f9cd31c5SJelle Sels res = vm_map(&spc->uctx, va, num_pgs * SMALL_PAGE_SIZE,
205f9cd31c5SJelle Sels prot, 0, mobj, 0);
206f9cd31c5SJelle Sels if (res)
207f9cd31c5SJelle Sels mobj_put(mobj);
208f9cd31c5SJelle Sels
209f9cd31c5SJelle Sels return TEE_SUCCESS;
210f9cd31c5SJelle Sels }
211f9cd31c5SJelle Sels
zalloc(void * opaque __unused,unsigned int items,unsigned int size)212f9cd31c5SJelle Sels static void *zalloc(void *opaque __unused, unsigned int items,
213f9cd31c5SJelle Sels unsigned int size)
214f9cd31c5SJelle Sels {
215a951fe52SEtienne Carriere return mempool_alloc(mempool_default, items * size);
216f9cd31c5SJelle Sels }
217f9cd31c5SJelle Sels
zfree(void * opaque __unused,void * address)218f9cd31c5SJelle Sels static void zfree(void *opaque __unused, void *address)
219f9cd31c5SJelle Sels {
220a951fe52SEtienne Carriere mempool_free(mempool_default, address);
221f9cd31c5SJelle Sels }
222f9cd31c5SJelle Sels
uncompress_image(void * dst,size_t dst_size,void * src,size_t src_size)223f9cd31c5SJelle Sels static void uncompress_image(void *dst, size_t dst_size, void *src,
224f9cd31c5SJelle Sels size_t src_size)
225f9cd31c5SJelle Sels {
226f9cd31c5SJelle Sels z_stream strm = {
227f9cd31c5SJelle Sels .next_in = src,
228f9cd31c5SJelle Sels .avail_in = src_size,
229f9cd31c5SJelle Sels .next_out = dst,
230f9cd31c5SJelle Sels .avail_out = dst_size,
231f9cd31c5SJelle Sels .zalloc = zalloc,
232f9cd31c5SJelle Sels .zfree = zfree,
233f9cd31c5SJelle Sels };
234f9cd31c5SJelle Sels
235f9cd31c5SJelle Sels if (inflateInit(&strm) != Z_OK)
236f9cd31c5SJelle Sels panic("inflateInit");
237f9cd31c5SJelle Sels
238f9cd31c5SJelle Sels if (inflate(&strm, Z_SYNC_FLUSH) != Z_STREAM_END)
239f9cd31c5SJelle Sels panic("inflate");
240f9cd31c5SJelle Sels
241f9cd31c5SJelle Sels if (inflateEnd(&strm) != Z_OK)
242f9cd31c5SJelle Sels panic("inflateEnd");
243f9cd31c5SJelle Sels }
244f9cd31c5SJelle Sels
245aa6d7fc3SLevi Yun static struct efi_hob_handoff_info_table *
build_stmm_boot_hob_list(vaddr_t sp_addr,uint32_t sp_size,uint32_t * hob_table_size)246aa6d7fc3SLevi Yun build_stmm_boot_hob_list(vaddr_t sp_addr,
247aa6d7fc3SLevi Yun uint32_t sp_size, uint32_t *hob_table_size)
248f9cd31c5SJelle Sels {
249aa6d7fc3SLevi Yun struct efi_hob_handoff_info_table *hob_table = NULL;
250f9cd31c5SJelle Sels unsigned int uncompressed_size_roundup = 0;
251aa6d7fc3SLevi Yun struct efi_mmram_descriptor *mmram_desc_data = NULL;
252aa6d7fc3SLevi Yun struct efi_mmram_hob_descriptor_block *mmram_resv_data = NULL;
253aa6d7fc3SLevi Yun uint16_t mmram_resv_data_size = 0;
254aa6d7fc3SLevi Yun TEE_Result ret = TEE_ERROR_GENERIC;
255aa6d7fc3SLevi Yun uint32_t hob_table_offset = 0;
256aa6d7fc3SLevi Yun void *guid_hob_data = NULL;
257f9cd31c5SJelle Sels
258f9cd31c5SJelle Sels uncompressed_size_roundup = ROUNDUP(stmm_image_uncompressed_size,
259f9cd31c5SJelle Sels SMALL_PAGE_SIZE);
260aa6d7fc3SLevi Yun stmm_image_addr = sp_addr;
261aa6d7fc3SLevi Yun stmm_heap_addr = stmm_image_addr + uncompressed_size_roundup;
262aa6d7fc3SLevi Yun stmm_sec_buf_addr = stmm_heap_addr + stmm_heap_size;
263aa6d7fc3SLevi Yun hob_table_offset = sizeof(struct ffa_boot_info_header_1_1) +
264aa6d7fc3SLevi Yun sizeof(struct ffa_boot_info_1_1);
265aa6d7fc3SLevi Yun
266aa6d7fc3SLevi Yun hob_table = efi_create_hob_list(sp_addr, sp_size,
267aa6d7fc3SLevi Yun stmm_sec_buf_addr + hob_table_offset,
268aa6d7fc3SLevi Yun stmm_sec_buf_size - hob_table_offset);
269aa6d7fc3SLevi Yun if (!hob_table) {
270aa6d7fc3SLevi Yun EMSG("Failed to create hob_table.");
271aa6d7fc3SLevi Yun return NULL;
272aa6d7fc3SLevi Yun }
273aa6d7fc3SLevi Yun
274aa6d7fc3SLevi Yun ret = efi_create_fv_hob(hob_table, sp_addr, uncompressed_size_roundup);
275aa6d7fc3SLevi Yun if (ret) {
276aa6d7fc3SLevi Yun EMSG("Failed to create fv hob.");
277aa6d7fc3SLevi Yun return NULL;
278aa6d7fc3SLevi Yun }
279aa6d7fc3SLevi Yun
280aa6d7fc3SLevi Yun ret = efi_create_guid_hob(hob_table, &ns_buf_guid,
281aa6d7fc3SLevi Yun sizeof(struct efi_mmram_descriptor),
282aa6d7fc3SLevi Yun &guid_hob_data);
283aa6d7fc3SLevi Yun if (ret) {
284aa6d7fc3SLevi Yun EMSG("Failed to create ns buffer hob.");
285aa6d7fc3SLevi Yun return NULL;
286aa6d7fc3SLevi Yun }
287aa6d7fc3SLevi Yun
288aa6d7fc3SLevi Yun mmram_desc_data = guid_hob_data;
289aa6d7fc3SLevi Yun mmram_desc_data->physical_start = stmm_ns_comm_buf_addr;
290aa6d7fc3SLevi Yun mmram_desc_data->physical_size = stmm_ns_comm_buf_size;
291aa6d7fc3SLevi Yun mmram_desc_data->cpu_start = stmm_ns_comm_buf_addr;
292aa6d7fc3SLevi Yun mmram_desc_data->region_state = EFI_CACHEABLE | EFI_ALLOCATED;
293aa6d7fc3SLevi Yun
294aa6d7fc3SLevi Yun mmram_resv_data_size = sizeof(struct efi_mmram_hob_descriptor_block) +
295aa6d7fc3SLevi Yun sizeof(struct efi_mmram_descriptor) * 5;
296aa6d7fc3SLevi Yun
297aa6d7fc3SLevi Yun ret = efi_create_guid_hob(hob_table, &mmram_resv_guid,
298aa6d7fc3SLevi Yun mmram_resv_data_size, &guid_hob_data);
299aa6d7fc3SLevi Yun if (ret) {
300aa6d7fc3SLevi Yun EMSG("Failed to create mm range hob");
301aa6d7fc3SLevi Yun return NULL;
302aa6d7fc3SLevi Yun }
303aa6d7fc3SLevi Yun
304aa6d7fc3SLevi Yun mmram_resv_data = guid_hob_data;
305aa6d7fc3SLevi Yun mmram_resv_data->number_of_mm_reserved_regions = 4;
306aa6d7fc3SLevi Yun mmram_desc_data = &mmram_resv_data->descriptor[0];
307aa6d7fc3SLevi Yun
308aa6d7fc3SLevi Yun mmram_desc_data[0].physical_start = stmm_image_addr;
309aa6d7fc3SLevi Yun mmram_desc_data[0].physical_size = uncompressed_size_roundup;
310aa6d7fc3SLevi Yun mmram_desc_data[0].cpu_start = stmm_image_addr;
311aa6d7fc3SLevi Yun mmram_desc_data[0].region_state = EFI_CACHEABLE | EFI_ALLOCATED;
312aa6d7fc3SLevi Yun
313aa6d7fc3SLevi Yun mmram_desc_data[1].physical_start = stmm_sec_buf_addr;
314aa6d7fc3SLevi Yun mmram_desc_data[1].physical_size = stmm_sec_buf_size;
315aa6d7fc3SLevi Yun mmram_desc_data[1].cpu_start = stmm_sec_buf_addr;
316aa6d7fc3SLevi Yun mmram_desc_data[1].region_state = EFI_CACHEABLE | EFI_ALLOCATED;
317aa6d7fc3SLevi Yun
318aa6d7fc3SLevi Yun mmram_desc_data[2].physical_start = stmm_ns_comm_buf_addr;
319aa6d7fc3SLevi Yun mmram_desc_data[2].physical_size = stmm_ns_comm_buf_size;
320aa6d7fc3SLevi Yun mmram_desc_data[2].cpu_start = stmm_ns_comm_buf_addr;
321aa6d7fc3SLevi Yun mmram_desc_data[2].region_state = EFI_CACHEABLE | EFI_ALLOCATED;
322aa6d7fc3SLevi Yun
323aa6d7fc3SLevi Yun mmram_desc_data[3].physical_start = stmm_heap_addr;
324aa6d7fc3SLevi Yun mmram_desc_data[3].physical_size = stmm_heap_size;
325aa6d7fc3SLevi Yun mmram_desc_data[3].cpu_start = stmm_heap_addr;
326aa6d7fc3SLevi Yun mmram_desc_data[3].region_state = EFI_CACHEABLE;
327aa6d7fc3SLevi Yun
328aa6d7fc3SLevi Yun *hob_table_size = hob_table->efi_free_memory_bottom -
329aa6d7fc3SLevi Yun (efi_physical_address_t)hob_table;
330aa6d7fc3SLevi Yun
331aa6d7fc3SLevi Yun return hob_table;
332aa6d7fc3SLevi Yun }
333aa6d7fc3SLevi Yun
load_stmm(struct stmm_ctx * spc)334aa6d7fc3SLevi Yun static TEE_Result load_stmm(struct stmm_ctx *spc)
335aa6d7fc3SLevi Yun {
336aa6d7fc3SLevi Yun struct ffa_boot_info_header_1_1 *hdr = NULL;
337aa6d7fc3SLevi Yun struct ffa_boot_info_1_1 *desc = NULL;
338aa6d7fc3SLevi Yun struct efi_hob_handoff_info_table *hob_table = NULL;
339aa6d7fc3SLevi Yun uint32_t hob_table_size = 0;
340aa6d7fc3SLevi Yun vaddr_t sp_addr = 0;
341aa6d7fc3SLevi Yun unsigned int sp_size = 0;
342aa6d7fc3SLevi Yun unsigned int uncompressed_size_roundup = 0;
343aa6d7fc3SLevi Yun TEE_Result res = TEE_ERROR_GENERIC;
344aa6d7fc3SLevi Yun
345aa6d7fc3SLevi Yun uncompressed_size_roundup = ROUNDUP(stmm_image_uncompressed_size,
346aa6d7fc3SLevi Yun SMALL_PAGE_SIZE);
347aa6d7fc3SLevi Yun sp_size = uncompressed_size_roundup + stmm_heap_size +
348aa6d7fc3SLevi Yun stmm_sec_buf_size;
349f9cd31c5SJelle Sels res = alloc_and_map_sp_fobj(spc, sp_size,
350f9cd31c5SJelle Sels TEE_MATTR_PRW, &sp_addr);
351f9cd31c5SJelle Sels if (res)
352f9cd31c5SJelle Sels return res;
353f9cd31c5SJelle Sels
354f9cd31c5SJelle Sels res = alloc_and_map_sp_fobj(spc, stmm_ns_comm_buf_size,
355f9cd31c5SJelle Sels TEE_MATTR_URW | TEE_MATTR_PRW,
356aa6d7fc3SLevi Yun &stmm_ns_comm_buf_addr);
357f9cd31c5SJelle Sels /*
358f9cd31c5SJelle Sels * We don't need to free the previous instance here, they'll all be
359f9cd31c5SJelle Sels * handled during the destruction call (stmm_ctx_destroy())
360f9cd31c5SJelle Sels */
361f9cd31c5SJelle Sels if (res)
362f9cd31c5SJelle Sels return res;
363f9cd31c5SJelle Sels
364aa6d7fc3SLevi Yun hob_table = build_stmm_boot_hob_list(sp_addr, sp_size, &hob_table_size);
365aa6d7fc3SLevi Yun if (!hob_table)
366aa6d7fc3SLevi Yun return TEE_ERROR_NO_DATA;
367aa6d7fc3SLevi Yun
368aa6d7fc3SLevi Yun hdr = (void *)stmm_sec_buf_addr;
369aa6d7fc3SLevi Yun
370aa6d7fc3SLevi Yun hdr->signature = FFA_BOOT_INFO_SIGNATURE;
371aa6d7fc3SLevi Yun hdr->version = FFA_VERSION_1_2;
372aa6d7fc3SLevi Yun hdr->desc_size = sizeof(struct ffa_boot_info_1_1);
373aa6d7fc3SLevi Yun hdr->desc_count = 1;
374aa6d7fc3SLevi Yun hdr->desc_offset = sizeof(struct ffa_boot_info_header_1_1);
375aa6d7fc3SLevi Yun hdr->reserved = 0;
376aa6d7fc3SLevi Yun hdr->blob_size = hdr->desc_size * hdr->desc_count + hdr->desc_offset;
377aa6d7fc3SLevi Yun
378aa6d7fc3SLevi Yun desc = (void *)(stmm_sec_buf_addr + hdr->desc_offset);
379aa6d7fc3SLevi Yun
380aa6d7fc3SLevi Yun memset(desc->name, 0, FFA_BOOT_INFO_NAME_LEN);
381aa6d7fc3SLevi Yun desc->type = FFA_BOOT_INFO_TYPE_ID_HOB;
382aa6d7fc3SLevi Yun desc->flags = FFA_BOOT_INFO_FLAG_NAME_FORMAT_UUID |
383aa6d7fc3SLevi Yun (FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_ADDR <<
384aa6d7fc3SLevi Yun FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_SHIFT);
385aa6d7fc3SLevi Yun desc->size = hob_table_size;
386aa6d7fc3SLevi Yun desc->contents = (vaddr_t)hob_table;
387f9cd31c5SJelle Sels
388f9cd31c5SJelle Sels vm_set_ctx(&spc->ta_ctx.ts_ctx);
389aa6d7fc3SLevi Yun uncompress_image((void *)stmm_image_addr, stmm_image_uncompressed_size,
390f9cd31c5SJelle Sels stmm_image, stmm_image_size);
391f9cd31c5SJelle Sels
392aa6d7fc3SLevi Yun res = vm_set_prot(&spc->uctx, stmm_image_addr,
393aa6d7fc3SLevi Yun uncompressed_size_roundup,
394f9cd31c5SJelle Sels TEE_MATTR_URX | TEE_MATTR_PR);
395f9cd31c5SJelle Sels if (res)
396f9cd31c5SJelle Sels return res;
397f9cd31c5SJelle Sels
398aa6d7fc3SLevi Yun res = vm_set_prot(&spc->uctx, stmm_heap_addr, stmm_heap_size,
399f9cd31c5SJelle Sels TEE_MATTR_URW | TEE_MATTR_PRW);
400f9cd31c5SJelle Sels if (res)
401f9cd31c5SJelle Sels return res;
402f9cd31c5SJelle Sels
403aa6d7fc3SLevi Yun res = vm_set_prot(&spc->uctx, stmm_sec_buf_addr, stmm_sec_buf_size,
404f9cd31c5SJelle Sels TEE_MATTR_URW | TEE_MATTR_PRW);
405f9cd31c5SJelle Sels if (res)
406f9cd31c5SJelle Sels return res;
407f9cd31c5SJelle Sels
408aa6d7fc3SLevi Yun DMSG("stmm load address %#"PRIxVA, stmm_image_addr);
409f9cd31c5SJelle Sels
410aa6d7fc3SLevi Yun spc->ns_comm_buf_addr = stmm_ns_comm_buf_addr;
411f9cd31c5SJelle Sels spc->ns_comm_buf_size = stmm_ns_comm_buf_size;
412f9cd31c5SJelle Sels
413aa6d7fc3SLevi Yun init_stmm_regs(spc, (unsigned long)hdr, 0, 0, 0, stmm_image_addr);
414f9cd31c5SJelle Sels
415f9cd31c5SJelle Sels return stmm_enter_user_mode(spc);
416f9cd31c5SJelle Sels }
417f9cd31c5SJelle Sels
stmm_init_session(const TEE_UUID * uuid,struct tee_ta_session * sess)418f9cd31c5SJelle Sels TEE_Result stmm_init_session(const TEE_UUID *uuid, struct tee_ta_session *sess)
419f9cd31c5SJelle Sels {
420f9cd31c5SJelle Sels struct stmm_ctx *spc = NULL;
421956c2d50SEtienne Carriere
422956c2d50SEtienne Carriere /* Caller is expected to hold tee_ta_mutex for safe changes in @sess */
423956c2d50SEtienne Carriere assert(mutex_is_locked(&tee_ta_mutex));
424f9cd31c5SJelle Sels
425f9cd31c5SJelle Sels if (memcmp(uuid, &stmm_uuid, sizeof(*uuid)))
426f9cd31c5SJelle Sels return TEE_ERROR_ITEM_NOT_FOUND;
427f9cd31c5SJelle Sels
428f9cd31c5SJelle Sels spc = stmm_alloc_ctx(uuid);
429f9cd31c5SJelle Sels if (!spc)
430f9cd31c5SJelle Sels return TEE_ERROR_OUT_OF_MEMORY;
431f9cd31c5SJelle Sels
432fee55718SEtienne Carriere spc->ta_ctx.is_initializing = true;
433f9cd31c5SJelle Sels
434f9cd31c5SJelle Sels sess->ts_sess.ctx = &spc->ta_ctx.ts_ctx;
435ab5363c6SJens Wiklander sess->ts_sess.handle_scall = sess->ts_sess.ctx->ops->handle_scall;
436956c2d50SEtienne Carriere
437956c2d50SEtienne Carriere return TEE_SUCCESS;
438956c2d50SEtienne Carriere }
439956c2d50SEtienne Carriere
stmm_complete_session(struct tee_ta_session * sess)440956c2d50SEtienne Carriere TEE_Result stmm_complete_session(struct tee_ta_session *sess)
441956c2d50SEtienne Carriere {
442956c2d50SEtienne Carriere struct stmm_ctx *spc = to_stmm_ctx(sess->ts_sess.ctx);
443aa6d7fc3SLevi Yun TEE_Result res = TEE_ERROR_GENERIC;
444f9cd31c5SJelle Sels
445f9cd31c5SJelle Sels ts_push_current_session(&sess->ts_sess);
446f9cd31c5SJelle Sels res = load_stmm(spc);
447f9cd31c5SJelle Sels ts_pop_current_session();
448f9cd31c5SJelle Sels vm_set_ctx(NULL);
449f9cd31c5SJelle Sels if (res) {
450f9cd31c5SJelle Sels sess->ts_sess.ctx = NULL;
451f9cd31c5SJelle Sels spc->ta_ctx.ts_ctx.ops->destroy(&spc->ta_ctx.ts_ctx);
452f9cd31c5SJelle Sels
453f9cd31c5SJelle Sels return res;
454f9cd31c5SJelle Sels }
455f9cd31c5SJelle Sels
456f9cd31c5SJelle Sels mutex_lock(&tee_ta_mutex);
457fee55718SEtienne Carriere spc->ta_ctx.is_initializing = false;
458f9cd31c5SJelle Sels TAILQ_INSERT_TAIL(&tee_ctxes, &spc->ta_ctx, link);
459f9cd31c5SJelle Sels mutex_unlock(&tee_ta_mutex);
460f9cd31c5SJelle Sels
461f9cd31c5SJelle Sels return TEE_SUCCESS;
462f9cd31c5SJelle Sels }
463f9cd31c5SJelle Sels
stmm_enter_open_session(struct ts_session * s)464f9cd31c5SJelle Sels static TEE_Result stmm_enter_open_session(struct ts_session *s)
465f9cd31c5SJelle Sels {
466f9cd31c5SJelle Sels struct stmm_ctx *spc = to_stmm_ctx(s->ctx);
467f9cd31c5SJelle Sels struct tee_ta_session *ta_sess = to_ta_session(s);
468f9cd31c5SJelle Sels const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE,
469f9cd31c5SJelle Sels TEE_PARAM_TYPE_NONE,
470f9cd31c5SJelle Sels TEE_PARAM_TYPE_NONE,
471f9cd31c5SJelle Sels TEE_PARAM_TYPE_NONE);
472f9cd31c5SJelle Sels
473f9cd31c5SJelle Sels if (ta_sess->param->types != exp_pt)
474f9cd31c5SJelle Sels return TEE_ERROR_BAD_PARAMETERS;
475f9cd31c5SJelle Sels
476fee55718SEtienne Carriere if (spc->ta_ctx.is_initializing) {
477f9cd31c5SJelle Sels /* StMM is initialized in stmm_init_session() */
478f9cd31c5SJelle Sels ta_sess->err_origin = TEE_ORIGIN_TEE;
479f9cd31c5SJelle Sels return TEE_ERROR_BAD_STATE;
480f9cd31c5SJelle Sels }
481f9cd31c5SJelle Sels
482f9cd31c5SJelle Sels return TEE_SUCCESS;
483f9cd31c5SJelle Sels }
484f9cd31c5SJelle Sels
stmm_enter_invoke_cmd(struct ts_session * s,uint32_t cmd)485f9cd31c5SJelle Sels static TEE_Result stmm_enter_invoke_cmd(struct ts_session *s, uint32_t cmd)
486f9cd31c5SJelle Sels {
487f9cd31c5SJelle Sels struct stmm_ctx *spc = to_stmm_ctx(s->ctx);
488f9cd31c5SJelle Sels struct tee_ta_session *ta_sess = to_ta_session(s);
489f9cd31c5SJelle Sels TEE_Result res = TEE_SUCCESS;
490f9cd31c5SJelle Sels TEE_Result __maybe_unused tmp_res = TEE_SUCCESS;
491f9cd31c5SJelle Sels unsigned int ns_buf_size = 0;
492f9cd31c5SJelle Sels struct param_mem *mem = NULL;
493f9cd31c5SJelle Sels void *va = NULL;
494f9cd31c5SJelle Sels const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
495f9cd31c5SJelle Sels TEE_PARAM_TYPE_VALUE_OUTPUT,
496f9cd31c5SJelle Sels TEE_PARAM_TYPE_NONE,
497f9cd31c5SJelle Sels TEE_PARAM_TYPE_NONE);
498f9cd31c5SJelle Sels
499f9cd31c5SJelle Sels if (cmd != PTA_STMM_CMD_COMMUNICATE)
500f9cd31c5SJelle Sels return TEE_ERROR_BAD_PARAMETERS;
501f9cd31c5SJelle Sels
502f9cd31c5SJelle Sels if (ta_sess->param->types != exp_pt)
503f9cd31c5SJelle Sels return TEE_ERROR_BAD_PARAMETERS;
504f9cd31c5SJelle Sels
505f9cd31c5SJelle Sels mem = &ta_sess->param->u[0].mem;
506f9cd31c5SJelle Sels ns_buf_size = mem->size;
507f9cd31c5SJelle Sels if (ns_buf_size > spc->ns_comm_buf_size) {
508f9cd31c5SJelle Sels mem->size = spc->ns_comm_buf_size;
509f9cd31c5SJelle Sels return TEE_ERROR_EXCESS_DATA;
510f9cd31c5SJelle Sels }
511f9cd31c5SJelle Sels
512f9cd31c5SJelle Sels res = mobj_inc_map(mem->mobj);
513f9cd31c5SJelle Sels if (res)
514f9cd31c5SJelle Sels return res;
515f9cd31c5SJelle Sels
5169c4aaf67SJens Wiklander va = mobj_get_va(mem->mobj, mem->offs, mem->size);
517f9cd31c5SJelle Sels if (!va) {
518f9cd31c5SJelle Sels EMSG("Can't get a valid VA for NS buffer");
519f9cd31c5SJelle Sels res = TEE_ERROR_BAD_PARAMETERS;
520f9cd31c5SJelle Sels goto out_va;
521f9cd31c5SJelle Sels }
522f9cd31c5SJelle Sels
523d9339333SEtienne Carriere #ifdef ARM64
524d9339333SEtienne Carriere spc->regs.x[0] = __FFA_MSG_SEND_DIRECT_REQ;
525f9cd31c5SJelle Sels spc->regs.x[1] = (stmm_pta_id << 16) | stmm_id;
526f9cd31c5SJelle Sels spc->regs.x[2] = FFA_PARAM_MBZ;
527f9cd31c5SJelle Sels spc->regs.x[3] = spc->ns_comm_buf_addr;
528f9cd31c5SJelle Sels spc->regs.x[4] = ns_buf_size;
529f9cd31c5SJelle Sels spc->regs.x[5] = 0;
530f9cd31c5SJelle Sels spc->regs.x[6] = 0;
531f9cd31c5SJelle Sels spc->regs.x[7] = 0;
532d9339333SEtienne Carriere #endif
533d9339333SEtienne Carriere #ifdef ARM32
534d9339333SEtienne Carriere spc->regs.r0 = __FFA_MSG_SEND_DIRECT_REQ;
535d9339333SEtienne Carriere spc->regs.r1 = (stmm_pta_id << 16) | stmm_id;
536d9339333SEtienne Carriere spc->regs.r2 = FFA_PARAM_MBZ;
537d9339333SEtienne Carriere spc->regs.r3 = spc->ns_comm_buf_addr;
538d9339333SEtienne Carriere spc->regs.r4 = ns_buf_size;
539d9339333SEtienne Carriere spc->regs.r5 = 0;
540d9339333SEtienne Carriere spc->regs.r6 = 0;
541d9339333SEtienne Carriere spc->regs.r7 = 0;
542d9339333SEtienne Carriere #endif
543f9cd31c5SJelle Sels
544f9cd31c5SJelle Sels ts_push_current_session(s);
545f9cd31c5SJelle Sels
546f9cd31c5SJelle Sels memcpy((void *)spc->ns_comm_buf_addr, va, ns_buf_size);
547f9cd31c5SJelle Sels
548f9cd31c5SJelle Sels res = stmm_enter_user_mode(spc);
549f9cd31c5SJelle Sels if (res)
550f9cd31c5SJelle Sels goto out_session;
551f9cd31c5SJelle Sels /*
552f9cd31c5SJelle Sels * Copy the SPM response from secure partition back to the non-secure
553f9cd31c5SJelle Sels * buffer of the client that called us.
554f9cd31c5SJelle Sels */
555d9339333SEtienne Carriere #ifdef ARM64
556f9cd31c5SJelle Sels ta_sess->param->u[1].val.a = spc->regs.x[4];
557d9339333SEtienne Carriere #endif
558d9339333SEtienne Carriere #ifdef ARM32
559d9339333SEtienne Carriere ta_sess->param->u[1].val.a = spc->regs.r4;
560d9339333SEtienne Carriere #endif
561f9cd31c5SJelle Sels
562f9cd31c5SJelle Sels memcpy(va, (void *)spc->ns_comm_buf_addr, ns_buf_size);
563f9cd31c5SJelle Sels
564f9cd31c5SJelle Sels out_session:
565f9cd31c5SJelle Sels ts_pop_current_session();
566f9cd31c5SJelle Sels out_va:
567f9cd31c5SJelle Sels tmp_res = mobj_dec_map(mem->mobj);
568f9cd31c5SJelle Sels assert(!tmp_res);
569f9cd31c5SJelle Sels
570f9cd31c5SJelle Sels return res;
571f9cd31c5SJelle Sels }
572f9cd31c5SJelle Sels
stmm_enter_close_session(struct ts_session * s __unused)573f9cd31c5SJelle Sels static void stmm_enter_close_session(struct ts_session *s __unused)
574f9cd31c5SJelle Sels {
575f9cd31c5SJelle Sels }
576f9cd31c5SJelle Sels
stmm_dump_state(struct ts_ctx * ctx)577f9cd31c5SJelle Sels static void stmm_dump_state(struct ts_ctx *ctx)
578f9cd31c5SJelle Sels {
579f9cd31c5SJelle Sels user_mode_ctx_print_mappings(to_user_mode_ctx(ctx));
580f9cd31c5SJelle Sels }
581409c619bSEtienne Carriere DECLARE_KEEP_PAGER(stmm_dump_state);
582f9cd31c5SJelle Sels
stmm_get_instance_id(struct ts_ctx * ctx)583f9cd31c5SJelle Sels static uint32_t stmm_get_instance_id(struct ts_ctx *ctx)
584f9cd31c5SJelle Sels {
585f9cd31c5SJelle Sels return to_stmm_ctx(ctx)->uctx.vm_info.asid;
586f9cd31c5SJelle Sels }
587f9cd31c5SJelle Sels
stmm_ctx_destroy(struct ts_ctx * ctx)588f9cd31c5SJelle Sels static void stmm_ctx_destroy(struct ts_ctx *ctx)
589f9cd31c5SJelle Sels {
590f9cd31c5SJelle Sels struct stmm_ctx *spc = to_stmm_ctx(ctx);
591f9cd31c5SJelle Sels
592f9cd31c5SJelle Sels vm_info_final(&spc->uctx);
593f9cd31c5SJelle Sels free(spc);
594f9cd31c5SJelle Sels }
595f9cd31c5SJelle Sels
596d9339333SEtienne Carriere #ifdef ARM64
save_sp_ctx(struct stmm_ctx * spc,struct thread_scall_regs * regs)597ab5363c6SJens Wiklander static void save_sp_ctx(struct stmm_ctx *spc,
598ab5363c6SJens Wiklander struct thread_scall_regs *regs)
599f9cd31c5SJelle Sels {
600f9cd31c5SJelle Sels size_t n = 0;
601f9cd31c5SJelle Sels
602f9cd31c5SJelle Sels /* Save the return values from StMM */
603f9cd31c5SJelle Sels for (n = 0; n <= 7; n++)
604ab5363c6SJens Wiklander spc->regs.x[n] = *(®s->x0 + n);
605f9cd31c5SJelle Sels
606ab5363c6SJens Wiklander spc->regs.sp = regs->sp_el0;
607ab5363c6SJens Wiklander spc->regs.pc = regs->elr;
608ab5363c6SJens Wiklander spc->regs.cpsr = regs->spsr;
609f9cd31c5SJelle Sels }
610d9339333SEtienne Carriere #endif
611f9cd31c5SJelle Sels
612d9339333SEtienne Carriere #ifdef ARM32
save_sp_ctx(struct stmm_ctx * spc,struct thread_scall_regs * regs)613ab5363c6SJens Wiklander static void save_sp_ctx(struct stmm_ctx *spc,
614ab5363c6SJens Wiklander struct thread_scall_regs *regs)
615d9339333SEtienne Carriere {
616ab5363c6SJens Wiklander spc->regs.r0 = regs->r0;
617ab5363c6SJens Wiklander spc->regs.r1 = regs->r1;
618ab5363c6SJens Wiklander spc->regs.r2 = regs->r2;
619ab5363c6SJens Wiklander spc->regs.r3 = regs->r3;
620ab5363c6SJens Wiklander spc->regs.r4 = regs->r4;
621ab5363c6SJens Wiklander spc->regs.r5 = regs->r5;
622ab5363c6SJens Wiklander spc->regs.r6 = regs->r6;
623ab5363c6SJens Wiklander spc->regs.r7 = regs->r7;
624ab5363c6SJens Wiklander spc->regs.pc = regs->lr;
625ab5363c6SJens Wiklander spc->regs.cpsr = regs->spsr;
626d9339333SEtienne Carriere spc->regs.usr_sp = thread_get_usr_sp();
627d9339333SEtienne Carriere }
628d9339333SEtienne Carriere #endif
629d9339333SEtienne Carriere
return_from_sp_helper(bool panic,uint32_t panic_code,struct thread_scall_regs * regs)630c232eb8dSEtienne Carriere static void return_from_sp_helper(bool panic, uint32_t panic_code,
631ab5363c6SJens Wiklander struct thread_scall_regs *regs)
632d9339333SEtienne Carriere {
633d9339333SEtienne Carriere struct ts_session *sess = ts_get_current_session();
634d9339333SEtienne Carriere struct stmm_ctx *spc = to_stmm_ctx(sess->ctx);
635d9339333SEtienne Carriere
6364348e834SEtienne Carriere if (panic)
6374348e834SEtienne Carriere spc->ta_ctx.panicked = true;
6384348e834SEtienne Carriere else
639ab5363c6SJens Wiklander save_sp_ctx(spc, regs);
640d9339333SEtienne Carriere
641ab5363c6SJens Wiklander SVC_REGS_A0(regs) = 0;
642ab5363c6SJens Wiklander SVC_REGS_A1(regs) = panic;
643ab5363c6SJens Wiklander SVC_REGS_A2(regs) = panic_code;
644f9cd31c5SJelle Sels }
645f9cd31c5SJelle Sels
service_compose_direct_resp(struct thread_scall_regs * regs,uint32_t ret_val)646ab5363c6SJens Wiklander static void service_compose_direct_resp(struct thread_scall_regs *regs,
647f9cd31c5SJelle Sels uint32_t ret_val)
648f9cd31c5SJelle Sels {
649f9cd31c5SJelle Sels uint16_t src_id = 0;
650f9cd31c5SJelle Sels uint16_t dst_id = 0;
651f9cd31c5SJelle Sels
652f9cd31c5SJelle Sels /* extract from request */
653d9339333SEtienne Carriere src_id = (SVC_REGS_A1(regs) >> 16) & UINT16_MAX;
654d9339333SEtienne Carriere dst_id = SVC_REGS_A1(regs) & UINT16_MAX;
655f9cd31c5SJelle Sels
656f9cd31c5SJelle Sels /* compose message */
657d9339333SEtienne Carriere SVC_REGS_A0(regs) = __FFA_MSG_SEND_DIRECT_RESP;
658f9cd31c5SJelle Sels /* swap endpoint ids */
659d9339333SEtienne Carriere SVC_REGS_A1(regs) = SHIFT_U32(dst_id, 16) | src_id;
660d9339333SEtienne Carriere SVC_REGS_A2(regs) = FFA_PARAM_MBZ;
661d9339333SEtienne Carriere SVC_REGS_A3(regs) = ret_val;
662d9339333SEtienne Carriere SVC_REGS_A4(regs) = 0;
663d9339333SEtienne Carriere SVC_REGS_A5(regs) = 0;
664d9339333SEtienne Carriere SVC_REGS_A6(regs) = 0;
665d9339333SEtienne Carriere SVC_REGS_A7(regs) = 0;
666f9cd31c5SJelle Sels }
667f9cd31c5SJelle Sels
668f9cd31c5SJelle Sels /*
669f9cd31c5SJelle Sels * Combined read from secure partition, this will open, read and
670f9cd31c5SJelle Sels * close the file object.
671f9cd31c5SJelle Sels */
sec_storage_obj_read(unsigned long storage_id,char * obj_id,unsigned long obj_id_len,void * data,unsigned long len,unsigned long offset,unsigned long flags)672f9cd31c5SJelle Sels static TEE_Result sec_storage_obj_read(unsigned long storage_id, char *obj_id,
673f9cd31c5SJelle Sels unsigned long obj_id_len, void *data,
674f9cd31c5SJelle Sels unsigned long len, unsigned long offset,
675f9cd31c5SJelle Sels unsigned long flags)
676f9cd31c5SJelle Sels {
677f9cd31c5SJelle Sels const struct tee_file_operations *fops = NULL;
678f9cd31c5SJelle Sels TEE_Result res = TEE_ERROR_BAD_STATE;
679f9cd31c5SJelle Sels struct ts_session *sess = NULL;
680f9cd31c5SJelle Sels struct tee_file_handle *fh = NULL;
681f9cd31c5SJelle Sels struct tee_pobj *po = NULL;
682f9cd31c5SJelle Sels size_t file_size = 0;
683f9cd31c5SJelle Sels size_t read_len = 0;
684f9cd31c5SJelle Sels
685f9cd31c5SJelle Sels fops = tee_svc_storage_file_ops(storage_id);
686f9cd31c5SJelle Sels if (!fops)
687f9cd31c5SJelle Sels return TEE_ERROR_ITEM_NOT_FOUND;
688f9cd31c5SJelle Sels
689f9cd31c5SJelle Sels if (obj_id_len > TEE_OBJECT_ID_MAX_LEN)
690f9cd31c5SJelle Sels return TEE_ERROR_BAD_PARAMETERS;
691f9cd31c5SJelle Sels
692f9cd31c5SJelle Sels sess = ts_get_current_session();
693f9cd31c5SJelle Sels
694f9cd31c5SJelle Sels res = tee_pobj_get(&sess->ctx->uuid, obj_id, obj_id_len, flags,
695d0989b48SEtienne Carriere TEE_POBJ_USAGE_OPEN, fops, &po);
696f9cd31c5SJelle Sels if (res != TEE_SUCCESS)
697f9cd31c5SJelle Sels return res;
698f9cd31c5SJelle Sels
699f9cd31c5SJelle Sels res = po->fops->open(po, &file_size, &fh);
700f9cd31c5SJelle Sels if (res != TEE_SUCCESS)
701f9cd31c5SJelle Sels goto out;
702f9cd31c5SJelle Sels
703f9cd31c5SJelle Sels read_len = len;
704b2284b11SJens Wiklander res = po->fops->read(fh, offset, NULL, data, &read_len);
705f9cd31c5SJelle Sels if (res == TEE_ERROR_CORRUPT_OBJECT) {
706f9cd31c5SJelle Sels EMSG("Object corrupt");
707f9cd31c5SJelle Sels po->fops->remove(po);
708f9cd31c5SJelle Sels } else if (res == TEE_SUCCESS && len != read_len) {
709f9cd31c5SJelle Sels res = TEE_ERROR_CORRUPT_OBJECT;
710f9cd31c5SJelle Sels }
711f9cd31c5SJelle Sels
712f9cd31c5SJelle Sels po->fops->close(&fh);
713f9cd31c5SJelle Sels
714f9cd31c5SJelle Sels out:
715f9cd31c5SJelle Sels tee_pobj_release(po);
716f9cd31c5SJelle Sels
717f9cd31c5SJelle Sels return res;
718f9cd31c5SJelle Sels }
719f9cd31c5SJelle Sels
720f9cd31c5SJelle Sels /*
721f9cd31c5SJelle Sels * Combined write from secure partition, this will create/open, write and
722f9cd31c5SJelle Sels * close the file object.
723f9cd31c5SJelle Sels */
sec_storage_obj_write(unsigned long storage_id,char * obj_id,unsigned long obj_id_len,void * data,unsigned long len,unsigned long offset,unsigned long flags)724f9cd31c5SJelle Sels static TEE_Result sec_storage_obj_write(unsigned long storage_id, char *obj_id,
725f9cd31c5SJelle Sels unsigned long obj_id_len, void *data,
726f9cd31c5SJelle Sels unsigned long len, unsigned long offset,
727f9cd31c5SJelle Sels unsigned long flags)
728f9cd31c5SJelle Sels
729f9cd31c5SJelle Sels {
730f9cd31c5SJelle Sels const struct tee_file_operations *fops = NULL;
731f9cd31c5SJelle Sels struct ts_session *sess = NULL;
732f9cd31c5SJelle Sels struct tee_file_handle *fh = NULL;
733f9cd31c5SJelle Sels TEE_Result res = TEE_SUCCESS;
734f9cd31c5SJelle Sels struct tee_pobj *po = NULL;
735f9cd31c5SJelle Sels
736f9cd31c5SJelle Sels fops = tee_svc_storage_file_ops(storage_id);
737f9cd31c5SJelle Sels if (!fops)
738f9cd31c5SJelle Sels return TEE_ERROR_ITEM_NOT_FOUND;
739f9cd31c5SJelle Sels
740f9cd31c5SJelle Sels if (obj_id_len > TEE_OBJECT_ID_MAX_LEN)
741f9cd31c5SJelle Sels return TEE_ERROR_BAD_PARAMETERS;
742f9cd31c5SJelle Sels
743f9cd31c5SJelle Sels sess = ts_get_current_session();
744f9cd31c5SJelle Sels
745f9cd31c5SJelle Sels res = tee_pobj_get(&sess->ctx->uuid, obj_id, obj_id_len, flags,
746d0989b48SEtienne Carriere TEE_POBJ_USAGE_OPEN, fops, &po);
747f9cd31c5SJelle Sels if (res != TEE_SUCCESS)
748f9cd31c5SJelle Sels return res;
749f9cd31c5SJelle Sels
750f9cd31c5SJelle Sels res = po->fops->open(po, NULL, &fh);
751f9cd31c5SJelle Sels if (res == TEE_ERROR_ITEM_NOT_FOUND)
752b2284b11SJens Wiklander res = po->fops->create(po, false, NULL, 0, NULL, 0,
753b2284b11SJens Wiklander NULL, NULL, 0, &fh);
754f9cd31c5SJelle Sels if (res == TEE_SUCCESS) {
755b2284b11SJens Wiklander res = po->fops->write(fh, offset, NULL, data, len);
756f9cd31c5SJelle Sels po->fops->close(&fh);
757f9cd31c5SJelle Sels }
758f9cd31c5SJelle Sels
759f9cd31c5SJelle Sels tee_pobj_release(po);
760f9cd31c5SJelle Sels
761f9cd31c5SJelle Sels return res;
762f9cd31c5SJelle Sels }
763f9cd31c5SJelle Sels
tee2ffa_ret_val(TEE_Result res)764aa6d7fc3SLevi Yun static uint32_t tee2ffa_ret_val(TEE_Result res)
765c899c027SEtienne Carriere {
766c899c027SEtienne Carriere switch (res) {
767c899c027SEtienne Carriere case TEE_SUCCESS:
768aa6d7fc3SLevi Yun return FFA_OK;
769aa6d7fc3SLevi Yun case TEE_ERROR_NOT_IMPLEMENTED:
770c899c027SEtienne Carriere case TEE_ERROR_NOT_SUPPORTED:
771aa6d7fc3SLevi Yun return FFA_NOT_SUPPORTED;
772c899c027SEtienne Carriere case TEE_ERROR_OUT_OF_MEMORY:
773aa6d7fc3SLevi Yun return FFA_NO_MEMORY;
774aa6d7fc3SLevi Yun case TEE_ERROR_ACCESS_DENIED:
775aa6d7fc3SLevi Yun return FFA_DENIED;
776aa6d7fc3SLevi Yun case TEE_ERROR_NO_DATA:
777aa6d7fc3SLevi Yun return FFA_NO_DATA;
778c899c027SEtienne Carriere case TEE_ERROR_BAD_PARAMETERS:
779c899c027SEtienne Carriere default:
780aa6d7fc3SLevi Yun return FFA_INVALID_PARAMETERS;
781c899c027SEtienne Carriere }
782c899c027SEtienne Carriere }
783c899c027SEtienne Carriere
spm_eret_error(int32_t error_code,struct thread_scall_regs * regs)784aa6d7fc3SLevi Yun static void spm_eret_error(int32_t error_code, struct thread_scall_regs *regs)
785aa6d7fc3SLevi Yun {
786aa6d7fc3SLevi Yun SVC_REGS_A0(regs) = FFA_ERROR;
787aa6d7fc3SLevi Yun SVC_REGS_A1(regs) = FFA_PARAM_MBZ;
788aa6d7fc3SLevi Yun SVC_REGS_A2(regs) = error_code;
789aa6d7fc3SLevi Yun SVC_REGS_A3(regs) = FFA_PARAM_MBZ;
790aa6d7fc3SLevi Yun SVC_REGS_A4(regs) = FFA_PARAM_MBZ;
791aa6d7fc3SLevi Yun SVC_REGS_A5(regs) = FFA_PARAM_MBZ;
792aa6d7fc3SLevi Yun SVC_REGS_A6(regs) = FFA_PARAM_MBZ;
793aa6d7fc3SLevi Yun SVC_REGS_A7(regs) = FFA_PARAM_MBZ;
794aa6d7fc3SLevi Yun }
795aa6d7fc3SLevi Yun
796f9cd31c5SJelle Sels #define FILENAME "EFI_VARS"
stmm_handle_storage_service(struct thread_scall_regs * regs)797ab5363c6SJens Wiklander static void stmm_handle_storage_service(struct thread_scall_regs *regs)
798f9cd31c5SJelle Sels {
799f9cd31c5SJelle Sels uint32_t flags = TEE_DATA_FLAG_ACCESS_READ |
800f9cd31c5SJelle Sels TEE_DATA_FLAG_ACCESS_WRITE |
801f9cd31c5SJelle Sels TEE_DATA_FLAG_SHARE_READ |
802f9cd31c5SJelle Sels TEE_DATA_FLAG_SHARE_WRITE;
803d9339333SEtienne Carriere uint32_t action = SVC_REGS_A3(regs);
804d9339333SEtienne Carriere void *va = (void *)SVC_REGS_A4(regs);
805d9339333SEtienne Carriere unsigned long len = SVC_REGS_A5(regs);
806d9339333SEtienne Carriere unsigned long offset = SVC_REGS_A6(regs);
807f9cd31c5SJelle Sels char obj_id[] = FILENAME;
808f9cd31c5SJelle Sels size_t obj_id_len = strlen(obj_id);
809f9cd31c5SJelle Sels TEE_Result res = TEE_SUCCESS;
810c899c027SEtienne Carriere uint32_t stmm_rc = STMM_RET_INVALID_PARAM;
811f9cd31c5SJelle Sels
812f9cd31c5SJelle Sels switch (action) {
813d9339333SEtienne Carriere case __FFA_SVC_RPMB_READ:
814d9339333SEtienne Carriere DMSG("RPMB read");
815f9cd31c5SJelle Sels res = sec_storage_obj_read(TEE_STORAGE_PRIVATE_RPMB, obj_id,
816f9cd31c5SJelle Sels obj_id_len, va, len, offset, flags);
817aa6d7fc3SLevi Yun stmm_rc = tee2ffa_ret_val(res);
818c899c027SEtienne Carriere break;
819d9339333SEtienne Carriere case __FFA_SVC_RPMB_WRITE:
820d9339333SEtienne Carriere DMSG("RPMB write");
821f9cd31c5SJelle Sels res = sec_storage_obj_write(TEE_STORAGE_PRIVATE_RPMB, obj_id,
822f9cd31c5SJelle Sels obj_id_len, va, len, offset, flags);
823aa6d7fc3SLevi Yun stmm_rc = tee2ffa_ret_val(res);
824c899c027SEtienne Carriere break;
825f9cd31c5SJelle Sels default:
826f9cd31c5SJelle Sels EMSG("Undefined service id %#"PRIx32, action);
827c899c027SEtienne Carriere break;
828f9cd31c5SJelle Sels }
829c899c027SEtienne Carriere
830c899c027SEtienne Carriere service_compose_direct_resp(regs, stmm_rc);
831f9cd31c5SJelle Sels }
832f9cd31c5SJelle Sels
spm_handle_direct_req(struct thread_scall_regs * regs)833ab5363c6SJens Wiklander static void spm_handle_direct_req(struct thread_scall_regs *regs)
834f9cd31c5SJelle Sels {
835d9339333SEtienne Carriere uint16_t dst_id = SVC_REGS_A1(regs) & UINT16_MAX;
836f9cd31c5SJelle Sels
837aa6d7fc3SLevi Yun if (dst_id == ffa_storage_id) {
838c232eb8dSEtienne Carriere stmm_handle_storage_service(regs);
839c232eb8dSEtienne Carriere } else {
840f9cd31c5SJelle Sels EMSG("Undefined endpoint id %#"PRIx16, dst_id);
841c232eb8dSEtienne Carriere spm_eret_error(STMM_RET_INVALID_PARAM, regs);
842c232eb8dSEtienne Carriere }
843f9cd31c5SJelle Sels }
844f9cd31c5SJelle Sels
spm_handle_get_mem_attr(struct thread_scall_regs * regs)845aa6d7fc3SLevi Yun static void spm_handle_get_mem_attr(struct thread_scall_regs *regs)
846aa6d7fc3SLevi Yun {
847aa6d7fc3SLevi Yun TEE_Result res = TEE_ERROR_GENERIC;
848aa6d7fc3SLevi Yun struct ts_session *sess = NULL;
849aa6d7fc3SLevi Yun struct stmm_ctx *spc = NULL;
850aa6d7fc3SLevi Yun uint16_t attrs = 0;
851aa6d7fc3SLevi Yun uint16_t perm = 0;
852aa6d7fc3SLevi Yun vaddr_t va = 0;
853aa6d7fc3SLevi Yun uint32_t ffa_ret = FFA_INVALID_PARAMETERS;
854aa6d7fc3SLevi Yun
855aa6d7fc3SLevi Yun sess = ts_get_current_session();
856aa6d7fc3SLevi Yun spc = to_stmm_ctx(sess->ctx);
857aa6d7fc3SLevi Yun
858aa6d7fc3SLevi Yun va = SVC_REGS_A1(regs);
859aa6d7fc3SLevi Yun if (!va)
860aa6d7fc3SLevi Yun goto err;
861aa6d7fc3SLevi Yun
862aa6d7fc3SLevi Yun res = vm_get_prot(&spc->uctx, va, SMALL_PAGE_SIZE, &attrs);
863aa6d7fc3SLevi Yun if (res)
864aa6d7fc3SLevi Yun goto err;
865aa6d7fc3SLevi Yun
866aa6d7fc3SLevi Yun if ((attrs & TEE_MATTR_URW) == TEE_MATTR_URW)
867aa6d7fc3SLevi Yun perm |= FFA_MEM_PERM_RW;
868aa6d7fc3SLevi Yun else if ((attrs & TEE_MATTR_UR) == TEE_MATTR_UR)
869aa6d7fc3SLevi Yun perm |= FFA_MEM_PERM_RO;
870aa6d7fc3SLevi Yun
871aa6d7fc3SLevi Yun if (!(attrs & TEE_MATTR_UX))
872aa6d7fc3SLevi Yun perm |= FFA_MEM_PERM_NX;
873aa6d7fc3SLevi Yun
874aa6d7fc3SLevi Yun SVC_REGS_A0(regs) = FFA_SUCCESS_32;
875aa6d7fc3SLevi Yun SVC_REGS_A1(regs) = FFA_PARAM_MBZ;
876aa6d7fc3SLevi Yun SVC_REGS_A2(regs) = perm;
877aa6d7fc3SLevi Yun SVC_REGS_A3(regs) = FFA_PARAM_MBZ;
878aa6d7fc3SLevi Yun SVC_REGS_A4(regs) = FFA_PARAM_MBZ;
879aa6d7fc3SLevi Yun SVC_REGS_A5(regs) = FFA_PARAM_MBZ;
880aa6d7fc3SLevi Yun SVC_REGS_A6(regs) = FFA_PARAM_MBZ;
881aa6d7fc3SLevi Yun SVC_REGS_A7(regs) = FFA_PARAM_MBZ;
882aa6d7fc3SLevi Yun
883aa6d7fc3SLevi Yun return;
884aa6d7fc3SLevi Yun
885aa6d7fc3SLevi Yun err:
886aa6d7fc3SLevi Yun spm_eret_error(ffa_ret, regs);
887aa6d7fc3SLevi Yun }
888aa6d7fc3SLevi Yun
spm_handle_set_mem_attr(struct thread_scall_regs * regs)889aa6d7fc3SLevi Yun static void spm_handle_set_mem_attr(struct thread_scall_regs *regs)
890aa6d7fc3SLevi Yun {
891aa6d7fc3SLevi Yun TEE_Result res = TEE_ERROR_GENERIC;
892aa6d7fc3SLevi Yun struct ts_session *sess = NULL;
893aa6d7fc3SLevi Yun struct stmm_ctx *spc = NULL;
894aa6d7fc3SLevi Yun uintptr_t va = SVC_REGS_A1(regs);
895aa6d7fc3SLevi Yun uint32_t nr_pages = SVC_REGS_A2(regs);
896aa6d7fc3SLevi Yun uint32_t perm = SVC_REGS_A3(regs);
897aa6d7fc3SLevi Yun size_t sz = 0;
898aa6d7fc3SLevi Yun uint32_t prot = 0;
899aa6d7fc3SLevi Yun uint32_t ffa_ret = FFA_INVALID_PARAMETERS;
900aa6d7fc3SLevi Yun
901aa6d7fc3SLevi Yun if (!va || !nr_pages ||
902aa6d7fc3SLevi Yun MUL_OVERFLOW(nr_pages, SMALL_PAGE_SIZE, &sz) ||
903aa6d7fc3SLevi Yun (perm & FFA_MEM_PERM_RESERVED))
904aa6d7fc3SLevi Yun goto err;
905aa6d7fc3SLevi Yun
906aa6d7fc3SLevi Yun sess = ts_get_current_session();
907aa6d7fc3SLevi Yun spc = to_stmm_ctx(sess->ctx);
908aa6d7fc3SLevi Yun
909aa6d7fc3SLevi Yun if ((perm & FFA_MEM_PERM_DATA_PERM) == FFA_MEM_PERM_RO)
910aa6d7fc3SLevi Yun prot |= TEE_MATTR_UR;
911aa6d7fc3SLevi Yun else if ((perm & FFA_MEM_PERM_DATA_PERM) == FFA_MEM_PERM_RW)
912aa6d7fc3SLevi Yun prot |= TEE_MATTR_URW;
913aa6d7fc3SLevi Yun
914aa6d7fc3SLevi Yun if ((perm & FFA_MEM_PERM_INSTRUCTION_PERM) != FFA_MEM_PERM_NX)
915aa6d7fc3SLevi Yun prot |= TEE_MATTR_UX;
916aa6d7fc3SLevi Yun
917aa6d7fc3SLevi Yun res = vm_set_prot(&spc->uctx, va, sz, prot);
918aa6d7fc3SLevi Yun if (res) {
919aa6d7fc3SLevi Yun ffa_ret = FFA_DENIED;
920aa6d7fc3SLevi Yun goto err;
921aa6d7fc3SLevi Yun }
922aa6d7fc3SLevi Yun
923aa6d7fc3SLevi Yun SVC_REGS_A0(regs) = FFA_SUCCESS_32;
924aa6d7fc3SLevi Yun SVC_REGS_A1(regs) = FFA_PARAM_MBZ;
925aa6d7fc3SLevi Yun SVC_REGS_A2(regs) = FFA_PARAM_MBZ;
926aa6d7fc3SLevi Yun SVC_REGS_A3(regs) = FFA_PARAM_MBZ;
927aa6d7fc3SLevi Yun SVC_REGS_A4(regs) = FFA_PARAM_MBZ;
928aa6d7fc3SLevi Yun SVC_REGS_A5(regs) = FFA_PARAM_MBZ;
929aa6d7fc3SLevi Yun SVC_REGS_A6(regs) = FFA_PARAM_MBZ;
930aa6d7fc3SLevi Yun SVC_REGS_A7(regs) = FFA_PARAM_MBZ;
931aa6d7fc3SLevi Yun
932aa6d7fc3SLevi Yun return;
933aa6d7fc3SLevi Yun
934aa6d7fc3SLevi Yun err:
935aa6d7fc3SLevi Yun spm_eret_error(ffa_ret, regs);
936aa6d7fc3SLevi Yun }
937aa6d7fc3SLevi Yun
938c232eb8dSEtienne Carriere /* Return true if returning to SP, false if returning to caller */
spm_handle_scall(struct thread_scall_regs * regs)939ab5363c6SJens Wiklander static bool spm_handle_scall(struct thread_scall_regs *regs)
940f9cd31c5SJelle Sels {
941d9339333SEtienne Carriere #ifdef ARM64
942d9339333SEtienne Carriere uint64_t *a0 = ®s->x0;
943d9339333SEtienne Carriere #endif
944d9339333SEtienne Carriere #ifdef ARM32
945d9339333SEtienne Carriere uint32_t *a0 = ®s->r0;
946d9339333SEtienne Carriere #endif
947d9339333SEtienne Carriere
948d9339333SEtienne Carriere switch (*a0) {
949f9cd31c5SJelle Sels case FFA_VERSION:
950f9cd31c5SJelle Sels DMSG("Received FFA version");
951bef959c8SJens Wiklander *a0 = FFA_VERSION_1_2;
952f9cd31c5SJelle Sels return true;
953aa6d7fc3SLevi Yun case FFA_ID_GET:
954aa6d7fc3SLevi Yun DMSG("Received FFA ID GET");
955aa6d7fc3SLevi Yun SVC_REGS_A0(regs) = FFA_SUCCESS_32;
956aa6d7fc3SLevi Yun SVC_REGS_A2(regs) = stmm_id;
957aa6d7fc3SLevi Yun return true;
958aa6d7fc3SLevi Yun case FFA_MSG_WAIT:
959aa6d7fc3SLevi Yun DMSG("Received FFA_MSG_WAIT");
960aa6d7fc3SLevi Yun return_from_sp_helper(false, 0, regs);
961aa6d7fc3SLevi Yun return false;
962d9339333SEtienne Carriere case __FFA_MSG_SEND_DIRECT_RESP:
963f9cd31c5SJelle Sels DMSG("Received FFA direct response");
964c232eb8dSEtienne Carriere return_from_sp_helper(false, 0, regs);
965c232eb8dSEtienne Carriere return false;
966d9339333SEtienne Carriere case __FFA_MSG_SEND_DIRECT_REQ:
967f9cd31c5SJelle Sels DMSG("Received FFA direct request");
968c232eb8dSEtienne Carriere spm_handle_direct_req(regs);
969c232eb8dSEtienne Carriere return true;
970aa6d7fc3SLevi Yun case __FFA_MEM_PERM_GET:
971aa6d7fc3SLevi Yun DMSG("Received FFA mem perm get");
972aa6d7fc3SLevi Yun spm_handle_get_mem_attr(regs);
973aa6d7fc3SLevi Yun return true;
974aa6d7fc3SLevi Yun case __FFA_MEM_PERM_SET:
975aa6d7fc3SLevi Yun DMSG("Received FFA mem perm set");
976aa6d7fc3SLevi Yun spm_handle_set_mem_attr(regs);
977aa6d7fc3SLevi Yun return true;
978*ed89aa36SYeoreum Yun case FFA_ERROR:
979*ed89aa36SYeoreum Yun EMSG("Received FFA error");
980c232eb8dSEtienne Carriere return_from_sp_helper(true /*panic*/, 0xabcd, regs);
981c232eb8dSEtienne Carriere return false;
982*ed89aa36SYeoreum Yun default:
983*ed89aa36SYeoreum Yun DMSG("Undefined syscall %#"PRIx32, (uint32_t)*a0);
984*ed89aa36SYeoreum Yun spm_eret_error(FFA_NOT_SUPPORTED, regs);
985*ed89aa36SYeoreum Yun return true;
986f9cd31c5SJelle Sels }
987f9cd31c5SJelle Sels }
988f9cd31c5SJelle Sels
9896abfa44eSJens Wiklander /*
9906abfa44eSJens Wiklander * Note: this variable is weak just to ease breaking its dependency chain
9916abfa44eSJens Wiklander * when added to the unpaged area.
9926abfa44eSJens Wiklander */
99339e8c200SJerome Forissier const struct ts_ops stmm_sp_ops __weak __relrodata_unpaged("stmm_sp_ops") = {
994f9cd31c5SJelle Sels .enter_open_session = stmm_enter_open_session,
995f9cd31c5SJelle Sels .enter_invoke_cmd = stmm_enter_invoke_cmd,
996f9cd31c5SJelle Sels .enter_close_session = stmm_enter_close_session,
997f9cd31c5SJelle Sels .dump_state = stmm_dump_state,
998f9cd31c5SJelle Sels .destroy = stmm_ctx_destroy,
999f9cd31c5SJelle Sels .get_instance_id = stmm_get_instance_id,
1000ab5363c6SJens Wiklander .handle_scall = spm_handle_scall,
1001f9cd31c5SJelle Sels };
1002