feat(ipi): introduce IPI paravirtualised interface

Interprocessor Interrupts (IPIs) allow an SP to send an interrupt to
itself on another CPU. This patch starts the implementation of this
feature and enables it for the case where the SP is in the RUNNING
state on the target_vcpu.

Signed-off-by: Daniel Boulby <daniel.boulby@arm.com>
Change-Id: Idd0e1a5863730ae0f169bd0f56ac3abcd2916870
diff --git a/inc/hf/api.h b/inc/hf/api.h
index f34d61c..b6234c9 100644
--- a/inc/hf/api.h
+++ b/inc/hf/api.h
@@ -49,7 +49,8 @@
 				    uint32_t intid,
 				    struct vcpu_locked current_locked,
 				    struct vcpu **next);
-void api_sri_send_if_delayed(struct vcpu *current);
+uint64_t api_hf_interrupt_send_ipi(uint32_t target_vcpu_id,
+				   struct vcpu *current);
 
 struct ffa_value api_ffa_msg_send(ffa_id_t sender_vm_id,
 				  ffa_id_t receiver_vm_id, uint32_t size,
diff --git a/inc/hf/cpu.h b/inc/hf/cpu.h
index ac1f7d5..3d7a35c 100644
--- a/inc/hf/cpu.h
+++ b/inc/hf/cpu.h
@@ -31,6 +31,9 @@
 
 	/* In case there is a pending SRI for the NWd. */
 	bool is_sri_delayed;
+
+	/* Track pending IPIs. */
+	struct vcpu *ipi_target_vcpu;
 };
 
 void cpu_module_init(const cpu_id_t *cpu_ids, size_t count);
diff --git a/inc/hf/hf_ipi.h b/inc/hf/hf_ipi.h
new file mode 100644
index 0000000..dd40b84
--- /dev/null
+++ b/inc/hf/hf_ipi.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2024 The Hafnium Authors.
+ *
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/BSD-3-Clause.
+ */
+
+#pragma once
+
+#include "hf/types.h"
+#include "hf/vcpu.h"
+#include "hf/vm.h"
+
+void hf_ipi_init_interrupt(void);
+struct vcpu *hf_ipi_get_pending_target_vcpu(struct cpu *current);
+void hf_ipi_send_interrupt(struct vm *vm, ffa_vcpu_index_t target_vcpu_index);
+bool hf_ipi_handle(struct vcpu_locked target_vcpu_locked);
diff --git a/inc/hf/vm.h b/inc/hf/vm.h
index 64df9f4..5bcb30c 100644
--- a/inc/hf/vm.h
+++ b/inc/hf/vm.h
@@ -395,6 +395,15 @@
 	return vm->id == HF_PRIMARY_VM_ID;
 }
 
+/**
+ * Convert a CPU ID for a secondary VM to the corresponding vCPU index.
+ */
+static inline ffa_vcpu_index_t vcpu_id_to_index(cpu_id_t vcpu_id)
+{
+	/* For now we use indices as IDs. */
+	return vcpu_id;
+}
+
 struct interrupt_descriptor *vm_interrupt_set_target_mpidr(
 	struct vm_locked vm_locked, uint32_t id, uint32_t target_mpidr);
 struct interrupt_descriptor *vm_interrupt_set_sec_state(
diff --git a/inc/vmapi/hf/abi.h b/inc/vmapi/hf/abi.h
index ee700a0..ad3d5f1 100644
--- a/inc/vmapi/hf/abi.h
+++ b/inc/vmapi/hf/abi.h
@@ -19,6 +19,7 @@
 #define HF_INTERRUPT_GET               0xff04
 #define HF_INTERRUPT_DEACTIVATE	       0xff08
 #define HF_INTERRUPT_RECONFIGURE       0xff09
+#define HF_INTERRUPT_SEND_IPI	       0xff0a
 
 /* Custom FF-A-like calls returned from FFA_RUN. */
 #define HF_FFA_RUN_WAIT_FOR_INTERRUPT 0xff06
diff --git a/inc/vmapi/hf/call.h b/inc/vmapi/hf/call.h
index 52c2cef..5fceae6 100644
--- a/inc/vmapi/hf/call.h
+++ b/inc/vmapi/hf/call.h
@@ -407,6 +407,14 @@
 					(uint32_t)target_cpu_index);
 }
 
+/**
+ * Trigger an IPI to target vcpu.
+ */
+static inline int64_t hf_interrupt_send_ipi(ffa_vcpu_index_t target_vcpu_id)
+{
+	return hf_call(HF_INTERRUPT_SEND_IPI, (uint32_t)target_vcpu_id, 0, 0);
+}
+
 /** Obtains the Hafnium's version of the implemented FF-A specification. */
 static inline enum ffa_version ffa_version(enum ffa_version requested_version)
 {
diff --git a/inc/vmapi/hf/types.h b/inc/vmapi/hf/types.h
index 4c2d5da..8191a78 100644
--- a/inc/vmapi/hf/types.h
+++ b/inc/vmapi/hf/types.h
@@ -61,5 +61,11 @@
 /** The virtual interrupt ID used for notification pending interrupt. */
 #define HF_NOTIFICATION_PENDING_INTID 5
 
+/**
+ * The interrupt ID (for both physical and virtual) used for
+ * the inter-processor interrupt.
+ */
+#define HF_IPI_INTID 9
+
 /** The physical interrupt ID use for the schedule receiver interrupt. */
 #define HF_SCHEDULE_RECEIVER_INTID 8