BL31: Add SDEI dispatcher

The implementation currently supports only interrupt-based SDEI events,
and supports all interfaces as defined by SDEI specification version
1.0 [1].

Introduce the build option SDEI_SUPPORT to include SDEI dispatcher in
BL31.

Update user guide and porting guide. SDEI documentation to follow.

[1] http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf

Change-Id: I758b733084e4ea3b27ac77d0259705565842241a
Co-authored-by: Yousuf A <yousuf.sait@arm.com>
Signed-off-by: Jeenu Viswambharan <jeenu.viswambharan@arm.com>
diff --git a/services/std_svc/sdei/sdei_event.c b/services/std_svc/sdei/sdei_event.c
new file mode 100644
index 0000000..bf0e779
--- /dev/null
+++ b/services/std_svc/sdei/sdei_event.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <utils.h>
+#include "sdei_private.h"
+
+#define MAP_OFF(_map, _mapping) ((_map) - (_mapping)->map)
+
+/*
+ * Get SDEI entry with the given mapping: on success, returns pointer to SDEI
+ * entry. On error, returns NULL.
+ *
+ * Both shared and private maps are stored in single-dimensional array. Private
+ * event entries are kept for each PE forming a 2D array.
+ */
+sdei_entry_t *get_event_entry(sdei_ev_map_t *map)
+{
+	const sdei_mapping_t *mapping;
+	sdei_entry_t *cpu_priv_base;
+	unsigned int idx, base_idx;
+
+	if (is_event_private(map)) {
+		/*
+		 * For a private map, find the index of the mapping in the
+		 * array.
+		 */
+		mapping = SDEI_PRIVATE_MAPPING();
+		idx = MAP_OFF(map, mapping);
+
+		/* Base of private mappings for this CPU */
+		base_idx = plat_my_core_pos() * mapping->num_maps;
+		cpu_priv_base = &sdei_private_event_table[base_idx];
+
+		/*
+		 * Return the address of the entry at the same index in the
+		 * per-CPU event entry.
+		 */
+		return &cpu_priv_base[idx];
+	} else {
+		mapping = SDEI_SHARED_MAPPING();
+		idx = MAP_OFF(map, mapping);
+
+		return &sdei_shared_event_table[idx];
+	}
+}
+
+/*
+ * Find event mapping for a given interrupt number: On success, returns pointer
+ * to the event mapping. On error, returns NULL.
+ */
+sdei_ev_map_t *find_event_map_by_intr(int intr_num, int shared)
+{
+	const sdei_mapping_t *mapping;
+	sdei_ev_map_t *map;
+	unsigned int i;
+
+	/*
+	 * Look for a match in private and shared mappings, as requested. This
+	 * is a linear search. However, if the mappings are required to be
+	 * sorted, for large maps, we could consider binary search.
+	 */
+	mapping = shared ? SDEI_SHARED_MAPPING() : SDEI_PRIVATE_MAPPING();
+	iterate_mapping(mapping, i, map) {
+		if (map->intr == intr_num)
+			return map;
+	}
+
+	return NULL;
+}
+
+/*
+ * Find event mapping for a given event number: On success returns pointer to
+ * the event mapping. On error, returns NULL.
+ */
+sdei_ev_map_t *find_event_map(int ev_num)
+{
+	const sdei_mapping_t *mapping;
+	sdei_ev_map_t *map;
+	unsigned int i, j;
+
+	/*
+	 * Iterate through mappings to find a match. This is a linear search.
+	 * However, if the mappings are required to be sorted, for large maps,
+	 * we could consider binary search.
+	 */
+	for_each_mapping_type(i, mapping) {
+		iterate_mapping(mapping, j, map) {
+			if (map->ev_num == ev_num)
+				return map;
+		}
+	}
+
+	return NULL;
+}