summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile18
-rw-r--r--bl1/bl1_main.c54
-rw-r--r--bl1/bl1_private.h9
-rw-r--r--bl2/bl2_main.c238
-rw-r--r--bl31/bl31.ld.S4
-rw-r--r--bl32/tsp/tsp-fvp.mk7
-rw-r--r--bl32/tsp/tsp.ld.S4
-rw-r--r--common/bl_common.c315
-rw-r--r--docs/firmware-design.md165
-rw-r--r--docs/porting-guide.md74
-rw-r--r--docs/user-guide.md10
-rw-r--r--drivers/arm/gic/arm_gic.c (renamed from plat/fvp/fvp_gic.c)244
-rw-r--r--drivers/io/io_fip.c4
-rw-r--r--include/common/bl_common.h39
-rw-r--r--include/drivers/arm/arm_gic.h57
-rw-r--r--include/drivers/arm/gic_v2.h4
-rw-r--r--include/lib/aarch64/arch.h19
-rw-r--r--include/plat/common/plat_config.h80
-rw-r--r--include/plat/common/platform.h41
-rw-r--r--lib/aarch64/xlat_tables.c53
-rw-r--r--plat/common/plat_gic.c73
-rw-r--r--plat/fvp/aarch64/fvp_common.c85
-rw-r--r--plat/fvp/bl1_fvp_setup.c42
-rw-r--r--plat/fvp/bl2_fvp_setup.c11
-rw-r--r--plat/fvp/bl31_fvp_setup.c4
-rw-r--r--plat/fvp/bl32_fvp_setup.c2
-rw-r--r--plat/fvp/fvp_def.h15
-rw-r--r--plat/fvp/fvp_pm.c43
-rw-r--r--plat/fvp/fvp_private.h7
-rw-r--r--plat/fvp/fvp_security.c3
-rw-r--r--plat/fvp/include/plat_macros.S6
-rw-r--r--plat/fvp/include/platform_def.h34
-rw-r--r--plat/fvp/platform.mk11
33 files changed, 1037 insertions, 738 deletions
diff --git a/Makefile b/Makefile
index 3561396..5272474 100644
--- a/Makefile
+++ b/Makefile
@@ -413,7 +413,23 @@ ifeq (${NEED_BL32},yes)
$(eval $(call MAKE_BL,32,in_fip))
endif
-${BUILD_PLAT}/fip.bin: ${FIP_DEPS} ${BL33} ${FIPTOOL}
+ifeq (${NEED_BL30},yes)
+FIP_DEPS += ${BL30}
+FIP_ARGS += --bl30 ${BL30}
+endif
+
+ifeq (${NEED_BL30},yes)
+# If BL3-0 is needed by the platform then 'BL30' variable must be defined.
+check_bl30:
+ $(if ${BL30},,$(error "To build a FIP for platform ${PLAT}, please set BL30 to point to the SCP firmware"))
+else
+# If BL3-0 is not needed by the platform but the user still specified the path
+# to a BL3-0 image then warn him that it will be ignored.
+check_bl30:
+ $(if ${BL30},$(warning "BL3-0 is not supported on platform ${PLAT}, it will just be ignored"),)
+endif
+
+${BUILD_PLAT}/fip.bin: ${FIP_DEPS} ${BL33} ${FIPTOOL} check_bl30
$(if ${BL33},,$(error "To build a FIP, please set BL33 to point to the Normal World binary, eg: BL33=../uefi/FVP_AARCH64_EFI.fd"))
${Q}${FIPTOOL} --dump \
${FIP_ARGS} \
diff --git a/bl1/bl1_main.c b/bl1/bl1_main.c
index 6771142..897660c 100644
--- a/bl1/bl1_main.c
+++ b/bl1/bl1_main.c
@@ -65,6 +65,38 @@ static void __dead2 bl1_run_bl2(entry_point_info_t *bl2_ep)
bl2_ep->args.arg7);
}
+/*******************************************************************************
+ * The next function has a weak definition. Platform specific code can override
+ * it if it wishes to.
+ ******************************************************************************/
+#pragma weak bl1_init_bl2_mem_layout
+
+/*******************************************************************************
+ * Function that takes a memory layout into which BL2 has been loaded and
+ * populates a new memory layout for BL2 that ensures that BL1's data sections
+ * resident in secure RAM are not visible to BL2.
+ ******************************************************************************/
+void bl1_init_bl2_mem_layout(const meminfo_t *bl1_mem_layout,
+ meminfo_t *bl2_mem_layout)
+{
+ const size_t bl1_size = BL1_RAM_LIMIT - BL1_RAM_BASE;
+
+ assert(bl1_mem_layout != NULL);
+ assert(bl2_mem_layout != NULL);
+
+ /* Check that BL1's memory is lying outside of the free memory */
+ assert((BL1_RAM_LIMIT <= bl1_mem_layout->free_base) ||
+ (BL1_RAM_BASE >= bl1_mem_layout->free_base + bl1_mem_layout->free_size));
+
+ /* Remove BL1 RW data from the scope of memory visible to BL2 */
+ *bl2_mem_layout = *bl1_mem_layout;
+ reserve_mem(&bl2_mem_layout->total_base,
+ &bl2_mem_layout->total_size,
+ BL1_RAM_BASE,
+ bl1_size);
+
+ flush_dcache_range((unsigned long)bl2_mem_layout, sizeof(meminfo_t));
+}
/*******************************************************************************
* Function to perform late architectural and platform specific initialization.
@@ -78,7 +110,6 @@ void bl1_main(void)
#if DEBUG
unsigned long sctlr_el3 = read_sctlr_el3();
#endif
- unsigned int load_type = TOP_LOAD;
image_info_t bl2_image_info = { {0} };
entry_point_info_t bl2_ep = { {0} };
meminfo_t *bl1_tzram_layout;
@@ -105,17 +136,15 @@ void bl1_main(void)
SET_PARAM_HEAD(&bl2_image_info, PARAM_IMAGE_BINARY, VERSION_1, 0);
SET_PARAM_HEAD(&bl2_ep, PARAM_EP, VERSION_1, 0);
- /*
- * Find out how much free trusted ram remains after BL1 load
- * & load the BL2 image at its top
- */
+ /* Find out how much free trusted ram remains after BL1 load */
bl1_tzram_layout = bl1_plat_sec_mem_layout();
+
+ /* Load the BL2 image */
err = load_image(bl1_tzram_layout,
- (const char *) BL2_IMAGE_NAME,
- load_type,
- BL2_BASE,
- &bl2_image_info,
- &bl2_ep);
+ BL2_IMAGE_NAME,
+ BL2_BASE,
+ &bl2_image_info,
+ &bl2_ep);
if (err) {
/*
* TODO: print failure to load BL2 but also add a tzwdog timer
@@ -132,10 +161,7 @@ void bl1_main(void)
* memory for other purposes.
*/
bl2_tzram_layout = (meminfo_t *) bl1_tzram_layout->free_base;
- init_bl2_mem_layout(bl1_tzram_layout,
- bl2_tzram_layout,
- load_type,
- bl2_image_info.image_base);
+ bl1_init_bl2_mem_layout(bl1_tzram_layout, bl2_tzram_layout);
bl1_plat_set_bl2_ep_info(&bl2_image_info, &bl2_ep);
bl2_ep.args.arg1 = (unsigned long)bl2_tzram_layout;
diff --git a/bl1/bl1_private.h b/bl1/bl1_private.h
index b54bf6b..0a8fc45 100644
--- a/bl1/bl1_private.h
+++ b/bl1/bl1_private.h
@@ -31,6 +31,15 @@
#ifndef __BL1_PRIVATE_H__
#define __BL1_PRIVATE_H__
+/*******************************************************************************
+ * Declarations of linker defined symbols which will tell us where BL1 lives
+ * in Trusted RAM
+ ******************************************************************************/
+extern uint64_t __BL1_RAM_START__;
+extern uint64_t __BL1_RAM_END__;
+#define BL1_RAM_BASE (uint64_t)(&__BL1_RAM_START__)
+#define BL1_RAM_LIMIT (uint64_t)(&__BL1_RAM_END__)
+
/******************************************
* Function prototypes
*****************************************/
diff --git a/bl2/bl2_main.c b/bl2/bl2_main.c
index 691973f..d96e199 100644
--- a/bl2/bl2_main.c
+++ b/bl2/bl2_main.c
@@ -38,123 +38,205 @@
#include <stdio.h>
#include "bl2_private.h"
+/*******************************************************************************
+ * Load the BL3-0 image if there's one.
+ * If a platform does not want to attempt to load BL3-0 image it must leave
+ * BL30_BASE undefined.
+ * Return 0 on success or if there's no BL3-0 image to load, a negative error
+ * code otherwise.
+ ******************************************************************************/
+static int load_bl30(void)
+{
+ int e = 0;
+#ifdef BL30_BASE
+ meminfo_t bl30_mem_info;
+ image_info_t bl30_image_info;
+
+ /*
+ * It is up to the platform to specify where BL3-0 should be loaded if
+ * it exists. It could create space in the secure sram or point to a
+ * completely different memory.
+ *
+ * The entry point information is not relevant in this case as the AP
+ * won't execute the BL3-0 image.
+ */
+ bl2_plat_get_bl30_meminfo(&bl30_mem_info);
+ e = load_image(&bl30_mem_info,
+ BL30_IMAGE_NAME,
+ BL30_BASE,
+ &bl30_image_info,
+ NULL);
+
+ if (e == 0) {
+ /* The subsequent handling of BL3-0 is platform specific */
+ bl2_plat_handle_bl30(&bl30_image_info);
+ }
+#endif /* BL30_BASE */
+
+ return e;
+}
/*******************************************************************************
- * The only thing to do in BL2 is to load further images and pass control to
- * BL31. The memory occupied by BL2 will be reclaimed by BL3_x stages. BL2 runs
- * entirely in S-EL1. Since arm standard c libraries are not PIC, printf et al
- * are not available. We rely on assertions to signal error conditions
+ * Load the BL3-1 image.
+ * The bl2_to_bl31_params and bl31_ep_info params will be updated with the
+ * relevant BL3-1 information.
+ * Return 0 on success, a negative error code otherwise.
******************************************************************************/
-void bl2_main(void)
+static int load_bl31(bl31_params_t *bl2_to_bl31_params,
+ entry_point_info_t *bl31_ep_info)
{
meminfo_t *bl2_tzram_layout;
- bl31_params_t *bl2_to_bl31_params;
- unsigned int bl2_load, bl31_load;
- entry_point_info_t *bl31_ep_info;
- meminfo_t bl32_mem_info;
- meminfo_t bl33_mem_info;
int e;
- /* Perform remaining generic architectural setup in S-El1 */
- bl2_arch_setup();
-
- /* Perform platform setup in BL1 */
- bl2_platform_setup();
-
- printf("BL2 %s\n\r", build_message);
+ assert(bl2_to_bl31_params != NULL);
+ assert(bl31_ep_info != NULL);
/* Find out how much free trusted ram remains after BL2 load */
bl2_tzram_layout = bl2_plat_sec_mem_layout();
- /*
- * Get a pointer to the memory the platform has set aside to pass
- * information to BL31.
- */
- bl2_to_bl31_params = bl2_plat_get_bl31_params();
- bl31_ep_info = bl2_plat_get_bl31_ep_info();
-
- /* Set the X0 parameter to bl31 */
+ /* Set the X0 parameter to BL3-1 */
bl31_ep_info->args.arg0 = (unsigned long)bl2_to_bl31_params;
- /*
- * Load BL31. BL1 tells BL2 whether it has been TOP or BOTTOM loaded.
- * To avoid fragmentation of trusted SRAM memory, BL31 is always
- * loaded opposite to BL2. This allows BL31 to reclaim BL2 memory
- * while maintaining its free space in one contiguous chunk.
- */
- bl2_load = bl2_tzram_layout->attr & LOAD_MASK;
- assert((bl2_load == TOP_LOAD) || (bl2_load == BOT_LOAD));
- bl31_load = (bl2_load == TOP_LOAD) ? BOT_LOAD : TOP_LOAD;
+ /* Load the BL3-1 image */
e = load_image(bl2_tzram_layout,
- BL31_IMAGE_NAME,
- bl31_load,
- BL31_BASE,
- bl2_to_bl31_params->bl31_image_info,
- bl31_ep_info);
+ BL31_IMAGE_NAME,
+ BL31_BASE,
+ bl2_to_bl31_params->bl31_image_info,
+ bl31_ep_info);
- /* Assert if it has not been possible to load BL31 */
- if (e) {
- ERROR("Failed to load BL3-1.\n");
- panic();
- }
+ if (e == 0)
+ bl2_plat_set_bl31_ep_info(bl2_to_bl31_params->bl31_image_info,
+ bl31_ep_info);
- bl2_plat_set_bl31_ep_info(bl2_to_bl31_params->bl31_image_info,
- bl31_ep_info);
-
- bl2_plat_get_bl33_meminfo(&bl33_mem_info);
-
- /* Load the BL33 image in non-secure memory provided by the platform */
- e = load_image(&bl33_mem_info,
- BL33_IMAGE_NAME,
- BOT_LOAD,
- plat_get_ns_image_entrypoint(),
- bl2_to_bl31_params->bl33_image_info,
- bl2_to_bl31_params->bl33_ep_info);
+ return e;
+}
- /* Halt if failed to load normal world firmware. */
- if (e) {
- ERROR("Failed to load BL3-3.\n");
- panic();
- }
- bl2_plat_set_bl33_ep_info(bl2_to_bl31_params->bl33_image_info,
- bl2_to_bl31_params->bl33_ep_info);
+/*******************************************************************************
+ * Load the BL3-2 image if there's one.
+ * The bl2_to_bl31_params param will be updated with the relevant BL3-2
+ * information.
+ * If a platform does not want to attempt to load BL3-2 image it must leave
+ * BL32_BASE undefined.
+ * Return 0 on success or if there's no BL3-2 image to load, a negative error
+ * code otherwise.
+ ******************************************************************************/
+static int load_bl32(bl31_params_t *bl2_to_bl31_params)
+{
+ int e = 0;
+#ifdef BL32_BASE
+ meminfo_t bl32_mem_info;
+ assert(bl2_to_bl31_params != NULL);
-#ifdef BL32_BASE
/*
- * Load the BL32 image if there's one. It is upto to platform
- * to specify where BL32 should be loaded if it exists. It
- * could create space in the secure sram or point to a
+ * It is up to the platform to specify where BL3-2 should be loaded if
+ * it exists. It could create space in the secure sram or point to a
* completely different memory.
- *
- * If a platform does not want to attempt to load BL3-2 image
- * it must leave BL32_BASE undefined
*/
bl2_plat_get_bl32_meminfo(&bl32_mem_info);
e = load_image(&bl32_mem_info,
BL32_IMAGE_NAME,
- bl32_mem_info.attr & LOAD_MASK,
BL32_BASE,
bl2_to_bl31_params->bl32_image_info,
bl2_to_bl31_params->bl32_ep_info);
- /* Issue a diagnostic if no Secure Payload could be loaded */
- if (e) {
- WARN("Failed to load BL3-2.\n");
- } else {
+ if (e == 0) {
bl2_plat_set_bl32_ep_info(
bl2_to_bl31_params->bl32_image_info,
bl2_to_bl31_params->bl32_ep_info);
}
#endif /* BL32_BASE */
+ return e;
+}
+
+/*******************************************************************************
+ * Load the BL3-3 image.
+ * The bl2_to_bl31_params param will be updated with the relevant BL3-3
+ * information.
+ * Return 0 on success, a negative error code otherwise.
+ ******************************************************************************/
+static int load_bl33(bl31_params_t *bl2_to_bl31_params)
+{
+ meminfo_t bl33_mem_info;
+ int e;
+
+ assert(bl2_to_bl31_params != NULL);
+
+ bl2_plat_get_bl33_meminfo(&bl33_mem_info);
+
+ /* Load the BL3-3 image in non-secure memory provided by the platform */
+ e = load_image(&bl33_mem_info,
+ BL33_IMAGE_NAME,
+ plat_get_ns_image_entrypoint(),
+ bl2_to_bl31_params->bl33_image_info,
+ bl2_to_bl31_params->bl33_ep_info);
+
+ if (e == 0)
+ bl2_plat_set_bl33_ep_info(bl2_to_bl31_params->bl33_image_info,
+ bl2_to_bl31_params->bl33_ep_info);
+
+ return e;
+}
+
+/*******************************************************************************
+ * The only thing to do in BL2 is to load further images and pass control to
+ * BL3-1. The memory occupied by BL2 will be reclaimed by BL3-x stages. BL2 runs
+ * entirely in S-EL1.
+ ******************************************************************************/
+void bl2_main(void)
+{
+ bl31_params_t *bl2_to_bl31_params;
+ entry_point_info_t *bl31_ep_info;
+ int e;
+
+ /* Perform remaining generic architectural setup in S-EL1 */
+ bl2_arch_setup();
+
+ /* Perform platform setup in BL2 */
+ bl2_platform_setup();
+
+ printf("BL2 %s\n\r", build_message);
+
+ /*
+ * Load the subsequent bootloader images
+ */
+ e = load_bl30();
+ if (e) {
+ ERROR("Failed to load BL3-0 (%i)\n", e);
+ panic();
+ }
+
+ /*
+ * Get a pointer to the memory the platform has set aside to pass
+ * information to BL3-1.
+ */
+ bl2_to_bl31_params = bl2_plat_get_bl31_params();
+ bl31_ep_info = bl2_plat_get_bl31_ep_info();
+
+ e = load_bl31(bl2_to_bl31_params, bl31_ep_info);
+ if (e) {
+ ERROR("Failed to load BL3-1 (%i)\n", e);
+ panic();
+ }
+
+ e = load_bl32(bl2_to_bl31_params);
+ if (e)
+ WARN("Failed to load BL3-2 (%i)\n", e);
+
+ e = load_bl33(bl2_to_bl31_params);
+ if (e) {
+ ERROR("Failed to load BL3-3 (%i)\n", e);
+ panic();
+ }
+
/* Flush the params to be passed to memory */
bl2_plat_flush_bl31_params();
/*
- * Run BL31 via an SMC to BL1. Information on how to pass control to
- * the BL32 (if present) and BL33 software images will be passed to
- * BL31 as an argument.
+ * Run BL3-1 via an SMC to BL1. Information on how to pass control to
+ * the BL3-2 (if present) and BL3-3 software images will be passed to
+ * BL3-1 as an argument.
*/
smc(RUN_IMAGE, (unsigned long)bl31_ep_info, 0, 0, 0, 0, 0, 0);
}
diff --git a/bl31/bl31.ld.S b/bl31/bl31.ld.S
index 1501742..34a349f 100644
--- a/bl31/bl31.ld.S
+++ b/bl31/bl31.ld.S
@@ -75,6 +75,10 @@ SECTIONS
__DATA_END__ = .;
} >RAM
+#ifdef BL31_PROGBITS_LIMIT
+ ASSERT(. <= BL31_PROGBITS_LIMIT, "BL3-1 progbits has exceeded its limit.")
+#endif
+
stacks (NOLOAD) : {
__STACKS_START__ = .;
*(tzfw_normal_stacks)
diff --git a/bl32/tsp/tsp-fvp.mk b/bl32/tsp/tsp-fvp.mk
index 21864d6..3220c08 100644
--- a/bl32/tsp/tsp-fvp.mk
+++ b/bl32/tsp/tsp-fvp.mk
@@ -29,9 +29,10 @@
#
# TSP source files specific to FVP platform
-BL32_SOURCES += drivers/arm/gic/gic_v2.c \
+BL32_SOURCES += drivers/arm/gic/arm_gic.c \
+ drivers/arm/gic/gic_v2.c \
plat/common/aarch64/platform_mp_stack.S \
+ plat/common/plat_gic.c \
plat/fvp/aarch64/fvp_common.c \
plat/fvp/aarch64/fvp_helpers.S \
- plat/fvp/bl32_fvp_setup.c \
- plat/fvp/fvp_gic.c
+ plat/fvp/bl32_fvp_setup.c
diff --git a/bl32/tsp/tsp.ld.S b/bl32/tsp/tsp.ld.S
index 187915b..5807141 100644
--- a/bl32/tsp/tsp.ld.S
+++ b/bl32/tsp/tsp.ld.S
@@ -68,6 +68,10 @@ SECTIONS
__DATA_END__ = .;
} >RAM
+#ifdef BL32_PROGBITS_LIMIT
+ ASSERT(. <= BL32_PROGBITS_LIMIT, "BL3-2 progbits has exceeded its limit.")
+#endif
+
stacks (NOLOAD) : {
__STACKS_START__ = .;
*(tzfw_normal_stacks)
diff --git a/common/bl_common.c b/common/bl_common.c
index 4affa76..d4bde51 100644
--- a/common/bl_common.c
+++ b/common/bl_common.c
@@ -33,10 +33,9 @@
#include <assert.h>
#include <bl_common.h>
#include <debug.h>
+#include <errno.h>
#include <io_storage.h>
#include <platform.h>
-#include <errno.h>
-#include <stdio.h>
unsigned long page_align(unsigned long value, unsigned dir)
{
@@ -72,43 +71,76 @@ void change_security_state(unsigned int target_security_state)
write_scr(scr);
}
+/******************************************************************************
+ * Determine whether the memory region delimited by 'addr' and 'size' is free,
+ * given the extents of free memory.
+ * Return 1 if it is free, 0 otherwise.
+ *****************************************************************************/
+static int is_mem_free(uint64_t free_base, size_t free_size,
+ uint64_t addr, size_t size)
+{
+ return (addr >= free_base) && (addr + size <= free_base + free_size);
+}
-/*******************************************************************************
- * The next function has a weak definition. Platform specific code can override
- * it if it wishes to.
- ******************************************************************************/
-#pragma weak init_bl2_mem_layout
-
-/*******************************************************************************
- * Function that takes a memory layout into which BL2 has been either top or
- * bottom loaded along with the address where BL2 has been loaded in it. Using
- * this information, it populates bl2_mem_layout to tell BL2 how much memory
- * it has access to and how much is available for use.
- ******************************************************************************/
-void init_bl2_mem_layout(meminfo_t *bl1_mem_layout,
- meminfo_t *bl2_mem_layout,
- unsigned int load_type,
- unsigned long bl2_base)
+/******************************************************************************
+ * Inside a given memory region, determine whether a sub-region of memory is
+ * closer from the top or the bottom of the encompassing region. Return the
+ * size of the smallest chunk of free memory surrounding the sub-region in
+ * 'small_chunk_size'.
+ *****************************************************************************/
+static unsigned int choose_mem_pos(uint64_t mem_start, uint64_t mem_end,
+ uint64_t submem_start, uint64_t submem_end,
+ size_t *small_chunk_size)
{
- unsigned tmp;
+ size_t top_chunk_size, bottom_chunk_size;
- if (load_type == BOT_LOAD) {
- bl2_mem_layout->total_base = bl2_base;
- tmp = bl1_mem_layout->free_base - bl2_base;
- bl2_mem_layout->total_size = bl1_mem_layout->free_size + tmp;
+ assert(mem_start <= submem_start);
+ assert(submem_start <= submem_end);
+ assert(submem_end <= mem_end);
+ assert(small_chunk_size != NULL);
+ top_chunk_size = mem_end - submem_end;
+ bottom_chunk_size = submem_start - mem_start;
+
+ if (top_chunk_size < bottom_chunk_size) {
+ *small_chunk_size = top_chunk_size;
+ return TOP;
} else {
- bl2_mem_layout->total_base = bl1_mem_layout->free_base;
- tmp = bl1_mem_layout->total_base + bl1_mem_layout->total_size;
- bl2_mem_layout->total_size = tmp - bl1_mem_layout->free_base;
+ *small_chunk_size = bottom_chunk_size;
+ return BOTTOM;
}
+}
- bl2_mem_layout->free_base = bl1_mem_layout->free_base;
- bl2_mem_layout->free_size = bl1_mem_layout->free_size;
- bl2_mem_layout->attr = load_type;
+/******************************************************************************
+ * Reserve the memory region delimited by 'addr' and 'size'. The extents of free
+ * memory are passed in 'free_base' and 'free_size' and they will be updated to
+ * reflect the memory usage.
+ * The caller must ensure the memory to reserve is free.
+ *****************************************************************************/
+void reserve_mem(uint64_t *free_base, size_t *free_size,
+ uint64_t addr, size_t size)
+{
+ size_t discard_size;
+ size_t reserved_size;
+ unsigned int pos;
- flush_dcache_range((unsigned long) bl2_mem_layout, sizeof(meminfo_t));
- return;
+ assert(free_base != NULL);
+ assert(free_size != NULL);
+ assert(is_mem_free(*free_base, *free_size, addr, size));
+
+ pos = choose_mem_pos(*free_base, *free_base + *free_size,
+ addr, addr + size,
+ &discard_size);
+
+ reserved_size = size + discard_size;
+ *free_size -= reserved_size;
+
+ if (pos == BOTTOM)
+ *free_base = addr + size;
+
+ INFO("Reserved %u bytes (discarded %u bytes %s)\n",
+ reserved_size, discard_size,
+ pos == TOP ? "above" : "below");
}
static void dump_load_info(unsigned long image_load_addr,
@@ -170,34 +202,32 @@ unsigned long image_size(const char *image_name)
return image_size;
}
+
/*******************************************************************************
- * Generic function to load an image into the trusted RAM,
- * given a name, extents of free memory & whether the image should be loaded at
- * the bottom or top of the free memory. It updates the memory layout if the
- * load is successful. It also updates the image information and the entry point
- * information in the params passed. The caller might pass a NULL pointer for
- * the entry point if it is not interested in this information, e.g. because
- * the image just needs to be loaded in memory but won't ever be executed.
+ * Generic function to load an image at a specific address given a name and
+ * extents of free memory. It updates the memory layout if the load is
+ * successful, as well as the image information and the entry point information.
+ * The caller might pass a NULL pointer for the entry point if it is not
+ * interested in this information, e.g. because the image just needs to be
+ * loaded in memory but won't ever be executed.
+ * Returns 0 on success, a negative error code otherwise.
******************************************************************************/
int load_image(meminfo_t *mem_layout,
- const char *image_name,
- unsigned int load_type,
- unsigned long fixed_addr,
- image_info_t *image_data,
- entry_point_info_t *entry_point_info)
+ const char *image_name,
+ uint64_t image_base,
+ image_info_t *image_data,
+ entry_point_info_t *entry_point_info)
{
uintptr_t dev_handle;
uintptr_t image_handle;
uintptr_t image_spec;
- unsigned long temp_image_base = 0;
- unsigned long image_base = 0;
- long offset = 0;
- size_t image_size = 0;
- size_t bytes_read = 0;
+ size_t image_size;
+ size_t bytes_read;
int io_result = IO_FAIL;
assert(mem_layout != NULL);
assert(image_name != NULL);
+ assert(image_data != NULL);
assert(image_data->h.version >= VERSION_1);
/* Obtain a reference to the image by querying the platform layer */
@@ -216,6 +246,8 @@ int load_image(meminfo_t *mem_layout,
return io_result;
}
+ INFO("Loading file '%s' at address 0x%lx\n", image_name, image_base);
+
/* Find the size of the image */
io_result = io_size(image_handle, &image_size);
if ((io_result != IO_SUCCESS) || (image_size == 0)) {
@@ -224,170 +256,14 @@ int load_image(meminfo_t *mem_layout,
goto exit;
}
- /* See if we have enough space */
- if (image_size > mem_layout->free_size) {
- WARN("Cannot load '%s' file: Not enough space.\n",
- image_name);
- dump_load_info(0, image_size, mem_layout);
- goto exit;
- }
-
- switch (load_type) {
-
- case TOP_LOAD:
-
- /* Load the image in the top of free memory */
- temp_image_base = mem_layout->free_base + mem_layout->free_size;
- temp_image_base -= image_size;
-
- /* Page align base address and check whether the image still fits */
- image_base = page_align(temp_image_base, DOWN);
- assert(image_base <= temp_image_base);
-
- if (image_base < mem_layout->free_base) {
- WARN("Cannot load '%s' file: Not enough space.\n",
- image_name);
- dump_load_info(image_base, image_size, mem_layout);
- io_result = -ENOMEM;
- goto exit;
- }
-
- /* Calculate the amount of extra memory used due to alignment */
- offset = temp_image_base - image_base;
-
- break;
-
- case BOT_LOAD:
-
- /* Load the BL2 image in the bottom of free memory */
- temp_image_base = mem_layout->free_base;
- image_base = page_align(temp_image_base, UP);
- assert(image_base >= temp_image_base);
-
- /* Page align base address and check whether the image still fits */
- if (image_base + image_size >
- mem_layout->free_base + mem_layout->free_size) {
- WARN("Cannot load '%s' file: Not enough space.\n",
- image_name);
+ /* Check that the memory where the image will be loaded is free */
+ if (!is_mem_free(mem_layout->free_base, mem_layout->free_size,
+ image_base, image_size)) {
+ WARN("Failed to reserve memory: 0x%lx - 0x%lx\n",
+ image_base, image_base + image_size);
dump_load_info(image_base, image_size, mem_layout);
io_result = -ENOMEM;
goto exit;
- }
-
- /* Calculate the amount of extra memory used due to alignment */
- offset = image_base - temp_image_base;
-
- break;
-
- default:
- assert(0);
-
- }
-
- /*
- * Some images must be loaded at a fixed address, not a dynamic one.
- *
- * This has been implemented as a hack on top of the existing dynamic
- * loading mechanism, for the time being. If the 'fixed_addr' function
- * argument is different from zero, then it will force the load address.
- * So we still have this principle of top/bottom loading but the code
- * determining the load address is bypassed and the load address is
- * forced to the fixed one.
- *
- * This can result in quite a lot of wasted space because we still use
- * 1 sole meminfo structure to represent the extents of free memory,
- * where we should use some sort of linked list.
- *
- * E.g. we want to load BL2 at address 0x04020000, the resulting memory
- * layout should look as follows:
- * ------------ 0x04040000
- * | | <- Free space (1)
- * |----------|
- * | BL2 |
- * |----------| 0x04020000
- * | | <- Free space (2)
- * |----------|
- * | BL1 |
- * ------------ 0x04000000
- *
- * But in the current hacky implementation, we'll need to specify
- * whether BL2 is loaded at the top or bottom of the free memory.
- * E.g. if BL2 is considered as top-loaded, the meminfo structure
- * will give the following view of the memory, hiding the chunk of
- * free memory above BL2:
- * ------------ 0x04040000
- * | |
- * | |
- * | BL2 |
- * |----------| 0x04020000
- * | | <- Free space (2)
- * |----------|
- * | BL1 |
- * ------------ 0x04000000
- */
- if (fixed_addr != 0) {
- /* Load the image at the given address. */
- image_base = fixed_addr;
-
- /* Check whether the image fits. */
- if ((image_base < mem_layout->free_base) ||
- (image_base + image_size >
- mem_layout->free_base + mem_layout->free_size)) {
- WARN("Cannot load '%s' file: Not enough space.\n",
- image_name);
- dump_load_info(image_base, image_size, mem_layout);
- io_result = -ENOMEM;
- goto exit;
- }
-
- /* Check whether the fixed load address is page-aligned. */
- if (!is_page_aligned(image_base)) {
- WARN("Cannot load '%s' file at unaligned address 0x%lx\n",
- image_name, fixed_addr);
- io_result = -ENOMEM;
- goto exit;
- }
-
- /*
- * Calculate the amount of extra memory used due to fixed
- * loading.
- */
- if (load_type == TOP_LOAD) {
- unsigned long max_addr, space_used;
- /*
- * ------------ max_addr
- * | /wasted/ | | offset
- * |..........|..............................
- * | image | | image_flen
- * |----------| fixed_addr
- * | |
- * | |
- * ------------ total_base
- */
- max_addr = mem_layout->total_base + mem_layout->total_size;
- /*
- * Compute the amount of memory used by the image.
- * Corresponds to all space above the image load
- * address.
- */
- space_used = max_addr - fixed_addr;
- /*
- * Calculate the amount of wasted memory within the
- * amount of memory used by the image.
- */
- offset = space_used - image_size;
- } else /* BOT_LOAD */
- /*
- * ------------
- * | |
- * | |
- * |----------|
- * | image |
- * |..........| fixed_addr
- * | /wasted/ | | offset
- * ------------ total_base
- */
- offset = fixed_addr - mem_layout->total_base;
}
/* We have enough space so load the image now */
@@ -398,6 +274,14 @@ int load_image(meminfo_t *mem_layout,
goto exit;
}
+ /*
+ * Update the memory usage info.
+ * This is done after the actual loading so that it is not updated when
+ * the load is unsuccessful.
+ */
+ reserve_mem(&mem_layout->free_base, &mem_layout->free_size,
+ image_base, image_size);
+
image_data->image_base = image_base;
image_data->image_size = image_size;
@@ -405,18 +289,13 @@ int load_image(meminfo_t *mem_layout,
entry_point_info->pc = image_base;
/*
- * File has been successfully loaded. Update the free memory
- * data structure & flush the contents of the TZRAM so that
- * the next EL can see it.
+ * File has been successfully loaded.
+ * Flush the image in TZRAM so that the next EL can see it.
*/
- /* Update the memory contents */
flush_dcache_range(image_base, image_size);
- mem_layout->free_size -= image_size + offset;
-
- /* Update the base of free memory since its moved up */
- if (load_type == BOT_LOAD)
- mem_layout->free_base += offset + image_size;
+ INFO("File '%s' loaded: 0x%lx - 0x%lx\n", image_name, image_base,
+ image_base + image_size);
exit:
io_close(image_handle);
diff --git a/docs/firmware-design.md b/docs/firmware-design.md
index b20f06b..9bdfefb 100644
--- a/docs/firmware-design.md
+++ b/docs/firmware-design.md
@@ -934,46 +934,62 @@ The sample crash output is shown below.
7. Memory layout on FVP platforms
----------------------------------
+Each bootloader image can be divided in 2 parts:
+
+ * the static contents of the image. These are data actually stored in the
+ binary on the disk. In the ELF terminology, they are called `PROGBITS`
+ sections;
+
+ * the run-time contents of the image. These are data that don't occupy any
+ space in the binary on the disk. The ELF binary just contains some
+ metadata indicating where these data will be stored at run-time and the
+ corresponding sections need to be allocated and initialized at run-time.
+ In the ELF terminology, they are called `NOBITS` sections.
+
+All PROGBITS sections are grouped together at the beginning of the image,
+followed by all NOBITS sections. This is true for all Trusted Firmware images
+and it is governed by the linker scripts. This ensures that the raw binary
+images are as small as possible. If a NOBITS section would sneak in between
+PROGBITS sections then the resulting binary file would contain a bunch of zero
+bytes at the location of this NOBITS section, making the image unnecessarily
+bigger. Smaller images allow faster loading from the FIP to the main memory.
+
On FVP platforms, we use the Trusted ROM and Trusted SRAM to store the trusted
-firmware binaries. BL1 is originally sitting in the Trusted ROM at address
-`0x0`. Its read-write data are relocated at the base of the Trusted SRAM at
-runtime. BL1 loads BL2 image near the top of the trusted SRAM. BL2 loads BL3-1
-image between BL1 and BL2. Optionally, BL2 then loads the TSP as the BL3-2
-image. By default it is loaded in Trusted SRAM, in this case it sits between
-BL3-1 and BL2. This memory layout is illustrated by the following diagram.
-
- Trusted SRAM
- +----------+ 0x04040000
- | |
- |----------|
- | BL2 |
- |----------|
- | |
- |----------|
- | BL32 | (optional)
- |----------|
- | |
- |----------|
- | BL31 |
- |----------|
- | |
- |----------|
- | BL1 (rw) |
- +----------+ 0x04000000
-
- Trusted ROM
- +----------+ 0x04000000
- | BL1 (ro) |
- +----------+ 0x00000000
+firmware binaries.
+
+ * BL1 is originally sitting in the Trusted ROM at address `0x0`. Its
+ read-write data are relocated at the top of the Trusted SRAM at runtime.
+
+ * BL3-1 is loaded at the top of the Trusted SRAM, such that its NOBITS
+ sections will overwrite BL1 R/W data.
+
+ * BL2 is loaded below BL3-1.
+
+ * The TSP is loaded as the BL3-2 image at the base of the Trusted SRAM. Its
+ NOBITS sections are allowed to overlay BL2.
+
+This memory layout is designed to give the BL3-2 image as much memory as
+possible. It is illustrated by the following diagram.
+
+ Trusted SRAM
+ 0x04040000 +----------+ loaded by BL2 ------------------
+ | BL1 (rw) | <<<<<<<<<<<<< | BL3-1 NOBITS |
+ |----------| <<<<<<<<<<<<< |----------------|
+ | | <<<<<<<<<<<<< | BL3-1 PROGBITS |
+ |----------| ------------------
+ | BL2 | <<<<<<<<<<<<< | BL3-2 NOBITS |
+ |----------| <<<<<<<<<<<<< |----------------|
+ | | <<<<<<<<<<<<< | BL3-2 PROGBITS |
+ 0x04000000 +----------+ ------------------
+
+ Trusted ROM
+ 0x04000000 +----------+
+ | BL1 (ro) |
+ 0x00000000 +----------+
The TSP image may be loaded in Trusted DRAM instead. This doesn't change the
memory layout of the other boot loader images in Trusted SRAM.
-Although the goal at long term is to give complete flexibility over the memory
-layout, all platforms should conform to this layout at the moment. This is
-because of some limitations in the implementation of the image loader in the
-Trusted Firmware. Refer to the "Limitations of the image loader" section below.
-
Each bootloader stage image layout is described by its own linker script. The
linker scripts export some symbols into the program symbol table. Their values
correspond to particular addresses. The trusted firmware code can refer to these
@@ -1095,82 +1111,9 @@ happens, the linker will issue a message similar to the following:
aarch64-none-elf-ld: BLx has exceeded its limit.
-On FVP platforms, the base addresses have been chosen such that all images can
-reside concurrently in Trusted RAM without overlapping each other. Note that
-this is not a requirement, as not all images live in memory at the same time.
-For example, when the BL3-1 image takes over execution, BL1 and BL2 images are
-not needed anymore.
-
-### Limitations of the image loader
-
-The current implementation of the image loader can result in wasted space
-because of the simplified data structure used to represent the extents of free
-memory. For example, to load BL2 at address `0x0402D000`, the resulting memory
-layout should be as follows:
-
- ------------ 0x04040000
- | | <- Free space (1)
- |----------|
- | BL2 |
- |----------| BL2_BASE (0x0402D000)
- | | <- Free space (2)
- |----------|
- | BL1 |
- ------------ 0x04000000
-
-In the current implementation, we need to specify whether BL2 is loaded at the
-top or bottom of the free memory. BL2 is top-loaded so in the example above,
-the free space (1) above BL2 is hidden, resulting in the following view of
-memory:
-
- ------------ 0x04040000
- | |
- | |
- | BL2 |
- |----------| BL2_BASE (0x0402D000)
- | | <- Free space (2)
- |----------|
- | BL1 |
- ------------ 0x04000000
-
-BL3-1 is bottom-loaded above BL1. For example, if BL3-1 is bottom-loaded at
-`0x0400E000`, the memory layout should look like this:
-
- ------------ 0x04040000
- | |
- | |
- | BL2 |
- |----------| BL2_BASE (0x0402D000)
- | | <- Free space (2)
- | |
- |----------|
- | |
- | BL31 |
- |----------| BL31_BASE (0x0400E000)
- | | <- Free space (3)
- |----------|
- | BL1 |
- ------------ 0x04000000
-
-But the free space (3) between BL1 and BL3-1 is wasted, resulting in the
-following view:
-
- ------------ 0x04040000
- | |
- | |
- | BL2 |
- |----------| BL2_BASE (0x0402D000)
- | | <- Free space (2)
- | |
- |----------|
- | |
- | |
- | BL31 | BL31_BASE (0x0400E000)
- | |
- |----------|
- | BL1 |
- ------------ 0x04000000
-
+Additionally, if the platform memory layout implies some image overlaying like
+on FVP, BL3-1 and TSP need to know the limit address that their PROGBITS
+sections must not overstep. The platform code must provide those.
8. Firmware Image Package (FIP)
--------------------------------
diff --git a/docs/porting-guide.md b/docs/porting-guide.md
index f854af9..813d0be 100644
--- a/docs/porting-guide.md
+++ b/docs/porting-guide.md
@@ -253,6 +253,17 @@ be defined as well:
the secure memory identified by `TSP_SEC_MEM_BASE` and `TSP_SEC_MEM_SIZE`
constants.
+The following constants are optional. They should be defined when the platform
+memory layout implies some image overlaying like on FVP.
+
+* **#define : BL31_PROGBITS_LIMIT**
+
+ Defines the maximum address in secure RAM that the BL3-1's progbits sections
+ can occupy.
+
+* **#define : BL32_PROGBITS_LIMIT**
+
+ Defines the maximum address that the TSP's progbits sections can occupy.
### File : plat_macros.S [mandatory]
@@ -511,7 +522,7 @@ warm boot. For each CPU, BL1 is responsible for the following tasks:
the platform to decide where it wants to place the `meminfo` structure for
BL2.
- BL1 implements the `init_bl2_mem_layout()` function to populate the
+ BL1 implements the `bl1_init_bl2_mem_layout()` function to populate the
BL2 `meminfo` structure. The platform may override this implementation, for
example if the platform wants to restrict the amount of memory visible to
BL2. Details of how to do this are given below.
@@ -574,7 +585,7 @@ its own use.
This function helps fulfill requirement 3 above.
-### Function : init_bl2_mem_layout() [optional]
+### Function : bl1_init_bl2_mem_layout() [optional]
Argument : meminfo *, meminfo *, unsigned int, unsigned long
Return : void
@@ -609,23 +620,24 @@ The BL2 stage is executed only by the primary CPU, which is determined in BL1
using the `platform_is_primary_cpu()` function. BL1 passed control to BL2 at
`BL2_BASE`. BL2 executes in Secure EL1 and is responsible for:
-1. Loading the BL3-1 binary image into secure RAM from non-volatile storage. To
+1. (Optional) Loading the BL3-0 binary image (if present) from platform
+ provided non-volatile storage. To load the BL3-0 image, BL2 makes use of
+ the `meminfo` returned by the `bl2_plat_get_bl30_meminfo()` function.
+ The platform also defines the address in memory where BL3-0 is loaded
+ through the optional constant `BL30_BASE`. BL2 uses this information
+ to determine if there is enough memory to load the BL3-0 image.
+ Subsequent handling of the BL3-0 image is platform-specific and is
+ implemented in the `bl2_plat_handle_bl30()` function.
+ If `BL30_BASE` is not defined then this step is not performed.
+
+2. Loading the BL3-1 binary image into secure RAM from non-volatile storage. To
load the BL3-1 image, BL2 makes use of the `meminfo` structure passed to it
by BL1. This structure allows BL2 to calculate how much secure RAM is
available for its use. The platform also defines the address in secure RAM
where BL3-1 is loaded through the constant `BL31_BASE`. BL2 uses this
information to determine if there is enough memory to load the BL3-1 image.
-2. Loading the normal world BL3-3 binary image into non-secure DRAM from
- platform storage and arranging for BL3-1 to pass control to this image. This
- address is determined using the `plat_get_ns_image_entrypoint()` function
- described below.
-
-3. BL2 populates an `entry_point_info` structure in memory provided by the
- platform with information about how BL3-1 should pass control to the
- other BL images.
-
-4. (Optional) Loading the BL3-2 binary image (if present) from platform
+3. (Optional) Loading the BL3-2 binary image (if present) from platform
provided non-volatile storage. To load the BL3-2 image, BL2 makes use of
the `meminfo` returned by the `bl2_plat_get_bl32_meminfo()` function.
The platform also defines the address in memory where BL3-2 is loaded
@@ -633,11 +645,20 @@ using the `platform_is_primary_cpu()` function. BL1 passed control to BL2 at
to determine if there is enough memory to load the BL3-2 image.
If `BL32_BASE` is not defined then this and the next step is not performed.
-5. (Optional) Arranging to pass control to the BL3-2 image (if present) that
+4. (Optional) Arranging to pass control to the BL3-2 image (if present) that
has been pre-loaded at `BL32_BASE`. BL2 populates an `entry_point_info`
structure in memory provided by the platform with information about how
BL3-1 should pass control to the BL3-2 image.
+5. Loading the normal world BL3-3 binary image into non-secure DRAM from
+ platform storage and arranging for BL3-1 to pass control to this image. This
+ address is determined using the `plat_get_ns_image_entrypoint()` function
+ described below.
+
+6. BL2 populates an `entry_point_info` structure in memory provided by the
+ platform with information about how BL3-1 should pass control to the
+ other BL images.
+
The following functions must be implemented by the platform port to enable BL2
to perform the above tasks.
@@ -704,6 +725,31 @@ populated with the extents of secure RAM available for BL2 to use. See
`bl2_early_platform_setup()` above.
+### Function : bl2_plat_get_bl30_meminfo() [mandatory]
+
+ Argument : meminfo *
+ Return : void
+
+This function is used to get the memory limits where BL2 can load the
+BL3-0 image. The meminfo provided by this is used by load_image() to
+validate whether the BL3-0 image can be loaded within the given
+memory from the given base.
+
+
+### Function : bl2_plat_handle_bl30() [mandatory]
+
+ Argument : image_info *
+ Return : int
+
+This function is called after loading BL3-0 image and it is used to perform any
+platform-specific actions required to handle the SCP firmware. Typically it
+transfers the image into SCP memory using a platform-specific protocol and waits
+until SCP executes it and signals to the Application Processor (AP) for BL2
+execution to continue.
+
+This function returns 0 on success, a negative error code otherwise.
+
+
### Function : bl2_plat_get_bl31_params() [mandatory]
Argument : void
diff --git a/docs/user-guide.md b/docs/user-guide.md
index 0105531..a4d7f46 100644
--- a/docs/user-guide.md
+++ b/docs/user-guide.md
@@ -133,6 +133,10 @@ the build system doesn't track dependency for build options. Therefore, if any
of the build options are changed from a previous build, a clean build must be
performed.
+* `BL30`: Path to BL3-0 image in the host file system. This image is optional.
+ If a BL3-0 image is present then this option must be passed for the `fip`
+ target
+
* `BL33`: Path to BL33 image in the host file system. This is mandatory for
`fip` target
@@ -158,9 +162,9 @@ performed.
* `V`: Verbose build. If assigned anything other than 0, the build commands
are printed. Default is 0
-* `FVP_GIC_ARCH`: Choice of ARM GIC architecture version used by the FVP port
- for implementing the platform GIC API. This API is used by the interrupt
- management framework. Default is 2 i.e. version 2.0
+* `ARM_GIC_ARCH`: Choice of ARM GIC architecture version used by the ARM GIC
+ driver for implementing the platform GIC API. This API is used
+ by the interrupt management framework. Default is 2 i.e. version 2.0.
* `IMF_READ_INTERRUPT_ID`: Boolean flag used by the interrupt management
framework to enable passing of the interrupt id to its handler. The id is
diff --git a/plat/fvp/fvp_gic.c b/drivers/arm/gic/arm_gic.c
index a48b29b..636348b 100644
--- a/plat/fvp/fvp_gic.c
+++ b/drivers/arm/gic/arm_gic.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -28,7 +28,9 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#include <arch.h>
#include <arch_helpers.h>
+#include <arm_gic.h>
#include <assert.h>
#include <bl_common.h>
#include <debug.h>
@@ -37,8 +39,14 @@
#include <interrupt_mgmt.h>
#include <platform.h>
#include <stdint.h>
-#include "fvp_def.h"
-#include "fvp_private.h"
+
+
+static unsigned int g_gicc_base;
+static unsigned int g_gicd_base;
+static unsigned long g_gicr_base;
+static const unsigned int *g_irq_sec_ptr;
+static unsigned int g_num_irqs;
+
/*******************************************************************************
* This function does some minimal GICv3 configuration. The Firmware itself does
@@ -46,7 +54,7 @@
* provided by GICv3. This function allows software (like Linux) in later stages
* to use full GICv3 features.
******************************************************************************/
-void gicv3_cpuif_setup(void)
+static void gicv3_cpuif_setup(void)
{
unsigned int scr_val, val;
uintptr_t base;
@@ -59,7 +67,8 @@ void gicv3_cpuif_setup(void)
* GICR_WAKER is NOT banked per CPU, compute the correct base address
* per CPU.
*/
- base = gicv3_get_rdist(BASE_GICR_BASE, read_mpidr());
+ assert(g_gicr_base);
+ base = gicv3_get_rdist(g_gicr_base, read_mpidr());
if (base == (uintptr_t)NULL) {
/* No re-distributor base address. This interface cannot be
* configured.
@@ -75,9 +84,8 @@ void gicv3_cpuif_setup(void)
/* We need to wait for ChildrenAsleep to clear. */
val = gicr_read_waker(base);
- while (val & WAKER_CA) {
+ while (val & WAKER_CA)
val = gicr_read_waker(base);
- }
/*
* We need to set SCR_EL3.NS in order to see GICv3 non-secure state.
@@ -103,7 +111,7 @@ void gicv3_cpuif_setup(void)
write_icc_sre_el2(val | ICC_SRE_EN | ICC_SRE_SRE);
write_icc_pmr_el1(GIC_PRI_MASK);
- isb(); /* commite ICC_* changes before setting NS=0 */
+ isb(); /* commit ICC_* changes before setting NS=0 */
/* Restore SCR_EL3 */
write_scr(scr_val);
@@ -114,7 +122,7 @@ void gicv3_cpuif_setup(void)
* This function does some minimal GICv3 configuration when cores go
* down.
******************************************************************************/
-void gicv3_cpuif_deactivate(void)
+static void gicv3_cpuif_deactivate(void)
{
unsigned int val;
uintptr_t base;
@@ -126,7 +134,8 @@ void gicv3_cpuif_deactivate(void)
* GICR_WAKER is NOT banked per CPU, compute the correct base address
* per CPU.
*/
- base = gicv3_get_rdist(BASE_GICR_BASE, read_mpidr());
+ assert(g_gicr_base);
+ base = gicv3_get_rdist(g_gicr_base, read_mpidr());
if (base == (uintptr_t)NULL) {
/* No re-distributor base address. This interface cannot be
* configured.
@@ -141,9 +150,8 @@ void gicv3_cpuif_deactivate(void)
/* We need to wait for ChildrenAsleep to set. */
val = gicr_read_waker(base);
- while ((val & WAKER_CA) == 0) {
+ while ((val & WAKER_CA) == 0)
val = gicr_read_waker(base);
- }
}
@@ -151,91 +159,76 @@ void gicv3_cpuif_deactivate(void)
* Enable secure interrupts and use FIQs to route them. Disable legacy bypass
* and set the priority mask register to allow all interrupts to trickle in.
******************************************************************************/
-void gic_cpuif_setup(unsigned int gicc_base)
+void arm_gic_cpuif_setup(void)
{
unsigned int val;
- val = gicc_read_iidr(gicc_base);
+ assert(g_gicc_base);
+ val = gicc_read_iidr(g_gicc_base);
/*
* If GICv3 we need to do a bit of additional setup. We want to
* allow default GICv2 behaviour but allow the next stage to
* enable full gicv3 features.
*/
- if (((val >> GICC_IIDR_ARCH_SHIFT) & GICC_IIDR_ARCH_MASK) >= 3) {
+ if (((val >> GICC_IIDR_ARCH_SHIFT) & GICC_IIDR_ARCH_MASK) >= 3)
gicv3_cpuif_setup();
- }
val = ENABLE_GRP0 | FIQ_EN | FIQ_BYP_DIS_GRP0;
val |= IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP1 | IRQ_BYP_DIS_GRP1;
- gicc_write_pmr(gicc_base, GIC_PRI_MASK);
- gicc_write_ctlr(gicc_base, val);
+ gicc_write_pmr(g_gicc_base, GIC_PRI_MASK);
+ gicc_write_ctlr(g_gicc_base, val);
}
/*******************************************************************************
* Place the cpu interface in a state where it can never make a cpu exit wfi as
* as result of an asserted interrupt. This is critical for powering down a cpu
******************************************************************************/
-void gic_cpuif_deactivate(unsigned int gicc_base)
+void arm_gic_cpuif_deactivate(void)
{
unsigned int val;
/* Disable secure, non-secure interrupts and disable their bypass */
- val = gicc_read_ctlr(gicc_base);
+ assert(g_gicc_base);
+ val = gicc_read_ctlr(g_gicc_base);
val &= ~(ENABLE_GRP0 | ENABLE_GRP1);
val |= FIQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP0;
val |= IRQ_BYP_DIS_GRP0 | IRQ_BYP_DIS_GRP1;
- gicc_write_ctlr(gicc_base, val);
+ gicc_write_ctlr(g_gicc_base, val);
- val = gicc_read_iidr(gicc_base);
+ val = gicc_read_iidr(g_gicc_base);
/*
* If GICv3 we need to do a bit of additional setup. Make sure the
* RDIST is put to sleep.
*/
- if (((val >> GICC_IIDR_ARCH_SHIFT) & GICC_IIDR_ARCH_MASK) >= 3) {
+ if (((val >> GICC_IIDR_ARCH_SHIFT) & GICC_IIDR_ARCH_MASK) >= 3)
gicv3_cpuif_deactivate();
- }
}
/*******************************************************************************
* Per cpu gic distributor setup which will be done by all cpus after a cold
* boot/hotplug. This marks out the secure interrupts & enables them.
******************************************************************************/
-void gic_pcpu_distif_setup(unsigned int gicd_base)
+void arm_gic_pcpu_distif_setup(void)
{
- gicd_write_igroupr(gicd_base, 0, ~0);
-
- gicd_clr_igroupr(gicd_base, IRQ_SEC_PHY_TIMER);
- gicd_clr_igroupr(gicd_base, IRQ_SEC_SGI_0);
- gicd_clr_igroupr(gicd_base, IRQ_SEC_SGI_1);
- gicd_clr_igroupr(gicd_base, IRQ_SEC_SGI_2);
- gicd_clr_igroupr(gicd_base, IRQ_SEC_SGI_3);
- gicd_clr_igroupr(gicd_base, IRQ_SEC_SGI_4);
- gicd_clr_igroupr(gicd_base, IRQ_SEC_SGI_5);
- gicd_clr_igroupr(gicd_base, IRQ_SEC_SGI_6);
- gicd_clr_igroupr(gicd_base, IRQ_SEC_SGI_7);
-
- gicd_set_ipriorityr(gicd_base, IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY);
- gicd_set_ipriorityr(gicd_base, IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY);
- gicd_set_ipriorityr(gicd_base, IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY);
- gicd_set_ipriorityr(gicd_base, IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY);
- gicd_set_ipriorityr(gicd_base, IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY);
- gicd_set_ipriorityr(gicd_base, IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY);
- gicd_set_ipriorityr(gicd_base, IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY);
- gicd_set_ipriorityr(gicd_base, IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY);
- gicd_set_ipriorityr(gicd_base, IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY);
-
- gicd_set_isenabler(gicd_base, IRQ_SEC_PHY_TIMER);
- gicd_set_isenabler(gicd_base, IRQ_SEC_SGI_0);
- gicd_set_isenabler(gicd_base, IRQ_SEC_SGI_1);
- gicd_set_isenabler(gicd_base, IRQ_SEC_SGI_2);
- gicd_set_isenabler(gicd_base, IRQ_SEC_SGI_3);
- gicd_set_isenabler(gicd_base, IRQ_SEC_SGI_4);
- gicd_set_isenabler(gicd_base, IRQ_SEC_SGI_5);
- gicd_set_isenabler(gicd_base, IRQ_SEC_SGI_6);
- gicd_set_isenabler(gicd_base, IRQ_SEC_SGI_7);
+ unsigned int index, irq_num;
+
+ assert(g_gicd_base);
+ gicd_write_igroupr(g_gicd_base, 0, ~0);
+
+ assert(g_irq_sec_ptr);
+ for (index = 0; index < g_num_irqs; index++) {
+ irq_num = g_irq_sec_ptr[index];
+ if (irq_num < MIN_SPI_ID) {
+ /* We have an SGI or a PPI */
+ gicd_clr_igroupr(g_gicd_base, irq_num);
+ gicd_set_ipriorityr(g_gicd_base, irq_num,
+ GIC_HIGHEST_SEC_PRIORITY);
+ gicd_set_isenabler(g_gicd_base, irq_num);
+ }
+ }
}
/*******************************************************************************
@@ -243,63 +236,88 @@ void gic_pcpu_distif_setup(unsigned int gicd_base)
* cold boot. It marks out the secure SPIs, PPIs & SGIs and enables them. It
* then enables the secure GIC distributor interface.
******************************************************************************/
-void gic_distif_setup(unsigned int gicd_base)
+static void arm_gic_distif_setup(void)
{
- unsigned int ctr, num_ints, ctlr;
+ unsigned int num_ints, ctlr, index, irq_num;
/* Disable the distributor before going further */
- ctlr = gicd_read_ctlr(gicd_base);
+ assert(g_gicd_base);
+ ctlr = gicd_read_ctlr(g_gicd_base);
ctlr &= ~(ENABLE_GRP0 | ENABLE_GRP1);
- gicd_write_ctlr(gicd_base, ctlr);
+ gicd_write_ctlr(g_gicd_base, ctlr);
/*
* Mark out non-secure interrupts. Calculate number of
* IGROUPR registers to consider. Will be equal to the
* number of IT_LINES
*/
- num_ints = gicd_read_typer(gicd_base) & IT_LINES_NO_MASK;
+ num_ints = gicd_read_typer(g_gicd_base) & IT_LINES_NO_MASK;
num_ints++;
- for (ctr = 0; ctr < num_ints; ctr++)
- gicd_write_igroupr(gicd_base, ctr << IGROUPR_SHIFT, ~0);
+ for (index = 0; index < num_ints; index++)
+ gicd_write_igroupr(g_gicd_base, index << IGROUPR_SHIFT, ~0);
/* Configure secure interrupts now */
- gicd_clr_igroupr(gicd_base, IRQ_TZ_WDOG);
- gicd_set_ipriorityr(gicd_base, IRQ_TZ_WDOG, GIC_HIGHEST_SEC_PRIORITY);
- gicd_set_itargetsr(gicd_base, IRQ_TZ_WDOG,
- platform_get_core_pos(read_mpidr()));
- gicd_set_isenabler(gicd_base, IRQ_TZ_WDOG);
- gic_pcpu_distif_setup(gicd_base);
-
- gicd_write_ctlr(gicd_base, ctlr | ENABLE_GRP0);
+ assert(g_irq_sec_ptr);
+ for (index = 0; index < g_num_irqs; index++) {
+ irq_num = g_irq_sec_ptr[index];
+ if (irq_num >= MIN_SPI_ID) {
+ /* We have an SPI */
+ gicd_clr_igroupr(g_gicd_base, irq_num);
+ gicd_set_ipriorityr(g_gicd_base, irq_num,
+ GIC_HIGHEST_SEC_PRIORITY);
+ gicd_set_itargetsr(g_gicd_base, irq_num,
+ platform_get_core_pos(read_mpidr()));
+ gicd_set_isenabler(g_gicd_base, irq_num);
+ }
+ }
+ arm_gic_pcpu_distif_setup();
+
+ gicd_write_ctlr(g_gicd_base, ctlr | ENABLE_GRP0);
}
-void gic_setup(void)
+/*******************************************************************************
+ * Initialize the ARM GIC driver with the provided platform inputs
+******************************************************************************/
+void arm_gic_init(unsigned int gicc_base,
+ unsigned int gicd_base,
+ unsigned long gicr_base,
+ const unsigned int *irq_sec_ptr,
+ unsigned int num_irqs
+ )
{
- unsigned int gicd_base, gicc_base;
-
- gicd_base = fvp_get_cfgvar(CONFIG_GICD_ADDR);
- gicc_base = fvp_get_cfgvar(CONFIG_GICC_ADDR);
+ assert(gicc_base);
+ assert(gicd_base);
+ assert(gicr_base);
+ assert(irq_sec_ptr);
+ g_gicc_base = gicc_base;
+ g_gicd_base = gicd_base;
+ g_gicr_base = gicr_base;
+ g_irq_sec_ptr = irq_sec_ptr;
+ g_num_irqs = num_irqs;
+}
- gic_cpuif_setup(gicc_base);
- gic_distif_setup(gicd_base);
+/*******************************************************************************
+ * Setup the ARM GIC CPU and distributor interfaces.
+******************************************************************************/
+void arm_gic_setup(void)
+{
+ arm_gic_cpuif_setup();
+ arm_gic_distif_setup();
}
/*******************************************************************************
* An ARM processor signals interrupt exceptions through the IRQ and FIQ pins.
* The interrupt controller knows which pin/line it uses to signal a type of
- * interrupt. The platform knows which interrupt controller type is being used
- * in a particular security state e.g. with an ARM GIC, normal world could use
- * the GICv2 features while the secure world could use GICv3 features and vice
- * versa.
- * This function is exported by the platform to let the interrupt management
- * framework determine for a type of interrupt and security state, which line
- * should be used in the SCR_EL3 to control its routing to EL3. The interrupt
- * line is represented as the bit position of the IRQ or FIQ bit in the SCR_EL3.
+ * interrupt. This function provides a common implementation of
+ * plat_interrupt_type_to_line() in an ARM GIC environment for optional re-use
+ * across platforms. It lets the interrupt management framework determine
+ * for a type of interrupt and security state, which line should be used in the
+ * SCR_EL3 to control its routing to EL3. The interrupt line is represented as
+ * the bit position of the IRQ or FIQ bit in the SCR_EL3.
******************************************************************************/
-uint32_t plat_interrupt_type_to_line(uint32_t type, uint32_t security_state)
+uint32_t arm_gic_interrupt_type_to_line(uint32_t type,
+ uint32_t security_state)
{
- uint32_t gicc_base = fvp_get_cfgvar(CONFIG_GICC_ADDR);
-
assert(type == INTR_TYPE_S_EL1 ||
type == INTR_TYPE_EL3 ||
type == INTR_TYPE_NS);
@@ -311,25 +329,25 @@ uint32_t plat_interrupt_type_to_line(uint32_t type, uint32_t security_state)
* both normal and secure worlds are using ARM GICv2. This parameter
* will be used when the secure world starts using GICv3.
*/
-#if FVP_GIC_ARCH == 2
- return gicv2_interrupt_type_to_line(gicc_base, type);
+#if ARM_GIC_ARCH == 2
+ return gicv2_interrupt_type_to_line(g_gicc_base, type);
#else
-#error "Invalid GIC architecture version specified for FVP port"
-#endif
+#error "Invalid ARM GIC architecture version specified for platform port"
+#endif /* ARM_GIC_ARCH */
}
-#if FVP_GIC_ARCH == 2
+#if ARM_GIC_ARCH == 2
/*******************************************************************************
* This function returns the type of the highest priority pending interrupt at
* the GIC cpu interface. INTR_TYPE_INVAL is returned when there is no
* interrupt pending.
******************************************************************************/
-uint32_t plat_ic_get_pending_interrupt_type(void)
+uint32_t arm_gic_get_pending_interrupt_type(void)
{
- uint32_t id, gicc_base;
+ uint32_t id;
- gicc_base = fvp_get_cfgvar(CONFIG_GICC_ADDR);
- id = gicc_read_hppir(gicc_base);
+ assert(g_gicc_base);
+ id = gicc_read_hppir(g_gicc_base);
/* Assume that all secure interrupts are S-EL1 interrupts */
if (id < 1022)
@@ -346,12 +364,12 @@ uint32_t plat_ic_get_pending_interrupt_type(void)
* the GIC cpu interface. INTR_ID_UNAVAILABLE is returned when there is no
* interrupt pending.
******************************************************************************/
-uint32_t plat_ic_get_pending_interrupt_id(void)
+uint32_t arm_gic_get_pending_interrupt_id(void)
{
- uint32_t id, gicc_base;
+ uint32_t id;
- gicc_base = fvp_get_cfgvar(CONFIG_GICC_ADDR);
- id = gicc_read_hppir(gicc_base);
+ assert(g_gicc_base);
+ id = gicc_read_hppir(g_gicc_base);
if (id < 1022)
return id;
@@ -363,26 +381,27 @@ uint32_t plat_ic_get_pending_interrupt_id(void)
* Find out which non-secure interrupt it is under the assumption that
* the GICC_CTLR.AckCtl bit is 0.
*/
- return gicc_read_ahppir(gicc_base);
+ return gicc_read_ahppir(g_gicc_base);
}
/*******************************************************************************
* This functions reads the GIC cpu interface Interrupt Acknowledge register
* to start handling the pending interrupt. It returns the contents of the IAR.
******************************************************************************/
-uint32_t plat_ic_acknowledge_interrupt(void)
+uint32_t arm_gic_acknowledge_interrupt(void)
{
- return gicc_read_IAR(fvp_get_cfgvar(CONFIG_GICC_ADDR));
+ assert(g_gicc_base);
+ return gicc_read_IAR(g_gicc_base);
}
/*******************************************************************************
* This functions writes the GIC cpu interface End Of Interrupt register with
* the passed value to finish handling the active interrupt
******************************************************************************/
-void plat_ic_end_of_interrupt(uint32_t id)
+void arm_gic_end_of_interrupt(uint32_t id)
{
- gicc_write_EOIR(fvp_get_cfgvar(CONFIG_GICC_ADDR), id);
- return;
+ assert(g_gicc_base);
+ gicc_write_EOIR(g_gicc_base, id);
}
/*******************************************************************************
@@ -390,11 +409,12 @@ void plat_ic_end_of_interrupt(uint32_t id)
* this interrupt has been configured under by the interrupt controller i.e.
* group0 or group1.
******************************************************************************/
-uint32_t plat_ic_get_interrupt_type(uint32_t id)
+uint32_t arm_gic_get_interrupt_type(uint32_t id)
{
uint32_t group;
- group = gicd_get_igroupr(fvp_get_cfgvar(CONFIG_GICD_ADDR), id);
+ assert(g_gicd_base);
+ group = gicd_get_igroupr(g_gicd_base, id);
/* Assume that all secure interrupts are S-EL1 interrupts */
if (group == GRP0)
@@ -404,5 +424,5 @@ uint32_t plat_ic_get_interrupt_type(uint32_t id)
}
#else
-#error "Invalid GIC architecture version specified for FVP port"
-#endif
+#error "Invalid ARM GIC architecture version specified for platform port"
+#endif /* ARM_GIC_ARCH */
diff --git a/drivers/io/io_fip.c b/drivers/io/io_fip.c
index 36788a2..7df229d 100644
--- a/drivers/io/io_fip.c
+++ b/drivers/io/io_fip.c
@@ -66,6 +66,10 @@ typedef struct {
static const plat_fip_name_uuid_t name_uuid[] = {
{BL2_IMAGE_NAME, UUID_TRUSTED_BOOT_FIRMWARE_BL2},
+#ifdef BL30_IMAGE_NAME
+ /* BL3-0 is optional in the platform */
+ {BL30_IMAGE_NAME, UUID_SCP_FIRMWARE_BL30},
+#endif /* BL30_IMAGE_NAME */
{BL31_IMAGE_NAME, UUID_EL3_RUNTIME_FIRMWARE_BL31},
#ifdef BL32_IMAGE_NAME
/* BL3-2 is optional in the platform */
diff --git a/include/common/bl_common.h b/include/common/bl_common.h
index f5e2a9a..154c0f4 100644
--- a/include/common/bl_common.h
+++ b/include/common/bl_common.h
@@ -38,15 +38,11 @@
#define DOWN 0
/*******************************************************************************
- * Constants for loading images. When BLx wants to load BLy, it looks at a
- * meminfo structure to find the extents of free memory. Then depending upon
- * how it has been configured, it can either load BLy at the top or bottom of
- * the free memory. These constants indicate the choice.
- * TODO: Make this configurable while building the trusted firmware.
- ******************************************************************************/
-#define TOP_LOAD 0x1
-#define BOT_LOAD !TOP_LOAD
-#define LOAD_MASK (1 << 0)
+ * Constants to identify the location of a memory region in a given memory
+ * layout.
+******************************************************************************/
+#define TOP 0x1
+#define BOTTOM !TOP
/******************************************************************************
* Opcode passed in x0 to tell next EL that we want to run an image.
@@ -97,18 +93,17 @@
#include <cdefs.h> /* For __dead2 */
#include <cassert.h>
#include <stdint.h>
+#include <stddef.h>
/*******************************************************************************
* Structure used for telling the next BL how much of a particular type of
* memory is available for its use and how much is already used.
******************************************************************************/
typedef struct meminfo {
- unsigned long total_base;
- long total_size;
- unsigned long free_base;
- long free_size;
- unsigned long attr;
- unsigned long next;
+ uint64_t total_base;
+ size_t total_size;
+ uint64_t free_base;
+ size_t free_size;
} meminfo_t;
typedef struct aapcs64_params {
@@ -209,14 +204,16 @@ CASSERT(sizeof(unsigned long) ==
unsigned long page_align(unsigned long, unsigned);
void change_security_state(unsigned int);
unsigned long image_size(const char *);
-int load_image(meminfo_t *,
- const char *,
- unsigned int,
- unsigned long,
- image_info_t *,
- entry_point_info_t *);
+int load_image(meminfo_t *mem_layout,
+ const char *image_name,
+ uint64_t image_base,
+ image_info_t *image_data,
+ entry_point_info_t *entry_point_info);
extern const char build_message[];
+void reserve_mem(uint64_t *free_base, size_t *free_size,
+ uint64_t addr, size_t size);
+
#endif /*__ASSEMBLY__*/
#endif /* __BL_COMMON_H__ */
diff --git a/include/drivers/arm/arm_gic.h b/include/drivers/arm/arm_gic.h
new file mode 100644
index 0000000..9ab1a95
--- /dev/null
+++ b/include/drivers/arm/arm_gic.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARM_GIC_H__
+#define __ARM_GIC_H__
+
+#include <stdint.h>
+
+/*******************************************************************************
+ * Function declarations
+ ******************************************************************************/
+void arm_gic_init(unsigned int gicc_base,
+ unsigned int gicd_base,
+ unsigned long gicr_base,
+ const unsigned int *irq_sec_ptr,
+ unsigned int num_irqs);
+void arm_gic_setup(void);
+void arm_gic_cpuif_deactivate(void);
+void arm_gic_cpuif_setup(void);
+void arm_gic_pcpu_distif_setup(void);
+
+uint32_t arm_gic_interrupt_type_to_line(uint32_t type,
+ uint32_t security_state);
+uint32_t arm_gic_get_pending_interrupt_type(void);
+uint32_t arm_gic_get_pending_interrupt_id(void);
+uint32_t arm_gic_acknowledge_interrupt(void);
+void arm_gic_end_of_interrupt(uint32_t id);
+uint32_t arm_gic_get_interrupt_type(uint32_t id);
+
+#endif /* __GIC_H__ */
diff --git a/include/drivers/arm/gic_v2.h b/include/drivers/arm/gic_v2.h
index 1859a8e..4c6b0dc 100644
--- a/include/drivers/arm/gic_v2.h
+++ b/include/drivers/arm/gic_v2.h
@@ -36,6 +36,10 @@
#define MAX_PPIS 14
#define MAX_SGIS 16
+#define MIN_SGI_ID 0
+#define MIN_PPI_ID 16
+#define MIN_SPI_ID 32
+
#define GRP0 0
#define GRP1 1
#define GIC_PRI_MASK 0xff
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index 5dc488b..ff91efc 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -211,8 +211,23 @@
* TCR defintions
*/
#define TCR_EL3_RES1 ((1UL << 31) | (1UL << 23))
-
-#define TCR_T0SZ_4GB 32
+#define TCR_EL1_IPS_SHIFT 32
+#define TCR_EL3_PS_SHIFT 16
+
+/* (internal) physical address size bits in EL3/EL1 */
+#define TCR_PS_BITS_4GB (0x0)
+#define TCR_PS_BITS_64GB (0x1)
+#define TCR_PS_BITS_1TB (0x2)
+#define TCR_PS_BITS_4TB (0x3)
+#define TCR_PS_BITS_16TB (0x4)
+#define TCR_PS_BITS_256TB (0x5)
+
+#define ADDR_MASK_48_TO_63 0xFFFF000000000000UL
+#define ADDR_MASK_44_TO_47 0x0000F00000000000UL
+#define ADDR_MASK_42_TO_43 0x00000C0000000000UL
+#define ADDR_MASK_40_TO_41 0x0000030000000000UL
+#define ADDR_MASK_36_TO_39 0x000000F000000000UL
+#define ADDR_MASK_32_TO_35 0x0000000F00000000UL
#define TCR_RGN_INNER_NC (0x0 << 8)
#define TCR_RGN_INNER_WBA (0x1 << 8)
diff --git a/include/plat/common/plat_config.h b/include/plat/common/plat_config.h
new file mode 100644
index 0000000..826d01b
--- /dev/null
+++ b/include/plat/common/plat_config.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __PLAT_CONFIG_H__
+#define __PLAT_CONFIG_H__
+
+#define CONFIG_GICC_BASE_OFFSET 0x4
+
+
+#ifndef __ASSEMBLY__
+
+#include <cassert.h>
+
+
+enum plat_config_flags {
+ /* Whether CPUECTLR SMP bit should be enabled */
+ CONFIG_CPUECTLR_SMP_BIT = 0x1,
+ /* Whether Base FVP memory map is in use */
+ CONFIG_BASE_MMAP = 0x2,
+ /* Whether CCI should be enabled */
+ CONFIG_HAS_CCI = 0x4,
+ /* Whether TZC should be configured */
+ CONFIG_HAS_TZC = 0x8
+};
+
+typedef struct plat_config {
+ unsigned int gicd_base;
+ unsigned int gicc_base;
+ unsigned int gich_base;
+ unsigned int gicv_base;
+ unsigned int max_aff0;
+ unsigned int max_aff1;
+ unsigned long flags;
+} plat_config_t;
+
+inline const plat_config_t *get_plat_config();
+
+
+CASSERT(CONFIG_GICC_BASE_OFFSET == __builtin_offsetof(
+ plat_config_t, gicc_base),
+ assert_gicc_base_offset_mismatch);
+
+/* If used, plat_config must be defined and populated in the platform port*/
+extern plat_config_t plat_config;
+
+inline const plat_config_t *get_plat_config()
+{
+ return &plat_config;
+}
+
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __PLAT_CONFIG_H__ */
diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h
index c087dc6..1eeaac2 100644
--- a/include/plat/common/platform.h
+++ b/include/plat/common/platform.h
@@ -90,10 +90,8 @@ void bl1_plat_set_bl2_ep_info(struct image_info *image,
/*******************************************************************************
* Optional BL1 functions (may be overridden)
******************************************************************************/
-void init_bl2_mem_layout(struct meminfo *,
- struct meminfo *,
- unsigned int,
- unsigned long);
+void bl1_init_bl2_mem_layout(const struct meminfo *bl1_mem_layout,
+ struct meminfo *bl2_mem_layout);
/*******************************************************************************
* Mandatory BL2 functions
@@ -122,25 +120,42 @@ struct entry_point_info *bl2_plat_get_bl31_ep_info(void);
void bl2_plat_flush_bl31_params(void);
/*
- * The next 3 functions allow the platform to change the entrypoint
- * information for the 3rd level BL images, after BL2 has loaded the 3rd
- * level BL images into memory but before BL3-1 is executed.
+ * The next 2 functions allow the platform to change the entrypoint information
+ * for the mandatory 3rd level BL images, BL3-1 and BL3-3. This is done after
+ * BL2 has loaded those images into memory but before BL3-1 is executed.
*/
void bl2_plat_set_bl31_ep_info(struct image_info *image,
struct entry_point_info *ep);
-void bl2_plat_set_bl32_ep_info(struct image_info *image,
+void bl2_plat_set_bl33_ep_info(struct image_info *image,
struct entry_point_info *ep);
-void bl2_plat_set_bl33_ep_info(struct image_info *image,
+/* Gets the memory layout for BL3-3 */
+void bl2_plat_get_bl33_meminfo(struct meminfo *mem_info);
+
+/*******************************************************************************
+ * Conditionally mandatory BL2 functions: must be implemented if BL3-0 image
+ * is supported
+ ******************************************************************************/
+/* Gets the memory layout for BL3-0 */
+void bl2_plat_get_bl30_meminfo(struct meminfo *mem_info);
+
+/*
+ * This function is called after loading BL3-0 image and it is used to perform
+ * any platform-specific actions required to handle the SCP firmware.
+ */
+int bl2_plat_handle_bl30(struct image_info *bl30_image_info);
+
+/*******************************************************************************
+ * Conditionally mandatory BL2 functions: must be implemented if BL3-2 image
+ * is supported
+ ******************************************************************************/
+void bl2_plat_set_bl32_ep_info(struct image_info *image,
struct entry_point_info *ep);
-/* Gets the memory layout for BL32 */
+/* Gets the memory layout for BL3-2 */
void bl2_plat_get_bl32_meminfo(struct meminfo *mem_info);
-/* Gets the memory layout for BL33 */
-void bl2_plat_get_bl33_meminfo(struct meminfo *mem_info);
-
/*******************************************************************************
* Optional BL2 functions (may be overridden)
******************************************************************************/
diff --git a/lib/aarch64/xlat_tables.c b/lib/aarch64/xlat_tables.c
index 1b99cc8..f1d658d 100644
--- a/lib/aarch64/xlat_tables.c
+++ b/lib/aarch64/xlat_tables.c
@@ -31,6 +31,7 @@
#include <arch.h>
#include <arch_helpers.h>
#include <assert.h>
+#include <cassert.h>
#include <platform_def.h>
#include <string.h>
#include <xlat_tables.h>
@@ -46,6 +47,7 @@
#define debug_print(...) ((void)0)
#endif
+CASSERT(ADDR_SPACE_SIZE > 0, assert_valid_addr_space_size);
#define UNSET_DESC ~0ul
@@ -58,6 +60,9 @@ static uint64_t xlat_tables[MAX_XLAT_TABLES][XLAT_TABLE_ENTRIES]
__aligned(XLAT_TABLE_SIZE) __attribute__((section("xlat_table")));
static unsigned next_xlat;
+static unsigned long max_pa;
+static unsigned long max_va;
+static unsigned long tcr_ps_bits;
/*
* Array of all memory regions stored in order of ascending base address.
@@ -85,6 +90,8 @@ void mmap_add_region(unsigned long base_pa, unsigned long base_va,
{
mmap_region_t *mm = mmap;
mmap_region_t *mm_last = mm + sizeof(mmap) / sizeof(mmap[0]) - 1;
+ unsigned long pa_end = base_pa + size - 1;
+ unsigned long va_end = base_va + size - 1;
assert(IS_PAGE_ALIGNED(base_pa));
assert(IS_PAGE_ALIGNED(base_va));
@@ -107,6 +114,11 @@ void mmap_add_region(unsigned long base_pa, unsigned long base_va,
mm->base_va = base_va;
mm->size = size;
mm->attr = attr;
+
+ if (pa_end > max_pa)
+ max_pa = pa_end;
+ if (va_end > max_va)
+ max_va = va_end;
}
void mmap_add(const mmap_region_t *mm)
@@ -233,10 +245,40 @@ static mmap_region_t *init_xlation_table(mmap_region_t *mm,
return mm;
}
+static unsigned int calc_physical_addr_size_bits(unsigned long max_addr)
+{
+ /* Physical address can't exceed 48 bits */
+ assert((max_addr & ADDR_MASK_48_TO_63) == 0);
+
+ /* 48 bits address */
+ if (max_addr & ADDR_MASK_44_TO_47)
+ return TCR_PS_BITS_256TB;
+
+ /* 44 bits address */
+ if (max_addr & ADDR_MASK_42_TO_43)
+ return TCR_PS_BITS_16TB;
+
+ /* 42 bits address */
+ if (max_addr & ADDR_MASK_40_TO_41)
+ return TCR_PS_BITS_4TB;
+
+ /* 40 bits address */
+ if (max_addr & ADDR_MASK_36_TO_39)
+ return TCR_PS_BITS_1TB;
+
+ /* 36 bits address */
+ if (max_addr & ADDR_MASK_32_TO_35)
+ return TCR_PS_BITS_64GB;
+
+ return TCR_PS_BITS_4GB;
+}
+
void init_xlat_tables(void)
{
print_mmap();
init_xlation_table(mmap, 0, l1_xlation_table, 1);
+ tcr_ps_bits = calc_physical_addr_size_bits(max_pa);
+ assert(max_va < ADDR_SPACE_SIZE);
}
/*******************************************************************************
@@ -270,7 +312,8 @@ void init_xlat_tables(void)
/* Set TCR bits as well. */ \
/* Inner & outer WBWA & shareable + T0SZ = 32 */ \
tcr = TCR_SH_INNER_SHAREABLE | TCR_RGN_OUTER_WBA | \
- TCR_RGN_INNER_WBA | TCR_T0SZ_4GB; \
+ TCR_RGN_INNER_WBA | \
+ (64 - __builtin_ctzl(ADDR_SPACE_SIZE)); \
tcr |= _tcr_extra; \
write_tcr_el##_el(tcr); \
\
@@ -295,5 +338,9 @@ void init_xlat_tables(void)
}
/* Define EL1 and EL3 variants of the function enabling the MMU */
-DEFINE_ENABLE_MMU_EL(1, 0, tlbivmalle1)
-DEFINE_ENABLE_MMU_EL(3, TCR_EL3_RES1, tlbialle3)
+DEFINE_ENABLE_MMU_EL(1,
+ (tcr_ps_bits << TCR_EL1_IPS_SHIFT),
+ tlbivmalle1)
+DEFINE_ENABLE_MMU_EL(3,
+ TCR_EL3_RES1 | (tcr_ps_bits << TCR_EL3_PS_SHIFT),
+ tlbialle3)
diff --git a/plat/common/plat_gic.c b/plat/common/plat_gic.c
new file mode 100644
index 0000000..f736e55
--- /dev/null
+++ b/plat/common/plat_gic.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <arm_gic.h>
+
+/*
+ * The following platform GIC functions are weakly defined. They
+ * provide typical implementations that may be re-used by multiple
+ * platforms but may also be overridden by a platform if required.
+ */
+#pragma weak plat_ic_get_pending_interrupt_id
+#pragma weak plat_ic_get_pending_interrupt_type
+#pragma weak plat_ic_acknowledge_interrupt
+#pragma weak plat_ic_get_interrupt_type
+#pragma weak plat_ic_end_of_interrupt
+#pragma weak plat_interrupt_type_to_line
+
+uint32_t plat_ic_get_pending_interrupt_id(void)
+{
+ return arm_gic_get_pending_interrupt_id();
+}
+
+uint32_t plat_ic_get_pending_interrupt_type(void)
+{
+ return arm_gic_get_pending_interrupt_type();
+}
+
+uint32_t plat_ic_acknowledge_interrupt(void)
+{
+ return arm_gic_acknowledge_interrupt();
+}
+
+uint32_t plat_ic_get_interrupt_type(uint32_t id)
+{
+ return arm_gic_get_interrupt_type(id);
+}
+
+void plat_ic_end_of_interrupt(uint32_t id)
+{
+ arm_gic_end_of_interrupt(id);
+}
+
+uint32_t plat_interrupt_type_to_line(uint32_t type,
+ uint32_t security_state)
+{
+ return arm_gic_interrupt_type_to_line(type, security_state);
+}
diff --git a/plat/fvp/aarch64/fvp_common.c b/plat/fvp/aarch64/fvp_common.c
index 174085f..3fe3a21 100644
--- a/plat/fvp/aarch64/fvp_common.c
+++ b/plat/fvp/aarch64/fvp_common.c
@@ -30,23 +30,25 @@
#include <arch.h>
#include <arch_helpers.h>
+#include <arm_gic.h>
#include <assert.h>
#include <bl_common.h>
#include <cci400.h>
#include <debug.h>
#include <mmio.h>
#include <platform.h>
+#include <plat_config.h>
#include <xlat_tables.h>
#include "../fvp_def.h"
/*******************************************************************************
- * This array holds the characteristics of the differences between the three
+ * plat_config holds the characteristics of the differences between the three
* FVP platforms (Base, A53_A57 & Foundation). It will be populated during cold
* boot at each boot stage by the primary before enabling the MMU (to allow cci
* configuration) & used thereafter. Each BL will have its own copy to allow
* independent operation.
******************************************************************************/
-static unsigned long fvp_config[CONFIG_LIMIT];
+plat_config_t plat_config;
/*
* Table of regions to map using the MMU.
@@ -76,6 +78,23 @@ const mmap_region_t fvp_mmap[] = {
{0}
};
+/* Array of secure interrupts to be configured by the gic driver */
+const unsigned int irq_sec_array[] = {
+ IRQ_TZ_WDOG,
+ IRQ_SEC_PHY_TIMER,
+ IRQ_SEC_SGI_0,
+ IRQ_SEC_SGI_1,
+ IRQ_SEC_SGI_2,
+ IRQ_SEC_SGI_3,
+ IRQ_SEC_SGI_4,
+ IRQ_SEC_SGI_5,
+ IRQ_SEC_SGI_6,
+ IRQ_SEC_SGI_7
+};
+
+const unsigned int num_sec_irqs = sizeof(irq_sec_array) /
+ sizeof(irq_sec_array[0]);
+
/*******************************************************************************
* Macro generating the code for the function setting up the pagetables as per
* the platform memory map & initialize the mmu, for the given exception level
@@ -107,13 +126,6 @@ const mmap_region_t fvp_mmap[] = {
DEFINE_CONFIGURE_MMU_EL(1)
DEFINE_CONFIGURE_MMU_EL(3)
-/* Simple routine which returns a configuration variable value */
-unsigned long fvp_get_cfgvar(unsigned int var_id)
-{
- assert(var_id < CONFIG_LIMIT);
- return fvp_config[var_id];
-}
-
/*******************************************************************************
* A single boot loader stack is expected to work on both the Foundation FVP
* models and the two flavours of the Base FVP models (AEMv8 & Cortex). The
@@ -142,16 +154,16 @@ int fvp_config_setup(void)
*/
switch (bld) {
case BLD_GIC_VE_MMAP:
- fvp_config[CONFIG_GICD_ADDR] = VE_GICD_BASE;
- fvp_config[CONFIG_GICC_ADDR] = VE_GICC_BASE;
- fvp_config[CONFIG_GICH_ADDR] = VE_GICH_BASE;
- fvp_config[CONFIG_GICV_ADDR] = VE_GICV_BASE;
+ plat_config.gicd_base = VE_GICD_BASE;
+ plat_config.gicc_base = VE_GICC_BASE;
+ plat_config.gich_base = VE_GICH_BASE;
+ plat_config.gicv_base = VE_GICV_BASE;
break;
case BLD_GIC_A53A57_MMAP:
- fvp_config[CONFIG_GICD_ADDR] = BASE_GICD_BASE;
- fvp_config[CONFIG_GICC_ADDR] = BASE_GICC_BASE;
- fvp_config[CONFIG_GICH_ADDR] = BASE_GICH_BASE;
- fvp_config[CONFIG_GICV_ADDR] = BASE_GICV_BASE;
+ plat_config.gicd_base = BASE_GICD_BASE;
+ plat_config.gicc_base = BASE_GICC_BASE;
+ plat_config.gich_base = BASE_GICH_BASE;
+ plat_config.gicv_base = BASE_GICV_BASE;
break;
default:
ERROR("Unsupported board build %x\n", bld);
@@ -164,12 +176,9 @@ int fvp_config_setup(void)
*/
switch (hbi) {
case HBI_FOUNDATION:
- fvp_config[CONFIG_MAX_AFF0] = 4;
- fvp_config[CONFIG_MAX_AFF1] = 1;
- fvp_config[CONFIG_CPU_SETUP] = 0;
- fvp_config[CONFIG_BASE_MMAP] = 0;
- fvp_config[CONFIG_HAS_CCI] = 0;
- fvp_config[CONFIG_HAS_TZC] = 0;
+ plat_config.max_aff0 = 4;
+ plat_config.max_aff1 = 1;
+ plat_config.flags = 0;
/*
* Check for supported revisions of Foundation FVP
@@ -186,16 +195,14 @@ int fvp_config_setup(void)
break;
case HBI_FVP_BASE:
midr_pn = (read_midr() >> MIDR_PN_SHIFT) & MIDR_PN_MASK;
- if ((midr_pn == MIDR_PN_A57) || (midr_pn == MIDR_PN_A53))
- fvp_config[CONFIG_CPU_SETUP] = 1;
- else
- fvp_config[CONFIG_CPU_SETUP] = 0;
+ plat_config.flags =
+ ((midr_pn == MIDR_PN_A57) || (midr_pn == MIDR_PN_A53))
+ ? CONFIG_CPUECTLR_SMP_BIT : 0;
- fvp_config[CONFIG_MAX_AFF0] = 4;
- fvp_config[CONFIG_MAX_AFF1] = 2;
- fvp_config[CONFIG_BASE_MMAP] = 1;
- fvp_config[CONFIG_HAS_CCI] = 1;
- fvp_config[CONFIG_HAS_TZC] = 1;
+ plat_config.max_aff0 = 4;
+ plat_config.max_aff1 = 2;
+ plat_config.flags |= CONFIG_BASE_MMAP | CONFIG_HAS_CCI |
+ CONFIG_HAS_TZC;
/*
* Check for supported revisions
@@ -237,18 +244,24 @@ uint64_t plat_get_syscnt_freq(void)
void fvp_cci_setup(void)
{
- unsigned long cci_setup;
-
/*
* Enable CCI-400 for this cluster. No need
* for locks as no other cpu is active at the
* moment
*/
- cci_setup = fvp_get_cfgvar(CONFIG_HAS_CCI);
- if (cci_setup)
+ if (plat_config.flags & CONFIG_HAS_CCI)
cci_enable_coherency(read_mpidr());
}
+void fvp_gic_init(void)
+{
+ arm_gic_init(plat_config.gicc_base,
+ plat_config.gicd_base,
+ BASE_GICR_BASE,
+ irq_sec_array,
+ num_sec_irqs);
+}
+
/*******************************************************************************
* Gets SPSR for BL32 entry
diff --git a/plat/fvp/bl1_fvp_setup.c b/plat/fvp/bl1_fvp_setup.c
index f758082..bfd0f55 100644
--- a/plat/fvp/bl1_fvp_setup.c
+++ b/plat/fvp/bl1_fvp_setup.c
@@ -31,10 +31,12 @@
#include <arch_helpers.h>
#include <assert.h>
#include <bl_common.h>
+#include <debug.h>
#include <console.h>
#include <mmio.h>
#include <platform.h>
#include <platform_def.h>
+#include "../../bl1/bl1_private.h"
#include "fvp_def.h"
#include "fvp_private.h"
@@ -45,9 +47,6 @@
extern unsigned long __COHERENT_RAM_START__;
extern unsigned long __COHERENT_RAM_END__;
-extern unsigned long __BL1_RAM_START__;
-extern unsigned long __BL1_RAM_END__;
-
/*
* The next 2 constants identify the extents of the coherent memory region.
* These addresses are used by the MMU setup code and therefore they must be
@@ -58,10 +57,6 @@ extern unsigned long __BL1_RAM_END__;
#define BL1_COHERENT_RAM_BASE (unsigned long)(&__COHERENT_RAM_START__)
#define BL1_COHERENT_RAM_LIMIT (unsigned long)(&__COHERENT_RAM_END__)
-#define BL1_RAM_BASE (unsigned long)(&__BL1_RAM_START__)
-#define BL1_RAM_LIMIT (unsigned long)(&__BL1_RAM_END__)
-
-
/* Data structure which holds the extents of the trusted SRAM for BL1*/
static meminfo_t bl1_tzram_layout;
@@ -75,34 +70,25 @@ meminfo_t *bl1_plat_sec_mem_layout(void)
******************************************************************************/
void bl1_early_platform_setup(void)
{
- const unsigned long bl1_ram_base = BL1_RAM_BASE;
- const unsigned long bl1_ram_limit = BL1_RAM_LIMIT;
- const unsigned long tzram_limit = TZRAM_BASE + TZRAM_SIZE;
+ const size_t bl1_size = BL1_RAM_LIMIT - BL1_RAM_BASE;
/* Initialize the console to provide early debug support */
console_init(PL011_UART0_BASE);
- /*
- * Calculate how much ram is BL1 using & how much remains free.
- * This also includes a rudimentary mechanism to detect whether
- * the BL1 data is loaded at the top or bottom of memory.
- * TODO: add support for discontigous chunks of free ram if
- * needed. Might need dynamic memory allocation support
- * et al.
- */
+ /* Allow BL1 to see the whole Trusted RAM */
bl1_tzram_layout.total_base = TZRAM_BASE;
bl1_tzram_layout.total_size = TZRAM_SIZE;
- if (bl1_ram_limit == tzram_limit) {
- /* BL1 has been loaded at the top of memory. */
- bl1_tzram_layout.free_base = TZRAM_BASE;
- bl1_tzram_layout.free_size = bl1_ram_base - TZRAM_BASE;
- } else {
- /* BL1 has been loaded at the bottom of memory. */
- bl1_tzram_layout.free_base = bl1_ram_limit;
- bl1_tzram_layout.free_size =
- tzram_limit - bl1_ram_limit;
- }
+ /* Calculate how much RAM BL1 is using and how much remains free */
+ bl1_tzram_layout.free_base = TZRAM_BASE;
+ bl1_tzram_layout.free_size = TZRAM_SIZE;
+ reserve_mem(&bl1_tzram_layout.free_base,
+ &bl1_tzram_layout.free_size,
+ BL1_RAM_BASE,
+ bl1_size);
+
+ INFO("BL1: 0x%lx - 0x%lx [size = %u]\n", BL1_RAM_BASE, BL1_RAM_LIMIT,
+ bl1_size);
/* Initialize the platform config for future decision making */
fvp_config_setup();
diff --git a/plat/fvp/bl2_fvp_setup.c b/plat/fvp/bl2_fvp_setup.c
index e6c2c36..beba804 100644
--- a/plat/fvp/bl2_fvp_setup.c
+++ b/plat/fvp/bl2_fvp_setup.c
@@ -171,12 +171,7 @@ void bl2_early_platform_setup(meminfo_t *mem_layout)
console_init(PL011_UART0_BASE);
/* Setup the BL2 memory layout */
- bl2_tzram_layout.total_base = mem_layout->total_base;
- bl2_tzram_layout.total_size = mem_layout->total_size;
- bl2_tzram_layout.free_base = mem_layout->free_base;
- bl2_tzram_layout.free_size = mem_layout->free_size;
- bl2_tzram_layout.attr = mem_layout->attr;
- bl2_tzram_layout.next = 0;
+ bl2_tzram_layout = *mem_layout;
/* Initialize the platform config for future decision making */
fvp_config_setup();
@@ -278,8 +273,6 @@ void bl2_plat_get_bl32_meminfo(meminfo_t *bl32_meminfo)
(TSP_SEC_MEM_BASE + TSP_SEC_MEM_SIZE) - BL32_BASE;
bl32_meminfo->free_size =
(TSP_SEC_MEM_BASE + TSP_SEC_MEM_SIZE) - BL32_BASE;
- bl32_meminfo->attr = BOT_LOAD;
- bl32_meminfo->next = 0;
}
@@ -292,6 +285,4 @@ void bl2_plat_get_bl33_meminfo(meminfo_t *bl33_meminfo)
bl33_meminfo->total_size = DRAM_SIZE - DRAM1_SEC_SIZE;
bl33_meminfo->free_base = DRAM_BASE;
bl33_meminfo->free_size = DRAM_SIZE - DRAM1_SEC_SIZE;
- bl33_meminfo->attr = 0;
- bl33_meminfo->attr = 0;
}
diff --git a/plat/fvp/bl31_fvp_setup.c b/plat/fvp/bl31_fvp_setup.c
index 8337ea4..96f4772 100644
--- a/plat/fvp/bl31_fvp_setup.c
+++ b/plat/fvp/bl31_fvp_setup.c
@@ -30,6 +30,7 @@
#include <arch.h>
#include <arch_helpers.h>
+#include <arm_gic.h>
#include <assert.h>
#include <bl_common.h>
#include <bl31.h>
@@ -183,7 +184,8 @@ void bl31_platform_setup(void)
unsigned int reg_val;
/* Initialize the gic cpu and distributor interfaces */
- gic_setup();
+ fvp_gic_init();
+ arm_gic_setup();
/*
* TODO: Configure the CLCD before handing control to
diff --git a/plat/fvp/bl32_fvp_setup.c b/plat/fvp/bl32_fvp_setup.c
index 3c09ca2..901c585 100644
--- a/plat/fvp/bl32_fvp_setup.c
+++ b/plat/fvp/bl32_fvp_setup.c
@@ -83,7 +83,7 @@ void bl32_early_platform_setup(void)
******************************************************************************/
void bl32_platform_setup(void)
{
-
+ fvp_gic_init();
}
/*******************************************************************************
diff --git a/plat/fvp/fvp_def.h b/plat/fvp/fvp_def.h
index 19422fd..89c8b02 100644
--- a/plat/fvp/fvp_def.h
+++ b/plat/fvp/fvp_def.h
@@ -37,21 +37,6 @@
/* Firmware Image Package */
#define FIP_IMAGE_NAME "fip.bin"
-/* Constants for accessing platform configuration */
-#define CONFIG_GICD_ADDR 0
-#define CONFIG_GICC_ADDR 1
-#define CONFIG_GICH_ADDR 2
-#define CONFIG_GICV_ADDR 3
-#define CONFIG_MAX_AFF0 4
-#define CONFIG_MAX_AFF1 5
-/* Indicate whether the CPUECTLR SMP bit should be enabled. */
-#define CONFIG_CPU_SETUP 6
-#define CONFIG_BASE_MMAP 7
-/* Indicates whether CCI should be enabled on the platform. */
-#define CONFIG_HAS_CCI 8
-#define CONFIG_HAS_TZC 9
-#define CONFIG_LIMIT 10
-
/*******************************************************************************
* FVP memory map related constants
******************************************************************************/
diff --git a/plat/fvp/fvp_pm.c b/plat/fvp/fvp_pm.c
index 03f06e7..55f465b 100644
--- a/plat/fvp/fvp_pm.c
+++ b/plat/fvp/fvp_pm.c
@@ -29,11 +29,13 @@
*/
#include <arch_helpers.h>
+#include <arm_gic.h>
#include <assert.h>
#include <bakery_lock.h>
#include <cci400.h>
#include <mmio.h>
#include <platform.h>
+#include <plat_config.h>
#include <platform_def.h>
#include <psci.h>
#include "drivers/pwrc/fvp_pwrc.h"
@@ -129,8 +131,7 @@ int fvp_affinst_off(unsigned long mpidr,
unsigned int state)
{
int rc = PSCI_E_SUCCESS;
- unsigned int gicc_base, ectlr;
- unsigned long cpu_setup, cci_setup;
+ unsigned int ectlr;
switch (afflvl) {
case MPIDR_AFFLVL1:
@@ -139,10 +140,8 @@ int fvp_affinst_off(unsigned long mpidr,
* Disable coherency if this cluster is to be
* turned off
*/
- cci_setup = fvp_get_cfgvar(CONFIG_HAS_CCI);
- if (cci_setup) {
+ if (get_plat_config()->flags & CONFIG_HAS_CCI)
cci_disable_coherency(mpidr);
- }
/*
* Program the power controller to turn the
@@ -160,8 +159,7 @@ int fvp_affinst_off(unsigned long mpidr,
* Take this cpu out of intra-cluster coherency if
* the FVP flavour supports the SMP bit.
*/
- cpu_setup = fvp_get_cfgvar(CONFIG_CPU_SETUP);
- if (cpu_setup) {
+ if (get_plat_config()->flags & CONFIG_CPUECTLR_SMP_BIT) {
ectlr = read_cpuectlr();
ectlr &= ~CPUECTLR_SMP_BIT;
write_cpuectlr(ectlr);
@@ -171,8 +169,7 @@ int fvp_affinst_off(unsigned long mpidr,
* Prevent interrupts from spuriously waking up
* this cpu
*/
- gicc_base = fvp_get_cfgvar(CONFIG_GICC_ADDR);
- gic_cpuif_deactivate(gicc_base);
+ arm_gic_cpuif_deactivate();
/*
* Program the power controller to power this
@@ -208,8 +205,8 @@ int fvp_affinst_suspend(unsigned long mpidr,
unsigned int state)
{
int rc = PSCI_E_SUCCESS;
- unsigned int gicc_base, ectlr;
- unsigned long cpu_setup, cci_setup, linear_id;
+ unsigned int ectlr;
+ unsigned long linear_id;
mailbox_t *fvp_mboxes;
switch (afflvl) {
@@ -219,10 +216,8 @@ int fvp_affinst_suspend(unsigned long mpidr,
* Disable coherency if this cluster is to be
* turned off
*/
- cci_setup = fvp_get_cfgvar(CONFIG_HAS_CCI);
- if (cci_setup) {
+ if (get_plat_config()->flags & CONFIG_HAS_CCI)
cci_disable_coherency(mpidr);
- }
/*
* Program the power controller to turn the
@@ -239,8 +234,7 @@ int fvp_affinst_suspend(unsigned long mpidr,
* Take this cpu out of intra-cluster coherency if
* the FVP flavour supports the SMP bit.
*/
- cpu_setup = fvp_get_cfgvar(CONFIG_CPU_SETUP);
- if (cpu_setup) {
+ if (get_plat_config()->flags & CONFIG_CPUECTLR_SMP_BIT) {
ectlr = read_cpuectlr();
ectlr &= ~CPUECTLR_SMP_BIT;
write_cpuectlr(ectlr);
@@ -257,8 +251,7 @@ int fvp_affinst_suspend(unsigned long mpidr,
* Prevent interrupts from spuriously waking up
* this cpu
*/
- gicc_base = fvp_get_cfgvar(CONFIG_GICC_ADDR);
- gic_cpuif_deactivate(gicc_base);
+ arm_gic_cpuif_deactivate();
/*
* Program the power controller to power this
@@ -288,9 +281,9 @@ int fvp_affinst_on_finish(unsigned long mpidr,
unsigned int state)
{
int rc = PSCI_E_SUCCESS;
- unsigned long linear_id, cpu_setup;
+ unsigned long linear_id;
mailbox_t *fvp_mboxes;
- unsigned int gicd_base, gicc_base, ectlr;
+ unsigned int ectlr;
switch (afflvl) {
@@ -325,8 +318,7 @@ int fvp_affinst_on_finish(unsigned long mpidr,
* Turn on intra-cluster coherency if the FVP flavour supports
* it.
*/
- cpu_setup = fvp_get_cfgvar(CONFIG_CPU_SETUP);
- if (cpu_setup) {
+ if (get_plat_config()->flags & CONFIG_CPUECTLR_SMP_BIT) {
ectlr = read_cpuectlr();
ectlr |= CPUECTLR_SMP_BIT;
write_cpuectlr(ectlr);
@@ -345,14 +337,11 @@ int fvp_affinst_on_finish(unsigned long mpidr,
flush_dcache_range((unsigned long) &fvp_mboxes[linear_id],
sizeof(unsigned long));
- gicd_base = fvp_get_cfgvar(CONFIG_GICD_ADDR);
- gicc_base = fvp_get_cfgvar(CONFIG_GICC_ADDR);
-
/* Enable the gic cpu interface */
- gic_cpuif_setup(gicc_base);
+ arm_gic_cpuif_setup();
/* TODO: This setup is needed only after a cold boot */
- gic_pcpu_distif_setup(gicd_base);
+ arm_gic_pcpu_distif_setup();
break;
diff --git a/plat/fvp/fvp_private.h b/plat/fvp/fvp_private.h
index b8578dd..054baa8 100644
--- a/plat/fvp/fvp_private.h
+++ b/plat/fvp/fvp_private.h
@@ -75,16 +75,11 @@ void fvp_configure_mmu_el3(unsigned long total_base,
unsigned long,
unsigned long,
unsigned long);
-unsigned long fvp_get_cfgvar(unsigned int);
int fvp_config_setup(void);
void fvp_cci_setup(void);
-/* Declarations for fvp_gic.c */
-void gic_cpuif_deactivate(unsigned int);
-void gic_cpuif_setup(unsigned int);
-void gic_pcpu_distif_setup(unsigned int);
-void gic_setup(void);
+void fvp_gic_init(void);
/* Declarations for fvp_topology.c */
int fvp_setup_topology(void);
diff --git a/plat/fvp/fvp_security.c b/plat/fvp/fvp_security.c
index 76c4541..0adbbc5 100644
--- a/plat/fvp/fvp_security.c
+++ b/plat/fvp/fvp_security.c
@@ -30,6 +30,7 @@
#include <assert.h>
#include <debug.h>
+#include <plat_config.h>
#include <tzc400.h>
#include "fvp_def.h"
#include "fvp_private.h"
@@ -56,7 +57,7 @@ void fvp_security_setup(void)
* configurations, those would be configured here.
*/
- if (!fvp_get_cfgvar(CONFIG_HAS_TZC))
+ if (!(get_plat_config()->flags & CONFIG_HAS_TZC))
return;
/*
diff --git a/plat/fvp/include/plat_macros.S b/plat/fvp/include/plat_macros.S
index d2e7cbc..602eaf1 100644
--- a/plat/fvp/include/plat_macros.S
+++ b/plat/fvp/include/plat_macros.S
@@ -29,7 +29,7 @@
*/
#include <gic_v2.h>
-#include "../fvp_def.h"
+#include <plat_config.h>
.section .rodata.gic_reg_name, "aS"
gic_regs: .asciz "gic_iar", "gic_ctlr", ""
@@ -43,8 +43,8 @@ gic_regs: .asciz "gic_iar", "gic_ctlr", ""
* ---------------------------------------------
*/
.macro plat_print_gic_regs
- mov x0, #CONFIG_GICC_ADDR
- bl fvp_get_cfgvar
+ adr x0, plat_config;
+ ldr w0, [x0, #CONFIG_GICC_BASE_OFFSET]
/* gic base address is now in x0 */
ldr w1, [x0, #GICC_IAR]
ldr w2, [x0, #GICC_CTLR]
diff --git a/plat/fvp/include/platform_def.h b/plat/fvp/include/platform_def.h
index fe4d73b..ec4cf52 100644
--- a/plat/fvp/include/platform_def.h
+++ b/plat/fvp/include/platform_def.h
@@ -101,24 +101,33 @@
******************************************************************************/
#define BL1_RO_BASE TZROM_BASE
#define BL1_RO_LIMIT (TZROM_BASE + TZROM_SIZE)
-#define BL1_RW_BASE TZRAM_BASE
-#define BL1_RW_LIMIT BL31_BASE
+/*
+ * Put BL1 RW at the top of the Trusted SRAM. BL1_RW_BASE is calculated using
+ * the current BL1 RW debug size plus a little space for growth.
+ */
+#define BL1_RW_BASE (TZRAM_BASE + TZRAM_SIZE - 0x6000)
+#define BL1_RW_LIMIT (TZRAM_BASE + TZRAM_SIZE)
/*******************************************************************************
* BL2 specific defines.
******************************************************************************/
-#define BL2_BASE (TZRAM_BASE + TZRAM_SIZE - 0xc000)
-#define BL2_LIMIT (TZRAM_BASE + TZRAM_SIZE)
+/*
+ * Put BL2 just below BL3-1. BL2_BASE is calculated using the current BL2 debug
+ * size plus a little space for growth.
+ */
+#define BL2_BASE (BL31_BASE - 0xC000)
+#define BL2_LIMIT BL31_BASE
/*******************************************************************************
* BL31 specific defines.
******************************************************************************/
-#define BL31_BASE (TZRAM_BASE + 0x6000)
-#if TSP_RAM_LOCATION_ID == TSP_IN_TZRAM
-#define BL31_LIMIT BL32_BASE
-#elif TSP_RAM_LOCATION_ID == TSP_IN_TZDRAM
-#define BL31_LIMIT BL2_BASE
-#endif
+/*
+ * Put BL3-1 at the top of the Trusted SRAM. BL31_BASE is calculated using the
+ * current BL3-1 debug size plus a little space for growth.
+ */
+#define BL31_BASE (TZRAM_BASE + TZRAM_SIZE - 0x1D000)
+#define BL31_PROGBITS_LIMIT BL1_RW_BASE
+#define BL31_LIMIT (TZRAM_BASE + TZRAM_SIZE)
/*******************************************************************************
* BL32 specific defines.
@@ -132,8 +141,9 @@
#if TSP_RAM_LOCATION_ID == TSP_IN_TZRAM
# define TSP_SEC_MEM_BASE TZRAM_BASE
# define TSP_SEC_MEM_SIZE TZRAM_SIZE
-# define BL32_BASE (TZRAM_BASE + TZRAM_SIZE - 0x1c000)
-# define BL32_LIMIT BL2_BASE
+# define BL32_BASE TZRAM_BASE
+# define BL32_PROGBITS_LIMIT BL2_BASE
+# define BL32_LIMIT BL31_BASE
#elif TSP_RAM_LOCATION_ID == TSP_IN_TZDRAM
# define TSP_SEC_MEM_BASE TZDRAM_BASE
# define TSP_SEC_MEM_SIZE TZDRAM_SIZE
diff --git a/plat/fvp/platform.mk b/plat/fvp/platform.mk
index ccd5afb..21ac1e7 100644
--- a/plat/fvp/platform.mk
+++ b/plat/fvp/platform.mk
@@ -69,12 +69,13 @@ BL2_SOURCES += drivers/arm/tzc400/tzc400.c \
plat/fvp/aarch64/fvp_common.c
BL31_SOURCES += drivers/arm/cci400/cci400.c \
+ drivers/arm/gic/arm_gic.c \
drivers/arm/gic/gic_v2.c \
drivers/arm/gic/gic_v3.c \
drivers/arm/tzc400/tzc400.c \
+ plat/common/plat_gic.c \
plat/common/aarch64/platform_mp_stack.S \
plat/fvp/bl31_fvp_setup.c \
- plat/fvp/fvp_gic.c \
plat/fvp/fvp_pm.c \
plat/fvp/fvp_security.c \
plat/fvp/fvp_topology.c \
@@ -82,7 +83,7 @@ BL31_SOURCES += drivers/arm/cci400/cci400.c \
plat/fvp/aarch64/fvp_common.c \
plat/fvp/drivers/pwrc/fvp_pwrc.c
-# Flag used by the FVP port to determine the version of ARM GIC architecture
-# to use for interrupt management in EL3.
-FVP_GIC_ARCH := 2
-$(eval $(call add_define,FVP_GIC_ARCH))
+# Flag used by the platform port to determine the version of ARM GIC
+# architecture to use for interrupt management in EL3.
+ARM_GIC_ARCH := 2
+$(eval $(call add_define,ARM_GIC_ARCH))