From b234b2c4a06169aa965b77dd40c17be454a9f609 Mon Sep 17 00:00:00 2001 From: Soby Mathew Date: Thu, 15 Jan 2015 11:49:49 +0000 Subject: [PATCH] Verify capabilities before handling PSCI calls This patch implements conditional checks in psci_smc_handler() to verify that the psci function invoked by the caller is supported by the platform or SPD implementation. The level of support is saved in the 'psci_caps' variable. This check allows the PSCI implementation to return an error early. As a result of the above verification, the checks performed within the psci handlers for the pm hooks are now removed and replaced with assertions. Change-Id: I9b5b646a01d8566dc28c4d77dd3aa54e9bf3981a --- services/std_svc/psci/psci_afflvl_off.c | 12 ++++++------ services/std_svc/psci/psci_afflvl_on.c | 18 +++++++----------- services/std_svc/psci/psci_afflvl_suspend.c | 18 +++++++----------- services/std_svc/psci/psci_main.c | 4 ++++ services/std_svc/psci/psci_system_off.c | 17 +++++------------ 5 files changed, 29 insertions(+), 40 deletions(-) diff --git a/services/std_svc/psci/psci_afflvl_off.c b/services/std_svc/psci/psci_afflvl_off.c index ceb51f83e..7eb968899 100644 --- a/services/std_svc/psci/psci_afflvl_off.c +++ b/services/std_svc/psci/psci_afflvl_off.c @@ -51,8 +51,6 @@ static void psci_afflvl0_off(aff_map_node_t *cpu_node) */ psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL0); - assert(psci_plat_pm_ops->affinst_off); - /* * Plat. management: Perform platform specific actions to turn this * cpu off e.g. exit cpu coherency, program the power controller etc. @@ -72,8 +70,6 @@ static void psci_afflvl1_off(aff_map_node_t *cluster_node) */ psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL1); - assert(psci_plat_pm_ops->affinst_off); - /* * Plat. Management. Allow the platform to do its cluster * specific bookeeping e.g. turn off interconnect coherency, @@ -99,8 +95,6 @@ static void psci_afflvl2_off(aff_map_node_t *system_node) */ psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL2); - assert(psci_plat_pm_ops->affinst_off); - /* * Plat. Management : Allow the platform to do its bookeeping * at this affinity level @@ -162,6 +156,12 @@ int psci_afflvl_off(int start_afflvl, mpidr_aff_map_nodes_t mpidr_nodes; unsigned int max_phys_off_afflvl; + /* + * This function must only be called on platforms where the + * CPU_OFF platform hooks have been implemented. + */ + assert(psci_plat_pm_ops->affinst_off); + /* * Collect the pointers to the nodes in the topology tree for * each affinity instance in the mpidr. If this function does diff --git a/services/std_svc/psci/psci_afflvl_on.c b/services/std_svc/psci/psci_afflvl_on.c index ad212b652..0ee03cb5e 100644 --- a/services/std_svc/psci/psci_afflvl_on.c +++ b/services/std_svc/psci/psci_afflvl_on.c @@ -75,8 +75,6 @@ static int psci_afflvl0_on(unsigned long target_cpu, /* Set the secure world (EL3) re-entry point after BL1 */ psci_entrypoint = (unsigned long) psci_aff_on_finish_entry; - assert(psci_plat_pm_ops->affinst_on); - /* * Plat. management: Give the platform the current state * of the target cpu to allow it to perform the necessary @@ -107,8 +105,6 @@ static int psci_afflvl1_on(unsigned long target_cpu, /* State management: Is not required while turning a cluster on */ - assert(psci_plat_pm_ops->affinst_on); - /* * Plat. management: Give the platform the current state * of the target cpu to allow it to perform the necessary @@ -141,8 +137,6 @@ static int psci_afflvl2_on(unsigned long target_cpu, /* State management: Is not required while turning a system on */ - assert(psci_plat_pm_ops->affinst_on); - /* * Plat. management: Give the platform the current state * of the target cpu to allow it to perform the necessary @@ -218,6 +212,13 @@ int psci_afflvl_on(unsigned long target_cpu, int rc; mpidr_aff_map_nodes_t target_cpu_nodes; + /* + * This function must only be called on platforms where the + * CPU_ON platform hooks have been implemented. + */ + assert(psci_plat_pm_ops->affinst_on && + psci_plat_pm_ops->affinst_on_finish); + /* * Collect the pointers to the nodes in the topology tree for * each affinity instance in the mpidr. If this function does @@ -313,7 +314,6 @@ static void psci_afflvl0_on_finish(aff_map_node_t *cpu_node) * register. The actual state of this cpu has already been * changed. */ - assert(psci_plat_pm_ops->affinst_on_finish); /* Get the physical state of this cpu */ plat_state = get_phys_state(state); @@ -357,8 +357,6 @@ static void psci_afflvl1_on_finish(aff_map_node_t *cluster_node) assert(cluster_node->level == MPIDR_AFFLVL1); - assert(psci_plat_pm_ops->affinst_on_finish); - /* * Plat. management: Perform the platform specific actions * as per the old state of the cluster e.g. enabling @@ -380,8 +378,6 @@ static void psci_afflvl2_on_finish(aff_map_node_t *system_node) /* Cannot go beyond this affinity level */ assert(system_node->level == MPIDR_AFFLVL2); - assert(psci_plat_pm_ops->affinst_on_finish); - /* * Currently, there are no architectural actions to perform * at the system level. diff --git a/services/std_svc/psci/psci_afflvl_suspend.c b/services/std_svc/psci/psci_afflvl_suspend.c index 9ede65d01..dad0cefd8 100644 --- a/services/std_svc/psci/psci_afflvl_suspend.c +++ b/services/std_svc/psci/psci_afflvl_suspend.c @@ -119,8 +119,6 @@ static void psci_afflvl0_suspend(aff_map_node_t *cpu_node) */ psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL0); - assert(psci_plat_pm_ops->affinst_suspend); - /* * Plat. management: Allow the platform to perform the * necessary actions to turn off this cpu e.g. set the @@ -146,8 +144,6 @@ static void psci_afflvl1_suspend(aff_map_node_t *cluster_node) */ psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL1); - assert(psci_plat_pm_ops->affinst_suspend); - /* * Plat. Management. Allow the platform to do its cluster specific * bookeeping e.g. turn off interconnect coherency, program the power @@ -188,7 +184,6 @@ static void psci_afflvl2_suspend(aff_map_node_t *system_node) * Plat. Management : Allow the platform to do its bookeeping * at this affinity level */ - assert(psci_plat_pm_ops->affinst_suspend); /* * Sending the psci entrypoint is currently redundant @@ -261,6 +256,13 @@ void psci_afflvl_suspend(entry_point_info_t *ep, mpidr_aff_map_nodes_t mpidr_nodes; unsigned int max_phys_off_afflvl; + /* + * This function must only be called on platforms where the + * CPU_SUSPEND platform hooks have been implemented. + */ + assert(psci_plat_pm_ops->affinst_suspend && + psci_plat_pm_ops->affinst_suspend_finish); + /* * Collect the pointers to the nodes in the topology tree for * each affinity instance in the mpidr. If this function does @@ -370,8 +372,6 @@ static void psci_afflvl0_suspend_finish(aff_map_node_t *cpu_node) * situation. */ - assert(psci_plat_pm_ops->affinst_suspend_finish); - /* Get the physical state of this cpu */ plat_state = get_phys_state(state); psci_plat_pm_ops->affinst_suspend_finish(cpu_node->level, @@ -428,8 +428,6 @@ static void psci_afflvl1_suspend_finish(aff_map_node_t *cluster_node) * situation. */ - assert(psci_plat_pm_ops->affinst_suspend_finish); - /* Get the physical state of this cpu */ plat_state = psci_get_phys_state(cluster_node); psci_plat_pm_ops->affinst_suspend_finish(cluster_node->level, @@ -458,8 +456,6 @@ static void psci_afflvl2_suspend_finish(aff_map_node_t *system_node) * situation. */ - assert(psci_plat_pm_ops->affinst_suspend_finish); - /* Get the physical state of the system */ plat_state = psci_get_phys_state(system_node); psci_plat_pm_ops->affinst_suspend_finish(system_node->level, diff --git a/services/std_svc/psci/psci_main.c b/services/std_svc/psci/psci_main.c index 0e10ac050..d8a00097b 100644 --- a/services/std_svc/psci/psci_main.c +++ b/services/std_svc/psci/psci_main.c @@ -321,6 +321,10 @@ uint64_t psci_smc_handler(uint32_t smc_fid, if (is_caller_secure(flags)) SMC_RET1(handle, SMC_UNK); + /* Check the fid against the capabilities */ + if (!(psci_caps & define_psci_cap(smc_fid))) + SMC_RET1(handle, SMC_UNK); + if (((smc_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_32) { /* 32-bit PSCI function, clear top parameter bits */ diff --git a/services/std_svc/psci/psci_system_off.c b/services/std_svc/psci/psci_system_off.c index f2520b6dd..970d4bb50 100644 --- a/services/std_svc/psci/psci_system_off.c +++ b/services/std_svc/psci/psci_system_off.c @@ -30,20 +30,17 @@ #include #include +#include #include #include #include "psci_private.h" void psci_system_off(void) { - /* Check platform support */ - if (!psci_plat_pm_ops->system_off) { - ERROR("Platform has not exported a PSCI System Off hook.\n"); - panic(); - } - psci_print_affinity_map(); + assert(psci_plat_pm_ops->system_off); + /* Notify the Secure Payload Dispatcher */ if (psci_spd_pm && psci_spd_pm->svc_system_off) { psci_spd_pm->svc_system_off(); @@ -57,14 +54,10 @@ void psci_system_off(void) void psci_system_reset(void) { - /* Check platform support */ - if (!psci_plat_pm_ops->system_reset) { - ERROR("Platform has not exported a PSCI System Reset hook.\n"); - panic(); - } - psci_print_affinity_map(); + assert(psci_plat_pm_ops->system_reset); + /* Notify the Secure Payload Dispatcher */ if (psci_spd_pm && psci_spd_pm->svc_system_reset) { psci_spd_pm->svc_system_reset();