Commit b234b2c4 authored by Soby Mathew's avatar Soby Mathew Committed by Dan Handley
Browse files

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
parent 90e8258e
...@@ -51,8 +51,6 @@ static void psci_afflvl0_off(aff_map_node_t *cpu_node) ...@@ -51,8 +51,6 @@ static void psci_afflvl0_off(aff_map_node_t *cpu_node)
*/ */
psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL0); psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL0);
assert(psci_plat_pm_ops->affinst_off);
/* /*
* Plat. management: Perform platform specific actions to turn this * Plat. management: Perform platform specific actions to turn this
* cpu off e.g. exit cpu coherency, program the power controller etc. * 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) ...@@ -72,8 +70,6 @@ static void psci_afflvl1_off(aff_map_node_t *cluster_node)
*/ */
psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL1); psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL1);
assert(psci_plat_pm_ops->affinst_off);
/* /*
* Plat. Management. Allow the platform to do its cluster * Plat. Management. Allow the platform to do its cluster
* specific bookeeping e.g. turn off interconnect coherency, * specific bookeeping e.g. turn off interconnect coherency,
...@@ -99,8 +95,6 @@ static void psci_afflvl2_off(aff_map_node_t *system_node) ...@@ -99,8 +95,6 @@ static void psci_afflvl2_off(aff_map_node_t *system_node)
*/ */
psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL2); psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL2);
assert(psci_plat_pm_ops->affinst_off);
/* /*
* Plat. Management : Allow the platform to do its bookeeping * Plat. Management : Allow the platform to do its bookeeping
* at this affinity level * at this affinity level
...@@ -162,6 +156,12 @@ int psci_afflvl_off(int start_afflvl, ...@@ -162,6 +156,12 @@ int psci_afflvl_off(int start_afflvl,
mpidr_aff_map_nodes_t mpidr_nodes; mpidr_aff_map_nodes_t mpidr_nodes;
unsigned int max_phys_off_afflvl; 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 * Collect the pointers to the nodes in the topology tree for
* each affinity instance in the mpidr. If this function does * each affinity instance in the mpidr. If this function does
......
...@@ -75,8 +75,6 @@ static int psci_afflvl0_on(unsigned long target_cpu, ...@@ -75,8 +75,6 @@ static int psci_afflvl0_on(unsigned long target_cpu,
/* Set the secure world (EL3) re-entry point after BL1 */ /* Set the secure world (EL3) re-entry point after BL1 */
psci_entrypoint = (unsigned long) psci_aff_on_finish_entry; psci_entrypoint = (unsigned long) psci_aff_on_finish_entry;
assert(psci_plat_pm_ops->affinst_on);
/* /*
* Plat. management: Give the platform the current state * Plat. management: Give the platform the current state
* of the target cpu to allow it to perform the necessary * of the target cpu to allow it to perform the necessary
...@@ -107,8 +105,6 @@ static int psci_afflvl1_on(unsigned long target_cpu, ...@@ -107,8 +105,6 @@ static int psci_afflvl1_on(unsigned long target_cpu,
/* State management: Is not required while turning a cluster on */ /* 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 * Plat. management: Give the platform the current state
* of the target cpu to allow it to perform the necessary * of the target cpu to allow it to perform the necessary
...@@ -141,8 +137,6 @@ static int psci_afflvl2_on(unsigned long target_cpu, ...@@ -141,8 +137,6 @@ static int psci_afflvl2_on(unsigned long target_cpu,
/* State management: Is not required while turning a system on */ /* 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 * Plat. management: Give the platform the current state
* of the target cpu to allow it to perform the necessary * of the target cpu to allow it to perform the necessary
...@@ -218,6 +212,13 @@ int psci_afflvl_on(unsigned long target_cpu, ...@@ -218,6 +212,13 @@ int psci_afflvl_on(unsigned long target_cpu,
int rc; int rc;
mpidr_aff_map_nodes_t target_cpu_nodes; 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 * Collect the pointers to the nodes in the topology tree for
* each affinity instance in the mpidr. If this function does * 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) ...@@ -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 * register. The actual state of this cpu has already been
* changed. * changed.
*/ */
assert(psci_plat_pm_ops->affinst_on_finish);
/* Get the physical state of this cpu */ /* Get the physical state of this cpu */
plat_state = get_phys_state(state); plat_state = get_phys_state(state);
...@@ -357,8 +357,6 @@ static void psci_afflvl1_on_finish(aff_map_node_t *cluster_node) ...@@ -357,8 +357,6 @@ static void psci_afflvl1_on_finish(aff_map_node_t *cluster_node)
assert(cluster_node->level == MPIDR_AFFLVL1); assert(cluster_node->level == MPIDR_AFFLVL1);
assert(psci_plat_pm_ops->affinst_on_finish);
/* /*
* Plat. management: Perform the platform specific actions * Plat. management: Perform the platform specific actions
* as per the old state of the cluster e.g. enabling * 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) ...@@ -380,8 +378,6 @@ static void psci_afflvl2_on_finish(aff_map_node_t *system_node)
/* Cannot go beyond this affinity level */ /* Cannot go beyond this affinity level */
assert(system_node->level == MPIDR_AFFLVL2); assert(system_node->level == MPIDR_AFFLVL2);
assert(psci_plat_pm_ops->affinst_on_finish);
/* /*
* Currently, there are no architectural actions to perform * Currently, there are no architectural actions to perform
* at the system level. * at the system level.
......
...@@ -119,8 +119,6 @@ static void psci_afflvl0_suspend(aff_map_node_t *cpu_node) ...@@ -119,8 +119,6 @@ static void psci_afflvl0_suspend(aff_map_node_t *cpu_node)
*/ */
psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL0); psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL0);
assert(psci_plat_pm_ops->affinst_suspend);
/* /*
* Plat. management: Allow the platform to perform the * Plat. management: Allow the platform to perform the
* necessary actions to turn off this cpu e.g. set 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) ...@@ -146,8 +144,6 @@ static void psci_afflvl1_suspend(aff_map_node_t *cluster_node)
*/ */
psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL1); psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL1);
assert(psci_plat_pm_ops->affinst_suspend);
/* /*
* Plat. Management. Allow the platform to do its cluster specific * Plat. Management. Allow the platform to do its cluster specific
* bookeeping e.g. turn off interconnect coherency, program the power * 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) ...@@ -188,7 +184,6 @@ static void psci_afflvl2_suspend(aff_map_node_t *system_node)
* Plat. Management : Allow the platform to do its bookeeping * Plat. Management : Allow the platform to do its bookeeping
* at this affinity level * at this affinity level
*/ */
assert(psci_plat_pm_ops->affinst_suspend);
/* /*
* Sending the psci entrypoint is currently redundant * Sending the psci entrypoint is currently redundant
...@@ -261,6 +256,13 @@ void psci_afflvl_suspend(entry_point_info_t *ep, ...@@ -261,6 +256,13 @@ void psci_afflvl_suspend(entry_point_info_t *ep,
mpidr_aff_map_nodes_t mpidr_nodes; mpidr_aff_map_nodes_t mpidr_nodes;
unsigned int max_phys_off_afflvl; 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 * Collect the pointers to the nodes in the topology tree for
* each affinity instance in the mpidr. If this function does * 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) ...@@ -370,8 +372,6 @@ static void psci_afflvl0_suspend_finish(aff_map_node_t *cpu_node)
* situation. * situation.
*/ */
assert(psci_plat_pm_ops->affinst_suspend_finish);
/* Get the physical state of this cpu */ /* Get the physical state of this cpu */
plat_state = get_phys_state(state); plat_state = get_phys_state(state);
psci_plat_pm_ops->affinst_suspend_finish(cpu_node->level, 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) ...@@ -428,8 +428,6 @@ static void psci_afflvl1_suspend_finish(aff_map_node_t *cluster_node)
* situation. * situation.
*/ */
assert(psci_plat_pm_ops->affinst_suspend_finish);
/* Get the physical state of this cpu */ /* Get the physical state of this cpu */
plat_state = psci_get_phys_state(cluster_node); plat_state = psci_get_phys_state(cluster_node);
psci_plat_pm_ops->affinst_suspend_finish(cluster_node->level, 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) ...@@ -458,8 +456,6 @@ static void psci_afflvl2_suspend_finish(aff_map_node_t *system_node)
* situation. * situation.
*/ */
assert(psci_plat_pm_ops->affinst_suspend_finish);
/* Get the physical state of the system */ /* Get the physical state of the system */
plat_state = psci_get_phys_state(system_node); plat_state = psci_get_phys_state(system_node);
psci_plat_pm_ops->affinst_suspend_finish(system_node->level, psci_plat_pm_ops->affinst_suspend_finish(system_node->level,
......
...@@ -321,6 +321,10 @@ uint64_t psci_smc_handler(uint32_t smc_fid, ...@@ -321,6 +321,10 @@ uint64_t psci_smc_handler(uint32_t smc_fid,
if (is_caller_secure(flags)) if (is_caller_secure(flags))
SMC_RET1(handle, SMC_UNK); 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) { if (((smc_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_32) {
/* 32-bit PSCI function, clear top parameter bits */ /* 32-bit PSCI function, clear top parameter bits */
......
...@@ -30,20 +30,17 @@ ...@@ -30,20 +30,17 @@
#include <stddef.h> #include <stddef.h>
#include <arch_helpers.h> #include <arch_helpers.h>
#include <assert.h>
#include <debug.h> #include <debug.h>
#include <platform.h> #include <platform.h>
#include "psci_private.h" #include "psci_private.h"
void psci_system_off(void) 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(); psci_print_affinity_map();
assert(psci_plat_pm_ops->system_off);
/* Notify the Secure Payload Dispatcher */ /* Notify the Secure Payload Dispatcher */
if (psci_spd_pm && psci_spd_pm->svc_system_off) { if (psci_spd_pm && psci_spd_pm->svc_system_off) {
psci_spd_pm->svc_system_off(); psci_spd_pm->svc_system_off();
...@@ -57,14 +54,10 @@ void psci_system_off(void) ...@@ -57,14 +54,10 @@ void psci_system_off(void)
void psci_system_reset(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(); psci_print_affinity_map();
assert(psci_plat_pm_ops->system_reset);
/* Notify the Secure Payload Dispatcher */ /* Notify the Secure Payload Dispatcher */
if (psci_spd_pm && psci_spd_pm->svc_system_reset) { if (psci_spd_pm && psci_spd_pm->svc_system_reset) {
psci_spd_pm->svc_system_reset(); psci_spd_pm->svc_system_reset();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment