From a86865ac42ac6f518da14474c94f38869c032488 Mon Sep 17 00:00:00 2001 From: Graeme Gregory Date: Wed, 2 Dec 2020 16:24:32 +0000 Subject: [PATCH] PSCI: fix limit of 256 CPUs caused by cast to unsigned char In psci_setup.c psci_init_pwr_domain_node() takes an unsigned char as node_idx which limits it to initialising only the first 256 CPUs. As the calling function does not check for a limit of 256 I think this is a bug so change the unsigned char to uint16_t and change the cast from the calling site in populate_power_domain_tree(). Also update the non_cpu_pwr_domain_node structure lock_index to uint16_t and update the function signature for psci_lock_init() appropriately. Finally add a define PSCI_MAX_CPUS_INDEX to psci_private.h and add a CASSERT to psci_setup.c to make sure PLATFORM_CORE_COUNT cannot exceed the index value. Signed-off-by: Graeme Gregory Change-Id: I9e26842277db7483fd698b46bbac62aa86e71b45 --- lib/psci/psci_private.h | 9 +++++++-- lib/psci/psci_setup.c | 14 ++++++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/lib/psci/psci_private.h b/lib/psci/psci_private.h index e2dcfa8b1..72bd6bd11 100644 --- a/lib/psci/psci_private.h +++ b/lib/psci/psci_private.h @@ -42,6 +42,11 @@ define_psci_cap(PSCI_SYSTEM_RESET2_AARCH64) | \ define_psci_cap(PSCI_MEM_CHK_RANGE_AARCH64)) +/* Internally PSCI uses a uint16_t for various cpu indexes so + * define a limit to number of CPUs that can be initialised. + */ +#define PSCI_MAX_CPUS_INDEX 0xFFFFU + /* * Helper functions to get/set the fields of PSCI per-cpu data. */ @@ -134,7 +139,7 @@ typedef struct non_cpu_pwr_domain_node { unsigned char level; /* For indexing the psci_lock array*/ - unsigned char lock_index; + uint16_t lock_index; } non_cpu_pd_node_t; typedef struct cpu_pwr_domain_node { @@ -239,7 +244,7 @@ static inline void psci_lock_release(non_cpu_pd_node_t *non_cpu_pd_node) #endif /* HW_ASSISTED_COHERENCY */ static inline void psci_lock_init(non_cpu_pd_node_t *non_cpu_pd_node, - unsigned char idx) + uint16_t idx) { non_cpu_pd_node[idx].lock_index = idx; } diff --git a/lib/psci/psci_setup.c b/lib/psci/psci_setup.c index d1ec99808..9c37d63f2 100644 --- a/lib/psci/psci_setup.c +++ b/lib/psci/psci_setup.c @@ -17,6 +17,12 @@ #include "psci_private.h" +/* + * Check that PLATFORM_CORE_COUNT fits into the number of cores + * that can be represented by PSCI_MAX_CPUS_INDEX. + */ +CASSERT(PLATFORM_CORE_COUNT <= (PSCI_MAX_CPUS_INDEX + 1U), assert_psci_cores_overflow); + /******************************************************************************* * Per cpu non-secure contexts used to program the architectural state prior * return to the normal world. @@ -34,11 +40,13 @@ unsigned int psci_caps; * Function which initializes the 'psci_non_cpu_pd_nodes' or the * 'psci_cpu_pd_nodes' corresponding to the power level. ******************************************************************************/ -static void __init psci_init_pwr_domain_node(unsigned char node_idx, +static void __init psci_init_pwr_domain_node(uint16_t node_idx, unsigned int parent_idx, unsigned char level) { if (level > PSCI_CPU_PWR_LVL) { + assert(node_idx < PSCI_NUM_NON_CPU_PWR_DOMAINS); + psci_non_cpu_pd_nodes[node_idx].level = level; psci_lock_init(psci_non_cpu_pd_nodes, node_idx); psci_non_cpu_pd_nodes[node_idx].parent_node = parent_idx; @@ -47,6 +55,8 @@ static void __init psci_init_pwr_domain_node(unsigned char node_idx, } else { psci_cpu_data_t *svc_cpu_data; + assert(node_idx < PLATFORM_CORE_COUNT); + psci_cpu_pd_nodes[node_idx].parent_node = parent_idx; /* Initialize with an invalid mpidr */ @@ -144,7 +154,7 @@ static unsigned int __init populate_power_domain_tree(const unsigned char for (j = node_index; j < (node_index + num_children); j++) - psci_init_pwr_domain_node((unsigned char)j, + psci_init_pwr_domain_node((uint16_t)j, parent_node_index - 1U, (unsigned char)level);