aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
******************************************************************************/