aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeenu Viswambharan <jeenu.viswambharan@arm.com>2014-02-20 17:11:00 +0000
committerDan Handley <dan.handley@arm.com>2014-02-26 19:53:48 +0000
commit7f36660559a7d4786e9a30de6c5af74338ed9469 (patch)
tree83a0563d40d60b490b33ca079cdc24c5a1432fcc
parent9128ffe9413c4070ec08042dfee28f2aec9804ed (diff)
downloadarm-trusted-firmware-7f36660559a7d4786e9a30de6c5af74338ed9469.tar.gz
Implement late binding for runtime hooks
At present SPD power management hooks and BL3-2 entry are implemented using weak references. This would have the handlers bound and registered with the core framework at build time, but leaves them dangling if a service fails to initialize at runtime. This patch replaces implementation by requiring runtime handlers to register power management and deferred initialization hooks with the core framework at runtime. The runtime services are to register the hooks only as the last step, after having all states successfully initialized. Change-Id: Ibe788a2a381ef39aec1d4af5ba02376e67269782
-rw-r--r--bl31/bl31_main.c40
-rw-r--r--include/bl31.h8
-rw-r--r--include/psci.h1
-rw-r--r--services/psci/psci_afflvl_off.c4
-rw-r--r--services/psci/psci_afflvl_on.c8
-rw-r--r--services/psci/psci_afflvl_suspend.c8
-rw-r--r--services/psci/psci_common.c16
-rw-r--r--services/psci/psci_private.h5
-rw-r--r--services/spd/tspd/tspd_main.c31
-rw-r--r--services/spd/tspd/tspd_pm.c3
-rw-r--r--services/spd/tspd/tspd_private.h3
11 files changed, 89 insertions, 38 deletions
diff --git a/bl31/bl31_main.c b/bl31/bl31_main.c
index ea44871..82449f5 100644
--- a/bl31/bl31_main.c
+++ b/bl31/bl31_main.c
@@ -40,6 +40,15 @@
#include <runtime_svc.h>
#include <context_mgmt.h>
+
+/*******************************************************************************
+ * This function pointer is used to initialise the BL32 image. It's initialized
+ * by SPD calling bl31_register_bl32_init after setting up all things necessary
+ * for SP execution. In cases where both SPD and SP are absent, or when SPD
+ * finds it impossible to execute SP, this pointer is left as NULL
+ ******************************************************************************/
+static int32_t (*bl32_init)(meminfo *);
+
/*******************************************************************************
* Variable to indicate whether next image to execute after BL31 is BL33
* (non-secure & default) or BL32 (secure).
@@ -97,19 +106,21 @@ void bl31_main(void)
write_vbar_el3((uint64_t) runtime_exceptions);
/*
- * All the cold boot actions on the primary cpu are done. We
- * now need to decide which is the next image (BL32 or BL33)
- * and how to execute it. If the SPD runtime service is
- * present, it would want to pass control to BL32 first in
- * S-EL1. It will export the bl32_init() routine where it takes
- * responsibility of entering S-EL1 and returning control back
- * to bl31_main. Once this is done we can prepare entry into
- * BL33 as normal.
+ * All the cold boot actions on the primary cpu are done. We now need to
+ * decide which is the next image (BL32 or BL33) and how to execute it.
+ * If the SPD runtime service is present, it would want to pass control
+ * to BL32 first in S-EL1. In that case, SPD would have registered a
+ * function to intialize bl32 where it takes responsibility of entering
+ * S-EL1 and returning control back to bl31_main. Once this is done we
+ * can prepare entry into BL33 as normal.
*/
- /* Tell BL32 about it memory extents as well */
+ /*
+ * If SPD had registerd an init hook, invoke it. Pass it the information
+ * about memory extents
+ */
if (bl32_init)
- bl32_init(bl31_plat_get_bl32_mem_layout());
+ (*bl32_init)(bl31_plat_get_bl32_mem_layout());
/*
* We are ready to enter the next EL. Prepare entry into the image
@@ -175,3 +186,12 @@ void bl31_prepare_next_image_entry()
/* Finally set the next context */
cm_set_next_eret_context(next_image_info->security_state);
}
+
+/*******************************************************************************
+ * This function initializes the pointer to BL32 init function. This is expected
+ * to be called by the SPD after it finishes all its initialization
+ ******************************************************************************/
+void bl31_register_bl32_init(int32_t (*func)(meminfo *))
+{
+ bl32_init = func;
+}
diff --git a/include/bl31.h b/include/bl31.h
index 8b2c787..b8c603a 100644
--- a/include/bl31.h
+++ b/include/bl31.h
@@ -49,11 +49,5 @@ extern el_change_info *bl31_get_next_image_info(uint32_t type);
extern void bl31_platform_setup(void);
extern meminfo *bl31_plat_get_bl32_mem_layout(void);
extern meminfo *bl31_plat_sec_mem_layout(void);
-
-/*
- * This function is used to initialise the BL32 image. It is a weak
- * declaration to cope with a system where the Secure Payload
- * Dispatcher is absent.
- */
-extern int32_t bl32_init(meminfo *) __attribute__ ((weak));
+extern void bl31_register_bl32_init(int32_t (*)(meminfo *));
#endif /* __BL31_H__ */
diff --git a/include/psci.h b/include/psci.h
index 3a040f9..922f95f 100644
--- a/include/psci.h
+++ b/include/psci.h
@@ -172,6 +172,7 @@ extern int psci_cpu_on(unsigned long,
unsigned long);
extern void psci_aff_on_finish_entry(void);
extern void psci_aff_suspend_finish_entry(void);
+extern void psci_register_spd_pm_hook(const spd_pm_ops *);
#endif /*__ASSEMBLY__*/
diff --git a/services/psci/psci_afflvl_off.c b/services/psci/psci_afflvl_off.c
index 24c212f..3763f6f 100644
--- a/services/psci/psci_afflvl_off.c
+++ b/services/psci/psci_afflvl_off.c
@@ -65,8 +65,8 @@ static int psci_afflvl0_off(unsigned long mpidr, aff_map_node *cpu_node)
* to let it do any bookeeping. Assume that the SPD always reports an
* E_DENIED error if SP refuse to power down
*/
- if (spd_pm.svc_off) {
- rc = spd_pm.svc_off(0);
+ if (psci_spd_pm && psci_spd_pm->svc_off) {
+ rc = psci_spd_pm->svc_off(0);
if (rc)
return rc;
}
diff --git a/services/psci/psci_afflvl_on.c b/services/psci/psci_afflvl_on.c
index ee16c73..0878f21 100644
--- a/services/psci/psci_afflvl_on.c
+++ b/services/psci/psci_afflvl_on.c
@@ -95,8 +95,8 @@ static int psci_afflvl0_on(unsigned long target_cpu,
* to let it do any bookeeping. If the handler encounters an error, it's
* expected to assert within
*/
- if (spd_pm.svc_on)
- spd_pm.svc_on(target_cpu);
+ if (psci_spd_pm && psci_spd_pm->svc_on)
+ psci_spd_pm->svc_on(target_cpu);
/*
* Arch. management: Derive the re-entry information for
@@ -387,8 +387,8 @@ static unsigned int psci_afflvl0_on_finish(unsigned long mpidr,
* Dispatcher to let it do any bookeeping. If the handler encounters an
* error, it's expected to assert within
*/
- if (spd_pm.svc_on_finish)
- spd_pm.svc_on_finish(0);
+ if (psci_spd_pm && psci_spd_pm->svc_on_finish)
+ psci_spd_pm->svc_on_finish(0);
/*
* Generic management: Now we just need to retrieve the
diff --git a/services/psci/psci_afflvl_suspend.c b/services/psci/psci_afflvl_suspend.c
index 62d270f..138d033 100644
--- a/services/psci/psci_afflvl_suspend.c
+++ b/services/psci/psci_afflvl_suspend.c
@@ -104,8 +104,8 @@ static int psci_afflvl0_suspend(unsigned long mpidr,
* Dispatcher to let it do any bookeeping. If the handler encounters an
* error, it's expected to assert within
*/
- if (spd_pm.svc_suspend)
- spd_pm.svc_suspend(power_state);
+ if (psci_spd_pm && psci_spd_pm->svc_suspend)
+ psci_spd_pm->svc_suspend(power_state);
/* State management: mark this cpu as suspended */
psci_set_state(cpu_node, PSCI_STATE_SUSPEND);
@@ -459,9 +459,9 @@ static unsigned int psci_afflvl0_suspend_finish(unsigned long mpidr,
* Dispatcher to let it do any bookeeping. If the handler encounters an
* error, it's expected to assert within
*/
- if (spd_pm.svc_suspend) {
+ if (psci_spd_pm && psci_spd_pm->svc_suspend) {
suspend_level = psci_get_suspend_afflvl(cpu_node);
- spd_pm.svc_suspend_finish(suspend_level);
+ psci_spd_pm->svc_suspend_finish(suspend_level);
}
/*
diff --git a/services/psci/psci_common.c b/services/psci/psci_common.c
index cacd97e..236309c 100644
--- a/services/psci/psci_common.c
+++ b/services/psci/psci_common.c
@@ -41,10 +41,10 @@
#include "debug.h"
/*
- * Provide a null weak instantiation for SPD power management operations. An SPD
- * can define its own instance overriding this one
+ * SPD power management operations, expected to be supplied by the registered
+ * SPD on successful SP initialization
*/
-const spd_pm_ops __attribute__((weak)) spd_pm = {0};
+const spd_pm_ops *psci_spd_pm;
/*******************************************************************************
* Arrays that contains information needs to resume a cpu's execution when woken
@@ -556,3 +556,13 @@ void psci_afflvl_power_on_finish(unsigned long mpidr,
end_afflvl,
mpidr_nodes);
}
+
+/*******************************************************************************
+ * This function initializes the set of hooks that PSCI invokes as part of power
+ * management operation. The power management hooks are expected to be provided
+ * by the SPD, after it finishes all its initialization
+ ******************************************************************************/
+void psci_register_spd_pm_hook(const spd_pm_ops *pm)
+{
+ psci_spd_pm = pm;
+}
diff --git a/services/psci/psci_private.h b/services/psci/psci_private.h
index 351cbe8..4f47ca5 100644
--- a/services/psci/psci_private.h
+++ b/services/psci/psci_private.h
@@ -96,10 +96,9 @@ extern afflvl_power_on_finisher psci_afflvl_off_finish_handlers[];
extern afflvl_power_on_finisher psci_afflvl_sus_finish_handlers[];
/*******************************************************************************
- * Weak declarations to allow PSCI to cope on a system where the Secure Payload
- * Dispatcher is missing. An SPD will define this structure when present.
+ * SPD's power management hooks registered with PSCI
******************************************************************************/
-extern const spd_pm_ops spd_pm;
+extern const spd_pm_ops *psci_spd_pm;
/*******************************************************************************
* Function prototypes
diff --git a/services/spd/tspd/tspd_main.c b/services/spd/tspd/tspd_main.c
index f4cfa43..ec28773 100644
--- a/services/spd/tspd/tspd_main.c
+++ b/services/spd/tspd/tspd_main.c
@@ -44,7 +44,6 @@
#include <arch_helpers.h>
#include <console.h>
#include <platform.h>
-#include <psci_private.h>
#include <context_mgmt.h>
#include <runtime_svc.h>
#include <bl31.h>
@@ -64,6 +63,10 @@ entry_info *tsp_entry_info;
******************************************************************************/
tsp_context tspd_sp_context[TSPD_CORE_COUNT];
+
+int32_t tspd_init(meminfo *bl32_meminfo);
+
+
/*******************************************************************************
* Secure Payload Dispatcher setup. The SPD finds out the SP entrypoint and type
* (aarch32/aarch64) if not already known and initialises the context for entry
@@ -87,6 +90,14 @@ int32_t tspd_setup(void)
assert(image_info);
/*
+ * If there's no valid entry point for SP, we return a non-zero value
+ * signalling failure initializing the service. We bail out without
+ * registering any handlers
+ */
+ if (!image_info->entrypoint)
+ return 1;
+
+ /*
* We could inspect the SP image and determine it's execution
* state i.e whether AArch32 or AArch64. Assuming it's AArch64
* for the time being.
@@ -97,6 +108,12 @@ int32_t tspd_setup(void)
&tspd_sp_context[linear_id]);
assert(rc == 0);
+ /*
+ * All TSPD initialization done. Now register our init function with
+ * BL31 for deferred invocation
+ */
+ bl31_register_bl32_init(&tspd_init);
+
return rc;
}
@@ -110,7 +127,7 @@ int32_t tspd_setup(void)
* back to this routine through a SMC. It also passes the extents of memory made
* available to BL32 by BL31.
******************************************************************************/
-int32_t bl32_init(meminfo *bl32_meminfo)
+int32_t tspd_init(meminfo *bl32_meminfo)
{
uint64_t mpidr = read_mpidr();
uint32_t linear_id = platform_get_core_pos(mpidr);
@@ -135,12 +152,20 @@ int32_t bl32_init(meminfo *bl32_meminfo)
*/
rc = tspd_synchronous_sp_entry(tsp_ctx);
assert(rc != 0);
- if (rc)
+ if (rc) {
tsp_ctx->state = TSP_STATE_ON;
+ /*
+ * TSP has been successfully initialized. Register power
+ * managemnt hooks with PSCI
+ */
+ psci_register_spd_pm_hook(&tspd_pm);
+ }
+
return rc;
}
+
/*******************************************************************************
* This function is responsible for handling all SMCs in the Trusted OS/App
* range from the non-secure state as defined in the SMC Calling Convention
diff --git a/services/spd/tspd/tspd_pm.c b/services/spd/tspd/tspd_pm.c
index 9e2f6c2..4ebafc7 100644
--- a/services/spd/tspd/tspd_pm.c
+++ b/services/spd/tspd/tspd_pm.c
@@ -34,7 +34,6 @@
#include <arch_helpers.h>
#include <console.h>
#include <platform.h>
-#include <psci_private.h>
#include <context_mgmt.h>
#include <runtime_svc.h>
#include <bl31.h>
@@ -199,7 +198,7 @@ static int32_t tspd_cpu_migrate_info(uint64_t *resident_cpu)
* Structure populated by the TSP Dispatcher to be given a chance to perform any
* TSP bookkeeping before PSCI executes a power mgmt. operation.
******************************************************************************/
-const spd_pm_ops spd_pm = {
+const spd_pm_ops tspd_pm = {
tspd_cpu_on_handler,
tspd_cpu_off_handler,
tspd_cpu_suspend_handler,
diff --git a/services/spd/tspd/tspd_private.h b/services/spd/tspd/tspd_private.h
index 2bc35c1..69cf199 100644
--- a/services/spd/tspd/tspd_private.h
+++ b/services/spd/tspd/tspd_private.h
@@ -116,6 +116,9 @@ typedef struct {
cpu_context cpu_ctx;
} tsp_context;
+/* TSPD power management handlers */
+extern const spd_pm_ops tspd_pm;
+
/*******************************************************************************
* Function & Data prototypes
******************************************************************************/