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 #include + +/******************************************************************************* + * 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 @@ 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 @@ /* 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 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 @@ 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 @@ * 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 @@ * 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 @@ * 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 @@ * 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 @@ * 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 @@ 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_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 #include #include -#include #include #include #include @@ -64,6 +63,10 @@ ******************************************************************************/ 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 @@ 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 @@ &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 @@ * 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 @@ */ 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 #include #include -#include #include #include #include @@ -199,7 +198,7 @@ * 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 @@ cpu_context cpu_ctx; } tsp_context; +/* TSPD power management handlers */ +extern const spd_pm_ops tspd_pm; + /******************************************************************************* * Function & Data prototypes ******************************************************************************/