feat(notifications): state structures and initialization

Defined the structures to keep track of Notifications state within
hafnium:
- 'struct notifications' keeps track of notification bindings, and
respective states (referring to 'struct notifications_state').
- 'struct notifications_state' keeps track of pending notifications and
those retrieved by the scheduler using FFA_NOTIFICATIONS_INFO_GET.
- Initialization of notifications structure, to allow for the
implementation of the notifications related FF-A calls.

The SPMC is responsible for maintaining the state of VM's notifications
from SPs. Reused 'struct vm' to represent NWd VMs, for simplicity and
scalability.

Change-Id: Id222aa0f6a11a29009668cfbae4edc067afd9130
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/inc/hf/arch/plat/ffa.h b/inc/hf/arch/plat/ffa.h
index 0d8813e..fde3bba 100644
--- a/inc/hf/arch/plat/ffa.h
+++ b/inc/hf/arch/plat/ffa.h
@@ -48,3 +48,8 @@
  */
 ffa_partition_properties_t plat_ffa_partition_properties(
 	ffa_vm_id_t current_id, const struct vm *target);
+
+/**
+ * Initializes the NWd VM structures for Notifications support.
+ */
+void plat_ffa_vm_init(void);
diff --git a/inc/hf/vm.h b/inc/hf/vm.h
index 1eccd91..f7a73da 100644
--- a/inc/hf/vm.h
+++ b/inc/hf/vm.h
@@ -92,6 +92,37 @@
 	struct list_entry ready_list;
 };
 
+struct notifications_state {
+	/**
+	 * To keep track of the notifications pending.
+	 * Set on call to FFA_NOTIFICATION_SET, and cleared on call to
+	 * FFA_NOTIFICATION_GET.
+	 */
+	ffa_notifications_bitmap_t pending;
+
+	/**
+	 * Set on FFA_NOTIFICATION_INFO_GET to keep track of the notifications
+	 * whose information has been retrieved by the referred ABI.
+	 * Cleared on call to FFA_NOTIFICATION_GET.
+	 */
+	ffa_notifications_bitmap_t info_get_retrieved;
+};
+
+struct notifications {
+	/**
+	 * The following array maps the notifications to the bound FF-A
+	 * endpoint.
+	 * The index in the bindings array relates to the notification
+	 * ID, and bit position in 'ffa_notifications_bitmap_t'.
+	 */
+	ffa_vm_id_t bindings_sender_id[MAX_FFA_NOTIFICATIONS];
+	ffa_notifications_bitmap_t bindings_per_vcpu;
+
+	/* The index of the array below relates to the ID of the VCPU. */
+	struct notifications_state per_vcpu[MAX_CPUS];
+	struct notifications_state global;
+};
+
 struct smc_whitelist {
 	uint32_t smcs[MAX_SMCS];
 	uint16_t smc_count;
@@ -109,6 +140,20 @@
 	struct vcpu vcpus[MAX_CPUS];
 	struct mm_ptable ptable;
 	struct mailbox mailbox;
+
+	struct {
+		/**
+		 * State structures for notifications coming from VMs or coming
+		 * from SPs. Both fields are maintained by the SPMC.
+		 * The hypervisor ignores the 'from_sp' field, given VM
+		 * notifications from SPs are managed by the SPMC.
+		 */
+		struct notifications from_vm;
+		struct notifications from_sp;
+		/* TODO: include framework notifications */
+		bool enabled;
+	} notifications;
+
 	char log_buffer[LOG_BUFFER_SIZE];
 	uint16_t log_buffer_length;
 
@@ -178,3 +223,5 @@
 
 void vm_update_boot(struct vm *vm);
 struct vm *vm_get_first_boot(void);
+
+void vm_notifications_init_bindings(struct notifications *n);
diff --git a/src/arch/aarch64/hypervisor/arch_init.c b/src/arch/aarch64/hypervisor/arch_init.c
index 1d38cca..c2dedbf 100644
--- a/src/arch/aarch64/hypervisor/arch_init.c
+++ b/src/arch/aarch64/hypervisor/arch_init.c
@@ -6,7 +6,6 @@
  * https://opensource.org/licenses/BSD-3-Clause.
  */
 
-#include "hf/arch/ffa.h"
 #include "hf/arch/plat/psci.h"
 
 /**
diff --git a/src/arch/aarch64/plat/ffa/absent.c b/src/arch/aarch64/plat/ffa/absent.c
index 979780c..23f1f64 100644
--- a/src/arch/aarch64/plat/ffa/absent.c
+++ b/src/arch/aarch64/plat/ffa/absent.c
@@ -84,3 +84,7 @@
 
 	return false;
 }
+
+void plat_ffa_vm_init(void)
+{
+}
diff --git a/src/arch/aarch64/plat/ffa/hypervisor.c b/src/arch/aarch64/plat/ffa/hypervisor.c
index dc786ae..3e50294 100644
--- a/src/arch/aarch64/plat/ffa/hypervisor.c
+++ b/src/arch/aarch64/plat/ffa/hypervisor.c
@@ -184,3 +184,7 @@
 
 	return false;
 }
+
+void plat_ffa_vm_init(void)
+{
+}
diff --git a/src/arch/aarch64/plat/ffa/spmc.c b/src/arch/aarch64/plat/ffa/spmc.c
index 94aef77..8efae8f 100644
--- a/src/arch/aarch64/plat/ffa/spmc.c
+++ b/src/arch/aarch64/plat/ffa/spmc.c
@@ -11,6 +11,7 @@
 
 #include "hf/dlog.h"
 #include "hf/ffa.h"
+#include "hf/std.h"
 #include "hf/vm.h"
 
 #include "smc.h"
@@ -18,6 +19,17 @@
 /** Other world SVE context (accessed from other_world_loop). */
 struct sve_context_t sve_context[MAX_CPUS];
 
+/**
+ * The SPMC needs to keep track of some information about NWd VMs.
+ * For the time being, only the notifications state structures.
+ * Allocation and deallocation of a slot in 'nwd_vms' to and from a given VM
+ * will happen upon calls to FFA_NOTIFICATION_BITMAP_CREATE and
+ * FFA_NOTIFICATION_BITMAP_DESTROY.
+ */
+static struct vm nwd_vms[MAX_VMS];
+
+const uint32_t nwd_vms_size = ARRAY_SIZE(nwd_vms);
+
 void plat_ffa_log_init(void)
 {
 	dlog_info("Initializing Hafnium (SPMC)\n");
@@ -32,11 +44,26 @@
 	return smc_ffa_call((struct ffa_value){.func = FFA_ID_GET_32});
 }
 
+static void plat_ffa_vm_init(void)
+{
+	/* Init NWd VMs structures for use of Notifications interfaces. */
+	for (uint32_t i = 0; i < nwd_vms_size; i++) {
+		/*
+		 * A slot in 'nwd_vms' is considered available if its id
+		 * is HF_INVALID_VM_ID.
+		 */
+		nwd_vms[i].id = HF_INVALID_VM_ID;
+		vm_notifications_init_bindings(
+			&nwd_vms[i].notifications.from_sp);
+	}
+}
+
 void plat_ffa_init(bool tee_enabled)
 {
 	(void)tee_enabled;
 
 	arch_ffa_init();
+	plat_ffa_vm_init();
 }
 
 /**
diff --git a/src/vm.c b/src/vm.c
index 1c67166..e321121 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -11,6 +11,7 @@
 #include "hf/api.h"
 #include "hf/check.h"
 #include "hf/cpu.h"
+#include "hf/dlog.h"
 #include "hf/ffa.h"
 #include "hf/layout.h"
 #include "hf/plat/iommu.h"
@@ -77,6 +78,13 @@
 		vcpu_init(vm_get_vcpu(vm, i), vm);
 	}
 
+	/* Basic initialization of the notifications structure. */
+	vm_notifications_init_bindings(&vm->notifications.from_sp);
+	vm_notifications_init_bindings(&vm->notifications.from_vm);
+
+	/* TODO: Enable in accordance to VM's manifest. */
+	vm->notifications.enabled = true;
+
 	return vm;
 }
 
@@ -361,3 +369,13 @@
 
 	vm->next_boot = current;
 }
+
+/*
+ * Initializes the notifications structure.
+ */
+void vm_notifications_init_bindings(struct notifications *notifications)
+{
+	for (uint32_t i = 0U; i < MAX_FFA_NOTIFICATIONS; i++) {
+		notifications->bindings_sender_id[i] = HF_INVALID_VM_ID;
+	}
+}