feat(notifications): information get interface
Handled FFA_NOTIFICATION_INFO_GET interface, to be used by a VM
(receiver's scheduler), Hypervisor or OS kernel.
Returns a list of IDs including Endpoints and vCPUs IDs that have
pending notifications. Provides support for multiple calls to the
FFA_NOTIFICATION_INFO_GET, in case there still are notifications whose
information needs to be retrieved after a call.
Change-Id: I4e73f18ee3301da4829313ffae247b6d0d262622
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/src/api.c b/src/api.c
index 542b461..7b615ce 100644
--- a/src/api.c
+++ b/src/api.c
@@ -2823,3 +2823,96 @@
return ret;
}
+
+/**
+ * Prepares successful return for FFA_NOTIFICATION_INFO_GET, as described by
+ * the section 17.7.1 of the FF-A v1.1 Beta0 specification.
+ */
+static struct ffa_value api_ffa_notification_info_get_success_return(
+ const uint16_t *ids, uint32_t ids_count, const uint32_t *lists_sizes,
+ uint32_t lists_count, bool list_is_full)
+{
+ struct ffa_value ret = (struct ffa_value){.func = FFA_SUCCESS_64};
+
+ /*
+ * Copying content of ids into ret structure. Use 5 registers (x3-x7) to
+ * hold the list of ids.
+ */
+ memcpy_s(&ret.arg3,
+ sizeof(ret.arg3) * FFA_NOTIFICATIONS_INFO_GET_REGS_RET, ids,
+ sizeof(ids[0]) * ids_count);
+
+ /*
+ * According to the spec x2 should have:
+ * - Bit flagging if there are more notifications pending;
+ * - The total number of elements (i.e. total list size);
+ * - The number of VCPU IDs within each VM specific list.
+ */
+ ret.arg2 =
+ list_is_full ? FFA_NOTIFICATIONS_INFO_GET_FLAG_MORE_PENDING : 0;
+
+ ret.arg2 |= (lists_count & FFA_NOTIFICATIONS_LISTS_COUNT_MASK)
+ << FFA_NOTIFICATIONS_LISTS_COUNT_SHIFT;
+
+ for (unsigned int i = 0; i < lists_count; i++) {
+ ret.arg2 |= (lists_sizes[i] & FFA_NOTIFICATIONS_LIST_SIZE_MASK)
+ << FFA_NOTIFICATIONS_LIST_SHIFT(i + 1);
+ }
+
+ return ret;
+}
+
+struct ffa_value api_ffa_notification_info_get(struct vcpu *current)
+{
+ /*
+ * Following set of variables should be populated with the return info.
+ * At a successfull handling of this interface, they should be used
+ * to populate the 'ret' structure in accordance to the table 17.29
+ * of the FF-A v1.1 Beta0 specification.
+ */
+ uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS];
+ uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+ uint32_t lists_count = 0;
+ uint32_t ids_count = 0;
+ bool list_is_full = false;
+
+ /*
+ * This interface can only be called at NS virtual/physical FF-A
+ * instance by the endpoint implementing the primary scheduler and the
+ * Hypervisor/OS kernel.
+ * In the SPM, following check passes if call has been forwarded from
+ * the hypervisor.
+ */
+ if (current->vm->id != HF_PRIMARY_VM_ID) {
+ dlog_verbose(
+ "Only the receiver's scheduler can use this "
+ "interface\n");
+ return ffa_error(FFA_NOT_SUPPORTED);
+ }
+
+ /* Get notifications' info from this world */
+ for (ffa_vm_count_t index = 0; index < vm_get_count() && !list_is_full;
+ ++index) {
+ struct vm_locked vm_locked = vm_lock(vm_find_index(index));
+
+ list_is_full = vm_notifications_info_get(
+ vm_locked, ids, &ids_count, lists_sizes, &lists_count,
+ FFA_NOTIFICATIONS_INFO_GET_MAX_IDS);
+
+ vm_unlock(&vm_locked);
+ }
+
+ if (!list_is_full) {
+ /* Grab notifications info from other world */
+ list_is_full = plat_ffa_vm_notifications_info_get(
+ ids, &ids_count, lists_sizes, &lists_count,
+ FFA_NOTIFICATIONS_INFO_GET_MAX_IDS);
+ }
+
+ if (ids_count == 0) {
+ return ffa_error(FFA_NO_DATA);
+ }
+
+ return api_ffa_notification_info_get_success_return(
+ ids, ids_count, lists_sizes, lists_count, list_is_full);
+}