Add runtime services framework

This patch introduces the framework to enable registration and
initialisation of runtime services. PSCI is registered and initialised
as a runtime service. Handling of runtime service requests will be
implemented in subsequent patches.

Change-Id: Id21e7ddc5a33d42b7d6e455b41155fc5441a9547
diff --git a/common/psci/psci_setup.c b/common/psci/psci_setup.c
index 91de1ab..c471d1f 100644
--- a/common/psci/psci_setup.c
+++ b/common/psci/psci_setup.c
@@ -36,6 +36,7 @@
 #include <platform.h>
 #include <psci_private.h>
 #include <context_mgmt.h>
+#include <runtime_svc.h>
 
 /*******************************************************************************
  * Per cpu non-secure contexts used to program the architectural state prior
@@ -275,8 +276,9 @@
  * level within the 'psci_aff_map' array. This allows restricting search of a
  * node at an affinity level between the indices in the limits array.
  ******************************************************************************/
-void psci_setup(unsigned long mpidr)
+int32_t psci_setup(void)
 {
+	unsigned long mpidr = read_mpidr();
 	int afflvl, affmap_idx, max_afflvl;
 	aff_map_node *node;
 
@@ -335,5 +337,16 @@
 	platform_setup_pm(&psci_plat_pm_ops);
 	assert(psci_plat_pm_ops);
 
-	return;
+	return 0;
 }
+
+/* Register PSCI as a run time service */
+DECLARE_RT_SVC(
+		psci,
+
+		OEN_STD_START,
+		OEN_STD_END,
+		SMC_TYPE_FAST,
+		psci_setup,
+		NULL
+);
diff --git a/common/runtime_svc.c b/common/runtime_svc.c
index 1bda151..c059078 100644
--- a/common/runtime_svc.c
+++ b/common/runtime_svc.c
@@ -39,13 +39,106 @@
 #include <bl_common.h>
 #include <psci.h>
 #include <runtime_svc.h>
+#include <debug.h>
 
 /*******************************************************************************
- * Perform initialization of runtime services possibly across exception levels
- * in the secure address space e.g. psci & interrupt handling.
+ * The 'rt_svc_descs' array holds the runtime service descriptors exported by
+ * services by placing them in the 'rt_svc_descs' linker section.
+ * The 'rt_svc_descs_indices' array holds the index of a descriptor in the
+ * 'rt_svc_descs' array. When an SMC arrives, the OEN[29:24] bits and the call
+ * type[31] bit in the function id are combined to get an index into the
+ * 'rt_svc_descs_indices' array. This gives the index of the descriptor in the
+ * 'rt_svc_descs' array which contains the SMC handler.
  ******************************************************************************/
-void runtime_svc_init(unsigned long mpidr)
+#define RT_SVC_DESCS_START	((uint64_t) (&__RT_SVC_DESCS_START__))
+#define RT_SVC_DESCS_END	((uint64_t) (&__RT_SVC_DESCS_END__))
+uint8_t rt_svc_descs_indices[MAX_RT_SVCS];
+static rt_svc_desc *rt_svc_descs;
+
+/*******************************************************************************
+ * Simple routine to sanity check a runtime service descriptor before using it
+ ******************************************************************************/
+static int32_t validate_rt_svc_desc(rt_svc_desc *desc)
 {
-	psci_setup(mpidr);
+	if (desc == NULL)
+		return -EINVAL;
+
+	if (desc->start_oen > desc->end_oen)
+		return -EINVAL;
+
+	if (desc->end_oen >= OEN_LIMIT)
+		return -EINVAL;
+
+	if (desc->call_type != SMC_TYPE_FAST && desc->call_type != SMC_TYPE_STD)
+		return -EINVAL;
+
+	/* A runtime service having no init or handle function doesn't make sense */
+	if (desc->init == NULL && desc->handle == NULL)
+		return -EINVAL;
+
+	return 0;
+}
+
+/*******************************************************************************
+ * This function calls the initialisation routine in the descriptor exported by
+ * a runtime service. Once a descriptor has been validated, its start & end
+ * owning entity numbers and the call type are combined to form a unique oen.
+ * The unique oen is used as an index into the 'rt_svc_descs_indices' array.
+ * The index of the runtime service descriptor is stored at this index.
+ ******************************************************************************/
+void runtime_svc_init()
+{
+	int32_t rc = 0;
+	uint32_t index, start_idx, end_idx;
+	uint64_t rt_svc_descs_num;
+
+	/* If no runtime services are implemented then simply bail out */
+	rt_svc_descs_num = RT_SVC_DESCS_END - RT_SVC_DESCS_START;
+	rt_svc_descs_num /= sizeof(rt_svc_desc);
+	if (rt_svc_descs_num == 0)
+		return;
+
+	/* Initialise internal variables to invalid state */
+	memset(rt_svc_descs_indices, -1, sizeof(rt_svc_descs_indices));
+
+	rt_svc_descs = (rt_svc_desc *) RT_SVC_DESCS_START;
+	for (index = 0; index < rt_svc_descs_num; index++) {
+
+		/*
+		 * An invalid descriptor is an error condition since it is
+		 * difficult to predict the system behaviour in the absence
+		 * of this service.
+		 */
+		rc = validate_rt_svc_desc(&rt_svc_descs[index]);
+		if (rc) {
+			ERROR("Invalid runtime service descriptor 0x%x (%s)\n",
+					&rt_svc_descs[index],
+					rt_svc_descs[index].name);
+			goto error;
+		}
+
+		/*
+		 * Fill the indices corresponding to the start and end owning
+		 * entity numbers with the index of the descriptor which will
+		 * handle the SMCs for this owning entity range.
+		 */
+		start_idx = get_unique_oen(rt_svc_descs[index].start_oen,
+					   rt_svc_descs[index].call_type);
+		end_idx = get_unique_oen(rt_svc_descs[index].end_oen,
+					 rt_svc_descs[index].call_type);
+		for (; start_idx <= end_idx; start_idx++)
+			rt_svc_descs_indices[start_idx] = index;
+
+		/* Call the initialisation routine for this runtime service */
+		rc = rt_svc_descs[index].init();
+		if (rc) {
+			ERROR("Error initializing runtime service %s\n",
+					rt_svc_descs[index].name);
+			goto error;
+		}
+	}
+
 	return;
+error:
+	panic();
 }