Snap for 13259233 from ecdcdc9e2f91729ac9dd7ed70e0ae9a389507778 to 25Q2-release Change-Id: I8a2f090f8d088c024a1df5f7312e1ab0d8b59954
diff --git a/lib/arm_ffa/arm_ffa.c b/lib/arm_ffa/arm_ffa.c index dd38f84..704ea79 100644 --- a/lib/arm_ffa/arm_ffa.c +++ b/lib/arm_ffa/arm_ffa.c
@@ -353,6 +353,68 @@ } } +static status_t arm_ffa_call_mem_share(size_t num_comp_mrd, + size_t num_cons_mrd, + uint32_t* total_len, + uint32_t* fragment_len, + uint64_t* handle) { + struct smc_ret8 smc_ret; + struct ffa_mtd_v1_0* req_v1_0 = ffa_tx; + struct ffa_mtd_v1_1* req_v1_1 = ffa_tx; + size_t len; + int32_t error; + + DEBUG_ASSERT(is_mutex_held(&ffa_rxtx_buffer_lock)); + + 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)) + + (num_comp_mrd * sizeof(struct ffa_comp_mrd)) + + (num_cons_mrd * sizeof(struct ffa_cons_mrd)); + } else { + len = req_v1_1->emad_offset + + (req_v1_1->emad_count * req_v1_1->emad_size) + + (num_comp_mrd * sizeof(struct ffa_comp_mrd)) + + (num_cons_mrd * sizeof(struct ffa_cons_mrd)); + } + + /* w3 and w4 MBZ since tx buffer is used, the rest SBZ */ + smc_ret = smc8(SMC_FC64_FFA_MEM_SHARE, len, len, 0, 0, 0, 0, 0); + switch ((uint32_t)smc_ret.r0) { + case SMC_FC_FFA_SUCCESS: + if (total_len) { + *total_len = (uint32_t)smc_ret.r1; + } + if (fragment_len) { + *fragment_len = (uint32_t)smc_ret.r2; + } + if (handle) { + *handle = (uint32_t)smc_ret.r2; + *handle |= ((uint64_t)smc_ret.r3) << 32; + } + return NO_ERROR; + case SMC_FC_FFA_ERROR: + error = (int32_t)smc_ret.r2; + switch (error) { + case FFA_ERROR_INVALID_PARAMETERS: + return ERR_NOT_SUPPORTED; + case FFA_ERROR_DENIED: + return ERR_BAD_STATE; + case FFA_ERROR_NO_MEMORY: + return ERR_NO_MEMORY; + case FFA_ERROR_BUSY: + return ERR_BUSY; + case FFA_ERROR_ABORTED: + return ERR_CANCELLED; + default: + TRACEF("Unexpected error: 0x%x\n", error); + return ERR_NOT_VALID; + } + default: + return ERR_NOT_VALID; + } +} + static status_t arm_ffa_call_mem_relinquish( uint64_t handle, uint32_t flags, @@ -821,6 +883,88 @@ emad[0].mapd.endpoint_id = ffa_local_id; } +static void arm_ffa_populate_share_tx_buffer(uint16_t receiver_id, + paddr_t buffer, + size_t num_ffa_pages, + uint arch_mmu_flags, + uint64_t tag) { + 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; + ffa_mem_attr8_t attributes = 0; + ffa_mem_perm8_t permissions = 0; + uint32_t comp_mrd_offset = 0; + struct ffa_comp_mrd* comp_mrd; + + DEBUG_ASSERT(is_mutex_held(&ffa_rxtx_buffer_lock)); + + 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 = ffa_local_id; + + switch (arch_mmu_flags & ARCH_MMU_FLAG_CACHE_MASK) { + case ARCH_MMU_FLAG_UNCACHED_DEVICE: + attributes |= FFA_MEM_ATTR_DEVICE_NGNRE; + break; + case ARCH_MMU_FLAG_UNCACHED: + attributes |= FFA_MEM_ATTR_NORMAL_MEMORY_UNCACHED; + break; + case ARCH_MMU_FLAG_CACHED: + attributes |= FFA_MEM_ATTR_NORMAL_MEMORY_CACHED_WB | + FFA_MEM_ATTR_INNER_SHAREABLE; + break; + } + + req->memory_region_attributes = attributes; + req->flags = FFA_MTD_FLAG_TYPE_SHARE_MEMORY; + /* We must use the same tag as the one used by the receiver to share . */ + req->tag = tag; + /* MBZ for MEM_SHARE */ + req->handle = 0; + + 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 = receiver_id; + permissions = FFA_MEM_PERM_NX; + if (arch_mmu_flags & ARCH_MMU_FLAG_PERM_RO) { + permissions |= FFA_MEM_PERM_RO; + } else { + permissions |= FFA_MEM_PERM_RW; + } + emad[0].mapd.memory_access_permissions = permissions; + if (ffa_version < FFA_VERSION(1, 1)) { + /* We only support one emad */ + comp_mrd_offset = sizeof(struct ffa_mtd_v1_0) + sizeof(struct ffa_emad); + } else { + comp_mrd_offset = sizeof(struct ffa_mtd_v1_1) + sizeof(struct ffa_emad); + } + emad[0].comp_mrd_offset = comp_mrd_offset; + + comp_mrd = (struct ffa_comp_mrd*)((uint8_t*)emad + sizeof(struct ffa_emad)); + comp_mrd->total_page_count = num_ffa_pages; + comp_mrd->address_range_count = 1; + comp_mrd->address_range_array[0].address = buffer; + comp_mrd->address_range_array[0].page_count = num_ffa_pages; +} + /* *desc_buffer is malloc'd and on success passes responsibility to free to the caller. Populate the tx buffer before calling. */ static status_t arm_ffa_mem_retrieve(uint16_t sender_id, @@ -1123,6 +1267,73 @@ return NO_ERROR; } +status_t arm_ffa_mem_share_kernel_buffer(uint16_t receiver_id, + paddr_t buffer, + size_t num_ffa_pages, + uint arch_mmu_flags, + uint64_t* handle) { + status_t res; + uint32_t len_out, fragment_len_out; + + DEBUG_ASSERT(handle); + + if (buffer % FFA_PAGE_SIZE) { + LTRACEF("Buffer address must be page-aligned\n"); + return ERR_INVALID_ARGS; + } + if (!(arch_mmu_flags & ARCH_MMU_FLAG_PERM_NO_EXECUTE)) { + LTRACEF("Only non-executable buffers may be shared over FFA\n"); + return ERR_INVALID_ARGS; + } + + mutex_acquire(&ffa_rxtx_buffer_lock); + + /* Populate the tx buffer with 1 composite mrd and 1 constituent mrd */ + arm_ffa_populate_share_tx_buffer(receiver_id, buffer, num_ffa_pages, + arch_mmu_flags, 0); + res = arm_ffa_call_mem_share(1, 1, &len_out, &fragment_len_out, handle); + LTRACEF("total_len: %u, fragment_len: %u, handle: %" PRIx64 "\n", len_out, + fragment_len_out, *handle); + if (res != NO_ERROR) { + TRACEF("FF-A memory share failed, err= %d\n", res); + } + + mutex_release(&ffa_rxtx_buffer_lock); + return res; +} + +status_t arm_ffa_mem_reclaim(uint64_t handle) { + struct smc_ret8 smc_ret; + uint32_t handle_lo = (uint32_t)handle; + uint32_t handle_hi = (uint32_t)(handle >> 32); + uint32_t flags = 0; + + smc_ret = smc8(SMC_FC_FFA_MEM_RECLAIM, handle_lo, handle_hi, flags, 0, 0, 0, + 0); + + switch ((uint32_t)smc_ret.r0) { + case SMC_FC_FFA_SUCCESS: + return NO_ERROR; + case SMC_FC_FFA_ERROR: + switch ((int32_t)smc_ret.r2) { + case FFA_ERROR_INVALID_PARAMETERS: + return ERR_INVALID_ARGS; + case FFA_ERROR_NO_MEMORY: + return ERR_NO_MEMORY; + case FFA_ERROR_DENIED: + return ERR_BAD_STATE; + case FFA_ERROR_ABORTED: + return ERR_CANCELLED; + default: + TRACEF("Unexpected FFA_ERROR: %lx\n", smc_ret.r2); + return ERR_NOT_VALID; + } + default: + TRACEF("Unexpected FFA SMC: %lx\n", smc_ret.r0); + return ERR_NOT_VALID; + } +} + status_t arm_ffa_rx_release(void) { status_t res; ASSERT(is_mutex_held(&ffa_rxtx_buffer_lock));
diff --git a/lib/arm_ffa/include/lib/arm_ffa/arm_ffa.h b/lib/arm_ffa/include/lib/arm_ffa/arm_ffa.h index 9f16363..e647b1b 100644 --- a/lib/arm_ffa/include/lib/arm_ffa/arm_ffa.h +++ b/lib/arm_ffa/include/lib/arm_ffa/arm_ffa.h
@@ -133,6 +133,41 @@ status_t arm_ffa_mem_retrieve_next_frag( uint64_t handle, struct arm_ffa_mem_frag_info* frag_info); + +/** + * arm_ffa_mem_share_kernel_buffer() - Share kernel buffer over FFA. + * + * @receiver_id: Id of the memory receiver. + * @buffer: The start of the buffer. The address must be aligned to + * FFA_PAGE_SIZE. + * @num_ffa_pages: Number of pages in the buffer. This uses FFA_PAGE_SIZE which + * may differ from Trusty's page size. + * @arch_mmu_flags: MMU flags used when allocating the buffer. Buffers must have + * the NO_EXECUTE bit. + * @handle: [out] The handle identifying the memory region in the + * transaction. + * + * Grabs and releases the RXTX buffer lock. + * + * Return: 0 on success, LK error code on failure. + */ +status_t arm_ffa_mem_share_kernel_buffer(uint16_t receiver_id, + paddr_t buffer, + size_t num_ffa_pages, + uint arch_mmu_flags, + uint64_t* handle); + +/** + * arm_ffa_mem_reclaim() - Reclaim memory shared over FFA. + * + * @handle: The handle identifying the previously shared memory region. This + * must have been the result of a call to + * arm_ffa_mem_share_kernel_buffer(). + * + * Return: 0 on success, LK error code on failure. + */ +status_t arm_ffa_mem_reclaim(uint64_t handle); + /** * arm_ffa_rx_release() - Relinquish ownership of the RX buffer. *