feat(errata_abi): errata management firmware interface

This patch adds the errata management firmware interface for lower ELs
to discover details about CPU erratum. Based on the CPU erratum
identifier the interface enables the OS to find the mitigation of an
erratum in EL3.

The ABI can only be present in a system that is compliant with SMCCCv1.1
or higher. This implements v1.0 of the errata ABI spec.

For details on all possible return values, refer the design
documentation below:

ABI design documentation:
https://developer.arm.com/documentation/den0100/1-0?lang=en

Signed-off-by: Sona Mathew <SonaRebecca.Mathew@arm.com>
Change-Id: I70f0e2569cf92e6e02ad82e3e77874546232b89a
diff --git a/services/std_svc/errata_abi/errata_abi_main.c b/services/std_svc/errata_abi/errata_abi_main.c
new file mode 100644
index 0000000..80fc39a
--- /dev/null
+++ b/services/std_svc/errata_abi/errata_abi_main.c
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include "cpu_errata_info.h"
+#include <lib/smccc.h>
+#include <lib/utils_def.h>
+#include <services/errata_abi_svc.h>
+#include <smccc_helpers.h>
+
+/*
+ * Global pointer that points to the specific
+ * structure based on the MIDR part number
+ */
+struct em_cpu_list *cpu_ptr;
+
+extern uint8_t cpu_get_rev_var(void);
+
+/* Structure array that holds CPU specific errata information */
+struct em_cpu_list cpu_list[] = {
+#if CORTEX_A9_H_INC
+{
+	.cpu_partnumber = CORTEX_A9_MIDR,
+	.cpu_errata_list = {
+		[0] = {794073, 0x00, 0xFF, ERRATA_A9_794073},
+		[1 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+	}
+},
+#endif /* CORTEX_A9_H_INC */
+
+#if CORTEX_A15_H_INC
+{
+	.cpu_partnumber = CORTEX_A15_MIDR,
+	.cpu_errata_list = {
+		[0] = {816470, 0x30, 0xFF, ERRATA_A15_816470},
+		[1] = {827671, 0x30, 0xFF, ERRATA_A15_827671},
+		[2 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+	}
+},
+#endif /* CORTEX_A15_H_INC */
+
+#if CORTEX_A17_H_INC
+{
+	.cpu_partnumber = CORTEX_A17_MIDR,
+	.cpu_errata_list = {
+		[0] = {852421, 0x00, 0x12, ERRATA_A17_852421},
+		[1] = {852423, 0x00, 0x12, ERRATA_A17_852423},
+		[2 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+	}
+},
+#endif /* CORTEX_A17_H_INC */
+
+#if CORTEX_A35_H_INC
+{
+	.cpu_partnumber = CORTEX_A35_MIDR,
+	.cpu_errata_list = {
+		[0] = {855472, 0x00, 0x00, ERRATA_A35_855472},
+		[1 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+	}
+},
+#endif /* CORTEX_A35_H_INC */
+
+#if CORTEX_A53_H_INC
+{
+	.cpu_partnumber = CORTEX_A53_MIDR,
+	.cpu_errata_list = {
+		[0] = {819472, 0x00, 0x01, ERRATA_A53_819472},
+		[1] = {824069, 0x00, 0x02, ERRATA_A53_824069},
+		[2] = {826319, 0x00, 0x02, ERRATA_A53_826319},
+		[3] = {827319, 0x00, 0x02, ERRATA_A53_827319},
+		[4] = {835769, 0x00, 0x04, ERRATA_A53_835769},
+		[5] = {836870, 0x00, 0x03, ERRATA_A53_836870},
+		[6] = {843419, 0x00, 0x04, ERRATA_A53_843419},
+		[7] = {855873, 0x03, 0xFF, ERRATA_A53_855873},
+		[8] = {1530924, 0x00, 0xFF, ERRATA_A53_1530924},
+		[9 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+	}
+},
+#endif /* CORTEX_A53_H_INC */
+
+#if CORTEX_A55_H_INC
+{
+	.cpu_partnumber = CORTEX_A55_MIDR,
+	.cpu_errata_list = {
+		[0] = {768277, 0x00, 0x00, ERRATA_A55_768277},
+		[1] = {778703, 0x00, 0x00, ERRATA_A55_778703},
+		[2] = {798797, 0x00, 0x00, ERRATA_A55_798797},
+		[3] = {846532, 0x00, 0x01, ERRATA_A55_846532},
+		[4] = {903758, 0x00, 0x01, ERRATA_A55_903758},
+		[5] = {1221012, 0x00, 0x10, ERRATA_A55_1221012},
+		[6] = {1530923, 0x00, 0xFF, ERRATA_A55_1530923},
+		[7 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+	}
+},
+#endif /* CORTEX_A55_H_INC */
+
+#if CORTEX_A57_H_INC
+{
+	.cpu_partnumber = CORTEX_A57_MIDR,
+	.cpu_errata_list = {
+		[0] = {806969, 0x00, 0x00, ERRATA_A57_806969},
+		[1] = {813419, 0x00, 0x00, ERRATA_A57_813419},
+		[2] = {813420, 0x00, 0x00, ERRATA_A57_813420},
+		[3] = {814670, 0x00, 0x00, ERRATA_A57_814670},
+		[4] = {817169, 0x00, 0x01, ERRATA_A57_817169},
+		[5] = {826974, 0x00, 0x11, ERRATA_A57_826974},
+		[6] = {826977, 0x00, 0x11, ERRATA_A57_826977},
+		[7] = {828024, 0x00, 0x11, ERRATA_A57_828024},
+		[8] = {829520, 0x00, 0x12, ERRATA_A57_829520},
+		[9] = {833471, 0x00, 0x12, ERRATA_A57_833471},
+		[10] = {859972, 0x00, 0x13, ERRATA_A57_859972},
+		[11] = {1319537, 0x00, 0xFF, ERRATA_A57_1319537},
+		[12 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+	}
+},
+#endif /* CORTEX_A57_H_INC */
+
+#if CORTEX_A72_H_INC
+{
+	.cpu_partnumber = CORTEX_A72_MIDR,
+	.cpu_errata_list = {
+		[0] = {859971, 0x00, 0x03, ERRATA_A72_859971},
+		[1] = {1319367, 0x00, 0xFF, ERRATA_A72_1319367},
+		[2 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+	}
+},
+#endif /* CORTEX_A72_H_INC */
+
+#if CORTEX_A73_H_INC
+{
+	.cpu_partnumber = CORTEX_A73_MIDR,
+	.cpu_errata_list = {
+		[0] = {852427, 0x00, 0x00, ERRATA_A73_852427},
+		[1] = {855423, 0x00, 0x01, ERRATA_A73_855423},
+		[2 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+	}
+},
+#endif /* CORTEX_A73_H_INC */
+
+#if CORTEX_A75_H_INC
+{
+	.cpu_partnumber = CORTEX_A75_MIDR,
+	.cpu_errata_list = {
+		[0] = {764081, 0x00, 0x00, ERRATA_A75_764081},
+		[1] = {790748, 0x00, 0x00, ERRATA_A75_790748},
+		[2 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+	}
+},
+#endif /* CORTEX_A75_H_INC */
+
+#if CORTEX_A76_H_INC
+{
+	.cpu_partnumber = CORTEX_A76_MIDR,
+	.cpu_errata_list = {
+		[0] = {1073348, 0x00, 0x10, ERRATA_A76_1073348},
+		[1] = {1130799, 0x00, 0x20, ERRATA_A76_1130799},
+		[2] = {1165522, 0x00, 0xFF, ERRATA_A76_1165522},
+		[3] = {1220197, 0x00, 0x20, ERRATA_A76_1220197},
+		[4] = {1257314, 0x00, 0x30, ERRATA_A76_1257314},
+		[5] = {1262606, 0x00, 0x30, ERRATA_A76_1262606},
+		[6] = {1262888, 0x00, 0x30, ERRATA_A76_1262888},
+		[7] = {1275112, 0x00, 0x30, ERRATA_A76_1275112},
+		[8] = {1791580, 0x00, 0x40, ERRATA_A76_1791580},
+		[9] = {1868343, 0x00, 0x40, ERRATA_A76_1868343},
+		[10] = {1946160, 0x30, 0x41, ERRATA_A76_1946160},
+		[11 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+	}
+},
+#endif /* CORTEX_A76_H_INC */
+
+#if CORTEX_A77_H_INC
+{
+	.cpu_partnumber = CORTEX_A77_MIDR,
+	.cpu_errata_list = {
+		[0] = {1508412, 0x00, 0x10, ERRATA_A77_1508412},
+		[1] = {1791578, 0x00, 0x11, ERRATA_A77_1791578},
+		[2] = {1800714, 0x00, 0x11, ERRATA_A77_1800714},
+		[3] = {1925769, 0x00, 0x11, ERRATA_A77_1925769},
+		[4] = {1946167, 0x00, 0x11, ERRATA_A77_1946167},
+		[5] = {2356587, 0x00, 0x11, ERRATA_A77_2356587},
+		[6] = {2743100, 0x00, 0x11, ERRATA_A77_2743100},
+		[7 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+	}
+},
+#endif /* CORTEX_A77_H_INC */
+
+#if CORTEX_A78_H_INC
+{
+	.cpu_partnumber = CORTEX_A78_MIDR,
+	.cpu_errata_list = {
+		[0] = {1688305, 0x00, 0x10, ERRATA_A78_1688305},
+		[1] = {1821534, 0x00, 0x10, ERRATA_A78_1821534},
+		[2] = {1941498, 0x00, 0x11, ERRATA_A78_1941498},
+		[3] = {1951500, 0x10, 0x11, ERRATA_A78_1951500},
+		[4] = {1952683, 0x00, 0x00, ERRATA_A78_1952683},
+		[5] = {2132060, 0x00, 0x12, ERRATA_A78_2132060},
+		[6] = {2242635, 0x10, 0x12, ERRATA_A78_2242635},
+		[7] = {2376745, 0x00, 0x12, ERRATA_A78_2376745},
+		[8] = {2395406, 0x00, 0x12, ERRATA_A78_2395406},
+		[9] = {2742426, 0x00, 0x12, ERRATA_A78_2742426},
+		[10] = {2772019, 0x00, 0x12, ERRATA_A78_2772019},
+		[11] = {2779479, 0x00, 0x12, ERRATA_A78_2779479},
+		[12 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+	}
+},
+#endif /* CORTEX_A78_H_INC */
+
+#if CORTEX_A78_AE_H_INC
+{
+	.cpu_partnumber = CORTEX_A78_AE_MIDR,
+	.cpu_errata_list = {
+		[0] = {1941500, 0x00, 0x01, ERRATA_A78_AE_1941500},
+		[1] = {1951502, 0x00, 0x01, ERRATA_A78_AE_1951502},
+		[2] = {2376748, 0x00, 0x01, ERRATA_A78_AE_2376748},
+		[3] = {2395408, 0x00, 0x01, ERRATA_A78_AE_2395408},
+		[4 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+	}
+},
+#endif /* CORTEX_A78_AE_H_INC */
+
+#if CORTEX_A78C_H_INC
+{
+	.cpu_partnumber = CORTEX_A78C_MIDR,
+	.cpu_errata_list = {
+		[0] = {2132064, 0x01, 0x02, ERRATA_A78C_2132064},
+		[1] = {2242638, 0x01, 0x02, ERRATA_A78C_2242638},
+		[2] = {2376749, 0x01, 0x02, ERRATA_A78C_2376749},
+		[3] = {2395411, 0x01, 0x02, ERRATA_A78C_2395411},
+		[4] = {2772121, 0x00, 0x02, ERRATA_A78C_2772121},
+		[5] = {2779484, 0x01, 0x02, ERRATA_A78C_2779484},
+		[6 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+	}
+},
+#endif /* CORTEX_A78C_H_INC */
+
+#if CORTEX_X1_H_INC
+{
+	.cpu_partnumber = CORTEX_X1_MIDR,
+	.cpu_errata_list = {
+		[0] = {1688305, 0x00, 0x10, ERRATA_X1_1688305},
+		[1] = {1821534, 0x00, 0x10, ERRATA_X1_1821534},
+		[2] = {1827429, 0x00, 0x10, ERRATA_X1_1827429},
+		[3 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+	}
+},
+#endif /* CORTEX_X1_H_INC */
+
+#if NEOVERSE_N1_H_INC
+{
+	.cpu_partnumber = NEOVERSE_N1_MIDR,
+	.cpu_errata_list = {
+		[0] = {1073348, 0x00, 0x10, ERRATA_N1_1073348},
+		[1] = {1130799, 0x00, 0x20, ERRATA_N1_1130799},
+		[2] = {1165347, 0x00, 0x20, ERRATA_N1_1165347},
+		[3] = {1207823, 0x00, 0x20, ERRATA_N1_1207823},
+		[4] = {1220197, 0x00, 0x20, ERRATA_N1_1220197},
+		[5] = {1257314, 0x00, 0x30, ERRATA_N1_1257314},
+		[6] = {1262606, 0x00, 0x30, ERRATA_N1_1262606},
+		[7] = {1262888, 0x00, 0x30, ERRATA_N1_1262888},
+		[8] = {1275112, 0x00, 0x30, ERRATA_N1_1275112},
+		[9] = {1315703, 0x00, 0x30, ERRATA_N1_1315703},
+		[10] = {1542419, 0x30, 0x40, ERRATA_N1_1542419},
+		[11] = {1868343, 0x00, 0x40, ERRATA_N1_1868343},
+		[12] = {1946160, 0x30, 0x41, ERRATA_N1_1946160},
+		[13] = {2743102, 0x00, 0x41, ERRATA_N1_2743102},
+		[14 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+	}
+},
+#endif /* NEOVERSE_N1_H_INC */
+
+#if NEOVERSE_V1_H_INC
+{
+	.cpu_partnumber = NEOVERSE_V1_MIDR,
+	.cpu_errata_list = {
+		[0] = {1618635, 0x00, 0x0F, ERRATA_V1_1618635},
+		[1] = {1774420, 0x00, 0x10, ERRATA_V1_1774420},
+		[2] = {1791573, 0x00, 0x10, ERRATA_V1_1791573},
+		[3] = {1852267, 0x00, 0x10, ERRATA_V1_1852267},
+		[4] = {1925756, 0x00, 0x11, ERRATA_V1_1925756},
+		[5] = {1940577, 0x10, 0x11, ERRATA_V1_1940577},
+		[6] = {1966096, 0x10, 0x11, ERRATA_V1_1966096},
+		[7] = {2108267, 0x00, 0x11, ERRATA_V1_2108267},
+		[8] = {2139242, 0x00, 0x11, ERRATA_V1_2139242},
+		[9] = {2216392, 0x10, 0x11, ERRATA_V1_2216392},
+		[10] = {2294912, 0x00, 0x11, ERRATA_V1_2294912},
+		[11] = {2372203, 0x00, 0x11, ERRATA_V1_2372203},
+		[12] = {2743093, 0x00, 0x12, ERRATA_V1_2743093},
+		[13] = {2779461, 0x00, 0x12, ERRATA_V1_2779461},
+		[14 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+	}
+},
+#endif /* NEOVERSE_V1_H_INC */
+
+#if CORTEX_A710_H_INC
+{
+	.cpu_partnumber = CORTEX_A710_MIDR,
+	.cpu_errata_list = {
+		[0] = {1987031, 0x00, 0x20, ERRATA_A710_1987031},
+		[1] = {2008768, 0x00, 0x20, ERRATA_A710_2008768},
+		[2] = {2017096, 0x00, 0x20, ERRATA_A710_2017096},
+		[3] = {2055002, 0x10, 0x20, ERRATA_A710_2055002},
+		[4] = {2058056, 0x00, 0x10, ERRATA_A710_2058056},
+		[5] = {2081180, 0x00, 0x20, ERRATA_A710_2081180},
+		[6] = {2083908, 0x20, 0x20, ERRATA_A710_2083908},
+		[7] = {2136059, 0x00, 0x20, ERRATA_A710_2136059},
+		[8] = {2147715, 0x20, 0x20, ERRATA_A710_2147715},
+		[9] = {2216384, 0x00, 0x20, ERRATA_A710_2216384},
+		[10] = {2267065, 0x00, 0x20, ERRATA_A710_2267065},
+		[11] = {2282622, 0x00, 0x21, ERRATA_A710_2282622},
+		[12] = {2291219, 0x00, 0x20, ERRATA_A710_2291219},
+		[13] = {2371105, 0x00, 0x20, ERRATA_A710_2371105},
+		[14] = {2768515, 0x00, 0x21, ERRATA_A710_2768515}
+	}
+},
+#endif /* CORTEX_A710_H_INC */
+
+#if NEOVERSE_N2_H_INC
+{
+	.cpu_partnumber = NEOVERSE_N2_MIDR,
+	.cpu_errata_list = {
+		[0] = {2002655, 0x00, 0x00, ERRATA_N2_2002655},
+		[1] = {2025414, 0x00, 0x00, ERRATA_N2_2025414},
+		[2] = {2067956, 0x00, 0x00, ERRATA_N2_2067956},
+		[3] = {2138953, 0x00, 0x00, ERRATA_N2_2138953},
+		[4] = {2138956, 0x00, 0x00, ERRATA_N2_2138956},
+		[5] = {2138958, 0x00, 0x00, ERRATA_N2_2138958},
+		[6] = {2189731, 0x00, 0x00, ERRATA_N2_2189731},
+		[7] = {2242400, 0x00, 0x00, ERRATA_N2_2242400},
+		[8] = {2242415, 0x00, 0x00, ERRATA_N2_2242415},
+		[9] = {2280757, 0x00, 0x00, ERRATA_N2_2280757},
+		[10] = {2326639, 0x00, 0x00, ERRATA_N2_2326639},
+		[11] = {2376738, 0x00, 0x00, ERRATA_N2_2376738},
+		[12] = {2388450, 0x00, 0x00, ERRATA_N2_2388450},
+		[13] = {2743089, 0x00, 0x02, ERRATA_N2_2743089},
+		[14 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+	}
+},
+#endif /* NEOVERSE_N2_H_INC */
+
+#if CORTEX_X2_H_INC
+{
+	.cpu_partnumber = CORTEX_X2_MIDR,
+	.cpu_errata_list = {
+		[0] = {2002765, 0x00, 0x20, ERRATA_X2_2002765},
+		[1] = {2017096, 0x00, 0x20, ERRATA_X2_2017096},
+		[2] = {2058056, 0x00, 0x20, ERRATA_X2_2058056},
+		[3] = {2081180, 0x00, 0x20, ERRATA_X2_2081180},
+		[4] = {2083908, 0x00, 0x20, ERRATA_X2_2083908},
+		[5] = {2147715, 0x20, 0x20, ERRATA_X2_2147715},
+		[6] = {2216384, 0x00, 0x20, ERRATA_X2_2216384},
+		[7] = {2282622, 0x00, 0x21, ERRATA_X2_2282622},
+		[8] = {2371105, 0x00, 0x21, ERRATA_X2_2371105},
+		[9] = {2768515, 0x00, 0x21, ERRATA_X2_2768515},
+		[10 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+	}
+},
+#endif /* CORTEX_X2_H_INC */
+
+#if CORTEX_A510_H_INC
+{
+	.cpu_partnumber = CORTEX_A510_MIDR,
+	.cpu_errata_list = {
+		[0] = {1922240, 0x00, 0x00, ERRATA_A510_1922240},
+		[1] = {2041909, 0x02, 0x02, ERRATA_A510_2041909},
+		[2] = {2042739, 0x00, 0x02, ERRATA_A510_2042739},
+		[3] = {2172148, 0x00, 0x10, ERRATA_A510_2172148},
+		[4] = {2218950, 0x00, 0x10, ERRATA_A510_2218950},
+		[5] = {2250311, 0x00, 0x10, ERRATA_A510_2250311},
+		[6] = {2288014, 0x00, 0x10, ERRATA_A510_2288014},
+		[7] = {2347730, 0x00, 0x11, ERRATA_A510_2347730},
+		[8] = {2371937, 0x00, 0x11, ERRATA_A510_2371937},
+		[9] = {2666669, 0x00, 0x11, ERRATA_A510_2666669},
+		[10] = {2684597, 0x00, 0x12, ERRATA_A510_2684597},
+		[11 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+	}
+},
+#endif /* CORTEX_A510_H_INC */
+};
+
+/*
+ * Function to do binary search and check for the specific errata ID
+ * in the array of structures specific to the cpu identified.
+ */
+int32_t binary_search(struct em_cpu_list *ptr, uint32_t erratum_id,
+			uint8_t rxpx_val)
+{
+	int low_index = 0U, mid_index = 0U;
+
+	int high_index = MAX_ERRATA_ENTRIES - 1;
+
+	while (low_index <= high_index) {
+		mid_index = (low_index + high_index) / 2;
+		if (erratum_id < ptr->cpu_errata_list[mid_index].em_errata_id) {
+			high_index = mid_index - 1;
+		} else if (erratum_id > ptr->cpu_errata_list[mid_index].em_errata_id) {
+			low_index = mid_index + 1;
+		} else if (erratum_id == ptr->cpu_errata_list[mid_index].em_errata_id) {
+
+			if (RXPX_RANGE(rxpx_val, ptr->cpu_errata_list[mid_index].em_rxpx_lo, \
+				ptr->cpu_errata_list[mid_index].em_rxpx_hi)) {
+					if (ptr->cpu_errata_list[mid_index].errata_enabled) {
+						return EM_HIGHER_EL_MITIGATION;
+					}
+					return EM_AFFECTED;
+			}
+			return EM_NOT_AFFECTED;
+		}
+	}
+	/* no matching errata ID */
+	return EM_UNKNOWN_ERRATUM;
+}
+
+/* Function to check if the errata exists for the specific CPU and rxpx */
+int32_t verify_errata_implemented(uint32_t errata_id, uint32_t forward_flag)
+{
+	/*
+	 * Read MIDR value and extract the revision, variant and partnumber
+	 */
+	static uint32_t midr_val, cpu_partnum;
+	static uint8_t  cpu_rxpx_val;
+	int32_t ret_val = EM_UNKNOWN_ERRATUM;
+
+	/* Determine the number of cpu listed in the cpu list */
+	uint8_t size_cpulist = ARRAY_SIZE(cpu_list);
+
+	/* Read the midr reg to extract cpu, revision and variant info */
+	midr_val = read_midr();
+
+	/* Extract revision and variant from the MIDR register */
+	cpu_rxpx_val = cpu_get_rev_var();
+
+	/* Extract the cpu partnumber and check if the cpu is in the cpu list */
+	cpu_partnum = EXTRACT_PARTNUM(midr_val);
+
+	for (uint8_t i = 0; i < size_cpulist; i++) {
+		cpu_ptr = &cpu_list[i];
+		uint16_t partnum_extracted = EXTRACT_PARTNUM(cpu_ptr->cpu_partnumber);
+
+		if (partnum_extracted == cpu_partnum) {
+			/*
+			 * If the midr value is in the cpu list, binary search
+			 * for the errata ID and specific revision in the list.
+			 */
+			ret_val = binary_search(cpu_ptr, errata_id, cpu_rxpx_val);
+			break;
+		}
+	}
+	return ret_val;
+}
+
+/* Predicate indicating that a function id is part of EM_ABI */
+bool is_errata_fid(uint32_t smc_fid)
+{
+	return ((smc_fid == ARM_EM_VERSION) ||
+		(smc_fid == ARM_EM_FEATURES) ||
+		(smc_fid == ARM_EM_CPU_ERRATUM_FEATURES));
+
+}
+
+bool validate_spsr_mode(void)
+{
+	/* In AArch64, if the caller is EL1, return true */
+
+	#if __aarch64__
+		if (GET_EL(read_spsr_el3()) == MODE_EL1) {
+			return true;
+		}
+		return false;
+	#else
+
+	/* In AArch32, if in system/svc mode, return true */
+		uint8_t read_el_state = GET_M32(read_spsr());
+
+		if ((read_el_state == (MODE32_svc)) || (read_el_state == MODE32_sys)) {
+			return true;
+		}
+		return false;
+	#endif /* __aarch64__ */
+}
+
+uintptr_t errata_abi_smc_handler(uint32_t smc_fid, u_register_t x1,
+				u_register_t x2, u_register_t x3, u_register_t x4,
+				void *cookie, void *handle, u_register_t flags)
+{
+	int32_t ret_id = EM_UNKNOWN_ERRATUM;
+
+	switch (smc_fid) {
+	case ARM_EM_VERSION:
+		SMC_RET1(handle, MAKE_SMCCC_VERSION(
+			EM_VERSION_MAJOR, EM_VERSION_MINOR
+		));
+		break; /* unreachable */
+	case ARM_EM_FEATURES:
+		if (is_errata_fid((uint32_t)x1)) {
+			SMC_RET1(handle, EM_SUCCESS);
+		}
+
+		SMC_RET1(handle, EM_NOT_SUPPORTED);
+		break; /* unreachable */
+	case ARM_EM_CPU_ERRATUM_FEATURES:
+
+		/*
+		 * If the forward flag is greater than zero and the calling EL
+		 * is EL1 in AArch64 or in system mode or svc mode in case of AArch32,
+		 * return Invalid Parameters.
+		 */
+		if (((uint32_t)x2 != 0) && (validate_spsr_mode())) {
+			SMC_RET1(handle, EM_INVALID_PARAMETERS);
+		}
+		ret_id = verify_errata_implemented((uint32_t)x1, (uint32_t)x2);
+		SMC_RET1(handle, ret_id);
+		break; /* unreachable */
+	default:
+		{
+		   WARN("Unimplemented Errata ABI Service Call: 0x%x\n", smc_fid);
+		   SMC_RET1(handle, EM_UNKNOWN_ERRATUM);
+		   break; /* unreachable */
+		}
+	}
+}