feat(gpt): statically allocate bitlocks array
Statically allocate 'gpt_bitlock' array of fine-grained
'bitlock_t' data structures in arm_bl31_setup.c.
The amount of memory needed for this array is controlled
by 'RME_GPT_BITLOCK_BLOCK' build option and 'PLAT_ARM_PPS'
macro defined in platform_def.h which specifies the size
of protected physical address space in bytes.
'PLAT_ARM_PPS' takes values from 4GB to 4PB supported by
Arm architecture.
Change-Id: Icf620b5039e45df6828d58fca089cad83b0bc669
Signed-off-by: AlexeiFedorov <Alexei.Fedorov@arm.com>
diff --git a/lib/gpt_rme/gpt_rme.c b/lib/gpt_rme/gpt_rme.c
index 79c4ea5..115f50d 100644
--- a/lib/gpt_rme/gpt_rme.c
+++ b/lib/gpt_rme/gpt_rme.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2025, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -12,14 +12,13 @@
#include <arch.h>
#include <arch_features.h>
-#include <arch_helpers.h>
#include <common/debug.h>
-#include "gpt_rme_private.h"
#include <lib/gpt_rme/gpt_rme.h>
#include <lib/smccc.h>
-#include <lib/spinlock.h>
#include <lib/xlat_tables/xlat_tables_v2.h>
+#include "gpt_rme_private.h"
+
#if !ENABLE_RME
#error "ENABLE_RME must be enabled to use the GPT library"
#endif
@@ -123,25 +122,19 @@
#define GPT_L1_INDEX(_pa) \
(((_pa) >> (unsigned int)GPT_L1_IDX_SHIFT(gpt_config.p)) & gpt_l1_index_mask)
-/* These variables are used during initialization of the L1 tables */
+/* This variable is used during initialization of the L1 tables */
static uintptr_t gpt_l1_tbl;
-/* These variable is used during runtime */
+/* These variables are used during runtime */
#if (RME_GPT_BITLOCK_BLOCK == 0)
/*
* The GPTs are protected by a global spinlock to ensure
* that multiple CPUs do not attempt to change the descriptors at once.
*/
static spinlock_t gpt_lock;
-#else
-/* Bitlocks base address */
-static bitlock_t *gpt_bitlock_base;
-#endif
-
-/* Lock/unlock macros for GPT entries */
-#if (RME_GPT_BITLOCK_BLOCK == 0)
-/*
+/* Lock/unlock macros for GPT entries
+ *
* Access to GPT is controlled by a global lock to ensure
* that no more than one CPU is allowed to make changes at any
* given time.
@@ -149,13 +142,17 @@
#define GPT_LOCK spin_lock(&gpt_lock)
#define GPT_UNLOCK spin_unlock(&gpt_lock)
#else
+
+/* Base address of bitlocks array */
+static bitlock_t *gpt_bitlock;
+
/*
* Access to a block of memory is controlled by a bitlock.
* Size of block = RME_GPT_BITLOCK_BLOCK * 512MB.
*/
#define GPT_LOCK bit_lock(gpi_info.lock, gpi_info.mask)
#define GPT_UNLOCK bit_unlock(gpi_info.lock, gpi_info.mask)
-#endif
+#endif /* RME_GPT_BITLOCK_BLOCK */
static void tlbi_page_dsbosh(uintptr_t base)
{
@@ -494,8 +491,8 @@
* This function validates L0 initialization parameters.
*
* Parameters
- * l0_mem_base Base address of memory used for L0 tables.
- * l0_mem_size Size of memory available for L0 tables.
+ * l0_mem_base Base address of memory used for L0 table.
+ * l0_mem_size Size of memory available for L0 table.
*
* Return
* Negative Linux error code in the event of a failure, 0 for success.
@@ -503,7 +500,7 @@
static int validate_l0_params(gpccr_pps_e pps, uintptr_t l0_mem_base,
size_t l0_mem_size)
{
- size_t l0_alignment, locks_size = 0;
+ size_t l0_alignment;
/*
* Make sure PPS is valid and then store it since macros need this value
@@ -516,8 +513,8 @@
gpt_config.pps = pps;
gpt_config.t = gpt_t_lookup[pps];
- /* Alignment must be the greater of 4KB or l0 table size */
- l0_alignment = PAGE_SIZE_4KB;
+ /* Alignment must be the greater of 4KB or L0 table size */
+ l0_alignment = SZ_4K;
if (l0_alignment < GPT_L0_TABLE_SIZE(gpt_config.t)) {
l0_alignment = GPT_L0_TABLE_SIZE(gpt_config.t);
}
@@ -529,28 +526,11 @@
return -EFAULT;
}
-#if (RME_GPT_BITLOCK_BLOCK != 0)
- /*
- * Size of bitlocks in bytes for the protected address space
- * with RME_GPT_BITLOCK_BLOCK * 512MB per bitlock.
- */
- locks_size = GPT_PPS_ACTUAL_SIZE(gpt_config.t) /
- (RME_GPT_BITLOCK_BLOCK * SZ_512M * 8U);
-
- /*
- * If protected space size is less than the size covered
- * by 'bitlock' structure, check for a single bitlock.
- */
- if (locks_size < LOCK_SIZE) {
- locks_size = LOCK_SIZE;
- }
-#endif
- /* Check size for L0 tables and bitlocks */
- if (l0_mem_size < (GPT_L0_TABLE_SIZE(gpt_config.t) + locks_size)) {
+ /* Check memory size for L0 table */
+ if (l0_mem_size < GPT_L0_TABLE_SIZE(gpt_config.t)) {
ERROR("GPT: Inadequate L0 memory\n");
- ERROR(" Expected 0x%lx bytes, got 0x%lx bytes\n",
- GPT_L0_TABLE_SIZE(gpt_config.t) + locks_size,
- l0_mem_size);
+ ERROR(" Expected 0x%lx bytes, got 0x%lx\n",
+ GPT_L0_TABLE_SIZE(gpt_config.t), l0_mem_size);
return -ENOMEM;
}
@@ -600,7 +580,7 @@
if (l1_mem_size < l1_gpt_mem_sz) {
ERROR("%sL1 GPTs%s", (const char *)"GPT: Inadequate ",
(const char *)" memory\n");
- ERROR(" Expected 0x%lx bytes, got 0x%lx bytes\n",
+ ERROR(" Expected 0x%lx bytes, got 0x%lx\n",
l1_gpt_mem_sz, l1_mem_size);
return -ENOMEM;
}
@@ -623,7 +603,7 @@
unsigned long idx, end_idx;
uint64_t *l0_gpt_arr;
- assert(gpt_config.plat_gpt_l0_base != 0U);
+ assert(gpt_config.plat_gpt_l0_base != 0UL);
assert(pas != NULL);
/*
@@ -928,7 +908,7 @@
uint64_t *l1_gpt_arr;
unsigned int l0_idx, gpi;
- assert(gpt_config.plat_gpt_l0_base != 0U);
+ assert(gpt_config.plat_gpt_l0_base != 0UL);
assert(pas != NULL);
/*
@@ -1121,12 +1101,10 @@
size_t l0_mem_size)
{
uint64_t gpt_desc;
- size_t locks_size = 0;
- __unused bitlock_t *bit_locks;
int ret;
/* Ensure that MMU and Data caches are enabled */
- assert((read_sctlr_el3() & SCTLR_C_BIT) != 0U);
+ assert((read_sctlr_el3() & SCTLR_C_BIT) != 0UL);
/* Validate other parameters */
ret = validate_l0_params(pps, l0_mem_base, l0_mem_size);
@@ -1141,32 +1119,9 @@
for (unsigned int i = 0U; i < GPT_L0_REGION_COUNT(gpt_config.t); i++) {
((uint64_t *)l0_mem_base)[i] = gpt_desc;
}
-
-#if (RME_GPT_BITLOCK_BLOCK != 0)
- /* Initialise bitlocks at the end of L0 table */
- bit_locks = (bitlock_t *)(l0_mem_base +
- GPT_L0_TABLE_SIZE(gpt_config.t));
-
- /* Size of bitlocks in bytes */
- locks_size = GPT_PPS_ACTUAL_SIZE(gpt_config.t) /
- (RME_GPT_BITLOCK_BLOCK * SZ_512M * 8U);
-
- /*
- * If protected space size is less than the size covered
- * by 'bitlock' structure, initialise a single bitlock.
- */
- if (locks_size < LOCK_SIZE) {
- locks_size = LOCK_SIZE;
- }
-
- for (size_t i = 0UL; i < (locks_size/LOCK_SIZE); i++) {
- bit_locks[i].lock = 0U;
- }
-#endif
- /* Flush updated L0 tables and bitlocks to memory */
- flush_dcache_range((uintptr_t)l0_mem_base,
- GPT_L0_TABLE_SIZE(gpt_config.t) + locks_size);
+ /* Flush updated L0 table to memory */
+ flush_dcache_range((uintptr_t)l0_mem_base, GPT_L0_TABLE_SIZE(gpt_config.t));
/* Stash the L0 base address once initial setup is complete */
gpt_config.plat_gpt_l0_base = l0_mem_base;
@@ -1202,7 +1157,7 @@
int l1_gpt_cnt, ret;
/* Ensure that MMU and Data caches are enabled */
- assert((read_sctlr_el3() & SCTLR_C_BIT) != 0U);
+ assert((read_sctlr_el3() & SCTLR_C_BIT) != 0UL);
/* PGS is needed for validate_pas_mappings so check it now */
if (pgs > GPT_PGS_MAX) {
@@ -1213,7 +1168,7 @@
gpt_config.p = gpt_p_lookup[pgs];
/* Make sure L0 tables have been initialized */
- if (gpt_config.plat_gpt_l0_base == 0U) {
+ if (gpt_config.plat_gpt_l0_base == 0UL) {
ERROR("GPT: L0 tables must be initialized first!\n");
return -EPERM;
}
@@ -1295,18 +1250,23 @@
* initialization from a previous stage. Granule protection checks must be
* enabled already or this function will return an error.
*
+ * Parameters
+ * l1_bitlocks_base Base address of memory for L1 tables bitlocks.
+ * l1_bitlocks_size Total size of memory available for L1 tables bitlocks.
+ *
* Return
* Negative Linux error code in the event of a failure, 0 for success.
*/
-int gpt_runtime_init(void)
+int gpt_runtime_init(uintptr_t l1_bitlocks_base, size_t l1_bitlocks_size)
{
u_register_t reg;
+ __unused size_t locks_size;
/* Ensure that MMU and Data caches are enabled */
- assert((read_sctlr_el3() & SCTLR_C_BIT) != 0U);
+ assert((read_sctlr_el3() & SCTLR_C_BIT) != 0UL);
/* Ensure GPC are already enabled */
- if ((read_gpccr_el3() & GPCCR_GPC_BIT) == 0U) {
+ if ((read_gpccr_el3() & GPCCR_GPC_BIT) == 0UL) {
ERROR("GPT: Granule protection checks are not enabled!\n");
return -EPERM;
}
@@ -1334,17 +1294,43 @@
gpt_l1_index_mask = GPT_L1_IDX_MASK(gpt_config.p);
#if (RME_GPT_BITLOCK_BLOCK != 0)
- /* Bitlocks at the end of L0 table */
- gpt_bitlock_base = (bitlock_t *)(gpt_config.plat_gpt_l0_base +
- GPT_L0_TABLE_SIZE(gpt_config.t));
-#endif
+ /*
+ * Size of GPT bitlocks in bytes for the protected address space
+ * with RME_GPT_BITLOCK_BLOCK * 512MB per bitlock.
+ */
+ locks_size = GPT_PPS_ACTUAL_SIZE(gpt_config.t) /
+ (RME_GPT_BITLOCK_BLOCK * SZ_512M * 8U);
+ /*
+ * If protected space size is less than the size covered
+ * by 'bitlock' structure, check for a single bitlock.
+ */
+ if (locks_size < LOCK_SIZE) {
+ locks_size = LOCK_SIZE;
+ /* Check bitlocks array size */
+ } else if (locks_size > l1_bitlocks_size) {
+ ERROR("GPT: Inadequate GPT bitlocks memory\n");
+ ERROR(" Expected 0x%lx bytes, got 0x%lx\n",
+ locks_size, l1_bitlocks_size);
+ return -ENOMEM;
+ }
+
+ gpt_bitlock = (bitlock_t *)l1_bitlocks_base;
+
+ /* Initialise GPT bitlocks */
+ (void)memset((void *)gpt_bitlock, 0, locks_size);
+
+ /* Flush GPT bitlocks to memory */
+ flush_dcache_range((uintptr_t)gpt_bitlock, locks_size);
+#endif /* RME_GPT_BITLOCK_BLOCK */
+
VERBOSE("GPT: Runtime Configuration\n");
VERBOSE(" PPS/T: 0x%x/%u\n", gpt_config.pps, gpt_config.t);
VERBOSE(" PGS/P: 0x%x/%u\n", gpt_config.pgs, gpt_config.p);
VERBOSE(" L0GPTSZ/S: 0x%x/%u\n", GPT_L0GPTSZ, GPT_S_VAL);
VERBOSE(" L0 base: 0x%"PRIxPTR"\n", gpt_config.plat_gpt_l0_base);
#if (RME_GPT_BITLOCK_BLOCK != 0)
- VERBOSE(" Bitlocks: 0x%"PRIxPTR"\n", (uintptr_t)gpt_bitlock_base);
+ VERBOSE(" Bitlocks: 0x%"PRIxPTR"/0x%lx\n", (uintptr_t)gpt_bitlock,
+ locks_size);
#endif
return 0;
}
@@ -1391,7 +1377,7 @@
block_idx = (unsigned int)(base / (RME_GPT_BITLOCK_BLOCK * SZ_512M));
/* Bitlock address and mask */
- gpi_info->lock = &gpt_bitlock_base[block_idx / LOCK_BITS];
+ gpi_info->lock = &gpt_bitlock[block_idx / LOCK_BITS];
gpi_info->mask = 1U << (block_idx & (LOCK_BITS - 1U));
#endif
return 0;
diff --git a/lib/gpt_rme/gpt_rme.mk b/lib/gpt_rme/gpt_rme.mk
index 7d6b61f..6878489 100644
--- a/lib/gpt_rme/gpt_rme.mk
+++ b/lib/gpt_rme/gpt_rme.mk
@@ -1,19 +1,24 @@
#
-# Copyright (c) 2021-2024, Arm Limited. All rights reserved.
+# Copyright (c) 2021-2025, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
+# RME_GPT_BITLOCK_BLOCK is the number of 512MB blocks
+# per bit and the value must be power of 2.
+BITLOCK_BLOCK_POWER_2=$(shell echo $$(( ${RME_GPT_BITLOCK_BLOCK} & (${RME_GPT_BITLOCK_BLOCK} - 1) )))
+
# Process RME_GPT_BITLOCK_BLOCK value
-ifeq ($(filter 0 1 2 4 8 16 32 64 128 256 512, ${RME_GPT_BITLOCK_BLOCK}),)
- $(error "Invalid value for RME_GPT_BITLOCK_BLOCK: ${RME_GPT_BITLOCK_BLOCK}")
+ifneq (${BITLOCK_BLOCK_POWER_2}, 0)
+ $(error "RME_GPT_BITLOCK_BLOCK must be power of 2. Invalid value ${RME_GPT_BITLOCK_BLOCK}.")
endif
ifeq (${RME_GPT_BITLOCK_BLOCK},0)
- $(warning "GPT library uses global spinlock")
+ $(info "GPT library uses global spinlock")
endif
-# Process RME_GPT_MAX_BLOCK value
+# Process the maximum size of supported contiguous blocks
+# RME_GPT_MAX_BLOCK
ifeq ($(filter 0 2 32 512, ${RME_GPT_MAX_BLOCK}),)
$(error "Invalid value for RME_GPT_MAX_BLOCK: ${RME_GPT_MAX_BLOCK}")
endif
diff --git a/lib/gpt_rme/gpt_rme_private.h b/lib/gpt_rme/gpt_rme_private.h
index 31dad20..78d1cec 100644
--- a/lib/gpt_rme/gpt_rme_private.h
+++ b/lib/gpt_rme/gpt_rme_private.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2025, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,9 +7,7 @@
#ifndef GPT_RME_PRIVATE_H
#define GPT_RME_PRIVATE_H
-#include <arch.h>
#include <lib/gpt_rme/gpt_rme.h>
-#include <lib/spinlock.h>
#include <lib/utils_def.h>
/******************************************************************************/
@@ -141,10 +139,6 @@
PGS_64KB_P = 16U
} gpt_p_val_e;
-#define LOCK_SIZE sizeof(((bitlock_t *)NULL)->lock)
-#define LOCK_TYPE typeof(((bitlock_t *)NULL)->lock)
-#define LOCK_BITS (LOCK_SIZE * 8U)
-
/*
* Internal structure to retrieve the values from get_gpi_params();
*/