mirror of
https://github.com/CTCaer/switch-l4t-atf.git
synced 2024-12-13 21:58:51 +00:00
fdb1964c34
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: Sandrine Bailleux <sandrine.bailleux@arm.com> Co-authored-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com> Signed-off-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
415 lines
18 KiB
ReStructuredText
415 lines
18 KiB
ReStructuredText
Translation Tables Library Design
|
|
=================================
|
|
|
|
|
|
.. section-numbering::
|
|
:suffix: .
|
|
|
|
.. contents::
|
|
|
|
|
|
This document describes the design of the translation tables library (version 2)
|
|
used by the ARM Trusted Firmware. This library provides APIs to create page
|
|
tables based on a description of the memory layout, as well as setting up system
|
|
registers related to the Memory Management Unit (MMU) and performing the
|
|
required Translation Lookaside Buffer (TLB) maintenance operations.
|
|
|
|
More specifically, some use cases that this library aims to support are:
|
|
|
|
#. Statically allocate translation tables and populate them (at run-time) based
|
|
on a description of the memory layout. The memory layout is typically
|
|
provided by the platform port as a list of memory regions;
|
|
|
|
#. Support for generating translation tables pertaining to a different
|
|
translation regime than the exception level the library code is executing at;
|
|
|
|
#. Support for dynamic mapping and unmapping of regions, even while the MMU is
|
|
on. This can be used to temporarily map some memory regions and unmap them
|
|
later on when no longer needed;
|
|
|
|
#. Support for non-identity virtual to physical mappings to compress the virtual
|
|
address space;
|
|
|
|
#. Support for changing memory attributes of memory regions at run-time.
|
|
|
|
|
|
About version 1 and version 2
|
|
-----------------------------
|
|
|
|
This document focuses on version 2 of the library, whose sources are available
|
|
in the `lib/xlat\_tables\_v2`_ directory. Version 1 of the library can still be
|
|
found in `lib/xlat\_tables`_ directory but it is less flexible and doesn't
|
|
support dynamic mapping. Although potential bug fixes will be applied to both
|
|
versions, future features enhancements will focus on version 2 and might not be
|
|
back-ported to version 1. Therefore, it is recommended to use version 2,
|
|
especially for new platform ports.
|
|
|
|
However, please note that version 2 is still in active development and is not
|
|
considered stable yet. Hence, compatibility breaks might be introduced.
|
|
|
|
From this point onwards, this document will implicitly refer to version 2 of the
|
|
library.
|
|
|
|
|
|
Design concepts and interfaces
|
|
------------------------------
|
|
|
|
This section presents some of the key concepts and data structures used in the
|
|
translation tables library.
|
|
|
|
`mmap` regions
|
|
~~~~~~~~~~~~~~
|
|
|
|
An ``mmap_region`` is an abstract, concise way to represent a memory region to
|
|
map. It is one of the key interfaces to the library. It is identified by:
|
|
|
|
- its physical base address;
|
|
- its virtual base address;
|
|
- its size;
|
|
- its attributes;
|
|
- its mapping granularity (optional).
|
|
|
|
See the ``struct mmap_region`` type in `xlat\_tables\_v2.h`_.
|
|
|
|
The user usually provides a list of such mmap regions to map and lets the
|
|
library transpose that in a set of translation tables. As a result, the library
|
|
might create new translation tables, update or split existing ones.
|
|
|
|
The region attributes specify the type of memory (for example device or cached
|
|
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
|
|
``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
|
|
~~~~~~~~~~~~~~~~~~~
|
|
|
|
The library can create or modify translation tables pertaining to a different
|
|
translation regime than the exception level the library code is executing at.
|
|
For example, the library might be used by EL3 software (for instance BL31) to
|
|
create translation tables pertaining to the S-EL1&0 translation regime.
|
|
|
|
This flexibility comes from the use of *translation contexts*. A *translation
|
|
context* constitutes the superset of information used by the library to track
|
|
the status of a set of translation tables for a given translation regime.
|
|
|
|
The library internally allocates a default translation context, which pertains
|
|
to the translation regime of the current exception level. Additional contexts
|
|
may be explicitly allocated and initialized using the
|
|
``REGISTER_XLAT_CONTEXT()`` macro. Separate APIs are provided to act either on
|
|
the default translation context or on an alternative one.
|
|
|
|
To register a translation context, the user must provide the library with the
|
|
following information:
|
|
|
|
* A name.
|
|
|
|
The resulting translation context variable will be called after this name, to
|
|
which ``_xlat_ctx`` is appended. For example, if the macro name parameter is
|
|
``foo``, the context variable name will be ``foo_xlat_ctx``.
|
|
|
|
* The maximum number of `mmap` regions to map.
|
|
|
|
Should account for both static and dynamic regions, if applicable.
|
|
|
|
* The number of sub-translation tables to allocate.
|
|
|
|
Number of translation tables to statically allocate for this context,
|
|
excluding the initial lookup level translation table, which is always
|
|
allocated. For example, if the initial lookup level is 1, this parameter would
|
|
specify the number of level-2 and level-3 translation tables to pre-allocate
|
|
for this context.
|
|
|
|
* The size of the virtual address space.
|
|
|
|
Size in bytes of the virtual address space to map using this context. This
|
|
will incidentally determine the number of entries in the initial lookup level
|
|
translation table : the library will allocate as many entries as is required
|
|
to map the entire virtual address space.
|
|
|
|
* The size of the physical address space.
|
|
|
|
Size in bytes of the physical address space to map using this context.
|
|
|
|
The default translation context is internally initialized using information
|
|
coming (for the most part) from platform-specific defines:
|
|
|
|
- name: hard-coded to ``tf`` ; hence the name of the default context variable is
|
|
``tf_xlat_ctx``;
|
|
- number of `mmap` regions: ``MAX_MMAP_REGIONS``;
|
|
- number of sub-translation tables: ``MAX_XLAT_TABLES``;
|
|
- size of the virtual address space: ``PLAT_VIRT_ADDR_SPACE_SIZE``;
|
|
- size of the physical address space: ``PLAT_PHY_ADDR_SPACE_SIZE``.
|
|
|
|
Please refer to the `Porting Guide`_ for more details about these macros.
|
|
|
|
|
|
Static and dynamic memory regions
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
The library optionally supports dynamic memory mapping. This feature may be
|
|
enabled using the ``PLAT_XLAT_TABLES_DYNAMIC`` platform build flag.
|
|
|
|
When dynamic memory mapping is enabled, the library categorises mmap regions as
|
|
*static* or *dynamic*.
|
|
|
|
- *Static regions* are fixed for the lifetime of the system. They can only be
|
|
added early on, before the translation tables are created and populated. They
|
|
cannot be removed afterwards.
|
|
|
|
- *Dynamic regions* can be added or removed any time.
|
|
|
|
When the dynamic memory mapping feature is disabled, only static regions exist.
|
|
|
|
The dynamic memory mapping feature may be used to map and unmap transient memory
|
|
areas. This is useful when the user needs to access some memory for a fixed
|
|
period of time, after which the memory may be discarded and reclaimed. For
|
|
example, a memory region that is only required at boot time while the system is
|
|
initializing, or to temporarily share a memory buffer between the normal world
|
|
and trusted world. Note that it is up to the caller to ensure that these regions
|
|
are not accessed concurrently while the regions are being added or removed.
|
|
|
|
Although this feature provides some level of dynamic memory allocation, this
|
|
does not allow dynamically allocating an arbitrary amount of memory at an
|
|
arbitrary memory location. The user is still required to declare at compile-time
|
|
the limits of these allocations ; the library will deny any mapping request that
|
|
does not fit within this pre-allocated pool of memory.
|
|
|
|
|
|
Library APIs
|
|
------------
|
|
|
|
The external APIs exposed by this library are declared and documented in the
|
|
`xlat\_tables\_v2.h`_ header file. This should be the reference point for
|
|
getting information about the usage of the different APIs this library
|
|
provides. This section just provides some extra details and clarifications.
|
|
|
|
Although the ``mmap_region`` structure is a publicly visible type, it is not
|
|
recommended to populate these structures by hand. Instead, wherever APIs expect
|
|
function arguments of type ``mmap_region_t``, these should be constructed using
|
|
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
|
|
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
|
|
disabled, there is no notion of dynamic regions. Conceptually, there are only
|
|
static regions. For this reason (and to retain backward compatibility with the
|
|
version 1 of the library), the APIs that map static regions do not embed the
|
|
word *static* in their functions names (for example ``mmap_add_region()``), in
|
|
contrast with the dynamic regions APIs (for example
|
|
``mmap_add_dynamic_region()``).
|
|
|
|
Although the definition of static and dynamic regions is not based on the state
|
|
of the MMU, the two are still related in some way. Static regions can only be
|
|
added before ``init_xlat_tables()`` is called and ``init_xlat_tables()`` must be
|
|
called while the MMU is still off. As a result, static regions cannot be added
|
|
once the MMU has been enabled. Dynamic regions can be added with the MMU on or
|
|
off. In practice, the usual call flow would look like this:
|
|
|
|
#. The MMU is initially off.
|
|
|
|
#. Add some static regions, add some dynamic regions.
|
|
|
|
#. Initialize translation tables based on the list of mmap regions (using one of
|
|
the ``init_xlat_tables*()`` APIs).
|
|
|
|
#. At this point, it is no longer possible to add static regions. Dynamic
|
|
regions can still be added or removed.
|
|
|
|
#. Enable the MMU.
|
|
|
|
#. Dynamic regions can continue to be added or removed.
|
|
|
|
Because static regions are added early on at boot time and are all in the
|
|
control of the platform initialization code, the ``mmap_add*()`` family of APIs
|
|
are not expected to fail. They do not return any error code.
|
|
|
|
Nonetheless, these APIs will check upfront whether the region can be
|
|
successfully added before updating the translation context structure. If the
|
|
library detects that there is insufficient memory to meet the request, or that
|
|
the new region will overlap another one in an invalid way, or if any other
|
|
unexpected error is encountered, they will print an error message on the UART.
|
|
Additionally, when asserts are enabled (typically in debug builds), an assertion
|
|
will be triggered. Otherwise, the function call will just return straight away,
|
|
without adding the offending memory region.
|
|
|
|
|
|
Library limitations
|
|
-------------------
|
|
|
|
Dynamic regions are not allowed to overlap each other. Static regions are
|
|
allowed to overlap as long as one of them is fully contained inside the other
|
|
one. This is allowed for backwards compatibility with the previous behaviour in
|
|
the version 1 of the library.
|
|
|
|
|
|
Implementation details
|
|
----------------------
|
|
|
|
Code structure
|
|
~~~~~~~~~~~~~~
|
|
|
|
The library is divided into 2 modules:
|
|
|
|
The core module
|
|
Provides the main functionality of the library.
|
|
|
|
See `xlat\_tables\_internal.c`_.
|
|
|
|
The architectural module
|
|
Provides functions that are dependent on the current execution state
|
|
(AArch32/AArch64), such as the functions used for TLB invalidation or MMU
|
|
setup.
|
|
|
|
See `aarch32/xlat\_tables\_arch.c`_ and `aarch64/xlat\_tables\_arch.c`_.
|
|
|
|
Core module
|
|
~~~~~~~~~~~
|
|
|
|
From mmap regions to translation tables
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
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
|
|
the regions that are mapped at any given time. Whenever there is a request to
|
|
map (resp. unmap) a memory region, it is added to (resp. removed from) the
|
|
``mmap_region`` list.
|
|
|
|
The mmap regions list is a conceptual way to represent the memory layout. At
|
|
some point, the library has to convert this information into actual translation
|
|
tables to program into the MMU.
|
|
|
|
Before the ``init_xlat_tables()`` API is called, the library only acts on the
|
|
mmap regions list. Adding a static or dynamic region at this point through one
|
|
of the ``mmap_add*()`` APIs does not affect the translation tables in any way,
|
|
they only get registered in the internal mmap region list. It is only when the
|
|
user calls the ``init_xlat_tables()`` that the translation tables are populated
|
|
in memory based on the list of mmap regions registered so far. This is an
|
|
optimization that allows creation of the initial set of translation tables in
|
|
one go, rather than having to edit them every time while the MMU is disabled.
|
|
|
|
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)
|
|
will take effect immediately.
|
|
|
|
The memory mapping algorithm
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
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
|
|
allows up to 4 lookup levels).
|
|
|
|
By default [#granularity-ref]_, the algorithm will attempt to minimize the
|
|
number of translation tables created to satisfy the user's request. It will
|
|
favour mapping a region using the biggest possible blocks, only creating a
|
|
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
|
|
requires a finer granularity. Misaligned regions also require a finer
|
|
granularity than what the user may had originally expected, using a lot more
|
|
memory than expected. The reason is that all levels of translation are
|
|
restricted to address translations of the same granularity as the size of the
|
|
blocks of that level. For example, for a 4 KiB page size, a level 2 block entry
|
|
can only translate up to a granularity of 2 MiB. If the Physical Address is not
|
|
aligned to 2 MiB then additional level 3 tables are also needed.
|
|
|
|
Note that not every translation level allows any type of descriptor. Depending
|
|
on the page size, levels 0 and 1 of translation may only allow table
|
|
descriptors. If a block entry could be able to describe a translation, but that
|
|
level does not allow block descriptors, a table descriptor will have to be used
|
|
instead, as well as additional tables at the next level.
|
|
|
|
|Alignment Example|
|
|
|
|
The mmap regions are sorted in a way that simplifies the code that maps
|
|
them. Even though this ordering is only strictly needed for overlapping static
|
|
regions, it must also be applied for dynamic regions to maintain a consistent
|
|
order of all regions at all times. As each new region is mapped, existing
|
|
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
|
|
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.
|
|
For example, when the user requests removing a dynamic region, the library
|
|
invalidates all TLB entries associated to that region to ensure that these
|
|
changes are visible to subsequent execution, including speculative execution,
|
|
that uses the changed translation table entries.
|
|
|
|
A counter-example is the initialization of translation tables. In this case,
|
|
explicit TLB maintenance is not required. The ARMv8-A architecture guarantees
|
|
that all TLBs are disabled from reset and their contents have no effect on
|
|
address translation at reset [#tlb-reset-ref]_. Therefore, the TLBs invalidation
|
|
is deferred to the ``enable_mmu*()`` family of functions, just before the MMU is
|
|
turned on.
|
|
|
|
TLB invalidation is not required when adding dynamic regions either. Dynamic
|
|
regions are not allowed to overlap existing memory region. Therefore, if the
|
|
dynamic mapping request is deemed legitimate, it automatically concerns memory
|
|
that was not mapped in this translation regime and the library will have
|
|
initialized its corresponding translation table entry to an invalid
|
|
descriptor. Given that the TLBs are not architecturally permitted to hold any
|
|
invalid translation table entry [#tlb-no-invalid-entry]_, this means that this
|
|
mapping cannot be cached in the TLBs.
|
|
|
|
.. [#tlb-reset-ref] See section D4.8 `Translation Lookaside Buffers (TLBs)`, subsection `TLB behavior at reset` in ARMv8-A, rev B.a.
|
|
|
|
.. [#tlb-no-invalid-entry] See section D4.9.1 `General TLB maintenance requirements` in ARMv8-A, rev B.a.
|
|
|
|
Architectural module
|
|
~~~~~~~~~~~~~~~~~~~~
|
|
|
|
This module contains functions that have different implementations for AArch32
|
|
and AArch64. For example, it provides APIs to perform TLB maintenance operations,
|
|
enable the MMU or calculate the Physical Address Space size. They do not need a
|
|
translation context to work on.
|
|
|
|
--------------
|
|
|
|
*Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.*
|
|
|
|
.. _lib/xlat\_tables\_v2: ../lib/xlat_tables_v2
|
|
.. _lib/xlat\_tables: ../lib/xlat_tables
|
|
.. _xlat\_tables\_v2.h: ../include/lib/xlat_tables/xlat_tables_v2.h
|
|
.. _xlat\_tables\_internal.c: ../lib/xlat_tables_v2/xlat_tables_internal.c
|
|
.. _aarch32/xlat\_tables\_arch.c: ../lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
|
|
.. _aarch64/xlat\_tables\_arch.c: ../lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
|
|
.. _Porting Guide: porting-guide.rst
|
|
.. |Alignment Example| image:: ./diagrams/xlat_align.png?raw=true
|