lib: arm_ffa: Support FF-A version 1.1 Update the use of ffa_mtd to support the new layout in v1.1. Bug: 284057071 Change-Id: I2fcd34b810c85b5e586a2fd159faa2d8a2a9c396
diff --git a/lib/arm_ffa/arm_ffa.c b/lib/arm_ffa/arm_ffa.c index e5d56ef..cac3053 100644 --- a/lib/arm_ffa/arm_ffa.c +++ b/lib/arm_ffa/arm_ffa.c
@@ -39,6 +39,7 @@ #include <trace.h> static enum arm_ffa_init_state ffa_init_state = ARM_FFA_INIT_UNINIT; +static uint32_t ffa_version; static uint16_t ffa_local_id; static size_t ffa_buf_size; static void* ffa_tx; @@ -151,18 +152,24 @@ /* * Call with ffa_rxtx_buffer_lock acquired and the ffa_tx buffer already - * populated with struct ffa_mtd. Transmit in a single fragment. + * populated with struct ffa_mtd_common. Transmit in a single fragment. */ static status_t arm_ffa_call_mem_retrieve_req(uint32_t* total_len, uint32_t* fragment_len) { struct smc_ret8 smc_ret; - struct ffa_mtd* req = ffa_tx; + struct ffa_mtd_v1_0* req_v1_0 = ffa_tx; + struct ffa_mtd_v1_1* req_v1_1 = ffa_tx; size_t len; DEBUG_ASSERT(is_mutex_held(&ffa_rxtx_buffer_lock)); - len = offsetof(struct ffa_mtd, emad[0]) + - req->emad_count * sizeof(struct ffa_emad); + if (ffa_version < FFA_VERSION(1, 1)) { + len = offsetof(struct ffa_mtd_v1_0, emad[0]) + + req_v1_0->emad_count * sizeof(struct ffa_emad); + } else { + len = req_v1_1->emad_offset + + req_v1_1->emad_count * req_v1_1->emad_size; + } smc_ret = smc8(SMC_FC_FFA_MEM_RETRIEVE_REQ, len, len, 0, 0, 0, 0, 0); @@ -584,23 +591,39 @@ static void arm_ffa_populate_receive_req_tx_buffer(uint16_t sender_id, uint64_t handle, uint64_t tag) { - struct ffa_mtd* req = ffa_tx; + struct ffa_mtd_v1_0* req_v1_0 = ffa_tx; + struct ffa_mtd_v1_1* req_v1_1 = ffa_tx; + struct ffa_mtd_common* req = ffa_tx; + struct ffa_emad* emad; DEBUG_ASSERT(is_mutex_held(&ffa_rxtx_buffer_lock)); - memset(req, 0, sizeof(struct ffa_mtd)); + if (ffa_version < FFA_VERSION(1, 1)) { + memset(req_v1_0, 0, sizeof(struct ffa_mtd_v1_0)); + } else { + memset(req_v1_1, 0, sizeof(struct ffa_mtd_v1_1)); + } req->sender_id = sender_id; req->handle = handle; /* We must use the same tag as the one used by the sender to retrieve. */ req->tag = tag; - /* - * We only support retrieving memory for ourselves for now. - * TODO: Also support stream endpoints. Possibly more than one. - */ - req->emad_count = 1; - memset(req->emad, 0, sizeof(struct ffa_emad)); - req->emad[0].mapd.endpoint_id = ffa_local_id; + if (ffa_version < FFA_VERSION(1, 1)) { + /* + * We only support retrieving memory for ourselves for now. + * TODO: Also support stream endpoints. Possibly more than one. + */ + req_v1_0->emad_count = 1; + emad = req_v1_0->emad; + } else { + req_v1_1->emad_count = 1; + req_v1_1->emad_size = sizeof(struct ffa_emad); + req_v1_1->emad_offset = sizeof(struct ffa_mtd_v1_1); + emad = (struct ffa_emad*)((uint8_t*)req_v1_1 + req_v1_1->emad_offset); + } + + memset(emad, 0, sizeof(struct ffa_emad)); + emad[0].mapd.endpoint_id = ffa_local_id; } /* *desc_buffer is malloc'd and on success passes responsibility to free to @@ -686,7 +709,9 @@ uint* arch_mmu_flags, struct arm_ffa_mem_frag_info* frag_info) { status_t res; - struct ffa_mtd* mtd; + struct ffa_mtd_v1_0* mtd_v1_0; + struct ffa_mtd_v1_1* mtd_v1_1; + struct ffa_mtd_common* mtd; struct ffa_emad* emad; struct ffa_comp_mrd* comp_mrd; uint32_t computed_len; @@ -706,22 +731,63 @@ return res; } - if (fragment_len < - offsetof(struct ffa_mtd, emad) + sizeof(struct ffa_emad)) { - TRACEF("Fragment too short for memory transaction descriptor\n"); - return ERR_IO; - } - mtd = ffa_rx; - emad = mtd->emad; + if (ffa_version < FFA_VERSION(1, 1)) { + if (fragment_len < sizeof(struct ffa_mtd_v1_0)) { + TRACEF("Fragment too short for memory transaction descriptor\n"); + return ERR_IO; + } - /* - * We don't retrieve the memory on behalf of anyone else, so we only - * expect one receiver address range descriptor. - */ - if (mtd->emad_count != 1) { - TRACEF("unexpected response count %d != 1\n", mtd->emad_count); - return ERR_IO; + mtd_v1_0 = ffa_rx; + if (fragment_len < + offsetof(struct ffa_mtd_v1_0, emad) + sizeof(struct ffa_emad)) { + TRACEF("Fragment too short for endpoint memory access descriptor\n"); + return ERR_IO; + } + emad = mtd_v1_0->emad; + + /* + * We don't retrieve the memory on behalf of anyone else, so we only + * expect one receiver address range descriptor. + */ + if (mtd_v1_0->emad_count != 1) { + TRACEF("unexpected response count %d != 1\n", mtd_v1_0->emad_count); + return ERR_IO; + } + } else { + if (fragment_len < sizeof(struct ffa_mtd_v1_1)) { + TRACEF("Fragment too short for memory transaction descriptor\n"); + return ERR_IO; + } + + mtd_v1_1 = ffa_rx; + /* + * We know from the check above that + * fragment_len >= sizeof(ffa_mtd_v1) >= sizeof(ffa_emad) + * so we can rewrite the following + * fragment_len < emad_offset + sizeof(ffa_emad) + * into + * fragment_len - sizeof(ffa_emad) < emad_offset + * to avoid a potential overflow. + */ + if (fragment_len - sizeof(struct ffa_emad) < mtd_v1_1->emad_offset) { + TRACEF("Fragment too short for endpoint memory access descriptor\n"); + return ERR_IO; + } + if (mtd_v1_1->emad_offset < sizeof(struct ffa_mtd_v1_1)) { + TRACEF("Endpoint memory access descriptor offset too short\n"); + return ERR_IO; + } + if (!IS_ALIGNED(mtd_v1_1->emad_offset, 16)) { + TRACEF("Endpoint memory access descriptor not aligned to 16 bytes\n"); + return ERR_IO; + } + emad = (struct ffa_emad*)((uint8_t*)mtd_v1_1 + mtd_v1_1->emad_offset); + + if (mtd_v1_1->emad_count != 1) { + TRACEF("unexpected response count %d != 1\n", mtd_v1_1->emad_count); + return ERR_IO; + } } LTRACEF("comp_mrd_offset: %u\n", emad->comp_mrd_offset); @@ -917,14 +983,17 @@ if (res != NO_ERROR) { TRACEF("No compatible FF-A version found\n"); return res; - } else if (FFA_CURRENT_VERSION_MAJOR != ver_major_ret || - FFA_CURRENT_VERSION_MINOR > ver_minor_ret) { - /* When trusty supports more FF-A versions downgrade may be possible */ + } else if (FFA_CURRENT_VERSION_MAJOR != ver_major_ret) { + /* Allow downgrade within the same major version */ TRACEF("Incompatible FF-A interface version, %" PRIu16 ".%" PRIu16 "\n", ver_major_ret, ver_minor_ret); return ERR_NOT_SUPPORTED; } + ffa_version = FFA_VERSION(ver_major_ret, ver_minor_ret); + LTRACEF("Negotiated FF-A version %" PRIu16 ".%" PRIu16 "\n", ver_major_ret, + ver_minor_ret); + res = arm_ffa_call_id_get(&ffa_local_id); if (res != NO_ERROR) { TRACEF("Failed to get FF-A partition id (err=%d)\n", res);