test(ipi): add unit tests for fetching pending IPIs
Expand the FFA_NOTIFICATION_INFO_GET unit tests to check that any
pending IPIs result in the partition ID and vCPU ID being added to
the returned list.
Signed-off-by: Daniel Boulby <daniel.boulby@arm.com>
Change-Id: If0f930578e78dff82772e16fa8d2318ba09ccdeb
diff --git a/src/vm_test.cc b/src/vm_test.cc
index b82aaf6..fd77a42 100644
--- a/src/vm_test.cc
+++ b/src/vm_test.cc
@@ -726,4 +726,174 @@
vm_unlock(&vm_locked);
}
+/**
+ * Validates simple getting of notifications info for pending IPI.
+ */
+TEST_F(vm, vm_notifications_info_get_ipi)
+{
+ /*
+ * Following set of variables that are also expected to be used when
+ * handling ffa_notification_info_get.
+ */
+ uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+ uint32_t ids_count = 0;
+ uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+ uint32_t lists_count = 0;
+ enum notifications_info_get_state current_state = INIT;
+ struct_vm *current_vm = vm_find_index(5);
+ struct vcpu *target_vcpu = vm_get_vcpu(current_vm, 1);
+ struct interrupts *interrupts = &target_vcpu->interrupts;
+ const bool is_from_vm = false;
+ struct vm_locked current_vm_locked = vm_lock(current_vm);
+
+ EXPECT_TRUE(current_vm->vcpu_count >= 2);
+
+ vcpu_virt_interrupt_set_pending(interrupts, HF_IPI_INTID);
+
+ vm_notifications_info_get_pending(current_vm_locked, is_from_vm, ids,
+ &ids_count, lists_sizes, &lists_count,
+ FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
+ ¤t_state);
+
+ EXPECT_EQ(ids_count, 2);
+ EXPECT_EQ(lists_count, 1);
+ EXPECT_EQ(lists_sizes[0], 1);
+ EXPECT_EQ(ids[0], current_vm->id);
+ EXPECT_EQ(ids[1], 1);
+ EXPECT_EQ(target_vcpu->ipi_info_get_retrieved, true);
+
+ /* Check it is not retrieved multiple times. */
+ current_state = INIT;
+ ids[0] = 0;
+ ids[1] = 0;
+ ids_count = 0;
+ lists_sizes[0] = 0;
+ lists_count = 0;
+
+ vm_notifications_info_get_pending(current_vm_locked, is_from_vm, ids,
+ &ids_count, lists_sizes, &lists_count,
+ FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
+ ¤t_state);
+ EXPECT_EQ(ids_count, 0);
+ EXPECT_EQ(lists_count, 0);
+ EXPECT_EQ(lists_sizes[0], 0);
+
+ vm_unlock(¤t_vm_locked);
+}
+
+/**
+ * Validates simple getting of notifications info for pending with IPI when
+ * notification for the same vcpu is also pending.
+ */
+TEST_F(vm, vm_notifications_info_get_ipi_with_per_vcpu)
+{
+ /*
+ * Following set of variables that are also expected to be used when
+ * handling ffa_notification_info_get.
+ */
+ uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+ uint32_t ids_count = 0;
+ uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+ uint32_t lists_count = 0;
+ enum notifications_info_get_state current_state = INIT;
+ struct_vm *current_vm = vm_find_index(5);
+ struct vcpu *target_vcpu = vm_get_vcpu(current_vm, 1);
+ struct interrupts *interrupts = &target_vcpu->interrupts;
+ const bool is_from_vm = false;
+ struct vm_locked current_vm_locked = vm_lock(current_vm);
+
+ EXPECT_TRUE(current_vm->vcpu_count >= 2);
+
+ vcpu_virt_interrupt_set_pending(interrupts, HF_IPI_INTID);
+
+ vm_notifications_partition_set_pending(current_vm_locked, is_from_vm,
+ true, 1, true);
+ vm_notifications_info_get_pending(current_vm_locked, is_from_vm, ids,
+ &ids_count, lists_sizes, &lists_count,
+ FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
+ ¤t_state);
+
+ EXPECT_EQ(ids_count, 2);
+ EXPECT_EQ(lists_count, 1);
+ EXPECT_EQ(lists_sizes[0], 1);
+ EXPECT_EQ(ids[0], current_vm->id);
+ EXPECT_EQ(ids[1], 1);
+ EXPECT_EQ(target_vcpu->ipi_info_get_retrieved, true);
+
+ /* Reset the state and values. */
+ current_state = INIT;
+ ids[0] = 0;
+ ids[1] = 0;
+ ids_count = 0;
+ lists_sizes[0] = 0;
+ lists_count = 0;
+
+ vm_notifications_info_get_pending(current_vm_locked, is_from_vm, ids,
+ &ids_count, lists_sizes, &lists_count,
+ FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
+ ¤t_state);
+ EXPECT_EQ(ids_count, 0);
+ EXPECT_EQ(lists_count, 0);
+ EXPECT_EQ(lists_sizes[0], 0);
+
+ vm_unlock(¤t_vm_locked);
+}
+
+/**
+ * Validate that a mix of a pending IPI and notifcations are correctly
+ * reported across vcpus.
+ */
+TEST_F(vm, vm_notifications_info_get_per_vcpu_all_vcpus_and_ipi)
+{
+ struct_vm *current_vm = vm_find_index(5);
+ ffa_vcpu_count_t vcpu_count = current_vm->vcpu_count;
+ CHECK(vcpu_count > 1);
+
+ struct vm_locked current_vm_locked = vm_lock(current_vm);
+
+ /*
+ * Following set of variables that are also expected to be used when
+ * handling ffa_notification_info_get.
+ */
+ const bool is_from_vm = false;
+ uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+ uint32_t ids_count = 0;
+ uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+ uint32_t lists_count = 0;
+ enum notifications_info_get_state current_state = INIT;
+ struct vcpu *target_vcpu = vm_get_vcpu(current_vm, 0);
+ struct interrupts *interrupts = &target_vcpu->interrupts;
+
+ vcpu_virt_interrupt_set_pending(interrupts, HF_IPI_INTID);
+
+ for (unsigned int i = 1; i < vcpu_count; i++) {
+ vm_notifications_partition_set_pending(
+ current_vm_locked, is_from_vm, FFA_NOTIFICATION_MASK(i),
+ i, true);
+ }
+
+ vm_notifications_info_get_pending(current_vm_locked, is_from_vm, ids,
+ &ids_count, lists_sizes, &lists_count,
+ FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
+ ¤t_state);
+
+ /*
+ * This test has been conceived for the expected MAX_CPUS 4.
+ * All VCPUs have notifications of the same VM, to be broken down in 2
+ * lists with 3 VCPU IDs, and 1 VCPU ID respectively.
+ * The list of IDs should look like: {<vm_id>, 0, 1, 2, <vm_id>, 3}.
+ */
+ EXPECT_EQ(ids_count, 6U);
+ EXPECT_EQ(lists_count, 2U);
+ EXPECT_EQ(lists_sizes[0], 3);
+ EXPECT_EQ(lists_sizes[1], 1);
+ EXPECT_EQ(ids[0], current_vm->id);
+ EXPECT_EQ(ids[1], 0);
+ EXPECT_EQ(ids[2], 1);
+ EXPECT_EQ(ids[3], 2);
+ EXPECT_EQ(ids[4], current_vm->id);
+ EXPECT_EQ(ids[5], 3);
+
+ vm_unlock(¤t_vm_locked);
+}
} /* namespace */