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.
  *