Commit fdb1964c authored by Sandrine Bailleux's avatar Sandrine Bailleux Committed by Antonio Nino Diaz
Browse files

xlat: Introduce MAP_REGION2() macro



The current implementation of the memory mapping API favours mapping
memory regions using the biggest possible block size in order to
reduce the number of translation tables needed.

In some cases, this behaviour might not be desirable. When translation
tables are edited at run-time, coarse-grain mappings like that might
need splitting into finer-grain tables. This operation has a
performance cost.

The MAP_REGION2() macro allows to specify the granularity of
translation tables used for the initial mapping of a memory region.
This might increase performance for memory regions that are likely to
be edited in the future, at the expense of a potentially increased
memory footprint.

The Translation Tables Library Design Guide has been updated to
explain the use case for this macro. Also added a few intermediate
titles to make the guide easier to digest.

Change-Id: I04de9302e0ee3d326b8877043a9f638766b81b7b
Co-authored-by: default avatarSandrine Bailleux <sandrine.bailleux@arm.com>
Co-authored-by: default avatarAntonio Nino Diaz <antonio.ninodiaz@arm.com>
Signed-off-by: default avatarAntonio Nino Diaz <antonio.ninodiaz@arm.com>
parent cb2cfae3
...@@ -66,7 +66,8 @@ map. It is one of the key interfaces to the library. It is identified by: ...@@ -66,7 +66,8 @@ map. It is one of the key interfaces to the library. It is identified by:
- its physical base address; - its physical base address;
- its virtual base address; - its virtual base address;
- its size; - its size;
- its attributes. - its attributes;
- its mapping granularity (optional).
See the ``struct mmap_region`` type in `xlat\_tables\_v2.h`_. See the ``struct mmap_region`` type in `xlat\_tables\_v2.h`_.
...@@ -79,6 +80,31 @@ normal memory) as well as the memory access permissions (read-only or ...@@ -79,6 +80,31 @@ normal memory) as well as the memory access permissions (read-only or
read-write, executable or not, secure or non-secure, and so on). See the read-write, executable or not, secure or non-secure, and so on). See the
``mmap_attr_t`` enumeration type in `xlat\_tables\_v2.h`_. ``mmap_attr_t`` enumeration type in `xlat\_tables\_v2.h`_.
The granularity controls the translation table level to go down to when mapping
the region. For example, assuming the MMU has been configured to use a 4KB
granule size, the library might map a 2MB memory region using either of the two
following options:
- using a single level-2 translation table entry;
- using a level-2 intermediate entry to a level-3 translation table (which
contains 512 entries, each mapping 4KB).
The first solution potentially requires less translation tables, hence
potentially less memory. However, if part of this 2MB region is later remapped
with different memory attributes, the library might need to split the existing
page tables to refine the mappings. If a single level-2 entry has been used
here, a level-3 table will need to be allocated on the fly and the level-2
modified to point to this new level-3 table. This has a performance cost at
run-time.
If the user knows upfront that such a remapping operation is likely to happen
then they might enforce a 4KB mapping granularity for this 2MB region from the
beginning; remapping some of these 4KB pages on the fly then becomes a
lightweight operation.
The region's granularity is an optional field; if it is not specified the
library will choose the mapping granularity for this region as it sees fit (more
details can be found in `The memory mapping algorithm`_ section below).
Translation Context Translation Context
~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~
...@@ -190,6 +216,11 @@ the ``MAP_REGION*()`` family of helper macros. This is to limit the risk of ...@@ -190,6 +216,11 @@ the ``MAP_REGION*()`` family of helper macros. This is to limit the risk of
compatibility breaks, should the ``mmap_region`` structure type evolve in the compatibility breaks, should the ``mmap_region`` structure type evolve in the
future. future.
The ``MAP_REGION()`` and ``MAP_REGION_FLAT()`` macros do not allow specifying a
mapping granularity, which leaves the library implementation free to choose
it. However, in cases where a specific granularity is required, the
``MAP_REGION2()`` macro might be used instead.
As explained earlier in this document, when the dynamic mapping feature is As explained earlier in this document, when the dynamic mapping feature is
disabled, there is no notion of dynamic regions. Conceptually, there are only disabled, there is no notion of dynamic regions. Conceptually, there are only
static regions. For this reason (and to retain backward compatibility with the static regions. For this reason (and to retain backward compatibility with the
...@@ -265,6 +296,9 @@ The architectural module ...@@ -265,6 +296,9 @@ The architectural module
Core module Core module
~~~~~~~~~~~ ~~~~~~~~~~~
From mmap regions to translation tables
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
All the APIs in this module work on a translation context. The translation All the APIs in this module work on a translation context. The translation
context contains the list of ``mmap_region``, which holds the information of all context contains the list of ``mmap_region``, which holds the information of all
the regions that are mapped at any given time. Whenever there is a request to the regions that are mapped at any given time. Whenever there is a request to
...@@ -288,14 +322,18 @@ After the ``init_xlat_tables()`` API has been called, only dynamic regions can ...@@ -288,14 +322,18 @@ After the ``init_xlat_tables()`` API has been called, only dynamic regions can
be added. Changes to the translation tables (as well as the mmap regions list) be added. Changes to the translation tables (as well as the mmap regions list)
will take effect immediately. will take effect immediately.
The memory mapping algorithm
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The mapping function is implemented as a recursive algorithm. It is however The mapping function is implemented as a recursive algorithm. It is however
bound by the level of depth of the translation tables (the ARMv8-A architecture bound by the level of depth of the translation tables (the ARMv8-A architecture
allows up to 4 lookup levels). allows up to 4 lookup levels).
By default, the algorithm will attempt to minimize the number of translation By default [#granularity-ref]_, the algorithm will attempt to minimize the
tables created to satisfy the user's request. It will favour mapping a region number of translation tables created to satisfy the user's request. It will
using the biggest possible blocks, only creating a sub-table if it is strictly favour mapping a region using the biggest possible blocks, only creating a
necessary. This is to reduce the memory footprint of the firmware. sub-table if it is strictly necessary. This is to reduce the memory footprint of
the firmware.
The most common reason for needing a sub-table is when a specific mapping The most common reason for needing a sub-table is when a specific mapping
requires a finer granularity. Misaligned regions also require a finer requires a finer granularity. Misaligned regions also require a finer
...@@ -322,6 +360,12 @@ entries in the translation tables are checked to ensure consistency. Please ...@@ -322,6 +360,12 @@ entries in the translation tables are checked to ensure consistency. Please
refer to the comments in the source code of the core module for more details refer to the comments in the source code of the core module for more details
about the sorting algorithm in use. about the sorting algorithm in use.
.. [#granularity-ref] That is, when mmap regions do not enforce their mapping
granularity.
TLB maintenance operations
^^^^^^^^^^^^^^^^^^^^^^^^^^
The library takes care of performing TLB maintenance operations when required. The library takes care of performing TLB maintenance operations when required.
For example, when the user requests removing a dynamic region, the library For example, when the user requests removing a dynamic region, the library
invalidates all TLB entries associated to that region to ensure that these invalidates all TLB entries associated to that region to ensure that these
......
...@@ -15,20 +15,36 @@ ...@@ -15,20 +15,36 @@
#include <xlat_mmu_helpers.h> #include <xlat_mmu_helpers.h>
#include <xlat_tables_v2_helpers.h> #include <xlat_tables_v2_helpers.h>
/* Helper macro to define entries for mmap_region_t. It creates /*
* identity mappings for each region. * Default granularity size for an mmap_region_t.
* Useful when no specific granularity is required.
*
* By default, choose the biggest possible block size allowed by the
* architectural state and granule size in order to minimize the number of page
* tables required for the mapping.
*/ */
#define MAP_REGION_FLAT(adr, sz, attr) MAP_REGION(adr, adr, sz, attr) #define REGION_DEFAULT_GRANULARITY XLAT_BLOCK_SIZE(MIN_LVL_BLOCK_DESC)
/* Helper macro to define an mmap_region_t. */
#define MAP_REGION(_pa, _va, _sz, _attr) \
_MAP_REGION_FULL_SPEC(_pa, _va, _sz, _attr, REGION_DEFAULT_GRANULARITY)
/* Helper macro to define entries for mmap_region_t. It allows to /* Helper macro to define an mmap_region_t with an identity mapping. */
* re-map address mappings from 'pa' to 'va' for each region. #define MAP_REGION_FLAT(_adr, _sz, _attr) \
MAP_REGION(_adr, _adr, _sz, _attr)
/*
* Helper macro to define an mmap_region_t to map with the desired granularity
* of translation tables.
*
* The granularity value passed to this macro must be a valid block or page
* size. When using a 4KB translation granule, this might be 4KB, 2MB or 1GB.
* Passing REGION_DEFAULT_GRANULARITY is also allowed and means that the library
* is free to choose the granularity for this region. In this case, it is
* equivalent to the MAP_REGION() macro.
*/ */
#define MAP_REGION(_pa, _va, _sz, _attr) { \ #define MAP_REGION2(_pa, _va, _sz, _attr, _gr) \
.base_pa = (_pa), \ _MAP_REGION_FULL_SPEC(_pa, _va, _sz, _attr, _gr)
.base_va = (_va), \
.size = (_sz), \
.attr = (_attr), \
}
/* /*
* Shifts and masks to access fields of an mmap_attr_t * Shifts and masks to access fields of an mmap_attr_t
...@@ -86,6 +102,8 @@ typedef struct mmap_region { ...@@ -86,6 +102,8 @@ typedef struct mmap_region {
uintptr_t base_va; uintptr_t base_va;
size_t size; size_t size;
mmap_attr_t attr; mmap_attr_t attr;
/* Desired granularity. See the MAP_REGION2() macro for more details. */
size_t granularity;
} mmap_region_t; } mmap_region_t;
/* /*
......
...@@ -27,6 +27,20 @@ ...@@ -27,6 +27,20 @@
/* Forward declaration */ /* Forward declaration */
struct mmap_region; struct mmap_region;
/*
* Helper macro to define an mmap_region_t. This macro allows to specify all
* the fields of the structure but its parameter list is not guaranteed to
* remain stable as we add members to mmap_region_t.
*/
#define _MAP_REGION_FULL_SPEC(_pa, _va, _sz, _attr, _gr) \
{ \
.base_pa = (_pa), \
.base_va = (_va), \
.size = (_sz), \
.attr = (_attr), \
.granularity = (_gr), \
}
/* Struct that holds all information about the translation tables. */ /* Struct that holds all information about the translation tables. */
struct xlat_ctx { struct xlat_ctx {
/* /*
......
...@@ -417,7 +417,8 @@ static action_t xlat_tables_map_region_action(const mmap_region_t *mm, ...@@ -417,7 +417,8 @@ static action_t xlat_tables_map_region_action(const mmap_region_t *mm,
* descriptors. If not, create a table instead. * descriptors. If not, create a table instead.
*/ */
if ((dest_pa & XLAT_BLOCK_MASK(level)) || if ((dest_pa & XLAT_BLOCK_MASK(level)) ||
(level < MIN_LVL_BLOCK_DESC)) (level < MIN_LVL_BLOCK_DESC) ||
(mm->granularity < XLAT_BLOCK_SIZE(level)))
return ACTION_CREATE_NEW_TABLE; return ACTION_CREATE_NEW_TABLE;
else else
return ACTION_WRITE_BLOCK_ENTRY; return ACTION_WRITE_BLOCK_ENTRY;
...@@ -590,9 +591,10 @@ void print_mmap(mmap_region_t *const mmap) ...@@ -590,9 +591,10 @@ void print_mmap(mmap_region_t *const mmap)
mmap_region_t *mm = mmap; mmap_region_t *mm = mmap;
while (mm->size) { while (mm->size) {
tf_printf(" VA:%p PA:0x%llx size:0x%zx attr:0x%x\n", tf_printf(" VA:%p PA:0x%llx size:0x%zx attr:0x%x",
(void *)mm->base_va, mm->base_pa, (void *)mm->base_va, mm->base_pa,
mm->size, mm->attr); mm->size, mm->attr);
tf_printf(" granularity:0x%zx\n", mm->granularity);
++mm; ++mm;
}; };
tf_printf("\n"); tf_printf("\n");
...@@ -613,7 +615,7 @@ static int mmap_add_region_check(xlat_ctx_t *ctx, const mmap_region_t *mm) ...@@ -613,7 +615,7 @@ static int mmap_add_region_check(xlat_ctx_t *ctx, const mmap_region_t *mm)
unsigned long long base_pa = mm->base_pa; unsigned long long base_pa = mm->base_pa;
uintptr_t base_va = mm->base_va; uintptr_t base_va = mm->base_va;
size_t size = mm->size; size_t size = mm->size;
mmap_attr_t attr = mm->attr; size_t granularity = mm->granularity;
unsigned long long end_pa = base_pa + size - 1; unsigned long long end_pa = base_pa + size - 1;
uintptr_t end_va = base_va + size - 1; uintptr_t end_va = base_va + size - 1;
...@@ -622,6 +624,12 @@ static int mmap_add_region_check(xlat_ctx_t *ctx, const mmap_region_t *mm) ...@@ -622,6 +624,12 @@ static int mmap_add_region_check(xlat_ctx_t *ctx, const mmap_region_t *mm)
!IS_PAGE_ALIGNED(size)) !IS_PAGE_ALIGNED(size))
return -EINVAL; return -EINVAL;
if ((granularity != XLAT_BLOCK_SIZE(1)) &&
(granularity != XLAT_BLOCK_SIZE(2)) &&
(granularity != XLAT_BLOCK_SIZE(3))) {
return -EINVAL;
}
/* Check for overflows */ /* Check for overflows */
if ((base_pa > end_pa) || (base_va > end_va)) if ((base_pa > end_pa) || (base_va > end_va))
return -ERANGE; return -ERANGE;
...@@ -663,11 +671,9 @@ static int mmap_add_region_check(xlat_ctx_t *ctx, const mmap_region_t *mm) ...@@ -663,11 +671,9 @@ static int mmap_add_region_check(xlat_ctx_t *ctx, const mmap_region_t *mm)
if (fully_overlapped_va) { if (fully_overlapped_va) {
#if PLAT_XLAT_TABLES_DYNAMIC #if PLAT_XLAT_TABLES_DYNAMIC
if ((attr & MT_DYNAMIC) || if ((mm->attr & MT_DYNAMIC) ||
(mm_cursor->attr & MT_DYNAMIC)) (mm_cursor->attr & MT_DYNAMIC))
return -EPERM; return -EPERM;
#else
(void)attr;
#endif /* PLAT_XLAT_TABLES_DYNAMIC */ #endif /* PLAT_XLAT_TABLES_DYNAMIC */
if ((mm_cursor->base_va - mm_cursor->base_pa) != if ((mm_cursor->base_va - mm_cursor->base_pa) !=
(base_va - base_pa)) (base_va - base_pa))
......
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