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>
This commit is contained in:
AlexeiFedorov 2025-01-24 15:53:50 +00:00 committed by Jean-Philippe Brucker
parent ac07f3ab6e
commit b0f1c84035
7 changed files with 138 additions and 118 deletions

View file

@ -124,10 +124,7 @@ Level 0 and Level 1 Tables
The GPT initialization APIs require memory to be passed in for the tables to be The GPT initialization APIs require memory to be passed in for the tables to be
constructed. The ``gpt_init_l0_tables`` API takes a memory address and size for constructed. The ``gpt_init_l0_tables`` API takes a memory address and size for
building the level 0 tables and also memory for allocating the fine-grained bitlock building the level 0 tables.
data structure. The amount of memory needed for bitlock structure is controlled via
``RME_GPT_BITLOCK_BLOCK`` config which defines the block size for each bit of the
the bitlock.
The ``gpt_init_pas_l1_tables`` API takes an address and size for The ``gpt_init_pas_l1_tables`` API takes an address and size for
building the level 1 tables which are linked from level 0 descriptors. The building the level 1 tables which are linked from level 0 descriptors. The
@ -156,7 +153,7 @@ Locking Scheme
During Granule Transition access to L1 tables is controlled by a lock to ensure During Granule Transition access to L1 tables is controlled by a lock to ensure
that no more than one CPU is allowed to make changes at any given time. that no more than one CPU is allowed to make changes at any given time.
The granularity of the lock is defined by ``RME_GPT_BITLOCK_BLOCK`` build option The granularity of the lock is defined by ``RME_GPT_BITLOCK_BLOCK`` build option
which defines the size of the memory block protected by one bit of ``bitlock`` which defines the size of the memory block protected by one bit of ``bitlock_t``
structure. Setting this option to 0 chooses a single spinlock for all GPT L1 structure. Setting this option to 0 chooses a single spinlock for all GPT L1
table entries. table entries.
@ -185,6 +182,10 @@ process.
#. In systems that make use of the granule transition service, runtime #. In systems that make use of the granule transition service, runtime
firmware must call ``gpt_runtime_init`` to set up the data structures needed firmware must call ``gpt_runtime_init`` to set up the data structures needed
by the GTSI to find the tables and transition granules between PAS types. by the GTSI to find the tables and transition granules between PAS types.
The base address of bitlocks array and its size are provided to this function
as arguments. These parameters are not used in case of a single spinlock for
all GPT L1 table entries(``RME_GPT_BITLOCK_BLOCK`` is 0) and are passed as zero
values.
API Constraints API Constraints
~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~
@ -225,9 +226,6 @@ The L0 table memory has some constraints that must be taken into account.
is greater. L0 table size is the total protected space (PPS) divided by the is greater. L0 table size is the total protected space (PPS) divided by the
size of each L0 region (L0GPTSZ) multiplied by the size of each L0 descriptor size of each L0 region (L0GPTSZ) multiplied by the size of each L0 descriptor
(8 bytes). ((PPS / L0GPTSZ) * 8) (8 bytes). ((PPS / L0GPTSZ) * 8)
* The L0 memory size must be greater than the table size and have enough space
to allocate array of ``bitlock`` structures at the end of L0 table if
required (``RME_GPT_BITLOCK_BLOCK`` is not 0).
* The L0 memory must fall within a PAS of type GPT_GPI_ROOT. * The L0 memory must fall within a PAS of type GPT_GPI_ROOT.
The L1 memory also has some constraints. The L1 memory also has some constraints.
@ -237,6 +235,10 @@ The L1 memory also has some constraints.
the granules controlled in each byte (2). ((L0GPTSZ / PGS) / 2) the granules controlled in each byte (2). ((L0GPTSZ / PGS) / 2)
* There must be enough L1 memory supplied to build all requested L1 tables. * There must be enough L1 memory supplied to build all requested L1 tables.
* The L1 memory must fall within a PAS of type GPT_GPI_ROOT. * The L1 memory must fall within a PAS of type GPT_GPI_ROOT.
* The platform allocates the bitlock array which contains fine-grained
``bitlock_t`` data structures. The RME GPT library will check that the array
has at least the amount of memory defined by PPS and ``RME_GPT_BITLOCK_BLOCK``
value.
If an invalid combination of parameters is supplied, the APIs will print an If an invalid combination of parameters is supplied, the APIs will print an
error message and return a negative value. The return values of APIs should be error message and return a negative value. The return values of APIs should be
@ -245,7 +247,7 @@ checked to ensure successful configuration.
Sample Calculation for L0 memory size and alignment Sample Calculation for L0 memory size and alignment
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Let PPS=GPCCR_PPS_4GB and L0GPTSZ=GPCCR_L0GPTSZ_30BITS Let PPS=4GB and L0GPTSZ=GPCCR_L0GPTSZ_30BITS
We can find the total L0 table size with ((PPS / L0GPTSZ) * 8) We can find the total L0 table size with ((PPS / L0GPTSZ) * 8)
@ -254,19 +256,19 @@ Substitute values to get this: ((0x100000000 / 0x40000000) * 8)
And solve to get 32 bytes. In this case, 4096 is greater than 32, so the L0 And solve to get 32 bytes. In this case, 4096 is greater than 32, so the L0
tables must be aligned to 4096 bytes. tables must be aligned to 4096 bytes.
Sample calculation for bitlock array size Sample calculation for bitlocks array size
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Let PGS=GPCCR_PPS_256TB and RME_GPT_BITLOCK_BLOCK=1 Let PPS=256TB and RME_GPT_BITLOCK_BLOCK=1
The size of bit lock array in bits is the total protected space (PPS) divided The size of bitlocks array in bits is the total protected space (PPS) divided
by the size of memory block per bit. The size of memory block by the size of memory block per bit. The size of memory block
is ``RME_GPT_BITLOCK_BLOCK`` (number of 512MB blocks per bit) times is ``RME_GPT_BITLOCK_BLOCK`` (number of 512MB blocks per bit) times
512MB (0x20000000). This is then divided by the number of bits in ``bitlock`` 512MB (0x20000000). This is then divided by the number of bits in ``bitlock_t``
structure (8) to get the size of bit array in bytes. structure (8) to get the size of array in bytes.
In other words, we can find the total size of ``bitlock`` array In other words, we can find the total size of ``bitlock_t`` array
in bytes with PPS / (RME_GPT_BITLOCK_BLOCK * 0x20000000 * 8). in bytes with PPS / (RME_GPT_BITLOCK_BLOCK * 0x20000000 * 8).
Substitute values to get this: 0x1000000000000 / (1 * 0x20000000 * 8) Substitute values to get this: 0x1000000000000 / (1 * 0x20000000 * 8)

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022, Arm Limited. All rights reserved. * Copyright (c) 2022-2025, Arm Limited. All rights reserved.
* *
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*/ */
@ -8,13 +8,20 @@
#define GPT_RME_H #define GPT_RME_H
#include <stdint.h> #include <stdint.h>
#include <lib/spinlock.h>
#include <arch.h>
/******************************************************************************/ /******************************************************************************/
/* GPT helper macros and definitions */ /* GPT helper macros and definitions */
/******************************************************************************/ /******************************************************************************/
#if (RME_GPT_BITLOCK_BLOCK != 0)
#define LOCK_SIZE sizeof(((bitlock_t *)NULL)->lock)
#define LOCK_TYPE typeof(((bitlock_t *)NULL)->lock)
#define LOCK_BITS (LOCK_SIZE * UL(8))
CASSERT((UL(1) == LOCK_SIZE), assert_bitlock_type_not_uint8_t);
#endif /* RME_GPT_BITLOCK_BLOCK */
/* /*
* Structure for specifying a mapping range and it's properties. This should not * Structure for specifying a mapping range and it's properties. This should not
* be manually initialized, using the MAP_GPT_REGION_x macros is recommended as * be manually initialized, using the MAP_GPT_REGION_x macros is recommended as
@ -238,10 +245,14 @@ int gpt_init_pas_l1_tables(gpccr_pgs_e pgs,
* initialization from a previous stage. Granule protection checks must be * initialization from a previous stage. Granule protection checks must be
* enabled already or this function will return an error. * 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 * Return
* Negative Linux error code in the event of a failure, 0 for success. * 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);
/* /*
* Public API to enable granule protection checks once the tables have all been * Public API to enable granule protection checks once the tables have all been

View file

@ -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 * SPDX-License-Identifier: BSD-3-Clause
*/ */
@ -12,14 +12,13 @@
#include <arch.h> #include <arch.h>
#include <arch_features.h> #include <arch_features.h>
#include <arch_helpers.h>
#include <common/debug.h> #include <common/debug.h>
#include "gpt_rme_private.h"
#include <lib/gpt_rme/gpt_rme.h> #include <lib/gpt_rme/gpt_rme.h>
#include <lib/smccc.h> #include <lib/smccc.h>
#include <lib/spinlock.h>
#include <lib/xlat_tables/xlat_tables_v2.h> #include <lib/xlat_tables/xlat_tables_v2.h>
#include "gpt_rme_private.h"
#if !ENABLE_RME #if !ENABLE_RME
#error "ENABLE_RME must be enabled to use the GPT library" #error "ENABLE_RME must be enabled to use the GPT library"
#endif #endif
@ -123,25 +122,19 @@ static uint64_t gpt_l1_index_mask;
#define GPT_L1_INDEX(_pa) \ #define GPT_L1_INDEX(_pa) \
(((_pa) >> (unsigned int)GPT_L1_IDX_SHIFT(gpt_config.p)) & gpt_l1_index_mask) (((_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; static uintptr_t gpt_l1_tbl;
/* These variable is used during runtime */ /* These variables are used during runtime */
#if (RME_GPT_BITLOCK_BLOCK == 0) #if (RME_GPT_BITLOCK_BLOCK == 0)
/* /*
* The GPTs are protected by a global spinlock to ensure * The GPTs are protected by a global spinlock to ensure
* that multiple CPUs do not attempt to change the descriptors at once. * that multiple CPUs do not attempt to change the descriptors at once.
*/ */
static spinlock_t gpt_lock; static spinlock_t gpt_lock;
#else
/* Bitlocks base address */ /* Lock/unlock macros for GPT entries
static bitlock_t *gpt_bitlock_base; *
#endif
/* Lock/unlock macros for GPT entries */
#if (RME_GPT_BITLOCK_BLOCK == 0)
/*
* Access to GPT is controlled by a global lock to ensure * Access to GPT is controlled by a global lock to ensure
* that no more than one CPU is allowed to make changes at any * that no more than one CPU is allowed to make changes at any
* given time. * given time.
@ -149,13 +142,17 @@ static bitlock_t *gpt_bitlock_base;
#define GPT_LOCK spin_lock(&gpt_lock) #define GPT_LOCK spin_lock(&gpt_lock)
#define GPT_UNLOCK spin_unlock(&gpt_lock) #define GPT_UNLOCK spin_unlock(&gpt_lock)
#else #else
/* Base address of bitlocks array */
static bitlock_t *gpt_bitlock;
/* /*
* Access to a block of memory is controlled by a bitlock. * Access to a block of memory is controlled by a bitlock.
* Size of block = RME_GPT_BITLOCK_BLOCK * 512MB. * Size of block = RME_GPT_BITLOCK_BLOCK * 512MB.
*/ */
#define GPT_LOCK bit_lock(gpi_info.lock, gpi_info.mask) #define GPT_LOCK bit_lock(gpi_info.lock, gpi_info.mask)
#define GPT_UNLOCK bit_unlock(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) static void tlbi_page_dsbosh(uintptr_t base)
{ {
@ -494,8 +491,8 @@ static int validate_pas_mappings(pas_region_t *pas_regions,
* This function validates L0 initialization parameters. * This function validates L0 initialization parameters.
* *
* Parameters * Parameters
* l0_mem_base Base address of memory used for L0 tables. * l0_mem_base Base address of memory used for L0 table.
* l0_mem_size Size of memory available for L0 tables. * l0_mem_size Size of memory available for L0 table.
* *
* Return * Return
* Negative Linux error code in the event of a failure, 0 for success. * Negative Linux error code in the event of a failure, 0 for success.
@ -503,7 +500,7 @@ static int validate_pas_mappings(pas_region_t *pas_regions,
static int validate_l0_params(gpccr_pps_e pps, uintptr_t l0_mem_base, static int validate_l0_params(gpccr_pps_e pps, uintptr_t l0_mem_base,
size_t l0_mem_size) 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 * Make sure PPS is valid and then store it since macros need this value
@ -516,8 +513,8 @@ static int validate_l0_params(gpccr_pps_e pps, uintptr_t l0_mem_base,
gpt_config.pps = pps; gpt_config.pps = pps;
gpt_config.t = gpt_t_lookup[pps]; gpt_config.t = gpt_t_lookup[pps];
/* Alignment must be the greater of 4KB or l0 table size */ /* Alignment must be the greater of 4KB or L0 table size */
l0_alignment = PAGE_SIZE_4KB; l0_alignment = SZ_4K;
if (l0_alignment < GPT_L0_TABLE_SIZE(gpt_config.t)) { if (l0_alignment < GPT_L0_TABLE_SIZE(gpt_config.t)) {
l0_alignment = GPT_L0_TABLE_SIZE(gpt_config.t); l0_alignment = GPT_L0_TABLE_SIZE(gpt_config.t);
} }
@ -529,28 +526,11 @@ static int validate_l0_params(gpccr_pps_e pps, uintptr_t l0_mem_base,
return -EFAULT; return -EFAULT;
} }
#if (RME_GPT_BITLOCK_BLOCK != 0) /* Check memory size for L0 table */
/* if (l0_mem_size < GPT_L0_TABLE_SIZE(gpt_config.t)) {
* 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)) {
ERROR("GPT: Inadequate L0 memory\n"); ERROR("GPT: Inadequate L0 memory\n");
ERROR(" Expected 0x%lx bytes, got 0x%lx bytes\n", ERROR(" Expected 0x%lx bytes, got 0x%lx\n",
GPT_L0_TABLE_SIZE(gpt_config.t) + locks_size, GPT_L0_TABLE_SIZE(gpt_config.t), l0_mem_size);
l0_mem_size);
return -ENOMEM; return -ENOMEM;
} }
@ -600,7 +580,7 @@ static int validate_l1_params(uintptr_t l1_mem_base, size_t l1_mem_size,
if (l1_mem_size < l1_gpt_mem_sz) { if (l1_mem_size < l1_gpt_mem_sz) {
ERROR("%sL1 GPTs%s", (const char *)"GPT: Inadequate ", ERROR("%sL1 GPTs%s", (const char *)"GPT: Inadequate ",
(const char *)" memory\n"); (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); l1_gpt_mem_sz, l1_mem_size);
return -ENOMEM; return -ENOMEM;
} }
@ -623,7 +603,7 @@ static void generate_l0_blk_desc(pas_region_t *pas)
unsigned long idx, end_idx; unsigned long idx, end_idx;
uint64_t *l0_gpt_arr; uint64_t *l0_gpt_arr;
assert(gpt_config.plat_gpt_l0_base != 0U); assert(gpt_config.plat_gpt_l0_base != 0UL);
assert(pas != NULL); assert(pas != NULL);
/* /*
@ -928,7 +908,7 @@ static void generate_l0_tbl_desc(pas_region_t *pas)
uint64_t *l1_gpt_arr; uint64_t *l1_gpt_arr;
unsigned int l0_idx, gpi; unsigned int l0_idx, gpi;
assert(gpt_config.plat_gpt_l0_base != 0U); assert(gpt_config.plat_gpt_l0_base != 0UL);
assert(pas != NULL); assert(pas != NULL);
/* /*
@ -1121,12 +1101,10 @@ int gpt_init_l0_tables(gpccr_pps_e pps, uintptr_t l0_mem_base,
size_t l0_mem_size) size_t l0_mem_size)
{ {
uint64_t gpt_desc; uint64_t gpt_desc;
size_t locks_size = 0;
__unused bitlock_t *bit_locks;
int ret; int ret;
/* Ensure that MMU and Data caches are enabled */ /* 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 */ /* Validate other parameters */
ret = validate_l0_params(pps, l0_mem_base, l0_mem_size); ret = validate_l0_params(pps, l0_mem_base, l0_mem_size);
@ -1142,31 +1120,8 @@ int gpt_init_l0_tables(gpccr_pps_e pps, uintptr_t l0_mem_base,
((uint64_t *)l0_mem_base)[i] = gpt_desc; ((uint64_t *)l0_mem_base)[i] = gpt_desc;
} }
#if (RME_GPT_BITLOCK_BLOCK != 0) /* Flush updated L0 table to memory */
/* Initialise bitlocks at the end of L0 table */ flush_dcache_range((uintptr_t)l0_mem_base, GPT_L0_TABLE_SIZE(gpt_config.t));
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);
/* Stash the L0 base address once initial setup is complete */ /* Stash the L0 base address once initial setup is complete */
gpt_config.plat_gpt_l0_base = l0_mem_base; gpt_config.plat_gpt_l0_base = l0_mem_base;
@ -1202,7 +1157,7 @@ int gpt_init_pas_l1_tables(gpccr_pgs_e pgs, uintptr_t l1_mem_base,
int l1_gpt_cnt, ret; int l1_gpt_cnt, ret;
/* Ensure that MMU and Data caches are enabled */ /* 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 */ /* PGS is needed for validate_pas_mappings so check it now */
if (pgs > GPT_PGS_MAX) { if (pgs > GPT_PGS_MAX) {
@ -1213,7 +1168,7 @@ int gpt_init_pas_l1_tables(gpccr_pgs_e pgs, uintptr_t l1_mem_base,
gpt_config.p = gpt_p_lookup[pgs]; gpt_config.p = gpt_p_lookup[pgs];
/* Make sure L0 tables have been initialized */ /* 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"); ERROR("GPT: L0 tables must be initialized first!\n");
return -EPERM; return -EPERM;
} }
@ -1295,18 +1250,23 @@ int gpt_init_pas_l1_tables(gpccr_pgs_e pgs, uintptr_t l1_mem_base,
* initialization from a previous stage. Granule protection checks must be * initialization from a previous stage. Granule protection checks must be
* enabled already or this function will return an error. * 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 * Return
* Negative Linux error code in the event of a failure, 0 for success. * 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; u_register_t reg;
__unused size_t locks_size;
/* Ensure that MMU and Data caches are enabled */ /* 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 */ /* 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"); ERROR("GPT: Granule protection checks are not enabled!\n");
return -EPERM; return -EPERM;
} }
@ -1334,17 +1294,43 @@ int gpt_runtime_init(void)
gpt_l1_index_mask = GPT_L1_IDX_MASK(gpt_config.p); gpt_l1_index_mask = GPT_L1_IDX_MASK(gpt_config.p);
#if (RME_GPT_BITLOCK_BLOCK != 0) #if (RME_GPT_BITLOCK_BLOCK != 0)
/* Bitlocks at the end of L0 table */ /*
gpt_bitlock_base = (bitlock_t *)(gpt_config.plat_gpt_l0_base + * Size of GPT bitlocks in bytes for the protected address space
GPT_L0_TABLE_SIZE(gpt_config.t)); * with RME_GPT_BITLOCK_BLOCK * 512MB per bitlock.
#endif */
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("GPT: Runtime Configuration\n");
VERBOSE(" PPS/T: 0x%x/%u\n", gpt_config.pps, gpt_config.t); 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(" 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(" L0GPTSZ/S: 0x%x/%u\n", GPT_L0GPTSZ, GPT_S_VAL);
VERBOSE(" L0 base: 0x%"PRIxPTR"\n", gpt_config.plat_gpt_l0_base); VERBOSE(" L0 base: 0x%"PRIxPTR"\n", gpt_config.plat_gpt_l0_base);
#if (RME_GPT_BITLOCK_BLOCK != 0) #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 #endif
return 0; return 0;
} }
@ -1391,7 +1377,7 @@ static int get_gpi_params(uint64_t base, gpi_info_t *gpi_info)
block_idx = (unsigned int)(base / (RME_GPT_BITLOCK_BLOCK * SZ_512M)); block_idx = (unsigned int)(base / (RME_GPT_BITLOCK_BLOCK * SZ_512M));
/* Bitlock address and mask */ /* 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)); gpi_info->mask = 1U << (block_idx & (LOCK_BITS - 1U));
#endif #endif
return 0; return 0;

View file

@ -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 # 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 # Process RME_GPT_BITLOCK_BLOCK value
ifeq ($(filter 0 1 2 4 8 16 32 64 128 256 512, ${RME_GPT_BITLOCK_BLOCK}),) ifneq (${BITLOCK_BLOCK_POWER_2}, 0)
$(error "Invalid value for RME_GPT_BITLOCK_BLOCK: ${RME_GPT_BITLOCK_BLOCK}") $(error "RME_GPT_BITLOCK_BLOCK must be power of 2. Invalid value ${RME_GPT_BITLOCK_BLOCK}.")
endif endif
ifeq (${RME_GPT_BITLOCK_BLOCK},0) ifeq (${RME_GPT_BITLOCK_BLOCK},0)
$(warning "GPT library uses global spinlock") $(info "GPT library uses global spinlock")
endif 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}),) ifeq ($(filter 0 2 32 512, ${RME_GPT_MAX_BLOCK}),)
$(error "Invalid value for RME_GPT_MAX_BLOCK: ${RME_GPT_MAX_BLOCK}") $(error "Invalid value for RME_GPT_MAX_BLOCK: ${RME_GPT_MAX_BLOCK}")
endif endif

View file

@ -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 * SPDX-License-Identifier: BSD-3-Clause
*/ */
@ -7,9 +7,7 @@
#ifndef GPT_RME_PRIVATE_H #ifndef GPT_RME_PRIVATE_H
#define GPT_RME_PRIVATE_H #define GPT_RME_PRIVATE_H
#include <arch.h>
#include <lib/gpt_rme/gpt_rme.h> #include <lib/gpt_rme/gpt_rme.h>
#include <lib/spinlock.h>
#include <lib/utils_def.h> #include <lib/utils_def.h>
/******************************************************************************/ /******************************************************************************/
@ -141,10 +139,6 @@ typedef enum {
PGS_64KB_P = 16U PGS_64KB_P = 16U
} gpt_p_val_e; } 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(); * Internal structure to retrieve the values from get_gpi_params();
*/ */

View file

@ -57,7 +57,7 @@
/* Protected physical address size */ /* Protected physical address size */
#define PLAT_ARM_PPS (64 * SZ_1G) #define PLAT_ARM_PPS (64 * SZ_1G)
#endif #endif /* ENABLE_RME */
/* /*
* Max size of SPMC is 2MB for fvp. With SPMD enabled this value corresponds to * Max size of SPMC is 2MB for fvp. With SPMD enabled this value corresponds to

View file

@ -34,9 +34,31 @@ struct transfer_list_header *ns_tl __unused;
*/ */
static entry_point_info_t bl32_image_ep_info; static entry_point_info_t bl32_image_ep_info;
static entry_point_info_t bl33_image_ep_info; static entry_point_info_t bl33_image_ep_info;
#if ENABLE_RME #if ENABLE_RME
static entry_point_info_t rmm_image_ep_info; static entry_point_info_t rmm_image_ep_info;
#if (RME_GPT_BITLOCK_BLOCK == 0)
#define BITLOCK_BASE UL(0)
#define BITLOCK_SIZE UL(0)
#else
/*
* Number of bitlock_t entries in bitlocks array for PLAT_ARM_PPS
* with RME_GPT_BITLOCK_BLOCK * 512MB per bitlock.
*/
#if (PLAT_ARM_PPS > (RME_GPT_BITLOCK_BLOCK * SZ_512M * UL(8)))
#define BITLOCKS_NUM (PLAT_ARM_PPS) / \
(RME_GPT_BITLOCK_BLOCK * SZ_512M * UL(8))
#else
#define BITLOCKS_NUM U(1)
#endif #endif
/*
* Bitlocks array
*/
static bitlock_t gpt_bitlock[BITLOCKS_NUM];
#define BITLOCK_BASE (uintptr_t)gpt_bitlock
#define BITLOCK_SIZE sizeof(gpt_bitlock)
#endif /* RME_GPT_BITLOCK_BLOCK */
#endif /* ENABLE_RME */
#if !RESET_TO_BL31 #if !RESET_TO_BL31
/* /*
@ -551,7 +573,7 @@ void __init arm_bl31_plat_arch_setup(void)
* stage, so there is no need to provide any PAS here. This function * stage, so there is no need to provide any PAS here. This function
* sets up pointers to those tables. * sets up pointers to those tables.
*/ */
if (gpt_runtime_init() < 0) { if (gpt_runtime_init(BITLOCK_BASE, BITLOCK_SIZE) < 0) {
ERROR("gpt_runtime_init() failed!\n"); ERROR("gpt_runtime_init() failed!\n");
panic(); panic();
} }