From 617540d860f24c324fbbf418388fb65c0ec83242 Mon Sep 17 00:00:00 2001 From: Soby Mathew <soby.mathew@arm.com> Date: Wed, 15 Jul 2015 12:13:26 +0100 Subject: [PATCH] PSCI: Fix the return code for invalid entrypoint As per PSCI1.0 specification, the error code to be returned when an invalid non secure entrypoint address is specified by the PSCI client for CPU_SUSPEND, CPU_ON or SYSTEM_SUSPEND must be PSCI_E_INVALID_ADDRESS. The current PSCI implementation returned PSCI_E_INVAL_PARAMS. This patch rectifies this error and also implements a common helper function to validate the entrypoint information to be used across these PSCI API implementations. Change-Id: I52d697d236c8bf0cd3297da4008c8e8c2399b170 --- include/bl31/services/psci.h | 1 + services/std_svc/psci/psci_common.c | 30 +++++++++++++++-- services/std_svc/psci/psci_main.c | 49 +++------------------------- services/std_svc/psci/psci_private.h | 2 +- 4 files changed, 35 insertions(+), 47 deletions(-) diff --git a/include/bl31/services/psci.h b/include/bl31/services/psci.h index c9b3f8d2c..f6fd4872c 100644 --- a/include/bl31/services/psci.h +++ b/include/bl31/services/psci.h @@ -165,6 +165,7 @@ #define PSCI_E_INTERN_FAIL -6 #define PSCI_E_NOT_PRESENT -7 #define PSCI_E_DISABLED -8 +#define PSCI_E_INVALID_ADDRESS -9 #define PSCI_INVALID_MPIDR ~(0ULL) diff --git a/services/std_svc/psci/psci_common.c b/services/std_svc/psci/psci_common.c index 7f1a5fd0d..f810ddfac 100644 --- a/services/std_svc/psci/psci_common.c +++ b/services/std_svc/psci/psci_common.c @@ -589,7 +589,7 @@ int psci_validate_mpidr(unsigned long mpidr) * This function determines the full entrypoint information for the requested * PSCI entrypoint on power on/resume and returns it. ******************************************************************************/ -int psci_get_ns_ep_info(entry_point_info_t *ep, +static int psci_get_ns_ep_info(entry_point_info_t *ep, uint64_t entrypoint, uint64_t context_id) { uint32_t ep_attr, mode, sctlr, daif, ee; @@ -621,7 +621,7 @@ int psci_get_ns_ep_info(entry_point_info_t *ep, * aarch64 EL */ if (entrypoint & 0x1) - return PSCI_E_INVALID_PARAMS; + return PSCI_E_INVALID_ADDRESS; mode = ns_scr_el3 & SCR_HCE_BIT ? MODE_EL2 : MODE_EL1; @@ -642,6 +642,32 @@ int psci_get_ns_ep_info(entry_point_info_t *ep, return PSCI_E_SUCCESS; } +/******************************************************************************* + * This function validates the entrypoint with the platform layer if the + * appropriate pm_ops hook is exported by the platform and returns the + * 'entry_point_info'. + ******************************************************************************/ +int psci_validate_entry_point(entry_point_info_t *ep, + uint64_t entrypoint, uint64_t context_id) +{ + int rc; + + /* Validate the entrypoint using platform psci_ops */ + if (psci_plat_pm_ops->validate_ns_entrypoint) { + rc = psci_plat_pm_ops->validate_ns_entrypoint(entrypoint); + if (rc != PSCI_E_SUCCESS) + return PSCI_E_INVALID_ADDRESS; + } + + /* + * Verify and derive the re-entry information for + * the non-secure world from the non-secure state from + * where this call originated. + */ + rc = psci_get_ns_ep_info(ep, entrypoint, context_id); + return rc; +} + /******************************************************************************* * Generic handler which is called when a cpu is physically powered on. It * traverses the node information and finds the highest power level powered diff --git a/services/std_svc/psci/psci_main.c b/services/std_svc/psci/psci_main.c index f02429102..6d3af2048 100644 --- a/services/std_svc/psci/psci_main.c +++ b/services/std_svc/psci/psci_main.c @@ -55,21 +55,8 @@ int psci_cpu_on(unsigned long target_cpu, if (rc != PSCI_E_SUCCESS) return PSCI_E_INVALID_PARAMS; - /* Validate the entrypoint using platform pm_ops */ - if (psci_plat_pm_ops->validate_ns_entrypoint) { - rc = psci_plat_pm_ops->validate_ns_entrypoint(entrypoint); - if (rc != PSCI_E_SUCCESS) { - assert(rc == PSCI_E_INVALID_PARAMS); - return PSCI_E_INVALID_PARAMS; - } - } - - /* - * Verify and derive the re-entry information for - * the non-secure world from the non-secure state from - * where this call originated. - */ - rc = psci_get_ns_ep_info(&ep, entrypoint, context_id); + /* Validate the entry point and get the entry_point_info */ + rc = psci_validate_entry_point(&ep, entrypoint, context_id); if (rc != PSCI_E_SUCCESS) return rc; @@ -141,20 +128,7 @@ int psci_cpu_suspend(unsigned int power_state, * point and program entry information. */ if (is_power_down_state) { - if (psci_plat_pm_ops->validate_ns_entrypoint) { - rc = psci_plat_pm_ops->validate_ns_entrypoint(entrypoint); - if (rc != PSCI_E_SUCCESS) { - assert(rc == PSCI_E_INVALID_PARAMS); - return rc; - } - } - - /* - * Verify and derive the re-entry information for - * the non-secure world from the non-secure state from - * where this call originated. - */ - rc = psci_get_ns_ep_info(&ep, entrypoint, context_id); + rc = psci_validate_entry_point(&ep, entrypoint, context_id); if (rc != PSCI_E_SUCCESS) return rc; } @@ -180,25 +154,12 @@ int psci_system_suspend(unsigned long entrypoint, psci_power_state_t state_info; entry_point_info_t ep; - /* Validate the entrypoint using platform pm_ops */ - if (psci_plat_pm_ops->validate_ns_entrypoint) { - rc = psci_plat_pm_ops->validate_ns_entrypoint(entrypoint); - if (rc != PSCI_E_SUCCESS) { - assert(rc == PSCI_E_INVALID_PARAMS); - return rc; - } - } - /* Check if the current CPU is the last ON CPU in the system */ if (!psci_is_last_on_cpu()) return PSCI_E_DENIED; - /* - * Verify and derive the re-entry information for - * the non-secure world from the non-secure state from - * where this call originated. - */ - rc = psci_get_ns_ep_info(&ep, entrypoint, context_id); + /* Validate the entry point and get the entry_point_info */ + rc = psci_validate_entry_point(&ep, entrypoint, context_id); if (rc != PSCI_E_SUCCESS) return rc; diff --git a/services/std_svc/psci/psci_private.h b/services/std_svc/psci/psci_private.h index e2e32c796..5345ee30f 100644 --- a/services/std_svc/psci/psci_private.h +++ b/services/std_svc/psci/psci_private.h @@ -189,7 +189,7 @@ void psci_query_sys_suspend_pwrstate(psci_power_state_t *state_info); int psci_validate_mpidr(unsigned long mpidr); void psci_init_req_local_pwr_states(void); void psci_power_up_finish(void); -int psci_get_ns_ep_info(entry_point_info_t *ep, +int psci_validate_entry_point(entry_point_info_t *ep, uint64_t entrypoint, uint64_t context_id); void psci_get_parent_pwr_domain_nodes(unsigned int cpu_idx, int end_lvl, -- GitLab