feat(arm): add ep_info handoff args setter

Add support for project specific APIs and re-introduce API for setting
TF-A `entry_point_info` arguments following the Arm register convention.

Change-Id: Ic40ef6d34771fe54b152312779620f22bc106640
Signed-off-by: Harrison Mutai <harrison.mutai@arm.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 35c8379..6aa68d9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,7 +19,12 @@
 
 SET(TARGET_GROUP release CACHE STRING "Specify the Build Target [\"release\" by default]")
 
-add_library(tl STATIC "${CMAKE_CURRENT_SOURCE_DIR}/src/transfer_list.c")
+
+add_library(tl
+    STATIC
+        ${PROJECT_SOURCE_DIR}/src/generic/transfer_list.c
+)
+
 target_include_directories(tl
     PUBLIC
         ${PROJECT_SOURCE_DIR}/include
@@ -27,6 +32,10 @@
 
 target_link_libraries(tl PUBLIC cxx_compiler_flags)
 
+if(PROJECT_API)
+    include(${PROJECT_SOURCE_DIR}/cmake/ProjectApi.cmake)
+endif()
+
 if(TARGET_GROUP STREQUAL test)
     include(CTest)
 
diff --git a/cmake/ProjectApi.cmake b/cmake/ProjectApi.cmake
new file mode 100644
index 0000000..c0d338a
--- /dev/null
+++ b/cmake/ProjectApi.cmake
@@ -0,0 +1,10 @@
+set(PROJECT_API_SRC_DIR ${PROJECT_SOURCE_DIR}/src/${PROJECT_API})
+set(PROJECT_API_INC_DIR ${PROJECT_SOURCE_DIR}/include/${PROJECT_API})
+
+if(EXISTS "${PROJECT_API_SRC_DIR}")
+    file(GLOB PROJECT_SOURCES "${PROJECT_API_SRC_DIR}/*.c")
+    target_sources(tl PRIVATE ${PROJECT_SOURCES})
+    target_include_directories(tl PUBLIC ${PROJECT_API_INC_DIR})
+else()
+    message(FATAL_ERROR "Project-specific API '${PROJECT_API}' not found")
+endif()
diff --git a/include/arm/ep_info.h b/include/arm/ep_info.h
new file mode 100644
index 0000000..a76c6ae
--- /dev/null
+++ b/include/arm/ep_info.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright The Transfer List Library Contributors
+ *
+ * SPDX-License-Identifier: MIT OR GPL-2.0-or-later
+ */
+
+#ifndef EP_INFO_H
+#define EP_INFO_H
+
+#include <stdint.h>
+
+struct param_header {
+	uint8_t type; /* type of the structure */
+	uint8_t version; /* version of this structure */
+	uint16_t size; /* size of this structure in bytes */
+	uint32_t attr; /* attributes: unused bits SBZ */
+};
+
+struct aapcs_params {
+#ifdef __aarch64__
+	uint64_t arg0;
+	uint64_t arg1;
+	uint64_t arg2;
+	uint64_t arg3;
+	uint64_t arg4;
+	uint64_t arg5;
+	uint64_t arg6;
+	uint64_t arg7;
+#else
+	uint32_t arg0;
+	uint32_t arg1;
+	uint32_t arg2;
+	uint32_t arg3;
+#endif
+};
+
+struct entry_point_info {
+	struct param_header h;
+	uintptr_t pc;
+	uint32_t spsr;
+#ifndef __aarch64__
+	uintptr_t lr_svc;
+#endif
+	struct aapcs_params args;
+};
+
+#define GET_SPSR_RW(mode) (((mode) >> 0x4U) & 0x1U)
+
+#endif
\ No newline at end of file
diff --git a/include/transfer_list.h b/include/transfer_list.h
index 1e4bd7b..0d9b5a3 100644
--- a/include/transfer_list.h
+++ b/include/transfer_list.h
@@ -9,6 +9,7 @@
 
 #include <assert.h>
 #include <stdbool.h>
+#include <stddef.h>
 #include <stdint.h>
 
 #define TRANSFER_LIST_SIGNATURE 0x4a0fb10b
@@ -163,5 +164,9 @@
 struct transfer_list_entry *transfer_list_find(struct transfer_list_header *tl,
 					       uint32_t tag_id);
 
+struct entry_point_info *
+transfer_list_set_handoff_args(struct transfer_list_header *tl,
+			       struct entry_point_info *ep_info);
+
 #endif /* __ASSEMBLER__ */
 #endif /* TRANSFER_LIST_H */
diff --git a/src/arm/ep_info.c b/src/arm/ep_info.c
new file mode 100644
index 0000000..f6b26be
--- /dev/null
+++ b/src/arm/ep_info.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright The Transfer List Library Contributors
+ *
+ * SPDX-License-Identifier: MIT OR GPL-2.0-or-later
+ */
+
+#include <ep_info.h>
+#include <stddef.h>
+#include <transfer_list.h>
+
+/**
+ * Set handoff arguments in the entry point info structure.
+ *
+ * This function populates the provided entry point info structure with data
+ * from the transfer list.
+ *
+ * @param[in] tl        Pointer to the transfer list.
+ * @param[out] ep_info  Pointer to the entry point info structure to populate.
+ *
+ * @return Pointer to the populated entry point info structure.
+ */
+struct entry_point_info *
+transfer_list_set_handoff_args(struct transfer_list_header *tl,
+			       struct entry_point_info *ep_info)
+{
+	struct transfer_list_entry *te = NULL;
+	void *dt = NULL;
+
+	if (!ep_info || !tl || transfer_list_check_header(tl) == TL_OPS_NON) {
+		return NULL;
+	}
+
+	te = transfer_list_find(tl, TL_TAG_FDT);
+	dt = transfer_list_entry_data(te);
+
+#ifdef __aarch64__
+	if (GET_SPSR_RW(ep_info->spsr) == 0U) {
+		ep_info->args.arg0 = (uintptr_t)dt;
+		ep_info->args.arg1 = TRANSFER_LIST_HANDOFF_X1_VALUE(
+			REGISTER_CONVENTION_VERSION);
+		ep_info->args.arg2 = 0;
+	} else
+#endif
+	{
+		ep_info->args.arg0 = 0;
+		ep_info->args.arg1 = TRANSFER_LIST_HANDOFF_R1_VALUE(
+			REGISTER_CONVENTION_VERSION);
+		ep_info->args.arg2 = (uintptr_t)dt;
+	}
+
+	ep_info->args.arg3 = (uintptr_t)tl;
+
+	return ep_info;
+}
diff --git a/src/transfer_list.c b/src/generic/transfer_list.c
similarity index 99%
rename from src/transfer_list.c
rename to src/generic/transfer_list.c
index 2aa584c..2e681dc 100644
--- a/src/transfer_list.c
+++ b/src/generic/transfer_list.c
@@ -47,7 +47,7 @@
 		printf("hdr_size   0x%x\n", te->hdr_size);
 		printf("data_size  0x%x\n", te->data_size);
 		printf("data_addr  0x%lx\n",
-		     (unsigned long)transfer_list_entry_data(te));
+		       (unsigned long)transfer_list_entry_data(te));
 	}
 }