feat(notifications): forward notification info get to SPMC
The hypervisor forward FFA_NOTIFICATION_INFO_GET to the SPMC, to
retrieve the pending notifications info from SWd. It includes
notifications to SPs, and notifications from SPs to VMs.
Change-Id: I46549cc5ef7eb49addace546946222792d2be25b
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/src/api.c b/src/api.c
index 8feb745..cb27a58 100644
--- a/src/api.c
+++ b/src/api.c
@@ -2972,6 +2972,16 @@
return ffa_error(FFA_NOT_SUPPORTED);
}
+ /*
+ * Forward call to the other world, and fill the arrays used to assemble
+ * return.
+ */
+ plat_ffa_notification_info_get_forward(
+ ids, &ids_count, lists_sizes, &lists_count,
+ FFA_NOTIFICATIONS_INFO_GET_MAX_IDS);
+
+ list_is_full = ids_count == FFA_NOTIFICATIONS_INFO_GET_MAX_IDS;
+
/* Get notifications' info from this world */
for (ffa_vm_count_t index = 0; index < vm_get_count() && !list_is_full;
++index) {
@@ -2992,6 +3002,8 @@
}
if (ids_count == 0) {
+ dlog_verbose(
+ "Notification info get has no data to retrieve.\n");
return ffa_error(FFA_NO_DATA);
}
diff --git a/src/arch/aarch64/plat/ffa/absent.c b/src/arch/aarch64/plat/ffa/absent.c
index 4eecac1..baeee11 100644
--- a/src/arch/aarch64/plat/ffa/absent.c
+++ b/src/arch/aarch64/plat/ffa/absent.c
@@ -272,3 +272,16 @@
return ffa_error(FFA_NOT_SUPPORTED);
}
+
+void plat_ffa_notification_info_get_forward(const uint16_t *ids,
+ const uint32_t *ids_count,
+ const uint32_t *lists_sizes,
+ const uint32_t *lists_count,
+ const uint32_t ids_count_max)
+{
+ (void)ids;
+ (void)ids_count;
+ (void)lists_sizes;
+ (void)lists_count;
+ (void)ids_count_max;
+}
diff --git a/src/arch/aarch64/plat/ffa/hypervisor.c b/src/arch/aarch64/plat/ffa/hypervisor.c
index 8a38579..dbc061b 100644
--- a/src/arch/aarch64/plat/ffa/hypervisor.c
+++ b/src/arch/aarch64/plat/ffa/hypervisor.c
@@ -13,6 +13,7 @@
#include "hf/dlog.h"
#include "hf/ffa.h"
#include "hf/ffa_internal.h"
+#include "hf/std.h"
#include "hf/vcpu.h"
#include "hf/vm.h"
@@ -354,6 +355,78 @@
return vm_id_is_current_world(vm_id);
}
+void plat_ffa_notification_info_get_forward(uint16_t *ids, uint32_t *ids_count,
+ uint32_t *lists_sizes,
+ uint32_t *lists_count,
+ const uint32_t ids_count_max)
+{
+ CHECK(ids != NULL);
+ CHECK(ids_count != NULL);
+ CHECK(lists_sizes != NULL);
+ CHECK(lists_count != NULL);
+ CHECK(ids_count_max == FFA_NOTIFICATIONS_INFO_GET_MAX_IDS);
+
+ uint32_t local_lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS];
+ struct ffa_value ret;
+
+ dlog_verbose("Forwarding notification info get to SPMC.\n");
+
+ ret = arch_other_world_call((struct ffa_value){
+ .func = FFA_NOTIFICATION_INFO_GET_64,
+ });
+
+ if (ret.func == FFA_ERROR_32) {
+ dlog_verbose("No notifications returned by SPMC.\n");
+ return;
+ }
+
+ *lists_count = ffa_notification_info_get_lists_count(ret);
+
+ if (*lists_count > ids_count_max) {
+ *lists_count = 0;
+ return;
+ }
+
+ /*
+ * The count of ids should be at least the number of lists, to encompass
+ * for at least the ids of the FF-A endpoints.
+ * List sizes will be between 0 and 3, and relates to the counting of
+ * vCPU of the endpoint that have pending notifications.
+ * If `lists_count` is already ids_count_max, each list size must be 0.
+ */
+ *ids_count = *lists_count;
+
+ for (uint32_t i = 0; i < *lists_count; i++) {
+ local_lists_sizes[i] =
+ ffa_notification_info_get_list_size(ret, i + 1);
+
+ /*
+ * ... sum the counting of each list size that are part of the
+ * main list.
+ */
+ *ids_count += local_lists_sizes[i];
+ }
+
+ /*
+ * Sanity check returned `lists_count` and determined `ids_count`.
+ * If something wrong, reset arguments to 0 such that hypervisor's
+ * handling of FFA_NOTIFICATION_INFO_GET can proceed without SPMC's
+ * values.
+ */
+ if (*ids_count > ids_count_max) {
+ *ids_count = 0;
+ return;
+ }
+
+ /* Copy now lists sizes, as return sizes have been validated. */
+ memcpy_s(lists_sizes, sizeof(lists_sizes[0]) * ids_count_max,
+ local_lists_sizes, FFA_NOTIFICATIONS_INFO_GET_MAX_IDS);
+
+ /* Unpack the notifications info from the return. */
+ memcpy_s(ids, sizeof(ids[0]) * ids_count_max, &ret.arg3,
+ sizeof(ret.arg3) * FFA_NOTIFICATIONS_INFO_GET_REGS_RET);
+}
+
bool plat_ffa_notifications_get_from_sp(struct vm_locked receiver_locked,
ffa_vcpu_index_t vcpu_id,
ffa_notifications_bitmap_t *from_sp,
diff --git a/src/arch/aarch64/plat/ffa/spmc.c b/src/arch/aarch64/plat/ffa/spmc.c
index b48b7c5..23cc039 100644
--- a/src/arch/aarch64/plat/ffa/spmc.c
+++ b/src/arch/aarch64/plat/ffa/spmc.c
@@ -267,6 +267,18 @@
!vm_id_is_current_world(receiver_id));
}
+void plat_ffa_notification_info_get_forward( // NOLINTNEXTLINE
+ uint16_t *ids, uint32_t *ids_count, // NOLINTNEXTLINE
+ uint32_t *lists_sizes, uint32_t *lists_count,
+ const uint32_t ids_count_max)
+{
+ (void)ids;
+ (void)ids_count;
+ (void)lists_sizes;
+ (void)lists_count;
+ (void)ids_count_max;
+}
+
ffa_memory_handle_t plat_ffa_memory_handle_make(uint64_t index)
{
return (index & ~FFA_MEMORY_HANDLE_ALLOCATOR_MASK) |
diff --git a/src/arch/fake/hypervisor/ffa.c b/src/arch/fake/hypervisor/ffa.c
index 1f6b587..8736afa 100644
--- a/src/arch/fake/hypervisor/ffa.c
+++ b/src/arch/fake/hypervisor/ffa.c
@@ -244,3 +244,15 @@
return true;
}
+
+void plat_ffa_notification_info_get_forward( // NOLINTNEXTLINE
+ uint16_t *ids, uint32_t *ids_count, // NOLINTNEXTLINE
+ uint32_t *lists_sizes, uint32_t *lists_count,
+ const uint32_t ids_count_max)
+{
+ (void)ids;
+ (void)ids_count;
+ (void)lists_sizes;
+ (void)lists_count;
+ (void)ids_count_max;
+}