Merge "fix(measured-boot): don't strip last non-0 char" into integration
diff --git a/.versionrc.js b/.versionrc.js
index 9e54c7b..4e9c71f 100644
--- a/.versionrc.js
+++ b/.versionrc.js
@@ -94,7 +94,6 @@
return contents.replace(/^(version\s=\s")((\d).?)*$/m, _ver)
}
-
},
},
{
diff --git a/Makefile b/Makefile
index 98f47a7..3dbf28e 100644
--- a/Makefile
+++ b/Makefile
@@ -710,16 +710,23 @@
BL32_LDFLAGS += $(PIE_LDFLAGS)
endif
-ifeq (${ARCH},aarch64)
+BL1_CPPFLAGS += -DREPORT_ERRATA=${DEBUG}
+BL31_CPPFLAGS += -DREPORT_ERRATA=${DEBUG}
+BL32_CPPFLAGS += -DREPORT_ERRATA=${DEBUG}
+
BL1_CPPFLAGS += -DIMAGE_AT_EL3
ifeq ($(RESET_TO_BL2),1)
BL2_CPPFLAGS += -DIMAGE_AT_EL3
else
BL2_CPPFLAGS += -DIMAGE_AT_EL1
endif
+
+ifeq (${ARCH},aarch64)
BL2U_CPPFLAGS += -DIMAGE_AT_EL1
BL31_CPPFLAGS += -DIMAGE_AT_EL3
BL32_CPPFLAGS += -DIMAGE_AT_EL1
+else
+BL32_CPPFLAGS += -DIMAGE_AT_EL3
endif
# Include the CPU specific operations makefile, which provides default
@@ -1074,11 +1081,6 @@
# Variable for use with Python
PYTHON ?= python3
-# Variables for use with PRINT_MEMORY_MAP
-PRINT_MEMORY_MAP_PATH ?= tools/memory
-PRINT_MEMORY_MAP ?= ${PRINT_MEMORY_MAP_PATH}/print_memory_map.py
-INVERTED_MEMMAP ?= 0
-
# Variables for use with documentation build using Sphinx tool
DOCS_PATH ?= docs
@@ -1139,7 +1141,6 @@
GICV2_G0_FOR_EL3 \
HANDLE_EA_EL3_FIRST_NS \
HW_ASSISTED_COHERENCY \
- INVERTED_MEMMAP \
MEASURED_BOOT \
DRTM_SUPPORT \
NS_TIMER_SWITCH \
@@ -1653,9 +1654,14 @@
romlib.bin: libraries FORCE
${Q}${MAKE} PLAT_DIR=${PLAT_DIR} BUILD_PLAT=${BUILD_PLAT} ENABLE_BTI=${ENABLE_BTI} ARM_ARCH_MINOR=${ARM_ARCH_MINOR} INCLUDES='${INCLUDES}' DEFINES='${DEFINES}' --no-print-directory -C ${ROMLIBPATH} all
-# Call print_memory_map tool
memmap: all
- ${Q}${PYTHON} ${PRINT_MEMORY_MAP} ${BUILD_PLAT} ${INVERTED_MEMMAP}
+ifdef UNIX_MK
+ ${Q}PYTHONPATH=${CURDIR}/tools/memory \
+ ${PYTHON} -m memory.memmap -sr ${BUILD_PLAT}
+else
+ ${Q}set PYTHONPATH=${CURDIR}/tools/memory && \
+ ${PYTHON} -m memory.memmap -sr ${BUILD_PLAT}
+endif
doc:
@echo " BUILD DOCUMENTATION"
diff --git a/bl1/bl1.ld.S b/bl1/bl1.ld.S
index bec234b..a2527e6 100644
--- a/bl1/bl1.ld.S
+++ b/bl1/bl1.ld.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2023, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -24,6 +24,11 @@
}
SECTIONS {
+ ROM_REGION_START = ORIGIN(ROM);
+ ROM_REGION_LENGTH = LENGTH(ROM);
+ RAM_REGION_START = ORIGIN(RAM);
+ RAM_REGION_LENGTH = LENGTH(RAM);
+
. = BL1_RO_BASE;
ASSERT(. == ALIGN(PAGE_SIZE),
@@ -97,6 +102,7 @@
ASSERT(__CPU_OPS_END__ > __CPU_OPS_START__,
"cpu_ops not defined for this platform.")
+ ROM_REGION_END = .;
. = BL1_RW_BASE;
ASSERT(BL1_RW_BASE == ALIGN(PAGE_SIZE),
@@ -157,4 +163,5 @@
#endif /* USE_COHERENT_MEM */
ASSERT(. <= BL1_RW_LIMIT, "BL1's RW section has exceeded its limit.")
+ RAM_REGION_END = .;
}
diff --git a/bl1/bl1_main.c b/bl1/bl1_main.c
index 7399bc8..3f64e27 100644
--- a/bl1/bl1_main.c
+++ b/bl1/bl1_main.c
@@ -17,7 +17,7 @@
#include <drivers/auth/auth_mod.h>
#include <drivers/auth/crypto_mod.h>
#include <drivers/console.h>
-#include <lib/cpus/errata_report.h>
+#include <lib/cpus/errata.h>
#include <lib/utils.h>
#include <plat/common/platform.h>
#include <smccc_helpers.h>
diff --git a/bl2/bl2.ld.S b/bl2/bl2.ld.S
index 458a12b..5f689d5 100644
--- a/bl2/bl2.ld.S
+++ b/bl2/bl2.ld.S
@@ -16,6 +16,8 @@
}
SECTIONS {
+ RAM_REGION_START = ORIGIN(RAM);
+ RAM_REGION_LENGTH = LENGTH(RAM);
. = BL2_BASE;
ASSERT(. == ALIGN(PAGE_SIZE),
@@ -116,6 +118,7 @@
__RW_END__ = .;
__BL2_END__ = .;
+ RAM_REGION_END = .;
__BSS_SIZE__ = SIZEOF(.bss);
diff --git a/bl2/bl2.mk b/bl2/bl2.mk
index 41bcd12..19b955f 100644
--- a/bl2/bl2.mk
+++ b/bl2/bl2.mk
@@ -41,8 +41,7 @@
BL2_SOURCES += bl2/${ARCH}/bl2_el3_entrypoint.S \
bl2/${ARCH}/bl2_el3_exceptions.S \
bl2/${ARCH}/bl2_run_next_image.S \
- lib/cpus/${ARCH}/cpu_helpers.S \
- lib/cpus/errata_report.c
+ lib/cpus/${ARCH}/cpu_helpers.S
ifeq (${DISABLE_MTPMU},1)
BL2_SOURCES += lib/extensions/mtpmu/${ARCH}/mtpmu.S
diff --git a/bl2/bl2_el3.ld.S b/bl2/bl2_el3.ld.S
index aa457fa..5da631c 100644
--- a/bl2/bl2_el3.ld.S
+++ b/bl2/bl2_el3.ld.S
@@ -31,7 +31,12 @@
#endif /* !BL2_IN_XIP_MEM */
SECTIONS {
+ RAM_REGION_START = ORIGIN(RAM);
+ RAM_REGION_LENGTH = LENGTH(RAM);
#if BL2_IN_XIP_MEM
+ ROM_REGION_START = ORIGIN(ROM);
+ ROM_REGION_LENGTH = LENGTH(ROM);
+
. = BL2_RO_BASE;
ASSERT(. == ALIGN(PAGE_SIZE),
@@ -43,6 +48,11 @@
"BL2_BASE address is not aligned on a page boundary.")
#endif /* BL2_IN_XIP_MEM */
+#if SEPARATE_BL2_NOLOAD_REGION
+ RAM_NOLOAD_REGION_START = ORIGIN(RAM_NOLOAD);
+ RAM_NOLOAD_REGION_LENGTH = LENGTH(RAM_NOLOAD);
+#endif
+
#if SEPARATE_CODE_AND_RODATA
.text . : {
__TEXT_START__ = .;
@@ -109,6 +119,7 @@
"cpu_ops not defined for this platform.")
#if BL2_IN_XIP_MEM
+ ROM_REGION_END = .;
. = BL2_RW_BASE;
ASSERT(BL2_RW_BASE == ALIGN(PAGE_SIZE),
@@ -138,6 +149,7 @@
#if SEPARATE_BL2_NOLOAD_REGION
__BL2_NOLOAD_END__ = .;
+ RAM_NOLOAD_REGION_END = .;
. = SAVED_ADDR;
#endif /* SEPARATE_BL2_NOLOAD_REGION */
@@ -198,6 +210,7 @@
__COHERENT_RAM_END_UNALIGNED__ - __COHERENT_RAM_START__;
#endif /* USE_COHERENT_MEM */
+ RAM_REGION_END = .;
#if BL2_IN_XIP_MEM
ASSERT(. <= BL2_RW_LIMIT, "BL2's RW content has exceeded its limit.")
#else /* BL2_IN_XIP_MEM */
diff --git a/bl2u/bl2u.ld.S b/bl2u/bl2u.ld.S
index 52a925b..21c91b4 100644
--- a/bl2u/bl2u.ld.S
+++ b/bl2u/bl2u.ld.S
@@ -18,6 +18,8 @@
}
SECTIONS {
+ RAM_REGION_START = ORIGIN(RAM);
+ RAM_REGION_LENGTH = LENGTH(RAM);
. = BL2U_BASE;
ASSERT(. == ALIGN(PAGE_SIZE),
@@ -115,4 +117,5 @@
__BSS_SIZE__ = SIZEOF(.bss);
ASSERT(. <= BL2U_LIMIT, "BL2U image has exceeded its limit.")
+ RAM_REGION_END = .;
}
diff --git a/bl31/bl31.ld.S b/bl31/bl31.ld.S
index 5ac83fa..abcae0c 100644
--- a/bl31/bl31.ld.S
+++ b/bl31/bl31.ld.S
@@ -26,6 +26,8 @@
#endif /* PLAT_EXTRA_LD_SCRIPT */
SECTIONS {
+ RAM_REGION_START = ORIGIN(RAM);
+ RAM_REGION_LENGTH = LENGTH(RAM);
. = BL31_BASE;
ASSERT(. == ALIGN(PAGE_SIZE),
@@ -198,6 +200,7 @@
ASSERT(. <= BL31_LIMIT, "BL31 image has exceeded its limit.")
#endif /* SEPARATE_NOBITS_REGION */
+ RAM_REGION_END = .;
/DISCARD/ : {
*(.dynsym .dynstr .hash .gnu.hash)
diff --git a/bl32/sp_min/sp_min.ld.S b/bl32/sp_min/sp_min.ld.S
index 1695e1e..0a2bad0 100644
--- a/bl32/sp_min/sp_min.ld.S
+++ b/bl32/sp_min/sp_min.ld.S
@@ -20,6 +20,8 @@
#endif /* PLAT_SP_MIN_EXTRA_LD_SCRIPT */
SECTIONS {
+ RAM_REGION_START = ORIGIN(RAM);
+ RAM_REGION_LENGTH = LENGTH(RAM);
. = BL32_BASE;
ASSERT(. == ALIGN(PAGE_SIZE),
@@ -149,4 +151,5 @@
}
ASSERT(. <= BL32_LIMIT, "BL32 image has exceeded its limit.")
+ RAM_REGION_END = .;
}
diff --git a/bl32/tsp/tsp.ld.S b/bl32/tsp/tsp.ld.S
index a6658dd..b735f45 100644
--- a/bl32/tsp/tsp.ld.S
+++ b/bl32/tsp/tsp.ld.S
@@ -16,6 +16,8 @@
}
SECTIONS {
+ RAM_REGION_START = ORIGIN(RAM);
+ RAM_REGION_LENGTH = LENGTH(RAM);
. = BL32_BASE;
ASSERT(. == ALIGN(PAGE_SIZE),
@@ -121,4 +123,5 @@
#endif /* USE_COHERENT_MEM */
ASSERT(. <= BL32_LIMIT, "BL32 image has exceeded its limit.")
+ RAM_REGION_END = .;
}
diff --git a/docs/about/maintainers.rst b/docs/about/maintainers.rst
index 0287d6c..b591f2a 100644
--- a/docs/about/maintainers.rst
+++ b/docs/about/maintainers.rst
@@ -2,12 +2,11 @@
===================
Trusted Firmware-A (TF-A) is an open governance community project. All
-contributions are ultimately merged by the maintainers listed below. Technical
-ownership of most parts of the codebase falls on the code owners listed
-below. An acknowledgement from these code owners is required before the
-maintainers merge a contribution.
+contributions are reviewed and merged by the community members listed below.
-More details may be found in the `Project Maintenance Process`_ document.
+For more details on the roles of `maintainers`, `code owners` and general
+information about code reviews in TF-A project, please refer to the :ref:`Code
+Review Guidelines`.
.. |M| replace:: **Mail**
.. |G| replace:: **GitHub ID**
@@ -18,6 +17,10 @@
Maintainers
-----------
+.. note::
+ If you wish to become a maintainer for TF-A project, please refer to the
+ :ref:`Project Maintenance Processes`.
+
:|M|: Dan Handley <dan.handley@arm.com>
:|G|: `danh-arm`_
:|M|: Soby Mathew <soby.mathew@arm.com>
@@ -980,5 +983,3 @@
.. _bytefire: https://github.com/bytefire
.. _rupsin01: https://github.com/rupsin01
.. _jimmy-brisson: https://github.com/theotherjimmy
-
-.. _Project Maintenance Process: https://developer.trustedfirmware.org/w/collaboration/project-maintenance-process/
diff --git a/docs/index.rst b/docs/index.rst
index d5ab8fc..bce9bb7 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -17,6 +17,7 @@
security_advisories/index
design_documents/index
threat_model/index
+ tools/index
change-log
glossary
license
diff --git a/docs/process/code-review-guidelines.rst b/docs/process/code-review-guidelines.rst
index 67a211f..ccdd110 100644
--- a/docs/process/code-review-guidelines.rst
+++ b/docs/process/code-review-guidelines.rst
@@ -1,11 +1,6 @@
Code Review Guidelines
======================
-This document provides TF-A specific details about the project's code review
-process. It should be read in conjunction with the `Project Maintenance
-Process`_, which it supplements.
-
-
Why do we do code reviews?
--------------------------
@@ -23,8 +18,34 @@
unfairly criticizing or belittling the work of any contributor.
-Good practices
---------------
+Overview of the code review process
+-----------------------------------
+
+All contributions to Trusted Firmware-A project are reviewed by the community to
+ensure they meet the project's expectations before they get merged, according to
+the `Project Maintenance Process`_ defined for all `Trusted Firmware` projects.
+
+Technical ownership of most parts of the codebase falls on the :ref:`code
+owners`. All patches are ultimately merged by the :ref:`maintainers`.
+
+Approval of a patch is tracked using Gerrit `labels`. For a patch to be merged,
+it must get all of the following votes:
+
+- At least one ``Code-Owner-Review+1`` up-vote, and no ``Code-Owner-Review-1``
+ down-vote.
+
+- At least one ``Maintainer-Review+1`` up-vote, and no ``Maintainer-Review-1``
+ down-vote.
+
+- ``Verified+1`` vote applied by the automated Continuous Integration (CI)
+ system.
+
+Note that, in some instances, the maintainers might give a waiver for some of
+the CI failures and manually override the ``Verified+1`` score.
+
+
+Good practices for all reviewers
+--------------------------------
To ensure the code review gives the greatest possible benefit, participants in
the project should:
@@ -211,6 +232,6 @@
--------------
-*Copyright (c) 2020, Arm Limited. All rights reserved.*
+*Copyright (c) 2020-2023, Arm Limited. All rights reserved.*
.. _Project Maintenance Process: https://developer.trustedfirmware.org/w/collaboration/project-maintenance-process/
diff --git a/docs/process/index.rst b/docs/process/index.rst
index 7914a4e..9b669c0 100644
--- a/docs/process/index.rst
+++ b/docs/process/index.rst
@@ -13,4 +13,5 @@
contributing
code-review-guidelines
faq
+ maintenance
security-hardening
diff --git a/docs/process/maintenance.rst b/docs/process/maintenance.rst
new file mode 100644
index 0000000..45aada2
--- /dev/null
+++ b/docs/process/maintenance.rst
@@ -0,0 +1,55 @@
+Project Maintenance Processes
+=============================
+
+Trusted Firmware-A (TF-A) project follows the generic `trustedfirmware.org
+Project Maintenance Process`_. The present document complements it by defining
+TF-A project-specific decisions.
+
+How to become a maintainer?
+---------------------------
+
+Qualifying Criteria
+~~~~~~~~~~~~~~~~~~~
+
+To be elligible to become a maintainer for TF-A project, all criteria outlined
+`here`_ must be fullfilled. These are:
+
+- Being an active member of the project for at least a couple of years.
+
+- Having contributed a substantial number of non-trivial and high-quality
+ patches.
+
+- Having reviewed a substantial number of non-trivial patches, preferably in the
+ generic layer, with high-quality constructive feedback.
+
+- Behaving in a professional and polite way, with the best interests of the
+ project at heart.
+
+- Showing a strong will to improve the project and to do the right thing, rather
+ than going for the quick and easy path.
+
+- Participating in design discussions on the development mailing list and during
+ TF-A tech forums calls.
+
+- Having appropriate bandwidth (minimum 2 hours per week) to deal with the workload.
+
+Election Process
+~~~~~~~~~~~~~~~~
+
+To put an individual's name up for election,
+
+#. Send an email to all existing TF-A maintainers, asking whether they have any
+ objections to this individual becoming a TF-A maintainer.
+
+#. Give existing maintainers one calendar week to participate in the discussion.
+
+#. If there are objections, the existing maintainers should try to resolve them
+ amongst themselves. If they cannot, this should be escalated to the
+ trustedfirmware.org Technical Steering Commitee (TSC).
+
+#. If there are no (more) objections, announce the news on the TF-A mailing list
+ and update the list of maintainers on the :ref:`Project
+ Maintenance<maintainers>` page.
+
+.. _trustedfirmware.org Project Maintenance Process: https://developer.trustedfirmware.org/w/collaboration/project-maintenance-process/
+.. _here: https://developer.trustedfirmware.org/w/collaboration/project-maintenance-process/#how-to-become-a-maintainer
diff --git a/docs/tools/index.rst b/docs/tools/index.rst
new file mode 100644
index 0000000..2dee2c0
--- /dev/null
+++ b/docs/tools/index.rst
@@ -0,0 +1,12 @@
+Tools
+=====
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Contents
+
+ memory-layout-tool
+
+--------------
+
+*Copyright (c) 2023, Arm Limited. All rights reserved.*
diff --git a/docs/tools/memory-layout-tool.rst b/docs/tools/memory-layout-tool.rst
new file mode 100644
index 0000000..ce14dab
--- /dev/null
+++ b/docs/tools/memory-layout-tool.rst
@@ -0,0 +1,120 @@
+TF-A Memory Layout Tool
+=======================
+
+TF-A's memory layout tool is a Python script for analyzing the virtual
+memory layout of TF-A builds.
+
+Prerequisites
+~~~~~~~~~~~~~
+
+#. Python (3.8 or later)
+#. `Poetry`_ Python package manager
+
+Getting Started
+~~~~~~~~~~~~~~~
+
+#. Install Poetry
+
+ .. code:: shell
+
+ curl -sSL https://install.python-poetry.org | python3 -
+
+#. Install the required packages
+
+ .. code:: shell
+
+ poetry install --with memory
+
+#. Verify that the tool runs in the installed virtual environment
+
+ .. code:: shell
+
+ poetry run memory --help
+
+Symbol Virtual Map
+~~~~~~~~~~~~~~~~~~
+
+The tool can be used to generate a visualisation of the symbol table. By
+default, it prints the symbols representing the start and end address of the
+main memory regions in an ELF file (i.e. text, bss, rodata) but can be modified
+to print any set of symbols.
+
+.. code:: shell
+
+ $ poetry run memory -s
+ build-path: build/fvp/release
+ Virtual Address Map:
+ +------------__BL1_RAM_END__------------+---------------------------------------+
+ +---------__COHERENT_RAM_END__----------+ |
+ +--------__COHERENT_RAM_START__---------+ |
+ 0x0403b000 +----------__XLAT_TABLE_END__-----------+ |
+ 0x04036000 +---------__XLAT_TABLE_START__----------+ |
+ +--------__BASE_XLAT_TABLE_END__--------+ |
+ 0x04035600 +--------------__BSS_END__--------------+ |
+ +-------__BASE_XLAT_TABLE_START__-------+ |
+ +-----__PMF_PERCPU_TIMESTAMP_END__------+ |
+ +---------__PMF_TIMESTAMP_END__---------+ |
+ 0x04035400 +--------__PMF_TIMESTAMP_START__--------+ |
+ +-------------__BSS_START__-------------+ |
+ 0x04034a00 +------------__STACKS_END__-------------+ |
+ 0x04034500 +-----------__STACKS_START__------------+ |
+ 0x040344c5 +-----------__DATA_RAM_END__------------+ |
+ +-----------__BL1_RAM_START__-----------+ |
+ 0x04034000 +----------__DATA_RAM_START__-----------+ |
+ | +---------__COHERENT_RAM_END__----------+
+ | +--------__COHERENT_RAM_START__---------+
+ 0x0402e000 | +----------__XLAT_TABLE_END__-----------+
+ 0x04029000 | +---------__XLAT_TABLE_START__----------+
+ | +--------__BASE_XLAT_TABLE_END__--------+
+ 0x04028800 | +--------------__BSS_END__--------------+
+ | +-------__BASE_XLAT_TABLE_START__-------+
+ | +-----__PMF_PERCPU_TIMESTAMP_END__------+
+ | +---------__PMF_TIMESTAMP_END__---------+
+ 0x04028580 | +--------__PMF_TIMESTAMP_START__--------+
+ 0x04028000 | +-------------__BSS_START__-------------+
+ 0x04027e40 | +------------__STACKS_END__-------------+
+ 0x04027840 | +-----------__STACKS_START__------------+
+ 0x04027000 | +------------__RODATA_END__-------------+
+ | +------------__CPU_OPS_END__------------+
+ | +-----------__CPU_OPS_START__-----------+
+ | +--------__FCONF_POPULATOR_END__--------+
+ | +--------------__GOT_END__--------------+
+ | +-------------__GOT_START__-------------+
+ | +---------__PMF_SVC_DESCS_END__---------+
+ 0x04026c10 | +--------__PMF_SVC_DESCS_START__--------+
+ 0x04026bf8 | +-------__FCONF_POPULATOR_START__-------+
+ | +-----------__RODATA_START__------------+
+ 0x04026000 | +-------------__TEXT_END__--------------+
+ 0x04021000 | +------------__TEXT_START__-------------+
+ 0x000062b5 +------------__BL1_ROM_END__------------+ |
+ 0x00005df0 +----------__DATA_ROM_START__-----------+ |
+ +------------__CPU_OPS_END__------------+ |
+ +--------------__GOT_END__--------------+ |
+ +-------------__GOT_START__-------------+ |
+ 0x00005de8 +------------__RODATA_END__-------------+ |
+ +-----------__CPU_OPS_START__-----------+ |
+ +--------__FCONF_POPULATOR_END__--------+ |
+ +---------__PMF_SVC_DESCS_END__---------+ |
+ 0x00005c98 +--------__PMF_SVC_DESCS_START__--------+ |
+ 0x00005c80 +-------__FCONF_POPULATOR_START__-------+ |
+ +-----------__RODATA_START__------------+ |
+ 0x00005000 +-------------__TEXT_END__--------------+ |
+ 0x00000000 +------------__TEXT_START__-------------+---------------------------------------+
+
+Addresses are displayed in hexadecimal by default but can be printed in decimal
+instead with the ``-d`` option.
+
+Because of the length of many of the symbols, the tool defaults to a text width
+of 120 chars. This can be increased if needed with the ``-w`` option.
+
+For more detailed help instructions, run:
+
+.. code:: shell
+
+ poetry run memory --help
+
+--------------
+
+*Copyright (c) 2023, Arm Limited. All rights reserved.*
+
+.. _Poetry: https://python-poetry.org/docs/
diff --git a/drivers/st/crypto/stm32_pka.c b/drivers/st/crypto/stm32_pka.c
index 1e7c42c..9124cf2 100644
--- a/drivers/st/crypto/stm32_pka.c
+++ b/drivers/st/crypto/stm32_pka.c
@@ -33,10 +33,10 @@
#define UINT8_LEN 8U
#define UINT64_LEN (UINT8_LEN * sizeof(uint64_t))
-#define WORD_SIZE (sizeof(uint64_t))
+#define PKA_WORD_SIZE (sizeof(uint64_t))
#define OP_NBW_FROM_LEN(len) (DIV_ROUND_UP_2EVAL((len), UINT64_LEN) + 1)
#define OP_NBW_FROM_SIZE(s) OP_NBW_FROM_LEN((s) * UINT8_LEN)
-#define OP_SIZE_FROM_SIZE(s) (OP_NBW_FROM_SIZE(s) * WORD_SIZE)
+#define OP_SIZE_FROM_SIZE(s) (OP_NBW_FROM_SIZE(s) * PKA_WORD_SIZE)
#define DT_PKA_COMPAT "st,stm32-pka64"
diff --git a/include/arch/aarch32/asm_macros.S b/include/arch/aarch32/asm_macros.S
index 483f9fe..83e94ca 100644
--- a/include/arch/aarch32/asm_macros.S
+++ b/include/arch/aarch32/asm_macros.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2023, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -8,6 +8,7 @@
#include <arch.h>
#include <common/asm_macros_common.S>
+#include <lib/cpus/cpu_ops.h>
#include <lib/spinlock.h>
/*
@@ -24,8 +25,6 @@
stcopr _reg, _coproc
#endif
-#define WORD_SIZE 4
-
/*
* Co processor register accessors
*/
@@ -49,14 +48,14 @@
.macro dcache_line_size reg, tmp
ldcopr \tmp, CTR
ubfx \tmp, \tmp, #CTR_DMINLINE_SHIFT, #CTR_DMINLINE_WIDTH
- mov \reg, #WORD_SIZE
+ mov \reg, #CPU_WORD_SIZE
lsl \reg, \reg, \tmp
.endm
.macro icache_line_size reg, tmp
ldcopr \tmp, CTR
and \tmp, \tmp, #CTR_IMINLINE_MASK
- mov \reg, #WORD_SIZE
+ mov \reg, #CPU_WORD_SIZE
lsl \reg, \reg, \tmp
.endm
diff --git a/include/lib/cpus/aarch32/cpu_macros.S b/include/lib/cpus/aarch32/cpu_macros.S
index ab2f2c6..096e0b1 100644
--- a/include/lib/cpus/aarch32/cpu_macros.S
+++ b/include/lib/cpus/aarch32/cpu_macros.S
@@ -1,82 +1,13 @@
/*
- * Copyright (c) 2016-2023, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef CPU_MACROS_S
#define CPU_MACROS_S
-#include <arch.h>
-#include <lib/cpus/errata_report.h>
-
-#if defined(IMAGE_BL1) || defined(IMAGE_BL32) \
- || (defined(IMAGE_BL2) && RESET_TO_BL2)
-#define IMAGE_AT_EL3
-#endif
-
-#define CPU_IMPL_PN_MASK (MIDR_IMPL_MASK << MIDR_IMPL_SHIFT) | \
- (MIDR_PN_MASK << MIDR_PN_SHIFT)
-
-/* The number of CPU operations allowed */
-#define CPU_MAX_PWR_DWN_OPS 2
-
-/* Special constant to specify that CPU has no reset function */
-#define CPU_NO_RESET_FUNC 0
-
-/* Word size for 32-bit CPUs */
-#define CPU_WORD_SIZE 4
-
-/*
- * Whether errata status needs reporting. Errata status is printed in debug
- * builds for both BL1 and BL32 images.
- */
-#if (defined(IMAGE_BL1) || defined(IMAGE_BL32)) && DEBUG
-# define REPORT_ERRATA 1
-#else
-# define REPORT_ERRATA 0
-#endif
-
-
- .equ CPU_MIDR_SIZE, CPU_WORD_SIZE
- .equ CPU_RESET_FUNC_SIZE, CPU_WORD_SIZE
- .equ CPU_PWR_DWN_OPS_SIZE, CPU_WORD_SIZE * CPU_MAX_PWR_DWN_OPS
- .equ CPU_ERRATA_FUNC_SIZE, CPU_WORD_SIZE
- .equ CPU_ERRATA_LOCK_SIZE, CPU_WORD_SIZE
- .equ CPU_ERRATA_PRINTED_SIZE, CPU_WORD_SIZE
-
-#ifndef IMAGE_AT_EL3
- .equ CPU_RESET_FUNC_SIZE, 0
-#endif
-
-/* The power down core and cluster is needed only in BL32 */
-#ifndef IMAGE_BL32
- .equ CPU_PWR_DWN_OPS_SIZE, 0
-#endif
-
-/* Fields required to print errata status */
-#if !REPORT_ERRATA
- .equ CPU_ERRATA_FUNC_SIZE, 0
-#endif
-
-/* Only BL32 requires mutual exclusion and printed flag. */
-#if !(REPORT_ERRATA && defined(IMAGE_BL32))
- .equ CPU_ERRATA_LOCK_SIZE, 0
- .equ CPU_ERRATA_PRINTED_SIZE, 0
-#endif
-
-
-/*
- * Define the offsets to the fields in cpu_ops structure.
- * Every offset is defined based on the offset and size of the previous
- * field.
- */
- .equ CPU_MIDR, 0
- .equ CPU_RESET_FUNC, CPU_MIDR + CPU_MIDR_SIZE
- .equ CPU_PWR_DWN_OPS, CPU_RESET_FUNC + CPU_RESET_FUNC_SIZE
- .equ CPU_ERRATA_FUNC, CPU_PWR_DWN_OPS + CPU_PWR_DWN_OPS_SIZE
- .equ CPU_ERRATA_LOCK, CPU_ERRATA_FUNC + CPU_ERRATA_FUNC_SIZE
- .equ CPU_ERRATA_PRINTED, CPU_ERRATA_LOCK + CPU_ERRATA_LOCK_SIZE
- .equ CPU_OPS_SIZE, CPU_ERRATA_PRINTED + CPU_ERRATA_PRINTED_SIZE
+#include <lib/cpus/cpu_ops.h>
+#include <lib/cpus/errata.h>
/*
* Write given expressions as words
@@ -142,6 +73,29 @@
fill_constants CPU_MAX_PWR_DWN_OPS, \_power_down_ops
#endif
+ /*
+ * It is possible (although unlikely) that a cpu may have no errata in
+ * code. In that case the start label will not be defined. The list is
+ * inteded to be used in a loop, so define it as zero-length for
+ * predictable behaviour. Since this macro is always called at the end
+ * of the cpu file (after all errata have been parsed) we can be sure
+ * that we are at the end of the list. Some cpus call the macro twice,
+ * so only do this once.
+ */
+ .pushsection .rodata.errata_entries
+ .ifndef \_name\()_errata_list_start
+ \_name\()_errata_list_start:
+ .endif
+ /* some call this multiple times, so only do this once */
+ .ifndef \_name\()_errata_list_end
+ \_name\()_errata_list_end:
+ .endif
+ .popsection
+
+ /* and now put them in cpu_ops */
+ .word \_name\()_errata_list_start
+ .word \_name\()_errata_list_end
+
#if REPORT_ERRATA
.ifndef \_name\()_cpu_str
/*
@@ -166,6 +120,7 @@
* this class.
*/
.word \_name\()_errata_report
+ .word \_name\()_cpu_str
#ifdef IMAGE_BL32
/* Pointers to errata lock and reported flag */
@@ -228,4 +183,77 @@
beq \_label
.endm
+/*
+ * NOTE an erratum and CVE id could clash. However, both numbers are very large
+ * and the probablity is minuscule. Working around this makes code very
+ * complicated and extremely difficult to read so it is not considered. In the
+ * unlikely event that this does happen, prepending the CVE id with a 0 should
+ * resolve the conflict
+ */
+
+/*
+ * Add an entry for this erratum to the errata framework
+ *
+ * _cpu:
+ * Name of cpu as given to declare_cpu_ops
+ *
+ * _cve:
+ * Whether erratum is a CVE. CVE year if yes, 0 otherwise
+ *
+ * _id:
+ * Erratum or CVE number. Please combine with the previous field with the
+ * ERRATUM or CVE macros
+ *
+ * _chosen:
+ * Compile time flag on whether the erratum is included
+ *
+ * _special:
+ * The special non-standard name of an erratum
+ */
+.macro add_erratum_entry _cpu:req, _cve:req, _id:req, _chosen:req, _special
+ .pushsection .rodata.errata_entries
+ .align 2
+ .ifndef \_cpu\()_errata_list_start
+ \_cpu\()_errata_list_start:
+ .endif
+
+ /* unused on AArch32, maintain for portability */
+ .word 0
+ /* TODO(errata ABI): this prevents all checker functions from
+ * being optimised away. Can be done away with unless the ABI
+ * needs them */
+ .ifnb \_special
+ .word check_errata_\_special
+ .elseif \_cve
+ .word check_errata_cve_\_cve\()_\_id
+ .else
+ .word check_errata_\_id
+ .endif
+ /* Will fit CVEs with up to 10 character in the ID field */
+ .word \_id
+ .hword \_cve
+ .byte \_chosen
+ /* TODO(errata ABI): mitigated field for known but unmitigated
+ * errata*/
+ .byte 0x1
+ .popsection
+.endm
+
+/*
+ * Maintain compatibility with the old scheme of "each cpu has its own reporter".
+ * TODO remove entirely once all cpus have been converted. This includes the
+ * cpu_ops entry, as print_errata_status can call this directly for all cpus
+ */
+.macro errata_report_shim _cpu:req
+ #if REPORT_ERRATA
+ func \_cpu\()_errata_report
+ push {r12, lr}
+
+ bl generic_errata_report
+
+ pop {r12, lr}
+ bx lr
+ endfunc \_cpu\()_errata_report
+ #endif
+.endm
#endif /* CPU_MACROS_S */
diff --git a/include/lib/cpus/aarch64/cpu_macros.S b/include/lib/cpus/aarch64/cpu_macros.S
index 041be51..724624c 100644
--- a/include/lib/cpus/aarch64/cpu_macros.S
+++ b/include/lib/cpus/aarch64/cpu_macros.S
@@ -1,95 +1,14 @@
/*
- * Copyright (c) 2014-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2023, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef CPU_MACROS_S
#define CPU_MACROS_S
-#include <arch.h>
#include <assert_macros.S>
-#include <lib/cpus/errata_report.h>
-
-#define CPU_IMPL_PN_MASK (MIDR_IMPL_MASK << MIDR_IMPL_SHIFT) | \
- (MIDR_PN_MASK << MIDR_PN_SHIFT)
-
-/* The number of CPU operations allowed */
-#define CPU_MAX_PWR_DWN_OPS 2
-
-/* Special constant to specify that CPU has no reset function */
-#define CPU_NO_RESET_FUNC 0
-
-#define CPU_NO_EXTRA1_FUNC 0
-#define CPU_NO_EXTRA2_FUNC 0
-#define CPU_NO_EXTRA3_FUNC 0
-
-/* Word size for 64-bit CPUs */
-#define CPU_WORD_SIZE 8
-
-/*
- * Whether errata status needs reporting. Errata status is printed in debug
- * builds for both BL1 and BL31 images.
- */
-#if (defined(IMAGE_BL1) || defined(IMAGE_BL31)) && DEBUG
-# define REPORT_ERRATA 1
-#else
-# define REPORT_ERRATA 0
-#endif
-
-
- .equ CPU_MIDR_SIZE, CPU_WORD_SIZE
- .equ CPU_EXTRA1_FUNC_SIZE, CPU_WORD_SIZE
- .equ CPU_EXTRA2_FUNC_SIZE, CPU_WORD_SIZE
- .equ CPU_EXTRA3_FUNC_SIZE, CPU_WORD_SIZE
- .equ CPU_E_HANDLER_FUNC_SIZE, CPU_WORD_SIZE
- .equ CPU_RESET_FUNC_SIZE, CPU_WORD_SIZE
- .equ CPU_PWR_DWN_OPS_SIZE, CPU_WORD_SIZE * CPU_MAX_PWR_DWN_OPS
- .equ CPU_ERRATA_FUNC_SIZE, CPU_WORD_SIZE
- .equ CPU_ERRATA_LOCK_SIZE, CPU_WORD_SIZE
- .equ CPU_ERRATA_PRINTED_SIZE, CPU_WORD_SIZE
- .equ CPU_REG_DUMP_SIZE, CPU_WORD_SIZE
-
-#ifndef IMAGE_AT_EL3
- .equ CPU_RESET_FUNC_SIZE, 0
-#endif
-
-/* The power down core and cluster is needed only in BL31 */
-#ifndef IMAGE_BL31
- .equ CPU_PWR_DWN_OPS_SIZE, 0
-#endif
-
-/* Fields required to print errata status. */
-#if !REPORT_ERRATA
- .equ CPU_ERRATA_FUNC_SIZE, 0
-#endif
-
-/* Only BL31 requieres mutual exclusion and printed flag. */
-#if !(REPORT_ERRATA && defined(IMAGE_BL31))
- .equ CPU_ERRATA_LOCK_SIZE, 0
- .equ CPU_ERRATA_PRINTED_SIZE, 0
-#endif
-
-#if !defined(IMAGE_BL31) || !CRASH_REPORTING
- .equ CPU_REG_DUMP_SIZE, 0
-#endif
-
-/*
- * Define the offsets to the fields in cpu_ops structure.
- * Every offset is defined based in the offset and size of the previous
- * field.
- */
- .equ CPU_MIDR, 0
- .equ CPU_RESET_FUNC, CPU_MIDR + CPU_MIDR_SIZE
- .equ CPU_EXTRA1_FUNC, CPU_RESET_FUNC + CPU_RESET_FUNC_SIZE
- .equ CPU_EXTRA2_FUNC, CPU_EXTRA1_FUNC + CPU_EXTRA1_FUNC_SIZE
- .equ CPU_EXTRA3_FUNC, CPU_EXTRA2_FUNC + CPU_EXTRA2_FUNC_SIZE
- .equ CPU_E_HANDLER_FUNC, CPU_EXTRA3_FUNC + CPU_EXTRA3_FUNC_SIZE
- .equ CPU_PWR_DWN_OPS, CPU_E_HANDLER_FUNC + CPU_E_HANDLER_FUNC_SIZE
- .equ CPU_ERRATA_FUNC, CPU_PWR_DWN_OPS + CPU_PWR_DWN_OPS_SIZE
- .equ CPU_ERRATA_LOCK, CPU_ERRATA_FUNC + CPU_ERRATA_FUNC_SIZE
- .equ CPU_ERRATA_PRINTED, CPU_ERRATA_LOCK + CPU_ERRATA_LOCK_SIZE
- .equ CPU_REG_DUMP, CPU_ERRATA_PRINTED + CPU_ERRATA_PRINTED_SIZE
- .equ CPU_OPS_SIZE, CPU_REG_DUMP + CPU_REG_DUMP_SIZE
+#include <lib/cpus/cpu_ops.h>
+#include <lib/cpus/errata.h>
/*
* Write given expressions as quad words
@@ -172,6 +91,27 @@
/* Insert list of functions */
fill_constants CPU_MAX_PWR_DWN_OPS, \_power_down_ops
#endif
+ /*
+ * It is possible (although unlikely) that a cpu may have no errata in
+ * code. In that case the start label will not be defined. The list is
+ * intended to be used in a loop, so define it as zero-length for
+ * predictable behaviour. Since this macro is always called at the end
+ * of the cpu file (after all errata have been parsed) we can be sure
+ * that we are at the end of the list. Some cpus call declare_cpu_ops
+ * twice, so only do this once.
+ */
+ .pushsection .rodata.errata_entries
+ .ifndef \_name\()_errata_list_start
+ \_name\()_errata_list_start:
+ .endif
+ .ifndef \_name\()_errata_list_end
+ \_name\()_errata_list_end:
+ .endif
+ .popsection
+
+ /* and now put them in cpu_ops */
+ .quad \_name\()_errata_list_start
+ .quad \_name\()_errata_list_end
#if REPORT_ERRATA
.ifndef \_name\()_cpu_str
@@ -192,18 +132,20 @@
.popsection
.endif
+
/*
* Mandatory errata status printing function for CPUs of
* this class.
*/
.quad \_name\()_errata_report
+ .quad \_name\()_cpu_str
#ifdef IMAGE_BL31
/* Pointers to errata lock and reported flag */
.quad \_name\()_errata_lock
.quad \_name\()_errata_reported
-#endif
-#endif
+#endif /* IMAGE_BL31 */
+#endif /* REPORT_ERRATA */
#if defined(IMAGE_BL31) && CRASH_REPORTING
.quad \_name\()_cpu_reg_dump
@@ -229,6 +171,7 @@
\_extra1, \_extra2, \_extra3, 0, \_power_down_ops
.endm
+/* TODO can be deleted once all CPUs have been converted */
#if REPORT_ERRATA
/*
* Print status of a CPU errata
@@ -311,4 +254,322 @@
b.eq \_label
.endm
+
+/*
+ * Workaround wrappers for errata that apply at reset or runtime. Reset errata
+ * will be applied automatically
+ *
+ * _cpu:
+ * Name of cpu as given to declare_cpu_ops
+ *
+ * _cve:
+ * Whether erratum is a CVE. CVE year if yes, 0 otherwise
+ *
+ * _id:
+ * Erratum or CVE number. Please combine with previous field with ERRATUM
+ * or CVE macros
+ *
+ * _chosen:
+ * Compile time flag on whether the erratum is included
+ *
+ * _apply_at_reset:
+ * Whether the erratum should be automatically applied at reset
+ */
+.macro add_erratum_entry _cpu:req, _cve:req, _id:req, _chosen:req, _apply_at_reset:req
+ .pushsection .rodata.errata_entries
+ .align 3
+ .ifndef \_cpu\()_errata_list_start
+ \_cpu\()_errata_list_start:
+ .endif
+
+ /* check if unused and compile out if no references */
+ .if \_apply_at_reset && \_chosen
+ .quad erratum_\_cpu\()_\_id\()_wa
+ .else
+ .quad 0
+ .endif
+ /* TODO(errata ABI): this prevents all checker functions from
+ * being optimised away. Can be done away with unless the ABI
+ * needs them */
+ .quad check_erratum_\_cpu\()_\_id
+ /* Will fit CVEs with up to 10 character in the ID field */
+ .word \_id
+ .hword \_cve
+ .byte \_chosen
+ /* TODO(errata ABI): mitigated field for known but unmitigated
+ * errata */
+ .byte 0x1
+ .popsection
+.endm
+
+.macro _workaround_start _cpu:req, _cve:req, _id:req, _chosen:req, _apply_at_reset:req
+ add_erratum_entry \_cpu, \_cve, \_id, \_chosen, \_apply_at_reset
+
+ func erratum_\_cpu\()_\_id\()_wa
+ mov x8, x30
+
+ /* save rev_var for workarounds that might need it but don't
+ * restore to x0 because few will care */
+ mov x7, x0
+ bl check_erratum_\_cpu\()_\_id
+ cbz x0, erratum_\_cpu\()_\_id\()_skip
+.endm
+
+.macro _workaround_end _cpu:req, _id:req
+ erratum_\_cpu\()_\_id\()_skip:
+ ret x8
+ endfunc erratum_\_cpu\()_\_id\()_wa
+.endm
+
+/*******************************************************************************
+ * Errata workaround wrappers
+ ******************************************************************************/
+/*
+ * Workaround wrappers for errata that apply at reset or runtime. Reset errata
+ * will be applied automatically
+ *
+ * _cpu:
+ * Name of cpu as given to declare_cpu_ops
+ *
+ * _cve:
+ * Whether erratum is a CVE. CVE year if yes, 0 otherwise
+ *
+ * _id:
+ * Erratum or CVE number. Please combine with previous field with ERRATUM
+ * or CVE macros
+ *
+ * _chosen:
+ * Compile time flag on whether the erratum is included
+ *
+ * in body:
+ * clobber x0 to x7 (please only use those)
+ * argument x7 - cpu_rev_var
+ *
+ * _wa clobbers: x0-x8 (PCS compliant)
+ */
+.macro workaround_reset_start _cpu:req, _cve:req, _id:req, _chosen:req
+ _workaround_start \_cpu, \_cve, \_id, \_chosen, 1
+.endm
+
+/*
+ * See `workaround_reset_start` for usage info. Additional arguments:
+ *
+ * _midr:
+ * Check if CPU's MIDR matches the CPU it's meant for. Must be specified
+ * for errata applied in generic code
+ */
+.macro workaround_runtime_start _cpu:req, _cve:req, _id:req, _chosen:req, _midr
+ /*
+ * Let errata specify if they need MIDR checking. Sadly, storing the
+ * MIDR in an .equ to retrieve automatically blows up as it stores some
+ * brackets in the symbol
+ */
+ .ifnb \_midr
+ jump_if_cpu_midr \_midr, 1f
+ b erratum_\_cpu\()_\_id\()_skip
+
+ 1:
+ .endif
+ _workaround_start \_cpu, \_cve, \_id, \_chosen, 0
+.endm
+
+/*
+ * Usage and arguments identical to `workaround_reset_start`. The _cve argument
+ * is kept here so the same #define can be used as that macro
+ */
+.macro workaround_reset_end _cpu:req, _cve:req, _id:req
+ _workaround_end \_cpu, \_id
+.endm
+
+/*
+ * See `workaround_reset_start` for usage info. The _cve argument is kept here
+ * so the same #define can be used as that macro. Additional arguments:
+ *
+ * _no_isb:
+ * Optionally do not include the trailing isb. Please disable with the
+ * NO_ISB macro
+ */
+.macro workaround_runtime_end _cpu:req, _cve:req, _id:req, _no_isb
+ /*
+ * Runtime errata do not have a reset function to call the isb for them
+ * and missing the isb could be very problematic. It is also likely as
+ * they tend to be scattered in generic code.
+ */
+ .ifb \_no_isb
+ isb
+ .endif
+ _workaround_end \_cpu, \_id
+.endm
+
+/*******************************************************************************
+ * Errata workaround helpers
+ ******************************************************************************/
+/*
+ * Set a bit in a system register. Can set multiple bits but is limited by the
+ * way the ORR instruction encodes them.
+ *
+ * _reg:
+ * Register to write to
+ *
+ * _bit:
+ * Bit to set. Please use a descriptive #define
+ *
+ * _assert:
+ * Optionally whether to read back and assert that the bit has been
+ * written. Please disable with NO_ASSERT macro
+ *
+ * clobbers: x1
+ */
+.macro sysreg_bit_set _reg:req, _bit:req, _assert=1
+ mrs x1, \_reg
+ orr x1, x1, #\_bit
+ msr \_reg, x1
+.endm
+
+/*
+ * Apply erratum
+ *
+ * _cpu:
+ * Name of cpu as given to declare_cpu_ops
+ *
+ * _cve:
+ * Whether erratum is a CVE. CVE year if yes, 0 otherwise
+ *
+ * _id:
+ * Erratum or CVE number. Please combine with previous field with ERRATUM
+ * or CVE macros
+ *
+ * _chosen:
+ * Compile time flag on whether the erratum is included
+ *
+ * clobbers: x0-x9 (PCS compliant)
+ */
+.macro apply_erratum _cpu:req, _cve:req, _id:req, _chosen:req
+ .if \_chosen
+ mov x9, x30
+ bl cpu_get_rev_var
+ bl erratum_\_cpu\()_\_id\()_wa
+ mov x30, x9
+
+ .endif
+.endm
+
+/*
+ * Helpers to select which revisions errata apply to. Don't leave a link
+ * register as the cpu_rev_var_*** will call the ret and we can save on one.
+ *
+ * _cpu:
+ * Name of cpu as given to declare_cpu_ops
+ *
+ * _cve:
+ * Whether erratum is a CVE. CVE year if yes, 0 otherwise
+ *
+ * _id:
+ * Erratum or CVE number. Please combine with previous field with ERRATUM
+ * or CVE macros
+ *
+ * _rev_num:
+ * Revision to apply to
+ *
+ * in body:
+ * clobber: x0 to x4
+ * argument: x0 - cpu_rev_var
+ */
+.macro check_erratum_ls _cpu:req, _cve:req, _id:req, _rev_num:req
+ func check_erratum_\_cpu\()_\_id
+ mov x1, #\_rev_num
+ b cpu_rev_var_ls
+ endfunc check_erratum_\_cpu\()_\_id
+.endm
+
+.macro check_erratum_hs _cpu:req, _cve:req, _id:req, _rev_num:req
+ func check_erratum_\_cpu\()_\_id
+ mov x1, #\_rev_num
+ b cpu_rev_var_hs
+ endfunc check_erratum_\_cpu\()_\_id
+.endm
+
+.macro check_erratum_range _cpu:req, _cve:req, _id:req, _rev_num_lo:req, _rev_num_hi:req
+ func check_erratum_\_cpu\()_\_id
+ mov x1, #\_rev_num_lo
+ mov x2, #\_rev_num_hi
+ b cpu_rev_var_range
+ endfunc check_erratum_\_cpu\()_\_id
+.endm
+
+/*******************************************************************************
+ * CPU reset function wrapper
+ ******************************************************************************/
+
+/*
+ * Wrapper to automatically apply all reset-time errata. Will end with an isb.
+ *
+ * _cpu:
+ * Name of cpu as given to declare_cpu_ops
+ *
+ * in body:
+ * clobber x8 to x14
+ * argument x14 - cpu_rev_var
+ */
+.macro cpu_reset_func_start _cpu:req
+ func \_cpu\()_reset_func
+ mov x15, x30
+ bl cpu_get_rev_var
+ mov x14, x0
+
+ /* short circuit the location to avoid searching the list */
+ adrp x12, \_cpu\()_errata_list_start
+ add x12, x12, :lo12:\_cpu\()_errata_list_start
+ adrp x13, \_cpu\()_errata_list_end
+ add x13, x13, :lo12:\_cpu\()_errata_list_end
+
+ errata_begin:
+ /* if head catches up with end of list, exit */
+ cmp x12, x13
+ b.eq errata_end
+
+ ldr x10, [x12, #ERRATUM_WA_FUNC]
+ /* TODO(errata ABI): check mitigated and checker function fields
+ * for 0 */
+ ldrb w11, [x12, #ERRATUM_CHOSEN]
+
+ /* skip if not chosen */
+ cbz x11, 1f
+ /* skip if runtime erratum */
+ cbz x10, 1f
+
+ /* put cpu revision in x0 and call workaround */
+ mov x0, x14
+ blr x10
+ 1:
+ add x12, x12, #ERRATUM_ENTRY_SIZE
+ b errata_begin
+ errata_end:
+.endm
+
+.macro cpu_reset_func_end _cpu:req
+ isb
+ ret x15
+ endfunc \_cpu\()_reset_func
+.endm
+
+/*
+ * Maintain compatibility with the old scheme of each cpu has its own reporting.
+ * TODO remove entirely once all cpus have been converted. This includes the
+ * cpu_ops entry, as print_errata_status can call this directly for all cpus
+ */
+.macro errata_report_shim _cpu:req
+ #if REPORT_ERRATA
+ func \_cpu\()_errata_report
+ /* normal stack frame for pretty debugging */
+ stp x29, x30, [sp, #-16]!
+ mov x29, sp
+
+ bl generic_errata_report
+
+ ldp x29, x30, [sp], #16
+ ret
+ endfunc \_cpu\()_errata_report
+ #endif
+.endm
#endif /* CPU_MACROS_S */
diff --git a/include/lib/cpus/cpu_ops.h b/include/lib/cpus/cpu_ops.h
new file mode 100644
index 0000000..8b36ff1
--- /dev/null
+++ b/include/lib/cpus/cpu_ops.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CPU_OPS_H
+#define CPU_OPS_H
+
+#include <arch.h>
+
+#define CPU_IMPL_PN_MASK (MIDR_IMPL_MASK << MIDR_IMPL_SHIFT) | \
+ (MIDR_PN_MASK << MIDR_PN_SHIFT)
+
+/* Hardcode to keep compatible with assembly. sizeof(uintptr_t) */
+#if __aarch64__
+#define CPU_WORD_SIZE 8
+#else
+#define CPU_WORD_SIZE 4
+#endif /* __aarch64__ */
+
+/* The number of CPU operations allowed */
+#define CPU_MAX_PWR_DWN_OPS 2
+/* Special constant to specify that CPU has no reset function */
+#define CPU_NO_RESET_FUNC 0
+
+#if __aarch64__
+#define CPU_NO_EXTRA1_FUNC 0
+#define CPU_NO_EXTRA2_FUNC 0
+#define CPU_NO_EXTRA3_FUNC 0
+#endif /* __aarch64__ */
+
+
+/*
+ * Define the sizes of the fields in the cpu_ops structure. Word size is set per
+ * Aarch so keep these definitions the same and each can include whatever it
+ * needs.
+ */
+#define CPU_MIDR_SIZE CPU_WORD_SIZE
+#ifdef IMAGE_AT_EL3
+#define CPU_RESET_FUNC_SIZE CPU_WORD_SIZE
+#else
+#define CPU_RESET_FUNC_SIZE 0
+#endif /* IMAGE_AT_EL3 */
+#define CPU_EXTRA1_FUNC_SIZE CPU_WORD_SIZE
+#define CPU_EXTRA2_FUNC_SIZE CPU_WORD_SIZE
+#define CPU_EXTRA3_FUNC_SIZE CPU_WORD_SIZE
+#define CPU_E_HANDLER_FUNC_SIZE CPU_WORD_SIZE
+/* The power down core and cluster is needed only in BL31 and BL32 */
+#if defined(IMAGE_BL31) || defined(IMAGE_BL32)
+#define CPU_PWR_DWN_OPS_SIZE CPU_WORD_SIZE * CPU_MAX_PWR_DWN_OPS
+#else
+#define CPU_PWR_DWN_OPS_SIZE 0
+#endif /* defined(IMAGE_BL31) || defined(IMAGE_BL32) */
+
+#define CPU_ERRATA_LIST_START_SIZE CPU_WORD_SIZE
+#define CPU_ERRATA_LIST_END_SIZE CPU_WORD_SIZE
+/* Fields required to print errata status */
+#if REPORT_ERRATA
+#define CPU_ERRATA_FUNC_SIZE CPU_WORD_SIZE
+#define CPU_CPU_STR_SIZE CPU_WORD_SIZE
+/* BL1 doesn't require mutual exclusion and printed flag. */
+#if defined(IMAGE_BL31) || defined(IMAGE_BL32)
+#define CPU_ERRATA_LOCK_SIZE CPU_WORD_SIZE
+#define CPU_ERRATA_PRINTED_SIZE CPU_WORD_SIZE
+#else
+#define CPU_ERRATA_LOCK_SIZE 0
+#define CPU_ERRATA_PRINTED_SIZE 0
+#endif /* defined(IMAGE_BL31) || defined(IMAGE_BL32) */
+#else
+#define CPU_ERRATA_FUNC_SIZE 0
+#define CPU_CPU_STR_SIZE 0
+#define CPU_ERRATA_LOCK_SIZE 0
+#define CPU_ERRATA_PRINTED_SIZE 0
+#endif /* REPORT_ERRATA */
+
+#if defined(IMAGE_BL31) && CRASH_REPORTING
+#define CPU_REG_DUMP_SIZE CPU_WORD_SIZE
+#else
+#define CPU_REG_DUMP_SIZE 0
+#endif /* defined(IMAGE_BL31) && CRASH_REPORTING */
+
+
+/*
+ * Define the offsets to the fields in cpu_ops structure. Every offset is
+ * defined based on the offset and size of the previous field.
+ */
+#define CPU_MIDR 0
+#define CPU_RESET_FUNC CPU_MIDR + CPU_MIDR_SIZE
+#if __aarch64__
+#define CPU_EXTRA1_FUNC CPU_RESET_FUNC + CPU_RESET_FUNC_SIZE
+#define CPU_EXTRA2_FUNC CPU_EXTRA1_FUNC + CPU_EXTRA1_FUNC_SIZE
+#define CPU_EXTRA3_FUNC CPU_EXTRA2_FUNC + CPU_EXTRA2_FUNC_SIZE
+#define CPU_E_HANDLER_FUNC CPU_EXTRA3_FUNC + CPU_EXTRA3_FUNC_SIZE
+#define CPU_PWR_DWN_OPS CPU_E_HANDLER_FUNC + CPU_E_HANDLER_FUNC_SIZE
+#else
+#define CPU_PWR_DWN_OPS CPU_RESET_FUNC + CPU_RESET_FUNC_SIZE
+#endif /* __aarch64__ */
+#define CPU_ERRATA_LIST_START CPU_PWR_DWN_OPS + CPU_PWR_DWN_OPS_SIZE
+#define CPU_ERRATA_LIST_END CPU_ERRATA_LIST_START + CPU_ERRATA_LIST_START_SIZE
+#define CPU_ERRATA_FUNC CPU_ERRATA_LIST_END + CPU_ERRATA_LIST_END_SIZE
+#define CPU_CPU_STR CPU_ERRATA_FUNC + CPU_ERRATA_FUNC_SIZE
+#define CPU_ERRATA_LOCK CPU_CPU_STR + CPU_CPU_STR_SIZE
+#define CPU_ERRATA_PRINTED CPU_ERRATA_LOCK + CPU_ERRATA_LOCK_SIZE
+#if __aarch64__
+#define CPU_REG_DUMP CPU_ERRATA_PRINTED + CPU_ERRATA_PRINTED_SIZE
+#define CPU_OPS_SIZE CPU_REG_DUMP + CPU_REG_DUMP_SIZE
+#else
+#define CPU_OPS_SIZE CPU_ERRATA_PRINTED + CPU_ERRATA_PRINTED_SIZE
+#endif /* __aarch64__ */
+
+#ifndef __ASSEMBLER__
+#include <lib/cassert.h>
+#include <lib/spinlock.h>
+
+struct cpu_ops {
+ unsigned long midr;
+#ifdef IMAGE_AT_EL3
+ void (*reset_func)(void);
+#endif /* IMAGE_AT_EL3 */
+#if __aarch64__
+ void (*extra1_func)(void);
+ void (*extra2_func)(void);
+ void (*extra3_func)(void);
+ void (*e_handler_func)(long es);
+#endif /* __aarch64__ */
+#if (defined(IMAGE_BL31) || defined(IMAGE_BL32)) && CPU_MAX_PWR_DWN_OPS
+ void (*pwr_dwn_ops[CPU_MAX_PWR_DWN_OPS])(void);
+#endif /* (defined(IMAGE_BL31) || defined(IMAGE_BL32)) && CPU_MAX_PWR_DWN_OPS */
+ void *errata_list_start;
+ void *errata_list_end;
+#if REPORT_ERRATA
+ void (*errata_func)(void);
+ char *cpu_str;
+#if defined(IMAGE_BL31) || defined(IMAGE_BL32)
+ spinlock_t *errata_lock;
+ unsigned int *errata_reported;
+#endif /* defined(IMAGE_BL31) || defined(IMAGE_BL32) */
+#endif /* REPORT_ERRATA */
+#if defined(IMAGE_BL31) && CRASH_REPORTING
+ void (*reg_dump)(void);
+#endif /* defined(IMAGE_BL31) && CRASH_REPORTING */
+} __packed;
+
+CASSERT(sizeof(struct cpu_ops) == CPU_OPS_SIZE,
+ assert_cpu_ops_asm_c_different_sizes);
+
+long cpu_get_rev_var(void);
+void *get_cpu_ops_ptr(void);
+
+#endif /* __ASSEMBLER__ */
+#endif /* CPU_OPS_H */
diff --git a/include/lib/cpus/errata.h b/include/lib/cpus/errata.h
new file mode 100644
index 0000000..f8f9555
--- /dev/null
+++ b/include/lib/cpus/errata.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ERRATA_REPORT_H
+#define ERRATA_REPORT_H
+
+#include <lib/cpus/cpu_ops.h>
+
+
+#define ERRATUM_WA_FUNC_SIZE CPU_WORD_SIZE
+#define ERRATUM_CHECK_FUNC_SIZE CPU_WORD_SIZE
+#define ERRATUM_ID_SIZE 4
+#define ERRATUM_CVE_SIZE 2
+#define ERRATUM_CHOSEN_SIZE 1
+#define ERRATUM_MITIGATED_SIZE 1
+
+#define ERRATUM_WA_FUNC 0
+#define ERRATUM_CHECK_FUNC ERRATUM_WA_FUNC + ERRATUM_WA_FUNC_SIZE
+#define ERRATUM_ID ERRATUM_CHECK_FUNC + ERRATUM_CHECK_FUNC_SIZE
+#define ERRATUM_CVE ERRATUM_ID + ERRATUM_ID_SIZE
+#define ERRATUM_CHOSEN ERRATUM_CVE + ERRATUM_CVE_SIZE
+#define ERRATUM_MITIGATED ERRATUM_CHOSEN + ERRATUM_CHOSEN_SIZE
+#define ERRATUM_ENTRY_SIZE ERRATUM_MITIGATED + ERRATUM_MITIGATED_SIZE
+
+#ifndef __ASSEMBLER__
+#include <lib/cassert.h>
+
+void print_errata_status(void);
+void errata_print_msg(unsigned int status, const char *cpu, const char *id);
+
+/*
+ * NOTE that this structure will be different on AArch32 and AArch64. The
+ * uintptr_t will reflect the change and the alignment will be correct in both.
+ */
+struct erratum_entry {
+ uintptr_t (*wa_func)(uint64_t cpu_rev);
+ uintptr_t (*check_func)(uint64_t cpu_rev);
+ /* Will fit CVEs with up to 10 character in the ID field */
+ uint32_t id;
+ /* Denote CVEs with their year or errata with 0 */
+ uint16_t cve;
+ uint8_t chosen;
+ /* TODO(errata ABI): placeholder for the mitigated field */
+ uint8_t _mitigated;
+} __packed;
+
+CASSERT(sizeof(struct erratum_entry) == ERRATUM_ENTRY_SIZE,
+ assert_erratum_entry_asm_c_different_sizes);
+#else
+
+/*
+ * errata framework macro helpers
+ *
+ * NOTE an erratum and CVE id could clash. However, both numbers are very large
+ * and the probablity is minuscule. Working around this makes code very
+ * complicated and extremely difficult to read so it is not considered. In the
+ * unlikely event that this does happen, prepending the CVE id with a 0 should
+ * resolve the conflict
+ */
+#define ERRATUM(id) 0, id
+#define CVE(year, id) year, id
+#define NO_ISB 1
+#define NO_ASSERT 0
+
+#endif /* __ASSEMBLER__ */
+
+/* Errata status */
+#define ERRATA_NOT_APPLIES 0
+#define ERRATA_APPLIES 1
+#define ERRATA_MISSING 2
+
+/* Macro to get CPU revision code for checking errata version compatibility. */
+#define CPU_REV(r, p) ((r << 4) | p)
+
+#endif /* ERRATA_REPORT_H */
diff --git a/include/lib/cpus/errata_report.h b/include/lib/cpus/errata_report.h
deleted file mode 100644
index efdedf0..0000000
--- a/include/lib/cpus/errata_report.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef ERRATA_REPORT_H
-#define ERRATA_REPORT_H
-
-#ifndef __ASSEMBLER__
-
-#include <arch.h>
-#include <arch_helpers.h>
-#include <lib/spinlock.h>
-#include <lib/utils_def.h>
-
-#if DEBUG
-void print_errata_status(void);
-#else
-static inline void print_errata_status(void) {}
-#endif
-
-void errata_print_msg(unsigned int status, const char *cpu, const char *id);
-int errata_needs_reporting(spinlock_t *lock, uint32_t *reported);
-
-#endif /* __ASSEMBLER__ */
-
-/* Errata status */
-#define ERRATA_NOT_APPLIES 0
-#define ERRATA_APPLIES 1
-#define ERRATA_MISSING 2
-
-/* Macro to get CPU revision code for checking errata version compatibility. */
-#define CPU_REV(r, p) ((r << 4) | p)
-
-#endif /* ERRATA_REPORT_H */
diff --git a/lib/cpus/aarch32/cpu_helpers.S b/lib/cpus/aarch32/cpu_helpers.S
index e25ce2a..05bc5d9 100644
--- a/lib/cpus/aarch32/cpu_helpers.S
+++ b/lib/cpus/aarch32/cpu_helpers.S
@@ -9,6 +9,7 @@
#include <assert_macros.S>
#include <cpu_macros.S>
#include <common/bl_common.h>
+#include <lib/cpus/cpu_ops.h>
#include <lib/el3_runtime/cpu_data.h>
#if defined(IMAGE_BL1) || defined(IMAGE_BL32) || \
@@ -204,62 +205,3 @@
movlt r0, #ERRATA_NOT_APPLIES
bx lr
endfunc cpu_rev_var_hs
-
-#if REPORT_ERRATA
-/*
- * void print_errata_status(void);
- *
- * Function to print errata status for CPUs of its class. Must be called only:
- *
- * - with MMU and data caches are enabled;
- * - after cpu_ops have been initialized in per-CPU data.
- */
- .globl print_errata_status
-func print_errata_status
- /* r12 is pushed only for the sake of 8-byte stack alignment */
- push {r4, r5, r12, lr}
-#ifdef IMAGE_BL1
- /*
- * BL1 doesn't have per-CPU data. So retrieve the CPU operations
- * directly.
- */
- bl get_cpu_ops_ptr
- ldr r0, [r0, #CPU_ERRATA_FUNC]
- cmp r0, #0
- blxne r0
-#else
- /*
- * Retrieve pointer to cpu_ops, and further, the errata printing
- * function. If it's non-NULL, jump to the function in turn.
- */
- bl _cpu_data
-#if ENABLE_ASSERTIONS
- cmp r0, #0
- ASM_ASSERT(ne)
-#endif
- ldr r1, [r0, #CPU_DATA_CPU_OPS_PTR]
-#if ENABLE_ASSERTIONS
- cmp r1, #0
- ASM_ASSERT(ne)
-#endif
- ldr r0, [r1, #CPU_ERRATA_FUNC]
- cmp r0, #0
- beq 1f
-
- mov r4, r0
-
- /*
- * Load pointers to errata lock and printed flag. Call
- * errata_needs_reporting to check whether this CPU needs to report
- * errata status pertaining to its class.
- */
- ldr r0, [r1, #CPU_ERRATA_LOCK]
- ldr r1, [r1, #CPU_ERRATA_PRINTED]
- bl errata_needs_reporting
- cmp r0, #0
- blxne r4
-1:
-#endif
- pop {r4, r5, r12, pc}
-endfunc print_errata_status
-#endif
diff --git a/lib/cpus/aarch64/cortex_a53.S b/lib/cpus/aarch64/cortex_a53.S
index df11d86..ecaf422 100644
--- a/lib/cpus/aarch64/cortex_a53.S
+++ b/lib/cpus/aarch64/cortex_a53.S
@@ -9,8 +9,8 @@
#include <common/debug.h>
#include <cortex_a53.h>
#include <cpu_macros.S>
-#include <lib/cpus/errata_report.h>
#include <plat_macros.S>
+#include <lib/cpus/errata.h>
#if A53_DISABLE_NON_TEMPORAL_HINT
#undef ERRATA_A53_836870
diff --git a/lib/cpus/aarch64/cpu_helpers.S b/lib/cpus/aarch64/cpu_helpers.S
index 0a03e38..a4285ed 100644
--- a/lib/cpus/aarch64/cpu_helpers.S
+++ b/lib/cpus/aarch64/cpu_helpers.S
@@ -10,7 +10,8 @@
#include <common/bl_common.h>
#include <common/debug.h>
#include <cpu_macros.S>
-#include <lib/cpus/errata_report.h>
+#include <lib/cpus/cpu_ops.h>
+#include <lib/cpus/errata.h>
#include <lib/el3_runtime/cpu_data.h>
/* Reset fn is needed in BL at reset vector */
@@ -279,72 +280,6 @@
ret
endfunc cpu_rev_var_range
-#if REPORT_ERRATA
-/*
- * void print_errata_status(void);
- *
- * Function to print errata status for CPUs of its class. Must be called only:
- *
- * - with MMU and data caches are enabled;
- * - after cpu_ops have been initialized in per-CPU data.
- */
- .globl print_errata_status
-func print_errata_status
-#ifdef IMAGE_BL1
- /*
- * BL1 doesn't have per-CPU data. So retrieve the CPU operations
- * directly.
- */
- stp xzr, x30, [sp, #-16]!
- bl get_cpu_ops_ptr
- ldp xzr, x30, [sp], #16
- ldr x1, [x0, #CPU_ERRATA_FUNC]
- cbnz x1, .Lprint
-#else
- /*
- * Retrieve pointer to cpu_ops from per-CPU data, and further, the
- * errata printing function. If it's non-NULL, jump to the function in
- * turn.
- */
- mrs x0, tpidr_el3
-#if ENABLE_ASSERTIONS
- cmp x0, #0
- ASM_ASSERT(ne)
-#endif
- ldr x1, [x0, #CPU_DATA_CPU_OPS_PTR]
-#if ENABLE_ASSERTIONS
- cmp x1, #0
- ASM_ASSERT(ne)
-#endif
- ldr x0, [x1, #CPU_ERRATA_FUNC]
- cbz x0, .Lnoprint
-
- /*
- * Printing errata status requires atomically testing the printed flag.
- */
- stp x19, x30, [sp, #-16]!
- mov x19, x0
-
- /*
- * Load pointers to errata lock and printed flag. Call
- * errata_needs_reporting to check whether this CPU needs to report
- * errata status pertaining to its class.
- */
- ldr x0, [x1, #CPU_ERRATA_LOCK]
- ldr x1, [x1, #CPU_ERRATA_PRINTED]
- bl errata_needs_reporting
- mov x1, x19
- ldp x19, x30, [sp], #16
- cbnz x0, .Lprint
-#endif
-.Lnoprint:
- ret
-.Lprint:
- /* Jump to errata reporting function for this CPU */
- br x1
-endfunc print_errata_status
-#endif
-
/*
* int check_wa_cve_2017_5715(void);
*
diff --git a/lib/cpus/aarch64/dsu_helpers.S b/lib/cpus/aarch64/dsu_helpers.S
index 419b6ea..b7e028a 100644
--- a/lib/cpus/aarch64/dsu_helpers.S
+++ b/lib/cpus/aarch64/dsu_helpers.S
@@ -6,7 +6,7 @@
#include <asm_macros.S>
#include <dsu_def.h>
-#include <lib/cpus/errata_report.h>
+#include <lib/cpus/errata.h>
/* -----------------------------------------------------------------------
* DSU erratum 798953 check function
diff --git a/lib/cpus/errata_report.c b/lib/cpus/errata_report.c
index 5f41aee..a37ba81 100644
--- a/lib/cpus/errata_report.c
+++ b/lib/cpus/errata_report.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2023, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -11,7 +11,8 @@
#include <arch_helpers.h>
#include <common/debug.h>
-#include <lib/cpus/errata_report.h>
+#include <lib/cpus/cpu_ops.h>
+#include <lib/cpus/errata.h>
#include <lib/el3_runtime/cpu_data.h>
#include <lib/spinlock.h>
@@ -30,11 +31,93 @@
/* Errata format: BL stage, CPU, errata ID, message */
#define ERRATA_FORMAT "%s: %s: CPU workaround for %s was %s\n"
+#define CVE_FORMAT "%s: %s: CPU workaround for CVE %u_%u was %s\n"
+#define ERRATUM_FORMAT "%s: %s: CPU workaround for erratum %u was %s\n"
+
+#define PRINT_STATUS_DISPATCH(status, ...) \
+ do { \
+ assert(status <= ERRATA_MISSING); \
+ switch (status) { \
+ case ERRATA_NOT_APPLIES: \
+ VERBOSE(__VA_ARGS__, "not applied"); \
+ break; \
+ case ERRATA_APPLIES: \
+ INFO(__VA_ARGS__, "applied"); \
+ break; \
+ case ERRATA_MISSING: \
+ WARN(__VA_ARGS__, "missing!"); \
+ break; \
+ } \
+ } while (0)
+
+
+#if !REPORT_ERRATA
+void print_errata_status(void) {}
+#else /* !REPORT_ERRATA */
+/* New errata status message printer */
+void __unused generic_errata_report(void)
+{
+ struct cpu_ops *cpu_ops = get_cpu_ops_ptr();
+ struct erratum_entry *entry = cpu_ops->errata_list_start;
+ struct erratum_entry *end = cpu_ops->errata_list_end;
+ long rev_var = cpu_get_rev_var();
+ uint32_t last_erratum_id = 0;
+ uint16_t last_cve_yr = 0;
+ bool check_cve = false;
+ /* unused because assert goes away on release */
+ bool failed __unused = false;
+
+ for (; entry != end; entry += 1) {
+ uint64_t status = entry->check_func(rev_var);
+
+ assert(entry->id != 0);
+
+ /*
+ * Errata workaround has not been compiled in. If the errata
+ * would have applied had it been compiled in, print its status
+ * as missing.
+ */
+ if (status == ERRATA_APPLIES && entry->chosen == 0) {
+ status = ERRATA_MISSING;
+ }
+
+ if (entry->cve) {
+ PRINT_STATUS_DISPATCH(status, CVE_FORMAT, BL_STRING,
+ cpu_ops->cpu_str, entry->cve, entry->id);
+
+ if (last_cve_yr > entry->cve ||
+ (last_cve_yr == entry->cve && last_erratum_id >= entry->id)) {
+ ERROR("CVE %u_%u was out of order!\n",
+ entry->cve, entry->id);
+ failed = true;
+ }
+ check_cve = true;
+ last_cve_yr = entry->cve;
+ } else {
+ PRINT_STATUS_DISPATCH(status, ERRATUM_FORMAT, BL_STRING,
+ cpu_ops->cpu_str, entry->id);
+
+ if (last_erratum_id >= entry->id || check_cve) {
+ ERROR("Erratum %u was out of order!\n",
+ entry->id);
+ failed = true;
+ }
+ }
+ last_erratum_id = entry->id;
+ }
+
+ /*
+ * enforce errata and CVEs are in ascending order and that CVEs are
+ * after errata
+ */
+ assert(!failed);
+}
+
/*
* Returns whether errata needs to be reported. Passed arguments are private to
* a CPU type.
*/
-int errata_needs_reporting(spinlock_t *lock, uint32_t *reported)
+static __unused int errata_needs_reporting(spinlock_t *lock, uint32_t *reported)
{
bool report_now;
@@ -56,14 +139,44 @@
}
/*
- * Print errata status message.
- *
- * Unknown: WARN
- * Missing: WARN
- * Applied: INFO
- * Not applied: VERBOSE
+ * Function to print errata status for the calling CPU (and others of the same
+ * type). Must be called only:
+ * - when MMU and data caches are enabled;
+ * - after cpu_ops have been initialized in per-CPU data.
+ */
+void print_errata_status(void)
+{
+ struct cpu_ops *cpu_ops;
+#ifdef IMAGE_BL1
+ /*
+ * BL1 doesn't have per-CPU data. So retrieve the CPU operations
+ * directly.
+ */
+ cpu_ops = get_cpu_ops_ptr();
+
+ if (cpu_ops->errata_func != NULL) {
+ cpu_ops->errata_func();
+ }
+#else /* IMAGE_BL1 */
+ cpu_ops = (void *) get_cpu_data(cpu_ops_ptr);
+
+ assert(cpu_ops != NULL);
+
+ if (cpu_ops->errata_func == NULL) {
+ return;
+ }
+
+ if (errata_needs_reporting(cpu_ops->errata_lock, cpu_ops->errata_reported)) {
+ cpu_ops->errata_func();
+ }
+#endif /* IMAGE_BL1 */
+}
+
+/*
+ * Old errata status message printer
+ * TODO: remove once all cpus have been converted to the new printing method
*/
-void errata_print_msg(unsigned int status, const char *cpu, const char *id)
+void __unused errata_print_msg(unsigned int status, const char *cpu, const char *id)
{
/* Errata status strings */
static const char *const errata_status_str[] = {
@@ -99,3 +212,4 @@
break;
}
}
+#endif /* !REPORT_ERRATA */
diff --git a/lib/psci/psci_setup.c b/lib/psci/psci_setup.c
index 16d6e45..1f93cc9 100644
--- a/lib/psci/psci_setup.c
+++ b/lib/psci/psci_setup.c
@@ -11,8 +11,8 @@
#include <arch_helpers.h>
#include <common/bl_common.h>
#include <context.h>
+#include <lib/cpus/errata.h>
#include <lib/el3_runtime/context_mgmt.h>
-#include <lib/cpus/errata_report.h>
#include <plat/common/platform.h>
#include "psci_private.h"
diff --git a/plat/arm/board/fvp_r/fvp_r_bl1_main.c b/plat/arm/board/fvp_r/fvp_r_bl1_main.c
index 841a176..252fc31 100644
--- a/plat/arm/board/fvp_r/fvp_r_bl1_main.c
+++ b/plat/arm/board/fvp_r/fvp_r_bl1_main.c
@@ -15,7 +15,7 @@
#include <common/debug.h>
#include <drivers/auth/auth_mod.h>
#include <drivers/console.h>
-#include <lib/cpus/errata_report.h>
+#include <lib/cpus/errata.h>
#include <lib/utils.h>
#include <smccc_helpers.h>
#include <tools_share/uuid.h>
diff --git a/plat/arm/board/fvp_r/platform.mk b/plat/arm/board/fvp_r/platform.mk
index 5dd28b9..f14ea54 100644
--- a/plat/arm/board/fvp_r/platform.mk
+++ b/plat/arm/board/fvp_r/platform.mk
@@ -83,6 +83,7 @@
drivers/io/io_storage.c \
drivers/io/io_semihosting.c \
lib/cpus/aarch64/cpu_helpers.S \
+ lib/cpus/errata_report.c \
lib/fconf/fconf_dyn_cfg_getter.c \
lib/semihosting/semihosting.c \
lib/semihosting/${ARCH}/semihosting_call.S \
diff --git a/poetry.lock b/poetry.lock
index 58522c9..92b38da 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -13,6 +13,25 @@
]
[[package]]
+name = "anytree"
+version = "2.8.0"
+description = "Powerful and Lightweight Python Tree Data Structure.."
+category = "dev"
+optional = false
+python-versions = "*"
+files = [
+ {file = "anytree-2.8.0-py2.py3-none-any.whl", hash = "sha256:14c55ac77492b11532395049a03b773d14c7e30b22aa012e337b1e983de31521"},
+ {file = "anytree-2.8.0.tar.gz", hash = "sha256:3f0f93f355a91bc3e6245319bf4c1d50e3416cc7a35cc1133c1ff38306bbccab"},
+]
+
+[package.dependencies]
+six = ">=1.9.0"
+
+[package.extras]
+dev = ["check-manifest"]
+test = ["coverage"]
+
+[[package]]
name = "babel"
version = "2.12.1"
description = "Internationalization utilities"
@@ -213,14 +232,14 @@
[[package]]
name = "importlib-metadata"
-version = "6.0.0"
+version = "6.6.0"
description = "Read metadata from Python packages"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
- {file = "importlib_metadata-6.0.0-py3-none-any.whl", hash = "sha256:7efb448ec9a5e313a57655d35aa54cd3e01b7e1fbcf72dce1bf06119420f5bad"},
- {file = "importlib_metadata-6.0.0.tar.gz", hash = "sha256:e354bedeb60efa6affdcc8ae121b73544a7aa74156d047311948f6d711cd378d"},
+ {file = "importlib_metadata-6.6.0-py3-none-any.whl", hash = "sha256:43dd286a2cd8995d5eaef7fee2066340423b818ed3fd70adf0bad5f1fac53fed"},
+ {file = "importlib_metadata-6.6.0.tar.gz", hash = "sha256:92501cdf9cc66ebd3e612f1b4f0c0765dfa42f0fa38ffb319b6bd84dd675d705"},
]
[package.dependencies]
@@ -395,38 +414,38 @@
[[package]]
name = "packaging"
-version = "23.0"
+version = "23.1"
description = "Core utilities for Python packages"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
- {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"},
- {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"},
+ {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"},
+ {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"},
]
[[package]]
name = "pip"
-version = "23.0.1"
+version = "23.1.2"
description = "The PyPA recommended tool for installing Python packages."
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
- {file = "pip-23.0.1-py3-none-any.whl", hash = "sha256:236bcb61156d76c4b8a05821b988c7b8c35bf0da28a4b614e8d6ab5212c25c6f"},
- {file = "pip-23.0.1.tar.gz", hash = "sha256:cd015ea1bfb0fcef59d8a286c1f8bebcb983f6317719d415dc5351efb7cd7024"},
+ {file = "pip-23.1.2-py3-none-any.whl", hash = "sha256:3ef6ac33239e4027d9a5598a381b9d30880a1477e50039db2eac6e8a8f6d1b18"},
+ {file = "pip-23.1.2.tar.gz", hash = "sha256:0e7c86f486935893c708287b30bd050a36ac827ec7fe5e43fe7cb198dd835fba"},
]
[[package]]
name = "pip-tools"
-version = "6.12.3"
+version = "6.13.0"
description = "pip-tools keeps your pinned dependencies fresh."
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
- {file = "pip-tools-6.12.3.tar.gz", hash = "sha256:480d44fae6e09fad3f9bd3d0a7e8423088715d10477e8ef0663440db25e3114f"},
- {file = "pip_tools-6.12.3-py3-none-any.whl", hash = "sha256:8510420f46572b2e26c357541390593d9365eb6edd2d1e7505267910ecaec080"},
+ {file = "pip-tools-6.13.0.tar.gz", hash = "sha256:61d46bd2eb8016ed4a924e196e6e5b0a268cd3babd79e593048720db23522bb1"},
+ {file = "pip_tools-6.13.0-py3-none-any.whl", hash = "sha256:50943f151d87e752abddec8158622c34ad7f292e193836e90e30d87da60b19d9"},
]
[package.dependencies]
@@ -441,15 +460,45 @@
testing = ["flit-core (>=2,<4)", "poetry-core (>=1.0.0)", "pytest (>=7.2.0)", "pytest-rerunfailures", "pytest-xdist"]
[[package]]
+name = "prettytable"
+version = "3.7.0"
+description = "A simple Python library for easily displaying tabular data in a visually appealing ASCII table format"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "prettytable-3.7.0-py3-none-any.whl", hash = "sha256:f4aaf2ed6e6062a82fd2e6e5289bbbe705ec2788fe401a3a1f62a1cea55526d2"},
+ {file = "prettytable-3.7.0.tar.gz", hash = "sha256:ef8334ee40b7ec721651fc4d37ecc7bb2ef55fde5098d994438f0dfdaa385c0c"},
+]
+
+[package.dependencies]
+wcwidth = "*"
+
+[package.extras]
+tests = ["pytest", "pytest-cov", "pytest-lazy-fixture"]
+
+[[package]]
+name = "pyelftools"
+version = "0.29"
+description = "Library for analyzing ELF files and DWARF debugging information"
+category = "dev"
+optional = false
+python-versions = "*"
+files = [
+ {file = "pyelftools-0.29-py2.py3-none-any.whl", hash = "sha256:519f38cf412f073b2d7393aa4682b0190fa901f7c3fa0bff2b82d537690c7fc1"},
+ {file = "pyelftools-0.29.tar.gz", hash = "sha256:ec761596aafa16e282a31de188737e5485552469ac63b60cfcccf22263fd24ff"},
+]
+
+[[package]]
name = "pygments"
-version = "2.14.0"
+version = "2.15.1"
description = "Pygments is a syntax highlighting package written in Python."
category = "dev"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
files = [
- {file = "Pygments-2.14.0-py3-none-any.whl", hash = "sha256:fa7bd7bd2771287c0de303af8bfdfc731f51bd2c6a47ab69d117138893b82717"},
- {file = "Pygments-2.14.0.tar.gz", hash = "sha256:b3ed06a9e8ac9a9aae5a6f5dbe78a8a58655d17b43b93c078f094ddc476ae297"},
+ {file = "Pygments-2.15.1-py3-none-any.whl", hash = "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1"},
+ {file = "Pygments-2.15.1.tar.gz", hash = "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c"},
]
[package.extras]
@@ -472,14 +521,14 @@
[[package]]
name = "pytz"
-version = "2022.7.1"
+version = "2023.3"
description = "World timezone definitions, modern and historical"
category = "dev"
optional = false
python-versions = "*"
files = [
- {file = "pytz-2022.7.1-py2.py3-none-any.whl", hash = "sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a"},
- {file = "pytz-2022.7.1.tar.gz", hash = "sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0"},
+ {file = "pytz-2023.3-py2.py3-none-any.whl", hash = "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb"},
+ {file = "pytz-2023.3.tar.gz", hash = "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588"},
]
[[package]]
@@ -534,21 +583,21 @@
[[package]]
name = "requests"
-version = "2.28.2"
+version = "2.30.0"
description = "Python HTTP for Humans."
category = "dev"
optional = false
-python-versions = ">=3.7, <4"
+python-versions = ">=3.7"
files = [
- {file = "requests-2.28.2-py3-none-any.whl", hash = "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa"},
- {file = "requests-2.28.2.tar.gz", hash = "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"},
+ {file = "requests-2.30.0-py3-none-any.whl", hash = "sha256:10e94cc4f3121ee6da529d358cdaeaff2f1c409cd377dbc72b825852f2f7e294"},
+ {file = "requests-2.30.0.tar.gz", hash = "sha256:239d7d4458afcb28a692cdd298d87542235f4ca8d36d03a15bfc128a6559a2f4"},
]
[package.dependencies]
certifi = ">=2017.4.17"
charset-normalizer = ">=2,<4"
idna = ">=2.5,<4"
-urllib3 = ">=1.21.1,<1.27"
+urllib3 = ">=1.21.1,<3"
[package.extras]
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
@@ -556,14 +605,14 @@
[[package]]
name = "setuptools"
-version = "67.6.0"
+version = "67.7.2"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
- {file = "setuptools-67.6.0-py3-none-any.whl", hash = "sha256:b78aaa36f6b90a074c1fa651168723acbf45d14cb1196b6f02c0fd07f17623b2"},
- {file = "setuptools-67.6.0.tar.gz", hash = "sha256:2ee892cd5f29f3373097f5a814697e397cf3ce313616df0af11231e2ad118077"},
+ {file = "setuptools-67.7.2-py3-none-any.whl", hash = "sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b"},
+ {file = "setuptools-67.7.2.tar.gz", hash = "sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990"},
]
[package.extras]
@@ -572,6 +621,18 @@
testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
[[package]]
+name = "six"
+version = "1.16.0"
+description = "Python 2 and 3 compatibility utilities"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
+files = [
+ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
+ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
+]
+
+[[package]]
name = "snowballstemmer"
version = "2.2.0"
description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms."
@@ -792,20 +853,33 @@
[[package]]
name = "urllib3"
-version = "1.26.15"
+version = "2.0.2"
description = "HTTP library with thread-safe connection pooling, file post, and more."
category = "dev"
optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
+python-versions = ">=3.7"
files = [
- {file = "urllib3-1.26.15-py2.py3-none-any.whl", hash = "sha256:aa751d169e23c7479ce47a0cb0da579e3ede798f994f5816a74e4f4500dcea42"},
- {file = "urllib3-1.26.15.tar.gz", hash = "sha256:8a388717b9476f934a21484e8c8e61875ab60644d29b9b39e11e4b9dc1c6b305"},
+ {file = "urllib3-2.0.2-py3-none-any.whl", hash = "sha256:d055c2f9d38dc53c808f6fdc8eab7360b6fdbbde02340ed25cfbcd817c62469e"},
+ {file = "urllib3-2.0.2.tar.gz", hash = "sha256:61717a1095d7e155cdb737ac7bb2f4324a858a1e2e6466f6d03ff630ca68d3cc"},
]
[package.extras]
-brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
-secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
-socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
+brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
+secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"]
+socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
+zstd = ["zstandard (>=0.18.0)"]
+
+[[package]]
+name = "wcwidth"
+version = "0.2.6"
+description = "Measures the displayed width of unicode strings in a terminal"
+category = "dev"
+optional = false
+python-versions = "*"
+files = [
+ {file = "wcwidth-0.2.6-py2.py3-none-any.whl", hash = "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e"},
+ {file = "wcwidth-0.2.6.tar.gz", hash = "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"},
+]
[[package]]
name = "wheel"
@@ -841,4 +915,4 @@
[metadata]
lock-version = "2.0"
python-versions = "^3.8"
-content-hash = "07432d506e3dc69114203b554d82c1489372ce0087d4a430d0380e437afa5714"
+content-hash = "9c25ef33612d10c7caafa551a3cf6a12753167c6400f49cc261fddd18c7eaf6e"
diff --git a/pyproject.toml b/pyproject.toml
index 437290a..44e78d3 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -5,6 +5,12 @@
authors = ["Arm Ltd."]
license = "BSD-3-Clause"
readme = "readme.rst"
+packages = [
+ { include = "memory", from = "tools/memory"}
+]
+
+[tool.poetry.scripts]
+memory = "memory.memmap:main"
[tool.poetry.dependencies]
python = "^3.8"
@@ -18,3 +24,9 @@
[tool.poetry.group.ci.dependencies]
click = "^8.1.3"
+
+[tool.poetry.group.memory.dependencies]
+pyelftools = "^0.29"
+anytree = "^2.8.0"
+click = "^8.1.3"
+prettytable = "^3.5.0"
diff --git a/services/arm_arch_svc/arm_arch_svc_setup.c b/services/arm_arch_svc/arm_arch_svc_setup.c
index 46ccd9e..bb042c7 100644
--- a/services/arm_arch_svc/arm_arch_svc_setup.c
+++ b/services/arm_arch_svc/arm_arch_svc_setup.c
@@ -6,7 +6,7 @@
#include <common/debug.h>
#include <common/runtime_svc.h>
-#include <lib/cpus/errata_report.h>
+#include <lib/cpus/errata.h>
#include <lib/cpus/wa_cve_2017_5715.h>
#include <lib/cpus/wa_cve_2018_3639.h>
#include <lib/cpus/wa_cve_2022_23960.h>
diff --git a/tools/memory/__init__.py b/tools/memory/__init__.py
new file mode 100644
index 0000000..0b4c8d3
--- /dev/null
+++ b/tools/memory/__init__.py
@@ -0,0 +1,7 @@
+#!/usr/bin/env python3
+
+#
+# Copyright (c) 2023, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
diff --git a/tools/memory/memory/__init__.py b/tools/memory/memory/__init__.py
new file mode 100644
index 0000000..0b4c8d3
--- /dev/null
+++ b/tools/memory/memory/__init__.py
@@ -0,0 +1,7 @@
+#!/usr/bin/env python3
+
+#
+# Copyright (c) 2023, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
diff --git a/tools/memory/memory/buildparser.py b/tools/memory/memory/buildparser.py
new file mode 100755
index 0000000..6f467cd
--- /dev/null
+++ b/tools/memory/memory/buildparser.py
@@ -0,0 +1,56 @@
+#
+# Copyright (c) 2023, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+import re
+from pathlib import Path
+
+from memory.elfparser import TfaElfParser
+
+
+class TfaBuildParser:
+ """A class for performing analysis on the memory layout of a TF-A build."""
+
+ def __init__(self, path: Path):
+ self._modules = dict()
+ self._path = path
+ self._parse_modules()
+
+ def __getitem__(self, module: str):
+ """Returns an TfaElfParser instance indexed by module."""
+ return self._modules[module]
+
+ def _parse_modules(self):
+ """Parse ELF files in the build path."""
+ for elf_file in self._path.glob("**/*.elf"):
+ module_name = elf_file.name.split("/")[-1].split(".")[0]
+ with open(elf_file, "rb") as file:
+ self._modules[module_name] = TfaElfParser(file)
+
+ if not len(self._modules):
+ raise FileNotFoundError(
+ f"failed to find ELF files in path {self._path}!"
+ )
+
+ @property
+ def symbols(self) -> list:
+ return [
+ (*sym, k) for k, v in self._modules.items() for sym in v.symbols
+ ]
+
+ @staticmethod
+ def filter_symbols(symbols: list, regex: str = None) -> list:
+ """Returns a map of symbols to modules."""
+ regex = r".*" if not regex else regex
+ return sorted(
+ filter(lambda s: re.match(regex, s[0]), symbols),
+ key=lambda s: (-s[1], s[0]),
+ reverse=True,
+ )
+
+ @property
+ def module_names(self):
+ """Returns sorted list of module names."""
+ return sorted(self._modules.keys())
diff --git a/tools/memory/memory/elfparser.py b/tools/memory/memory/elfparser.py
new file mode 100644
index 0000000..3964e6c
--- /dev/null
+++ b/tools/memory/memory/elfparser.py
@@ -0,0 +1,33 @@
+#
+# Copyright (c) 2023, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+from typing import BinaryIO
+
+from elftools.elf.elffile import ELFFile
+
+
+class TfaElfParser:
+ """A class representing an ELF file built for TF-A.
+
+ Provides a basic interface for reading the symbol table and other
+ attributes of an ELF file. The constructor accepts a file-like object with
+ the contents an ELF file.
+ """
+
+ def __init__(self, elf_file: BinaryIO):
+ self._segments = {}
+ self._memory_layout = {}
+
+ elf = ELFFile(elf_file)
+
+ self._symbols = {
+ sym.name: sym.entry["st_value"]
+ for sym in elf.get_section_by_name(".symtab").iter_symbols()
+ }
+
+ @property
+ def symbols(self):
+ return self._symbols.items()
diff --git a/tools/memory/memory/memmap.py b/tools/memory/memory/memmap.py
new file mode 100755
index 0000000..7057228
--- /dev/null
+++ b/tools/memory/memory/memmap.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python3
+
+#
+# Copyright (c) 2023, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+from pathlib import Path
+
+import click
+from memory.buildparser import TfaBuildParser
+from memory.printer import TfaPrettyPrinter
+
+
+@click.command()
+@click.option(
+ "-r",
+ "--root",
+ type=Path,
+ default=None,
+ help="Root containing build output.",
+)
+@click.option(
+ "-p",
+ "--platform",
+ show_default=True,
+ default="fvp",
+ help="The platform targeted for analysis.",
+)
+@click.option(
+ "-b",
+ "--build-type",
+ default="release",
+ help="The target build type.",
+ type=click.Choice(["debug", "release"], case_sensitive=False),
+)
+@click.option(
+ "-s",
+ "--symbols",
+ is_flag=True,
+ show_default=True,
+ default=True,
+ help="Generate a map of important TF symbols.",
+)
+@click.option("-w", "--width", type=int, envvar="COLUMNS")
+@click.option(
+ "-d",
+ is_flag=True,
+ default=False,
+ help="Display numbers in decimal base.",
+)
+def main(
+ root: Path,
+ platform: str,
+ build_type: str,
+ symbols: bool,
+ width: int,
+ d: bool,
+):
+ build_path = root if root else Path("build/", platform, build_type)
+ click.echo(f"build-path: {build_path.resolve()}")
+
+ parser = TfaBuildParser(build_path)
+ printer = TfaPrettyPrinter(columns=width, as_decimal=d)
+
+ if symbols:
+ expr = (
+ r"(.*)(TEXT|BSS|RODATA|STACKS|_OPS|PMF|XLAT|GOT|FCONF"
+ r"|R.M)(.*)(START|END)__$"
+ )
+ printer.print_symbol_table(
+ parser.filter_symbols(parser.symbols, expr), parser.module_names
+ )
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tools/memory/memory/printer.py b/tools/memory/memory/printer.py
new file mode 100755
index 0000000..11fd7f0
--- /dev/null
+++ b/tools/memory/memory/printer.py
@@ -0,0 +1,93 @@
+#
+# Copyright (c) 2023, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+
+class TfaPrettyPrinter:
+ """A class for printing the memory layout of ELF files.
+
+ This class provides interfaces for printing various memory layout views of
+ ELF files in a TF-A build. It can be used to understand how the memory is
+ structured and consumed.
+ """
+
+ def __init__(self, columns: int = None, as_decimal: bool = False):
+ self.term_size = columns if columns and columns > 120 else 120
+ self._symbol_map = None
+ self.as_decimal = as_decimal
+
+ def format_args(self, *args, width=10, fmt=None):
+ if not fmt and type(args[0]) is int:
+ fmt = f">{width}x" if not self.as_decimal else f">{width}"
+ return [f"{arg:{fmt}}" if fmt else arg for arg in args]
+
+ @staticmethod
+ def map_elf_symbol(
+ leading: str,
+ section_name: str,
+ rel_pos: int,
+ columns: int,
+ width: int = None,
+ is_edge: bool = False,
+ ):
+ empty_col = "{:{}{}}"
+
+ # Some symbols are longer than the column width, truncate them until
+ # we find a more elegant way to display them!
+ len_over = len(section_name) - width
+ if len_over > 0:
+ section_name = section_name[len_over:-len_over]
+
+ sec_row = f"+{section_name:-^{width-1}}+"
+ sep, fill = ("+", "-") if is_edge else ("|", "")
+
+ sec_row_l = empty_col.format(sep, fill + "<", width) * rel_pos
+ sec_row_r = empty_col.format(sep, fill + ">", width) * (
+ columns - rel_pos - 1
+ )
+
+ return leading + sec_row_l + sec_row + sec_row_r
+
+ def print_symbol_table(
+ self,
+ symbols: list,
+ modules: list,
+ start: int = 11,
+ ):
+ assert len(symbols), "Empty symbol list!"
+ modules = sorted(modules)
+ col_width = int((self.term_size - start) / len(modules))
+
+ num_fmt = "0=#010x" if not self.as_decimal else ">10"
+
+ _symbol_map = [
+ " " * start
+ + "".join(self.format_args(*modules, fmt=f"^{col_width}"))
+ ]
+ last_addr = None
+
+ for i, (name, addr, mod) in enumerate(symbols):
+ # Do not print out an address twice if two symbols overlap,
+ # for example, at the end of one region and start of another.
+ leading = (
+ f"{addr:{num_fmt}}" + " " if addr != last_addr else " " * start
+ )
+
+ _symbol_map.append(
+ self.map_elf_symbol(
+ leading,
+ name,
+ modules.index(mod),
+ len(modules),
+ width=col_width,
+ is_edge=(not i or i == len(symbols) - 1),
+ )
+ )
+
+ last_addr = addr
+
+ self._symbol_map = ["Memory Layout:"]
+ self._symbol_map += list(reversed(_symbol_map))
+ print("\n".join(self._symbol_map))
diff --git a/tools/memory/print_memory_map.py b/tools/memory/print_memory_map.py
deleted file mode 100755
index ef53f7e..0000000
--- a/tools/memory/print_memory_map.py
+++ /dev/null
@@ -1,102 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright (c) 2019-2022, Arm Limited and Contributors. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-
-import re
-import os
-import sys
-import operator
-
-# List of folder/map to parse
-bl_images = ['bl1', 'bl2', 'bl31']
-
-# List of symbols to search for
-blx_symbols = ['__BL1_RAM_START__', '__BL1_RAM_END__',
- '__BL2_END__',
- '__BL31_END__',
- '__RO_START__', '__RO_END_UNALIGNED__', '__RO_END__',
- '__TEXT_START__', '__TEXT_END__',
- '__TEXT_RESIDENT_START__', '__TEXT_RESIDENT_END__',
- '__RODATA_START__', '__RODATA_END__',
- '__DATA_START__', '__DATA_END__',
- '__STACKS_START__', '__STACKS_END__',
- '__BSS_START__', '__BSS_END__',
- '__COHERENT_RAM_START__', '__COHERENT_RAM_END__',
- '__CPU_OPS_START__', '__CPU_OPS_END__',
- '__FCONF_POPULATOR_START__', '__FCONF_POPULATOR_END__',
- '__GOT_START__', '__GOT_END__',
- '__PARSER_LIB_DESCS_START__', '__PARSER_LIB_DESCS_END__',
- '__PMF_TIMESTAMP_START__', '__PMF_TIMESTAMP_END__',
- '__PMF_SVC_DESCS_START__', '__PMF_SVC_DESCS_END__',
- '__RELA_START__', '__RELA_END__',
- '__RT_SVC_DESCS_START__', '__RT_SVC_DESCS_END__',
- '__BASE_XLAT_TABLE_START__', '__BASE_XLAT_TABLE_END__',
- '__XLAT_TABLE_START__', '__XLAT_TABLE_END__',
- ]
-
-# Regex to extract address from map file
-address_pattern = re.compile(r"\b0x\w*")
-
-# List of found element: [address, symbol, file]
-address_list = []
-
-# Get the directory from command line or use a default one
-inverted_print = True
-if len(sys.argv) >= 2:
- build_dir = sys.argv[1]
- if len(sys.argv) >= 3:
- inverted_print = sys.argv[2] == '0'
-else:
- build_dir = 'build/fvp/debug'
-
-max_len = max(len(word) for word in blx_symbols) + 2
-if (max_len % 2) != 0:
- max_len += 1
-
-# Extract all the required symbols from the map files
-for image in bl_images:
- file_path = os.path.join(build_dir, image, '{}.map'.format(image))
- if os.path.isfile(file_path):
- with open (file_path, 'rt') as mapfile:
- for line in mapfile:
- for symbol in blx_symbols:
- skip_symbol = 0
- # Regex to find symbol definition
- line_pattern = re.compile(r"\b0x\w*\s*" + symbol + "\s= .")
- match = line_pattern.search(line)
- if match:
- # Extract address from line
- match = address_pattern.search(line)
- if match:
- if '_END__' in symbol:
- sym_start = symbol.replace('_END__', '_START__')
- if [match.group(0), sym_start, image] in address_list:
- address_list.remove([match.group(0), sym_start, image])
- skip_symbol = 1
- if skip_symbol == 0:
- address_list.append([match.group(0), symbol, image])
-
-# Sort by address
-address_list.sort(key=operator.itemgetter(0))
-
-# Invert list for lower address at bottom
-if inverted_print:
- address_list = reversed(address_list)
-
-# Generate memory view
-print(('{:-^%d}' % (max_len * 3 + 20 + 7)).format('Memory Map from: ' + build_dir))
-for address in address_list:
- if "bl1" in address[2]:
- print(address[0], ('+{:-^%d}+ |{:^%d}| |{:^%d}|' % (max_len, max_len, max_len)).format(address[1], '', ''))
- elif "bl2" in address[2]:
- print(address[0], ('|{:^%d}| +{:-^%d}+ |{:^%d}|' % (max_len, max_len, max_len)).format('', address[1], ''))
- elif "bl31" in address[2]:
- print(address[0], ('|{:^%d}| |{:^%d}| +{:-^%d}+' % (max_len, max_len, max_len)).format('', '', address[1]))
- else:
- print(address[0], ('|{:^%d}| |{:^%d}| +{:-^%d}+' % (max_len, max_len, max_len)).format('', '', address[1]))
-
-print(('{:^20}{:_^%d} {:_^%d} {:_^%d}' % (max_len, max_len, max_len)).format('', '', '', ''))
-print(('{:^20}{:^%d} {:^%d} {:^%d}' % (max_len, max_len, max_len)).format('address', 'bl1', 'bl2', 'bl31'))