feat(app): add code to parse app bin headers

Add code in lib/el0_app that is able to iterate over the attached app
bins, and save the header addresses.

Modify the boot code so that the parsing function in lib/el0_app is
called

Also update the build system so that the bin gnerating/bundling scripts
are called on the apps

Change-Id: I97c93edc58bd0fea25770f1d2001c1b2742e1f13
Signed-off-by: Mate Toth-Pal <mate.toth-pal@arm.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0d94f41..c231396 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -107,6 +107,7 @@
 # Recurse into the various component subdirectories
 #
 add_subdirectory("lib")
+add_subdirectory("app")
 add_subdirectory("runtime")
 
 if(RMM_DOCS)
@@ -114,25 +115,33 @@
 endif()
 
 #
-# Copy 'rmm-runtime' executable to 'build/$<CONFIG>/rmm.elf'.
+# Copy 'rmm-runtime' executable to 'build/$<CONFIG>/rmm_core.elf'.
 #
 
 set(ARTEFACT_DIR "${CMAKE_BINARY_DIR}/$<CONFIG>")
 add_custom_command(
     COMMAND ${CMAKE_COMMAND} -E make_directory "${ARTEFACT_DIR}"
-    COMMAND "${CMAKE_COMMAND}" -E copy_if_different "$<TARGET_FILE:rmm-runtime>" "${ARTEFACT_DIR}/rmm.elf"
-    OUTPUT rmm.elf
+    COMMAND "${CMAKE_COMMAND}" -E copy_if_different "$<TARGET_FILE:rmm-runtime>" "${ARTEFACT_DIR}/rmm_core.elf"
+    OUTPUT rmm_core.elf
     DEPENDS rmm-runtime)
 
 #
+# Create rmm.elf as a copy of rmm_core.elf to keep CI working
+#
+add_custom_command(
+    COMMAND "${CMAKE_COMMAND}" -E copy ${ARTEFACT_DIR}/rmm_core.elf ${ARTEFACT_DIR}/rmm.elf
+    OUTPUT rmm.elf
+    DEPENDS rmm_core.elf)
+
+#
 # Create the flat binary using whatever tool comes with the toolchain.
 #
 
 if(CMAKE_OBJCOPY)
     add_custom_command(
-        COMMAND "${CMAKE_OBJCOPY}" -O binary "${ARTEFACT_DIR}/rmm.elf" "${ARTEFACT_DIR}/rmm.img"
-        OUTPUT rmm.img
-        DEPENDS rmm.elf)
+        COMMAND "${CMAKE_OBJCOPY}" -O binary "${ARTEFACT_DIR}/rmm_core.elf" "${ARTEFACT_DIR}/rmm_core.img"
+        OUTPUT rmm_core.img
+        DEPENDS rmm_core.elf)
 endif()
 
 #
@@ -141,21 +150,36 @@
 
 if(CMAKE_OBJDUMP)
     add_custom_command(
-        COMMAND "${CMAKE_OBJDUMP}" -dxS "${ARTEFACT_DIR}/rmm.elf" > "${ARTEFACT_DIR}/rmm.dump"
-        OUTPUT rmm.dump
-        DEPENDS rmm.elf)
+        COMMAND "${CMAKE_OBJDUMP}" -dxS "${ARTEFACT_DIR}/rmm_core.elf" > "${ARTEFACT_DIR}/rmm_core.dump"
+        OUTPUT rmm_core.dump
+        DEPENDS rmm_core.elf)
 endif()
 
 #
-# Copy 'rmm-runtime.map' to 'build/$<CONFIG>/rmm.map'
+# Copy 'rmm-runtime.map' to 'build/$<CONFIG>/rmm_core.map'
 #
 
 add_custom_command(
-    COMMAND "${CMAKE_COMMAND}" -E copy_if_different "$<TARGET_FILE:rmm-runtime>.map" "${ARTEFACT_DIR}/rmm.map"
-    OUTPUT rmm.map
+    COMMAND "${CMAKE_COMMAND}" -E copy_if_different "$<TARGET_FILE:rmm-runtime>.map" "${ARTEFACT_DIR}/rmm_core.map"
+    OUTPUT rmm_core.map
     DEPENDS rmm-runtime)
 
-add_custom_target(rmm ALL DEPENDS rmm.img rmm.dump rmm.elf rmm.map)
+if(NOT RMM_ARCH STREQUAL fake_host)
+    set(RMM_IMG "rmm.img")
+    find_program(BUNDLE_APP_RMM "bundle_app_rmm.py"
+        PATHS ${CMAKE_SOURCE_DIR}
+        PATH_SUFFIXES app
+        DOC "bundle_app_rmm.py")
+
+    set(BUNDLE_COMMAND_OUTPUT "${ARTEFACT_DIR}/bundle_app_out.txt")
+    add_custom_command(
+        # TODO: Call ${BUNDLE_APP_RMM} instead of copy if an app is added.
+        COMMAND "${CMAKE_COMMAND}" -E copy ${ARTEFACT_DIR}/rmm_core.img ${ARTEFACT_DIR}/${RMM_IMG} 2> ${BUNDLE_COMMAND_OUTPUT}
+        OUTPUT ${RMM_IMG}
+        DEPENDS rmm_core.img)
+endif()
+
+add_custom_target(rmm ALL DEPENDS rmm_core.img rmm_core.dump rmm_core.elf rmm.elf rmm_core.map ${RMM_IMG})
 
 #
 # Set up additional tooling.
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
new file mode 100644
index 0000000..287878a
--- /dev/null
+++ b/app/CMakeLists.txt
@@ -0,0 +1,19 @@
+#
+# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+#
+
+# List of libraries that are included in the app stub library
+set(RMM_EL2_STUB_LIBRARIES "")
+
+add_subdirectory("common")
+
+# List of apps to be packaged to final binary
+# The contents of the list is populated by the CMakeLists in the subdirectories
+set(EL0_APP_BIN_LIST "")
+
+set(EL0_APP_BIN_LIST ${EL0_APP_BIN_LIST} PARENT_SCOPE)
+
+add_library(rmm-el2-stub INTERFACE)
+target_link_libraries(rmm-el2-stub
+    INTERFACE ${RMM_EL2_STUB_LIBRARIES})
diff --git a/app/common/CMakeLists.txt b/app/common/CMakeLists.txt
new file mode 100644
index 0000000..2747a3f
--- /dev/null
+++ b/app/common/CMakeLists.txt
@@ -0,0 +1,8 @@
+#
+# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+#
+
+add_subdirectory("framework")
+
+set(RMM_EL2_STUB_LIBRARIES ${RMM_EL2_STUB_LIBRARIES} PARENT_SCOPE)
diff --git a/app/common/framework/CMakeLists.txt b/app/common/framework/CMakeLists.txt
new file mode 100644
index 0000000..dc24fe3
--- /dev/null
+++ b/app/common/framework/CMakeLists.txt
@@ -0,0 +1,25 @@
+#
+# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+#
+
+add_library(rmm-app-cmn-fw)
+
+target_link_libraries(rmm-app-cmn-fw
+    PRIVATE
+        rmm-lib-arch
+        rmm-lib-console
+        rmm-lib-slot_buf)
+
+target_include_directories(rmm-app-cmn-fw
+    PRIVATE "src"
+    PUBLIC "include"
+           "include/${RMM_ARCH}")
+
+target_sources(rmm-app-cmn-fw
+    PRIVATE
+        "src/${RMM_ARCH}/app_header.c"
+    )
+
+list(APPEND RMM_EL2_STUB_LIBRARIES "rmm-app-cmn-fw")
+set(RMM_EL2_STUB_LIBRARIES ${RMM_EL2_STUB_LIBRARIES} PARENT_SCOPE)
diff --git a/app/common/framework/include/aarch64/app_header_structures.h b/app/common/framework/include/aarch64/app_header_structures.h
new file mode 100644
index 0000000..341143e
--- /dev/null
+++ b/app/common/framework/include/aarch64/app_header_structures.h
@@ -0,0 +1,66 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+
+#ifndef APP_HEADER_STRUCTURES_H
+#define APP_HEADER_STRUCTURES_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <utils_def.h>
+
+#define APP_NAME_BUF_SIZE	32U
+#define APP_HEADER_SIZE		GRANULE_SIZE
+
+struct app_header {
+	/* When the final rmm binary is constructed, an initial bl instruction
+	 * is inserted at the beginning of the img file that branches to the
+	 * offset of the function rmm_entry.
+	 * The first 4 bytes of the padding field is modified to hold the bl
+	 * instruction. This technique allows image packing logic to avoid
+	 * adding an extra 4K alignment to the overall image and keep the
+	 * alignments intact.
+	 * Section offsets in this structures are calculated from the byte after
+	 * the page containing the header.
+	 * This structure needs to match the header format in app/gen_app_bin.py
+	 * file.
+	 */
+	uint64_t padding;
+
+	uint64_t app_header_magic;
+	uint32_t app_header_version;
+	const char app_name[APP_NAME_BUF_SIZE]; /* Null terminated string */
+	uint32_t app_id;
+	uint64_t app_len; /* including header */
+
+	uintptr_t section_text_offset;
+	uintptr_t section_text_va;
+	size_t section_text_size;
+
+	uintptr_t section_rodata_offset;
+	uintptr_t section_rodata_va;
+	size_t section_rodata_size;
+
+	uintptr_t section_data_offset;
+	uintptr_t section_data_va;
+	size_t section_data_size;
+
+	/* Following are not allocated in the bin */
+	uintptr_t section_bss_va;
+	size_t section_bss_size;
+
+	uintptr_t section_shared_va;
+
+	size_t stack_page_count;
+
+	size_t heap_page_count;
+
+	/* Reserve a few dwords for later extending the header */
+	uint64_t reserved[10];
+
+	uint64_t app_header_magic2;
+};
+COMPILER_ASSERT(sizeof(struct app_header) <= APP_HEADER_SIZE);
+
+#endif /* APP_HEADER_STRUCTURES_H */
diff --git a/app/common/framework/include/app.h b/app/common/framework/include/app.h
new file mode 100644
index 0000000..a1fc419
--- /dev/null
+++ b/app/common/framework/include/app.h
@@ -0,0 +1,11 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+
+#ifndef APP_H
+#define APP_H
+
+#define GRANULE_COUNT(size)	(round_up(size, GRANULE_SIZE) / GRANULE_SIZE)
+
+#endif /* APP_H */
diff --git a/app/common/framework/include/app_header.h b/app/common/framework/include/app_header.h
new file mode 100644
index 0000000..3f87360
--- /dev/null
+++ b/app/common/framework/include/app_header.h
@@ -0,0 +1,46 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+
+#ifndef APP_HEADER_H
+#define APP_HEADER_H
+
+#ifndef __ASSEMBLER__
+#include <app_header_structures.h>
+#endif
+
+#define APP_COUNT		0U
+
+#ifndef __ASSEMBLER__
+
+/*
+ * Return the RMM image start address.
+ *
+ * Return:
+ *	- The physical address of the start of the RMM image.
+ */
+uint64_t app_get_rmm_start(void);
+
+/*
+ * Return a pointer to the app_header structure at an index.
+ *
+ * Arguments:
+ *	- app_idx: The index of the app
+ *	- app_header: Out parameter, pointer to the app header of the `app_idx`.
+ *
+ * Return:
+ *	- 0 on success or a negative POSIX error otherwise.
+ */
+int app_get_header_ptr_at_index(unsigned long app_index, struct app_header **app_header);
+
+/*
+ * Initialise the internal app header structures.
+ *
+ * This function must be called once during cold boot to initialise the internal
+ * app header structures.
+ */
+void app_info_setup(void);
+#endif
+
+#endif /* APP_HEADER_H */
diff --git a/app/common/framework/src/aarch64/app_header.c b/app/common/framework/src/aarch64/app_header.c
new file mode 100644
index 0000000..e171d42
--- /dev/null
+++ b/app/common/framework/src/aarch64/app_header.c
@@ -0,0 +1,236 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+
+#include <app.h>
+#include <app_header.h>
+#include <app_header_private.h>
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <stddef.h>
+#include <utils_def.h>
+
+static struct app_header *app_header_ptrs[APP_COUNT];
+static uint64_t rmm_start_address;
+static uint64_t rmm_core_start_address;
+
+/* The function is called from assembly */
+void app_save_rmm_entry_info(uint64_t rmm_start, uint64_t rmm_core_start);
+
+void app_save_rmm_entry_info(uint64_t rmm_start, uint64_t rmm_core_start)
+{
+	if ((rmm_start == 0U) || (rmm_core_start < rmm_start)) {
+		panic();
+	}
+	rmm_start_address = rmm_start;
+	rmm_core_start_address = rmm_core_start;
+}
+
+uint64_t app_get_rmm_start(void)
+{
+	return rmm_start_address;
+}
+
+int app_get_index(unsigned long app_id, size_t *app_index)
+{
+	size_t i;
+
+	assert(app_index != NULL);
+	/* cppcheck-suppress unsignedLessThanZero
+	 * As i is unsigned, i < APP_COUNT cannot be true when APP_COUNT is 0.
+	 */
+	/* coverity[no_effect:SUPPRESS] */
+	/* coverity[misra_c_2012_rule_14_3_violation:SUPPRESS] */
+	for (i = 0; i < APP_COUNT; ++i) {
+		/* coverity[deadcode:SUPPRESS] */
+		/* coverity[misra_c_2012_rule_14_3_violation:SUPPRESS] */
+		if (app_header_ptrs[i]->app_id == app_id) {
+			*app_index = i;
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+int app_get_header_ptr(unsigned long app_id, struct app_header **app_header)
+{
+	size_t app_index;
+
+	assert(app_header != NULL);
+	if (app_get_index(app_id, &app_index) < 0) {
+		return -EINVAL;
+	}
+
+	*app_header = app_header_ptrs[app_index];
+
+	return 0;
+}
+
+int app_get_header_ptr_at_index(unsigned long app_index, struct app_header **app_header)
+{
+	/* cppcheck-suppress unsignedPositive
+	 * As app_index is unsigned, app_index >= APP_COUNT is always true if
+	 * APP_COUNT is zero.
+	 */
+	/* coverity[no_effect:SUPPRESS] */
+	/* coverity[misra_c_2012_rule_14_3_violation:SUPPRESS] */
+	if (app_index >= APP_COUNT) {
+		return -EINVAL;
+	}
+	/* coverity[deadcode:SUPPRESS] */
+	/* coverity[misra_c_2012_rule_14_3_violation:SUPPRESS] */
+	*app_header = app_header_ptrs[app_index];
+	return 0;
+}
+
+size_t app_get_required_granule_count_from_header(struct app_header *app_header)
+{
+	assert(app_header != NULL);
+
+	return app_header->stack_page_count +
+	       app_header->heap_page_count +
+	       1U + /* Shared page */
+	       1U + /* App register context */
+	       1U;  /* Page Table (assuming single page) */
+}
+
+static void dump_header(struct app_header *app_header)
+{
+
+	INFO("    app_header_magic: #1=%016lx, #2=%016lx\n",
+		app_header->app_header_magic, app_header->app_header_magic2);
+	if ((app_header->app_name[APP_NAME_BUF_SIZE - 1U] == '\0')) {
+		INFO("    app_name               =   %s\n", app_header->app_name);
+	} else {
+		INFO("    app_name INVALID\n");
+	}
+	INFO("    app_header_version     =   0x%16x\n",
+		app_header->app_header_version);
+	INFO("    app_id                 =     %16d\n", app_header->app_id);
+	INFO("    app_len                =   0x%16lx\n", app_header->app_len);
+	INFO("    required granule_count =     %16lu\n\n",
+		app_get_required_granule_count_from_header(app_header));
+
+	INFO("    section  |   offset |               va |     size\n");
+	INFO("    ---------|----------|------------------|---------\n");
+	INFO("    text     | %8lx | %16lx | %8lx\n",
+		app_header->section_text_offset,
+		app_header->section_text_va,
+		app_header->section_text_size);
+	INFO("    rodata   | %8lx | %16lx | %8lx\n",
+		app_header->section_rodata_offset,
+		app_header->section_rodata_va,
+		app_header->section_rodata_size);
+	INFO("    data     | %8lx | %16lx | %8lx\n",
+		app_header->section_data_offset,
+		app_header->section_data_va,
+		app_header->section_data_size);
+	INFO("    bss      |      N/A | %16lx | %8lx\n",
+		app_header->section_bss_va,
+		app_header->section_bss_size);
+	INFO("    shared   |      N/A | %16lx | %8lx\n",
+		app_header->section_shared_va,
+		GRANULE_SIZE);
+	INFO("    stack    |      N/A |              N/A | %8lx\n",
+		app_header->stack_page_count * GRANULE_SIZE);
+	INFO("    heap     |      N/A |              N/A | %8lx\n\n",
+		app_header->heap_page_count * GRANULE_SIZE);
+}
+
+static int sanity_check_header(struct app_header *app_header)
+{
+	if (
+		/* Version */
+		(app_header->app_header_version !=
+			(((uint32_t)HEADER_VERSION_MAJOR << 16U) | HEADER_VERSION_MINOR)) ||
+		/* App name is NULL terminated */
+		(app_header->app_name[APP_NAME_BUF_SIZE - 1U] != '\0') ||
+		/* Alignments */
+		(!GRANULE_ALIGNED(app_header->app_len)) ||
+		(!GRANULE_ALIGNED(app_header->section_text_offset)) ||
+		(!GRANULE_ALIGNED(app_header->section_text_va)) ||
+		(!GRANULE_ALIGNED(app_header->section_text_size)) ||
+		(!GRANULE_ALIGNED(app_header->section_rodata_offset)) ||
+		(!GRANULE_ALIGNED(app_header->section_rodata_va)) ||
+		(!GRANULE_ALIGNED(app_header->section_rodata_size)) ||
+		(!GRANULE_ALIGNED(app_header->section_data_offset)) ||
+		(!GRANULE_ALIGNED(app_header->section_data_va)) ||
+		(!GRANULE_ALIGNED(app_header->section_data_size)) ||
+		(!GRANULE_ALIGNED(app_header->section_bss_va)) ||
+		(!GRANULE_ALIGNED(app_header->section_bss_size)) ||
+		(!GRANULE_ALIGNED(app_header->section_shared_va)) ||
+		/* Magic */
+		(app_header->app_header_magic != APP_HEADER_MAGIC) ||
+		(app_header->app_header_magic2 != APP_HEADER_MAGIC) ||
+		/* Section overlap / order */
+		((app_header->section_text_offset + app_header->section_text_size) !=
+			app_header->section_rodata_offset) ||
+		((app_header->section_rodata_offset + app_header->section_rodata_size) !=
+			app_header->section_data_offset) ||
+		/* App va space is expected to be contiguous */
+		((app_header->section_text_va + app_header->section_text_size) !=
+			app_header->section_rodata_va) ||
+		((app_header->section_rodata_va + app_header->section_rodata_size) !=
+			app_header->section_data_va) ||
+		((app_header->section_data_va + app_header->section_data_size) !=
+			app_header->section_bss_va) ||
+		((app_header->section_bss_va + app_header->section_bss_size) !=
+			app_header->section_shared_va) ||
+		/* app bin is long enough */
+		((app_header->section_data_offset + app_header->section_data_size +
+			APP_HEADER_SIZE) != app_header->app_len)
+	) {
+		return 1;
+	}
+	return 0;
+}
+
+void app_info_setup(void)
+{
+	unsigned long i;
+	struct app_header *app_header = (struct app_header *)rmm_start_address;
+
+	INFO("Loading apps. RMM Core start address: 0x%lx\n", rmm_core_start_address);
+
+	/* cppcheck-suppress unsignedLessThanZero
+	 * As i is unsigned, i < APP_COUNT cannot be true when APP_COUNT is 0.
+	 */
+	/* coverity[no_effect:SUPPRESS] */
+	/* coverity[misra_c_2012_rule_14_3_violation:SUPPRESS] */
+	for (i = 0; i < APP_COUNT; ++i) {
+		/* coverity[deadcode:SUPPRESS] */
+		/* coverity[misra_c_2012_rule_14_3_violation:SUPPRESS] */
+		if ((uintptr_t)app_header >= (uintptr_t)rmm_core_start_address) {
+			ERROR("App header overlaps with RMM binary\n");
+			panic();
+		}
+
+		INFO("App header @%lu (at 0x%lx):\n", i, (uintptr_t)app_header);
+		dump_header(app_header);
+
+		if (sanity_check_header(app_header) != 0) {
+			ERROR("App header sanity check failed\n");
+			panic();
+		}
+
+		app_header_ptrs[i] = app_header;
+
+		/* Check overflow */
+		if ((UINT64_MAX - app_header->app_len) < (uintptr_t)app_header) {
+			panic();
+		}
+		app_header = (struct app_header *)&(((char *)app_header)[app_header->app_len]);
+	}
+
+	if ((uintptr_t)app_header != (uintptr_t)rmm_core_start_address) {
+		/* There are extra bytes after the last header before the
+		 * rmm_entry function. Maybe there were more apps provided to
+		 * the bundle app than APP_COUNT?
+		 */
+		ERROR("Unexpected bytes between last app and RMM Core start\n");
+		panic();
+	}
+}
diff --git a/app/common/framework/src/app_header_private.h b/app/common/framework/src/app_header_private.h
new file mode 100644
index 0000000..de51c06
--- /dev/null
+++ b/app/common/framework/src/app_header_private.h
@@ -0,0 +1,66 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+
+#ifndef APP_HEADER_PRIVATE_H
+#define APP_HEADER_PRIVATE_H
+
+#ifndef __ASSEMBLER__
+#include <app_header_structures.h>
+#include <stddef.h>
+#include <stdint.h>
+#endif
+
+#define APP_HEADER_MAGIC	0x000E10ABB4EAD000UL  /* El0 APP HEAD */
+
+#define HEADER_VERSION_MAJOR	0U
+#define HEADER_VERSION_MINOR	1U
+#define HEADER_VERSION		((HEADER_VERSION_MAJOR << 16) | HEADER_VERSION_MINOR)
+
+#ifndef __ASSEMBLER__
+
+/*
+ * Get the index of the app from the app_id.
+ *
+ * Apps are indexed starting from 0, in the same order they appear in the RMM
+ * image.
+ *
+ * Arguments:
+ *	- app_id: The id of the app.
+ *	- app_idx: Out parameter, the index of the app with `app_id`.
+ *
+ * Return:
+ *	- 0 on success or a negative POSIX error otherwise.
+ */
+int app_get_index(unsigned long app_id, size_t *app_index);
+
+/*
+ * Return a pointer to the app_header structure of an app of an app_id.
+ *
+ * Arguments:
+ *	- app_id: The id of the app.
+ *	- app_header: Out parameter, pointer to the app header of the `app_id`.
+ *
+ * Return:
+ *	- 0 on success or a negative POSIX error otherwise.
+ */
+int app_get_header_ptr(unsigned long app_id, struct app_header **app_header);
+
+/*
+ * Get the number of instance specific pages that are necessary for the app.
+ *
+ * This can be used to get the number of instance specific granules necessary
+ * to instantiate an application that is identified by the app_header.
+ *
+ * Arguments:
+ *	- app_header: pointer to the app header.
+ *
+ * Return:
+ *	- The number of granules necessary.
+ */
+size_t app_get_required_granule_count_from_header(struct app_header *app_header);
+
+#endif
+
+#endif /* APP_HEADER_PRIVATE_H */
diff --git a/cmake/Modules/UnitTestFramework.cmake b/cmake/Modules/UnitTestFramework.cmake
index 48d3cf8..a6457f7 100644
--- a/cmake/Modules/UnitTestFramework.cmake
+++ b/cmake/Modules/UnitTestFramework.cmake
@@ -68,7 +68,7 @@
     add_custom_target(run-unittests
         WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
         COMMAND ctest "${CMAKE_CTEST_ARGUMENTS}" -C "$<CONFIG>"
-        DEPENDS rmm.elf rmm.map
+        DEPENDS rmm_core.elf rmm_core.map
     )
 endif()
 
@@ -115,7 +115,7 @@
             # Run all tests at once
             add_test(NAME "${arg_NAME}"
                     WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
-                    COMMAND ${CMAKE_BINARY_DIR}/$<CONFIG>/rmm.elf
+                    COMMAND ${CMAKE_BINARY_DIR}/$<CONFIG>/rmm_core.elf
                             -g${arg_NAME}
                             -r${arg_ITERATIONS})
         else()
@@ -124,7 +124,7 @@
             foreach(TEST IN LISTS arg_RUN_ISOLATED_TESTS)
                 add_test(NAME "${arg_NAME}::${TEST}"
                          WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
-                         COMMAND ${CMAKE_BINARY_DIR}/$<CONFIG>/rmm.elf
+                         COMMAND ${CMAKE_BINARY_DIR}/$<CONFIG>/rmm_core.elf
                                  -sg${arg_NAME}
                                  -sn${TEST})
             endforeach()
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index a3a17b7..e82c232 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -204,7 +204,7 @@
 
     cmake -DRMM_CONFIG=host_defcfg -DHOST_VARIANT=host_test -DCMAKE_BUILD_TYPE=Debug -S ${RMM_SOURCE_DIR} -B ${RMM_BUILD_DIR}
     cmake --build ${RMM_BUILD_DIR} -- build -j
-    ${RMM_BUILD_DIR}/Debug/rmm.elf -gxlat -v -r${NUMBER_OF_TEST_ITERATIONS}
+    ${RMM_BUILD_DIR}/Debug/rmm_core.elf -gxlat -v -r${NUMBER_OF_TEST_ITERATIONS}
 
 16. Generate Coverage Report.
 
@@ -225,7 +225,7 @@
 
     cmake -DRMM_CONFIG=host_defcfg -DHOST_VARIANT=host_test -DRMM_COVERAGE=ON -DCMAKE_BUILD_TYPE=Debug -S ${RMM_SOURCE_DIR} -B ${RMM_BUILD_DIR}
     cmake --build ${RMM_BUILD_DIR} -- build -j
-    ${RMM_BUILD_DIR}/Debug/rmm.elf -gxlat
+    ${RMM_BUILD_DIR}/Debug/rmm_core.elf -gxlat
     cmake --build ${RMM_BUILD_DIR} -- run-coverage
 
 Run coverage analysis on the `host_build` variant of host platform:
@@ -233,7 +233,7 @@
 .. code-block:: bash
 
     cmake -DRMM_CONFIG=host_defcfg -DHOST_VARIANT=host_build -DRMM_COVERAGE=ON -DCMAKE_BUILD_TYPE=Debug -S ${RMM_SOURCE_DIR} -B ${RMM_BUILD_DIR}
-    ${RMM_BUILD_DIR}/Debug/rmm.elf
+    ${RMM_BUILD_DIR}/Debug/rmm_core.elf
     cmake --build ${RMM_BUILD_DIR} -- run-coverage
 
 The above commands will automatically generate the HTML coverage report in folder
diff --git a/docs/getting_started/getting-started.rst b/docs/getting_started/getting-started.rst
index 1c2b7d1..0a49039 100644
--- a/docs/getting_started/getting-started.rst
+++ b/docs/getting_started/getting-started.rst
@@ -315,7 +315,7 @@
 |RMM|.
 
 If |RMM| is built for the `fake_host` architecture
-(see :ref:`RMM Fake Host Build`), then the generated `rmm.elf` binary can
+(see :ref:`RMM Fake Host Build`), then the generated `rmm_core.elf` binary can
 run natively on the Host machine. It does this by emulating parts of the system
 as described in :ref:`RMM Fake host architecture` design.
 
diff --git a/plat/common/CMakeLists.txt b/plat/common/CMakeLists.txt
index 31ec794..bc4f93f 100644
--- a/plat/common/CMakeLists.txt
+++ b/plat/common/CMakeLists.txt
@@ -9,7 +9,8 @@
 add_library(rmm-plat-common)
 
 target_link_libraries(rmm-plat-common
-    PRIVATE rmm-lib)
+    PRIVATE rmm-lib
+            rmm-el2-stub)
 
 #
 # PLAT_CMN_CTX_MAX_XLAT_TABLES is allowed to be 0, and in case when there are
diff --git a/plat/common/src/plat_common_init.c b/plat/common/src/plat_common_init.c
index 7ad9986..719da85 100644
--- a/plat/common/src/plat_common_init.c
+++ b/plat/common/src/plat_common_init.c
@@ -5,6 +5,7 @@
 
 #ifndef CBMC
 
+#include <app_header.h>
 #include <arch_helpers.h>
 #include <assert.h>
 #include <buffer.h>
@@ -37,6 +38,19 @@
 #define RMM_RO_SIZE		(RMM_RO_END - RMM_RO_START)
 #define RMM_RW_SIZE		(RMM_RW_END - RMM_RW_START)
 
+/* Map the application binary data as RO. This is necessary so that the RMM can
+ * simply access the app header structures. Execution is not enabled as RMM is
+ * never intended to run app code in EL2. Write is not enabled as data pages
+ * might only be written from EL0, and for that purpose a separate mapping is
+ * created.
+ */
+#if APP_COUNT != 0
+#define RMM_APP			MAP_REGION_FLAT(			\
+					0,				\
+					0,				\
+					(MT_RO_DATA | MT_REALM))
+#endif
+
 #define RMM_CODE		MAP_REGION_FLAT(			\
 					RMM_CODE_START,			\
 					RMM_CODE_SIZE,			\
@@ -75,8 +89,17 @@
 					0,				\
 					(MT_DEVICE | MT_RW | MT_REALM))
 
+
+#if APP_COUNT == 0
 /* Number of common memory mapping regions */
 #define COMMON_REGIONS		(4U)
+#define REGION_RMM_SHARED_IDX	3
+#else
+/* Number of common memory mapping regions */
+#define COMMON_REGIONS		(5U)
+#define REGION_RMM_APP_IDX	0
+#define REGION_RMM_SHARED_IDX	4
+#endif
 
 /* Total number of memory mapping regions */
 #define TOTAL_MMAP_REGIONS	(COMMON_REGIONS + PLAT_CMN_EXTRA_MMAP_REGIONS)
@@ -118,9 +141,15 @@
 {
 	int ret;
 	unsigned int plat_offset, cmn_offset;
+#if APP_COUNT != 0
+	uint64_t rmm_img_start = app_get_rmm_start();
+#endif
 
 	/* Common regions sorted by ascending VA */
 	struct xlat_mmap_region regions[COMMON_REGIONS] = {
+#if APP_COUNT != 0
+		RMM_APP,
+#endif
 		RMM_CODE,
 		RMM_RO,
 		RMM_RW,
@@ -135,9 +164,16 @@
 		return -EINVAL;
 	}
 
+#if APP_COUNT != 0
+	/* setup the parameters for the application binary data */
+	regions[REGION_RMM_APP_IDX].base_pa = rmm_img_start;
+	regions[REGION_RMM_APP_IDX].base_va = rmm_img_start;
+	regions[REGION_RMM_APP_IDX].size = RMM_CODE_START - rmm_img_start;
+#endif
+
 	/* Setup the parameters of the shared area */
-	regions[3].base_pa = get_shared_buf_pa();
-	regions[3].size = rmm_el3_ifc_get_shared_buf_size();
+	regions[REGION_RMM_SHARED_IDX].base_pa = get_shared_buf_pa();
+	regions[REGION_RMM_SHARED_IDX].size = rmm_el3_ifc_get_shared_buf_size();
 
 	plat_offset = COMMON_REGIONS;
 	cmn_offset = 0U;
diff --git a/runtime/core/aarch64/head.S b/runtime/core/aarch64/head.S
index f89232f..44fe582 100644
--- a/runtime/core/aarch64/head.S
+++ b/runtime/core/aarch64/head.S
@@ -3,6 +3,7 @@
  * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
  */
 
+#include <app_header.h>
 #include <arch.h>
 #include <asm_macros.S>
 #include <rmm_el3_ifc.h>
@@ -21,6 +22,7 @@
 	mov	x21, x1
 	mov	x22, x2
 	mov	x23, x3
+	mov	x24, lr
 
 	/* Disable DIT */
 	msr	DIT, xzr
@@ -124,6 +126,20 @@
 	bl	memset
 
 	/*
+	 * Save RMM image addresses.
+	 */
+	adrp	x1, rmm_entry /* rmm_entry is page alined */
+#ifndef APP_COUNT
+#error APP_COUNT is not defined
+#endif
+#if APP_COUNT == 0
+	mov	x0, x1
+#else
+	sub	x0, x24, #4
+#endif
+	bl 	app_save_rmm_entry_info
+
+	/*
 	 * Restore args received from previous BL image
 	 */
 	mov	x0, x20
diff --git a/runtime/core/init.c b/runtime/core/init.c
index a89f2ed..21b135c 100644
--- a/runtime/core/init.c
+++ b/runtime/core/init.c
@@ -3,6 +3,7 @@
  * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
  */
 
+#include <app_header.h>
 #include <arch_features.h>
 #include <attestation.h>
 #include <buffer.h>
@@ -107,6 +108,8 @@
 	       RSI_ABI_VERSION_GET_MAJOR(rsi_revision),
 	       RSI_ABI_VERSION_GET_MINOR(rsi_revision));
 
+	app_info_setup();
+
 	rmm_warmboot_main();
 
 	simd_init();
diff --git a/toolchains/common.cmake b/toolchains/common.cmake
index 1bd2b91..c3eb449 100644
--- a/toolchains/common.cmake
+++ b/toolchains/common.cmake
@@ -17,6 +17,7 @@
     string(APPEND CMAKE_${language}_FLAGS_INIT "-fno-delete-null-pointer-checks ")
     string(APPEND CMAKE_${language}_FLAGS_INIT "-Wall -Werror -Wstrict-overflow ")
     string(APPEND CMAKE_${language}_FLAGS_INIT "-Wextra -Wno-implicit-fallthrough ")
+    string(APPEND CMAKE_${language}_FLAGS_INIT "-Wno-type-limits ")
     string(APPEND CMAKE_${language}_FLAGS_INIT "-gdwarf-4 ")
     string(APPEND CMAKE_${language}_FLAGS_INIT "-D_FORTIFY_SOURCE=2 ")
     string(APPEND CMAKE_${language}_FLAGS_DEBUG_INIT "-Og -Wnull-dereference ")