feat(FF-A): implement FFA_SPM_ID_GET interface

If FFA_SPM_ID_GET is invoked at the secure virtual FF-A instance
(a secure partition) return the SPMC id. The SPMC id is queried by
the SPMC to the SPMD by calling FFA_ID_GET or by the Hypervisor to
the SPMD by calling FFA_SPM_ID_GET. Introduce plat_ffa module to
allow for the SPMC and hypervisor specific code.

Signed-off-by: Daniel Boulby <daniel.boulby@arm.com>
Change-Id: I892fa034ac00a1c0ada7ac13e9384a8c5ccfc507
diff --git a/src/api.c b/src/api.c
index 38475a7..01c91b5 100644
--- a/src/api.c
+++ b/src/api.c
@@ -9,6 +9,7 @@
 #include "hf/api.h"
 
 #include "hf/arch/cpu.h"
+#include "hf/arch/ffa.h"
 #include "hf/arch/ffa_memory_handle.h"
 #include "hf/arch/mm.h"
 #include "hf/arch/other_world.h"
@@ -436,6 +437,24 @@
 }
 
 /**
+ * Returns the ID of the SPMC.
+ */
+struct ffa_value api_ffa_spm_id_get(void)
+{
+	struct ffa_value ret = ffa_error(FFA_NOT_SUPPORTED);
+
+	if (MAKE_FFA_VERSION(1, 1) <= FFA_VERSION_COMPILED) {
+		/*
+		 * Return the SPMC ID that was fetched during FF-A
+		 * initialization.
+		 */
+		ret = (struct ffa_value){.func = FFA_SUCCESS_32,
+					 .arg2 = arch_ffa_spmc_id_get()};
+	}
+	return ret;
+}
+
+/**
  * This function is called by the architecture-specific context switching
  * function to indicate that register state for the given vCPU has been saved
  * and can therefore be used by other pCPUs.
@@ -1692,6 +1711,11 @@
 	case FFA_MSG_SEND_DIRECT_REQ_64:
 	case FFA_MSG_SEND_DIRECT_REQ_32:
 		return (struct ffa_value){.func = FFA_SUCCESS_32};
+	/* FF-A v1.1 features. */
+	case FFA_SPM_ID_GET_32:
+		if (MAKE_FFA_VERSION(1, 1) <= FFA_VERSION_COMPILED) {
+			return (struct ffa_value){.func = FFA_SUCCESS_32};
+		}
 	default:
 		return ffa_error(FFA_NOT_SUPPORTED);
 	}
diff --git a/src/arch/aarch64/args.gni b/src/arch/aarch64/args.gni
index e51f164..f42d228 100644
--- a/src/arch/aarch64/args.gni
+++ b/src/arch/aarch64/args.gni
@@ -5,6 +5,9 @@
 # https://opensource.org/licenses/BSD-3-Clause.
 
 declare_args() {
+  # FF-A hooks to be used for the platform, specified as build target.
+  plat_ffa = "//src/arch/aarch64/plat/ffa:absent"
+
   # PSCI hooks to be used for the platform, specified as build target.
   plat_psci = "//src/arch/aarch64/plat/psci:hypervisor"
 
diff --git a/src/arch/aarch64/hypervisor/BUILD.gn b/src/arch/aarch64/hypervisor/BUILD.gn
index 3648cba..4473cd2 100644
--- a/src/arch/aarch64/hypervisor/BUILD.gn
+++ b/src/arch/aarch64/hypervisor/BUILD.gn
@@ -41,6 +41,7 @@
     "cpu.c",
     "debug_el1.c",
     "feature_id.c",
+    "ffa.c",
     "handler.c",
     "perfmon.c",
     "psci_handler.c",
@@ -52,6 +53,7 @@
     "//src/arch/aarch64:arch",
     "//src/arch/aarch64:entry",
     "//src/arch/aarch64:smc",
+    plat_ffa,
     plat_interrupts,
     plat_prng,
     plat_psci,
diff --git a/src/arch/aarch64/hypervisor/ffa.c b/src/arch/aarch64/hypervisor/ffa.c
new file mode 100644
index 0000000..33786cc
--- /dev/null
+++ b/src/arch/aarch64/hypervisor/ffa.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2021 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.
+ */
+
+#include "hf/arch/plat/ffa.h"
+
+#include "hf/ffa.h"
+#include "hf/panic.h"
+#include "hf/vm_ids.h"
+
+/**
+ * Returns the SPMC ID returned from the SPMD.
+ */
+ffa_vm_id_t arch_ffa_spmc_id_get(void)
+{
+	struct ffa_value ret = plat_ffa_spmc_id_get();
+
+	if (ret.func == FFA_SUCCESS_32) {
+		return (ffa_vm_id_t)ret.arg2;
+	}
+	if (ret.func == FFA_ERROR_32 &&
+	    ffa_error_code(ret) != FFA_NOT_SUPPORTED) {
+		panic("Failed to get SPMC ID\n");
+	}
+
+	return HF_SPMC_VM_ID;
+}
diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
index cd98722..fc82b1b 100644
--- a/src/arch/aarch64/hypervisor/handler.c
+++ b/src/arch/aarch64/hypervisor/handler.c
@@ -473,6 +473,9 @@
 	case FFA_ID_GET_32:
 		*args = api_ffa_id_get(current);
 		return true;
+	case FFA_SPM_ID_GET_32:
+		*args = api_ffa_spm_id_get();
+		return true;
 	case FFA_FEATURES_32:
 		*args = api_ffa_features(args->arg1);
 		return true;
diff --git a/src/arch/aarch64/plat/ffa/BUILD.gn b/src/arch/aarch64/plat/ffa/BUILD.gn
new file mode 100644
index 0000000..8b278fd
--- /dev/null
+++ b/src/arch/aarch64/plat/ffa/BUILD.gn
@@ -0,0 +1,27 @@
+# Copyright 2021 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.
+
+import("//build/toolchain/platform.gni")
+
+source_set("absent") {
+  sources = [
+    "absent.c",
+  ]
+}
+
+source_set("hypervisor") {
+  public_configs = [ "//src/arch/${plat_arch}:config" ]
+  sources = [
+    "hypervisor.c",
+  ]
+}
+
+source_set("spmc") {
+  public_configs = [ "//src/arch/${plat_arch}:config" ]
+  sources = [
+    "spmc.c",
+  ]
+}
diff --git a/src/arch/aarch64/plat/ffa/absent.c b/src/arch/aarch64/plat/ffa/absent.c
new file mode 100644
index 0000000..141e97e
--- /dev/null
+++ b/src/arch/aarch64/plat/ffa/absent.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2021 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.
+ */
+
+#include "hf/ffa.h"
+
+struct ffa_value plat_ffa_spmc_id_get(void)
+{
+	return (struct ffa_value){.func = FFA_ERROR_32,
+				  .arg2 = FFA_NOT_SUPPORTED};
+}
diff --git a/src/arch/aarch64/plat/ffa/hypervisor.c b/src/arch/aarch64/plat/ffa/hypervisor.c
new file mode 100644
index 0000000..9bdf0ab
--- /dev/null
+++ b/src/arch/aarch64/plat/ffa/hypervisor.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2021 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.
+ */
+
+#include "hf/ffa.h"
+
+#include "smc.h"
+
+struct ffa_value plat_ffa_spmc_id_get(void)
+{
+	/* Fetch the SPMC ID from the SPMD using FFA_SPM_ID_GET. */
+	return smc_ffa_call((struct ffa_value){.func = FFA_SPM_ID_GET_32});
+}
diff --git a/src/arch/aarch64/plat/ffa/spmc.c b/src/arch/aarch64/plat/ffa/spmc.c
new file mode 100644
index 0000000..8cd65c4
--- /dev/null
+++ b/src/arch/aarch64/plat/ffa/spmc.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2021 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.
+ */
+
+#include "hf/ffa.h"
+
+#include "smc.h"
+
+struct ffa_value plat_ffa_spmc_id_get(void)
+{
+	/*
+	 * Since we are running in the SPMC use FFA_ID_GET to fetch our
+	 * ID from the SPMD.
+	 */
+	return smc_ffa_call((struct ffa_value){.func = FFA_ID_GET_32});
+}
diff --git a/src/arch/fake/hypervisor/BUILD.gn b/src/arch/fake/hypervisor/BUILD.gn
index 8f28802..4c6f2c2 100644
--- a/src/arch/fake/hypervisor/BUILD.gn
+++ b/src/arch/fake/hypervisor/BUILD.gn
@@ -7,6 +7,7 @@
 source_set("hypervisor") {
   sources = [
     "cpu.c",
+    "ffa.c",
     "vm.c",
   ]
   deps = [
diff --git a/src/arch/fake/hypervisor/ffa.c b/src/arch/fake/hypervisor/ffa.c
new file mode 100644
index 0000000..08183e8
--- /dev/null
+++ b/src/arch/fake/hypervisor/ffa.c
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2021 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.
+ */
+
+#include "hf/ffa.h"
+
+#include "hf/vm_ids.h"
+
+ffa_vm_id_t arch_ffa_spmc_id_get(void)
+{
+	return HF_SPMC_VM_ID;
+}