diff --git a/core/arch/arm/include/ffa.h b/core/arch/arm/include/ffa.h index 6f03cd00b49..a7519348c12 100644 --- a/core/arch/arm/include/ffa.h +++ b/core/arch/arm/include/ffa.h @@ -224,6 +224,8 @@ static inline uint16_t ffa_target_info_get_vcpu_id(uint32_t target_info) #define FFA_PART_PROP_NOTIF_CREATED BIT(6) #define FFA_PART_PROP_NOTIF_DESTROYED BIT(7) #define FFA_PART_PROP_AARCH64_STATE BIT(8) +#define FFA_PART_PROP_DIRECT_REQ2_RECV BIT(9) +#define FFA_PART_PROP_DIRECT_REQ2_SEND BIT(10) #define FFA_MEMORY_HANDLE_HYPERVISOR_BIT BIT64(63) #define FFA_MEMORY_HANDLE_SECURE_BIT BIT64(45) diff --git a/core/arch/arm/include/kernel/secure_partition.h b/core/arch/arm/include/kernel/secure_partition.h index 9b79989fc91..83c483c8df3 100644 --- a/core/arch/arm/include/kernel/secure_partition.h +++ b/core/arch/arm/include/kernel/secure_partition.h @@ -26,6 +26,7 @@ struct sp_session { uint16_t endpoint_id; uint16_t thread_id; uint16_t caller_id; + uint32_t caller_fid; uint32_t boot_order; struct ts_session ts_sess; unsigned int spinlock; @@ -77,6 +78,7 @@ TEE_Result sp_enter(struct thread_smc_1_2_regs *args, struct sp_session *sp); TEE_Result sp_partition_info_get(uint32_t ffa_vers, void *buf, size_t buf_size, const uint32_t uuid_words[4], size_t *elem_count, bool count_only); +bool sp_has_ffa_uuid(struct sp_session *sp, const uint32_t uuid_words[4]); bool sp_has_exclusive_access(struct sp_mem_map_region *mem, struct user_mode_ctx *uctx); TEE_Result sp_map_shared(struct sp_session *s, diff --git a/core/arch/arm/include/kernel/thread_private_arch.h b/core/arch/arm/include/kernel/thread_private_arch.h index eb50b9a1d97..585a38df903 100644 --- a/core/arch/arm/include/kernel/thread_private_arch.h +++ b/core/arch/arm/include/kernel/thread_private_arch.h @@ -130,7 +130,7 @@ void thread_std_smc_entry(uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t __thread_std_smc_entry(uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5); -void thread_sp_alloc_and_run(struct thread_smc_args *args); +void thread_sp_alloc_and_run(struct thread_smc_1_2_regs *args); /* * Resumes execution of currently active thread by restoring context and diff --git a/core/arch/arm/kernel/secure_partition.c b/core/arch/arm/kernel/secure_partition.c index 4a31a365e76..325d3e169ba 100644 --- a/core/arch/arm/kernel/secure_partition.c +++ b/core/arch/arm/kernel/secure_partition.c @@ -63,6 +63,8 @@ #define SP_MANIFEST_DIRECT_REQ_RECEIVE BIT(0) #define SP_MANIFEST_DIRECT_REQ_SEND BIT(1) #define SP_MANIFEST_INDIRECT_REQ BIT(2) +#define SP_MANIFEST_DIRECT_REQ2_RECEIVE BIT(9) +#define SP_MANIFEST_DIRECT_REQ2_SEND BIT(10) #define SP_MANIFEST_VM_CREATED_MSG BIT(0) #define SP_MANIFEST_VM_DESTROYED_MSG BIT(1) @@ -459,6 +461,18 @@ static TEE_Result sp_dt_get_uuid(const void *fdt, int node, return TEE_SUCCESS; } +bool sp_has_ffa_uuid(struct sp_session *sp, const uint32_t uuid_words[4]) +{ + TEE_UUID uuid = { }; + + if (!sp || !uuid_words) + return false; + + tee_uuid_from_octets(&uuid, (const uint8_t *)uuid_words); + + return !memcmp(&sp->ffa_uuid, &uuid, sizeof(uuid)); +} + static TEE_Result sp_is_elf_format(const void *fdt, int sp_node, bool *is_elf_format) { @@ -1488,7 +1502,7 @@ static TEE_Result read_ffa_version(const void *fdt, struct sp_session *s) return res; } - if (ffa_version != FFA_VERSION_1_0 && ffa_version != FFA_VERSION_1_1) { + if (ffa_version < FFA_VERSION_1_0 || ffa_version > FFA_VERSION_1_2) { EMSG("Invalid FF-A version value: 0x%08"PRIx32, ffa_version); return TEE_ERROR_BAD_PARAMETERS; } @@ -1537,6 +1551,14 @@ static TEE_Result read_sp_msg_types(const void *fdt, struct sp_session *s) if (msg_method & SP_MANIFEST_DIRECT_REQ_SEND) s->props |= FFA_PART_PROP_DIRECT_REQ_SEND; + if (s->rxtx.ffa_vers >= FFA_VERSION_1_2 && + (s->props & FFA_PART_PROP_AARCH64_STATE)) { + if (msg_method & SP_MANIFEST_DIRECT_REQ2_RECEIVE) + s->props |= FFA_PART_PROP_DIRECT_REQ2_RECV; + if (msg_method & SP_MANIFEST_DIRECT_REQ2_SEND) + s->props |= FFA_PART_PROP_DIRECT_REQ2_SEND; + } + if (msg_method & SP_MANIFEST_INDIRECT_REQ) IMSG("Indirect messaging is not supported"); @@ -1729,14 +1751,7 @@ TEE_Result sp_enter(struct thread_smc_1_2_regs *args, struct sp_session *sp) TEE_Result res = TEE_SUCCESS; struct sp_ctx *ctx = to_sp_ctx(sp->ts_sess.ctx); - ctx->sp_regs.x[0] = args->a0; - ctx->sp_regs.x[1] = args->a1; - ctx->sp_regs.x[2] = args->a2; - ctx->sp_regs.x[3] = args->a3; - ctx->sp_regs.x[4] = args->a4; - ctx->sp_regs.x[5] = args->a5; - ctx->sp_regs.x[6] = args->a6; - ctx->sp_regs.x[7] = args->a7; + memcpy(ctx->sp_regs.x, args->a, sizeof(args->a)); #ifdef CFG_TA_PAUTH ctx->sp_regs.apiakey_hi = ctx->uctx.keys.apia_hi; ctx->sp_regs.apiakey_lo = ctx->uctx.keys.apia_lo; @@ -1744,14 +1759,7 @@ TEE_Result sp_enter(struct thread_smc_1_2_regs *args, struct sp_session *sp) res = sp->ts_sess.ctx->ops->enter_invoke_cmd(&sp->ts_sess, 0); - args->a0 = ctx->sp_regs.x[0]; - args->a1 = ctx->sp_regs.x[1]; - args->a2 = ctx->sp_regs.x[2]; - args->a3 = ctx->sp_regs.x[3]; - args->a4 = ctx->sp_regs.x[4]; - args->a5 = ctx->sp_regs.x[5]; - args->a6 = ctx->sp_regs.x[6]; - args->a7 = ctx->sp_regs.x[7]; + memcpy(args->a, ctx->sp_regs.x, sizeof(args->a)); return res; } @@ -1877,8 +1885,8 @@ static bool sp_handle_scall(struct thread_scall_regs *regs) * handler. * We always return to S-El1 after handling the SVC. We will continue * in sp_enter_invoke_cmd() (return from __thread_enter_user_mode). - * The sp_enter() function copies the FF-A parameters (a0-a7) from the - * saved registers to the thread_smc_args. The thread_smc_args object is + * The sp_enter() function copies the FF-A parameters from the + * saved registers to the thread_smc_1_2_regs object. This object is * afterward used by the spmc_sp_msg_handler() to handle the * FF-A message send by the SP. */ diff --git a/core/arch/arm/kernel/spmc_sp_handler.c b/core/arch/arm/kernel/spmc_sp_handler.c index 48940bae280..77cc0b59d74 100644 --- a/core/arch/arm/kernel/spmc_sp_handler.c +++ b/core/arch/arm/kernel/spmc_sp_handler.c @@ -16,13 +16,14 @@ #include #include #include +#include /* Protects the ref_count field in struct sp_mem_receiver */ static unsigned int mem_ref_lock = SPINLOCK_UNLOCK; int spmc_sp_start_thread(struct thread_smc_1_2_regs *args) { - thread_sp_alloc_and_run(&args->arg11); + thread_sp_alloc_and_run(args); /* * thread_sp_alloc_and_run() only returns if all threads are busy. * The caller must try again. @@ -41,6 +42,21 @@ static void ffa_success(struct thread_smc_1_2_regs *args) spmc_set_args(args, FFA_SUCCESS_32, 0, 0, 0, 0, 0); } +static bool is_nil_uuid_words(const uint32_t uuid_words[4]) +{ + return !uuid_words || (!uuid_words[0] && !uuid_words[1] && + !uuid_words[2] && !uuid_words[3]); +} + +static void direct_req2_uuid_from_args(struct thread_smc_1_2_regs *args, + uint32_t uuid_words[4]) +{ + uuid_words[0] = low32_from_64(args->a2); + uuid_words[1] = high32_from_64(args->a2); + uuid_words[2] = low32_from_64(args->a3); + uuid_words[3] = high32_from_64(args->a3); +} + static TEE_Result ffa_get_dst(struct thread_smc_1_2_regs *args, struct sp_session *caller, struct sp_session **dst) @@ -899,6 +915,16 @@ ffa_handle_sp_direct_req(struct thread_smc_1_2_regs *args, struct sp_session *dst = NULL; struct spmc_lsp_desc *lsp = NULL; TEE_Result res = FFA_OK; + uint32_t caller_props = 0; + uint32_t dst_props = 0; + + if (args->a0 == FFA_MSG_SEND_DIRECT_REQ2) { + caller_props = FFA_PART_PROP_DIRECT_REQ2_SEND; + dst_props = FFA_PART_PROP_DIRECT_REQ2_RECV; + } else { + caller_props = FFA_PART_PROP_DIRECT_REQ_SEND; + dst_props = FFA_PART_PROP_DIRECT_REQ_RECV; + } res = ffa_get_dst(args, caller_sp, &dst); if (res) { @@ -921,22 +947,21 @@ ffa_handle_sp_direct_req(struct thread_smc_1_2_regs *args, return caller_sp; } - if (caller_sp && - !(caller_sp->props & FFA_PART_PROP_DIRECT_REQ_SEND)) { + if (caller_sp && !(caller_sp->props & caller_props)) { EMSG("SP 0x%"PRIx16" doesn't support sending direct requests", caller_sp->endpoint_id); ffa_set_error(args, FFA_NOT_SUPPORTED); return caller_sp; } - if (dst && !(dst->props & FFA_PART_PROP_DIRECT_REQ_RECV)) { + if (dst && !(dst->props & dst_props)) { EMSG("SP 0x%"PRIx16" doesn't support receipt of direct requests", dst->endpoint_id); ffa_set_error(args, FFA_NOT_SUPPORTED); return caller_sp; } - if (lsp && !(lsp->properties & FFA_PART_PROP_DIRECT_REQ_RECV)) { + if (lsp && !(lsp->properties & dst_props)) { EMSG("LSP 0x%"PRIx16" doesn't support receipt of direct requests", lsp->sp_id); ffa_set_error(args, FFA_NOT_SUPPORTED); @@ -948,7 +973,16 @@ ffa_handle_sp_direct_req(struct thread_smc_1_2_regs *args, return caller_sp; } - if (args->a2 & FFA_MSG_FLAG_FRAMEWORK) { + if (args->a0 == FFA_MSG_SEND_DIRECT_REQ2) { + uint32_t uuid_words[4] = { }; + + direct_req2_uuid_from_args(args, uuid_words); + if (!is_nil_uuid_words(uuid_words) && + !sp_has_ffa_uuid(dst, uuid_words)) { + ffa_set_error(args, FFA_INVALID_PARAMETERS); + return caller_sp; + } + } else if (args->a2 & FFA_MSG_FLAG_FRAMEWORK) { switch (args->a2 & FFA_MSG_TYPE_MASK) { case FFA_MSG_SEND_VM_CREATED: /* The sender must be the NWd hypervisor (ID 0) */ @@ -997,10 +1031,12 @@ ffa_handle_sp_direct_req(struct thread_smc_1_2_regs *args, cpu_spin_unlock(&dst->spinlock); /* - * Store the calling endpoint id. This will make it possible to check - * if the response is sent back to the correct endpoint. + * Store the calling endpoint ID and request function ID. This makes it + * possible to check that the response is sent back to the correct + * endpoint and uses the matching direct response ABI. */ dst->caller_id = FFA_SRC(args->a1); + dst->caller_fid = args->a0; /* Forward the message to the destination SP */ res = sp_enter(args, dst); @@ -1014,6 +1050,20 @@ ffa_handle_sp_direct_req(struct thread_smc_1_2_regs *args, return dst; } +static bool direct_resp_matches_req(uint32_t req_fid, uint32_t resp_fid) +{ + switch (resp_fid) { + case FFA_MSG_SEND_DIRECT_RESP_32: + return req_fid == FFA_MSG_SEND_DIRECT_REQ_32; + case FFA_MSG_SEND_DIRECT_RESP_64: + return req_fid == FFA_MSG_SEND_DIRECT_REQ_64; + case FFA_MSG_SEND_DIRECT_RESP2: + return req_fid == FFA_MSG_SEND_DIRECT_REQ2; + default: + return false; + } +} + static struct sp_session * ffa_handle_sp_direct_resp(struct thread_smc_1_2_regs *args, struct sp_session *caller_sp) @@ -1035,7 +1085,20 @@ ffa_handle_sp_direct_resp(struct thread_smc_1_2_regs *args, return caller_sp; } - if (args->a2 & FFA_MSG_FLAG_FRAMEWORK) { + if (args->a0 == FFA_MSG_SEND_DIRECT_RESP2) { + if (args->a2 || args->a3) { + ffa_set_error(args, FFA_INVALID_PARAMETERS); + return caller_sp; + } + if (!(caller_sp->props & FFA_PART_PROP_DIRECT_REQ2_RECV)) { + ffa_set_error(args, FFA_DENIED); + return caller_sp; + } + if (dst && !(dst->props & FFA_PART_PROP_DIRECT_REQ2_SEND)) { + ffa_set_error(args, FFA_DENIED); + return caller_sp; + } + } else if (args->a2 & FFA_MSG_FLAG_FRAMEWORK) { switch (args->a2 & FFA_MSG_TYPE_MASK) { case FFA_MSG_RESP_VM_CREATED: /* The destination must be the NWd hypervisor (ID 0) */ @@ -1090,7 +1153,14 @@ ffa_handle_sp_direct_resp(struct thread_smc_1_2_regs *args, return caller_sp; } + if (!direct_resp_matches_req(caller_sp->caller_fid, args->a0)) { + EMSG("Direct response type doesn't match direct request"); + ffa_set_error(args, FFA_INVALID_PARAMETERS); + return caller_sp; + } + caller_sp->caller_id = 0; + caller_sp->caller_fid = 0; cpu_spin_lock(&caller_sp->spinlock); caller_sp->state = sp_idle; @@ -1146,6 +1216,11 @@ static void handle_features(struct thread_smc_1_2_regs *args) ret_fid = FFA_SUCCESS_32; ret_w2 = 0; /* 4kB Minimum buffer size and alignment boundary */ break; + case FFA_MSG_SEND_DIRECT_REQ2: + case FFA_MSG_SEND_DIRECT_RESP2: + ret_fid = FFA_SUCCESS_32; + ret_w2 = FFA_PARAM_MBZ; + break; case FFA_ERROR: case FFA_VERSION: case FFA_SUCCESS_32: @@ -1341,12 +1416,14 @@ void spmc_sp_msg_handler(struct thread_smc_1_2_regs *args, case FFA_MSG_SEND_DIRECT_REQ_64: #endif case FFA_MSG_SEND_DIRECT_REQ_32: + case FFA_MSG_SEND_DIRECT_REQ2: caller_sp = ffa_handle_sp_direct_req(args, caller_sp); break; #ifdef ARM64 case FFA_MSG_SEND_DIRECT_RESP_64: #endif case FFA_MSG_SEND_DIRECT_RESP_32: + case FFA_MSG_SEND_DIRECT_RESP2: caller_sp = ffa_handle_sp_direct_resp(args, caller_sp); break; case FFA_ERROR: diff --git a/core/arch/arm/kernel/thread.c b/core/arch/arm/kernel/thread.c index e3751115003..1d8920a52e8 100644 --- a/core/arch/arm/kernel/thread.c +++ b/core/arch/arm/kernel/thread.c @@ -217,10 +217,7 @@ static void init_regs(struct thread_ctx *thread, uint32_t a0, uint32_t a1, } #endif /*ARM64*/ -static void __thread_alloc_and_run(uint32_t a0, uint32_t a1, uint32_t a2, - uint32_t a3, uint32_t a4, uint32_t a5, - uint32_t a6, uint32_t a7, - void *pc, uint32_t flags) +static struct thread_ctx *alloc_thread(uint32_t flags) { struct thread_core_local *l = thread_get_core_local(); bool found_thread = false; @@ -241,25 +238,39 @@ static void __thread_alloc_and_run(uint32_t a0, uint32_t a1, uint32_t a2, thread_unlock_global(); if (!found_thread) - return; + return NULL; l->curr_thread = n; - threads[n].flags = flags; - init_regs(threads + n, a0, a1, a2, a3, a4, a5, a6, a7, pc); + + return threads + n; +} + +static void __thread_alloc_and_run(uint32_t a0, uint32_t a1, uint32_t a2, + uint32_t a3, uint32_t a4, uint32_t a5, + uint32_t a6, uint32_t a7, + void *pc, uint32_t flags) +{ + struct thread_core_local *l = thread_get_core_local(); + struct thread_ctx *thread = alloc_thread(flags); + + if (!thread) + return; + + init_regs(thread, a0, a1, a2, a3, a4, a5, a6, a7, pc); #ifdef CFG_CORE_PAUTH /* * Copy the APIA key into the registers to be restored with * thread_resume(). */ - threads[n].regs.apiakey_hi = threads[n].keys.apia_hi; - threads[n].regs.apiakey_lo = threads[n].keys.apia_lo; + thread->regs.apiakey_hi = thread->keys.apia_hi; + thread->regs.apiakey_lo = thread->keys.apia_lo; #endif thread_lazy_save_ns_vfp(); l->flags &= ~THREAD_CLF_TMP; - thread_resume(&threads[n].regs); + thread_resume(&thread->regs); /*NOTREACHED*/ panic(); } @@ -272,11 +283,41 @@ void thread_alloc_and_run(uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, } #ifdef CFG_SECURE_PARTITION -void thread_sp_alloc_and_run(struct thread_smc_args *args __maybe_unused) +static void init_regs_spmc(struct thread_ctx *thread, + const struct thread_smc_1_2_regs *args, void *pc) { - __thread_alloc_and_run(args->a0, args->a1, args->a2, args->a3, args->a4, - args->a5, args->a6, args->a7, - spmc_sp_thread_entry, THREAD_FLAGS_FFA_ONLY); + size_t n = 0; + + thread->regs.pc = (vaddr_t)pc; + thread->regs.cpsr = SPSR_64(SPSR_64_MODE_EL1, SPSR_64_MODE_SP_EL0, + THREAD_EXCP_FOREIGN_INTR | DAIFBIT_ABT); + thread->regs.sp = thread->stack_va_end; + + for (n = 0; n < ARRAY_SIZE(args->a); n++) + thread->regs.x[n] = args->a[n]; + for (; n < ARRAY_SIZE(thread->regs.x); n++) + thread->regs.x[n] = 0; +} + +void thread_sp_alloc_and_run(struct thread_smc_1_2_regs *args) +{ + struct thread_core_local *l = thread_get_core_local(); + struct thread_ctx *thread = alloc_thread(THREAD_FLAGS_FFA_ONLY); + + if (!thread) + return; + + init_regs_spmc(thread, args, spmc_sp_thread_entry); +#ifdef CFG_CORE_PAUTH + thread->regs.apiakey_hi = thread->keys.apia_hi; + thread->regs.apiakey_lo = thread->keys.apia_lo; +#endif + + thread_lazy_save_ns_vfp(); + + l->flags &= ~THREAD_CLF_TMP; + thread_resume(&thread->regs); + panic(); } #endif diff --git a/core/arch/arm/kernel/thread_spmc.c b/core/arch/arm/kernel/thread_spmc.c index 21639756125..7ce5c0da64d 100644 --- a/core/arch/arm/kernel/thread_spmc.c +++ b/core/arch/arm/kernel/thread_spmc.c @@ -274,6 +274,15 @@ static void handle_features(struct thread_smc_1_2_regs *args) ret_fid = FFA_SUCCESS_32; ret_w2 = 0; /* 4kB Minimum buffer size and alignment boundary */ break; +#ifdef ARM64 + case FFA_MSG_SEND_DIRECT_REQ2: + case FFA_MSG_SEND_DIRECT_RESP2: + if (my_rxtx.ffa_vers >= FFA_VERSION_1_2) { + ret_fid = FFA_SUCCESS_32; + ret_w2 = FFA_PARAM_MBZ; + } + break; +#endif #ifdef ARM64 case FFA_MEM_SHARE_64: #endif @@ -548,12 +557,26 @@ TEE_Result spmc_fill_partition_entry(uint32_t ffa_vers, void *buf, size_t blen, fpi->partition_properties = part_props; - /* In FF-A 1.0 only bits [2:0] are defined, let's mask others */ + /* Mask out bits introduced with FF-A version 1.1 */ if (ffa_vers < FFA_VERSION_1_1) fpi->partition_properties &= FFA_PART_PROP_DIRECT_REQ_RECV | FFA_PART_PROP_DIRECT_REQ_SEND | FFA_PART_PROP_INDIRECT_MSGS; + /* Mask out bits introduced with FF-A version 1.2 */ + if (ffa_vers < FFA_VERSION_1_2) + fpi->partition_properties &= FFA_PART_PROP_DIRECT_REQ_RECV | + FFA_PART_PROP_DIRECT_REQ_SEND | + FFA_PART_PROP_INDIRECT_MSGS | + FFA_PART_PROP_RECV_NOTIF | + FFA_PART_PROP_IS_PE_ID | + FFA_PART_PROP_IS_SEPID_INDEP | + FFA_PART_PROP_IS_SEPID_DEP | + FFA_PART_PROP_IS_AUX_ID | + FFA_PART_PROP_NOTIF_CREATED | + FFA_PART_PROP_NOTIF_DESTROYED | + FFA_PART_PROP_AARCH64_STATE; + if (ffa_vers >= FFA_VERSION_1_1) { if (uuid_words) memcpy(fpi->uuid, uuid_words, FFA_UUID_SIZE); @@ -739,7 +762,11 @@ static uint32_t spmc_enable_async_notif(uint32_t bottom_half_value, static uint32_t get_direct_resp_fid(uint32_t fid) { assert(fid == FFA_MSG_SEND_DIRECT_REQ_64 || - fid == FFA_MSG_SEND_DIRECT_REQ_32); + fid == FFA_MSG_SEND_DIRECT_REQ_32 || + fid == FFA_MSG_SEND_DIRECT_REQ2); + + if (fid == FFA_MSG_SEND_DIRECT_REQ2) + return FFA_MSG_SEND_DIRECT_RESP2; if (OPTEE_SMC_IS_64(fid)) return FFA_MSG_SEND_DIRECT_RESP_64; @@ -905,6 +932,11 @@ optee_lsp_handle_direct_request(struct thread_smc_1_2_regs *args, return; } + if (args->a0 == FFA_MSG_SEND_DIRECT_REQ2) { + set_simple_ret_val(args, FFA_NOT_SUPPORTED); + return; + } + if (args->a2 & FFA_MSG_FLAG_FRAMEWORK) { handle_framework_direct_request(args); return; @@ -941,6 +973,11 @@ optee_spmc_lsp_handle_direct_request(struct thread_smc_1_2_regs *args, return; } + if (args->a0 == FFA_MSG_SEND_DIRECT_REQ2) { + set_simple_ret_val(args, FFA_NOT_SUPPORTED); + return; + } + if (args->a2 & FFA_MSG_FLAG_FRAMEWORK) handle_framework_direct_request(args); else @@ -1985,6 +2022,14 @@ void thread_spmc_msg_recv(struct thread_smc_1_2_regs *args) case FFA_MSG_SEND_DIRECT_REQ_32: handle_direct_request(args); break; +#ifdef ARM64 + case FFA_MSG_SEND_DIRECT_REQ2: + if (my_rxtx.ffa_vers < FFA_VERSION_1_2) + set_simple_ret_val(args, FFA_NOT_SUPPORTED); + else + handle_direct_request(args); + break; +#endif #if defined(CFG_CORE_SEL1_SPMC) #ifdef ARM64 case FFA_MEM_SHARE_64: