Merge "feat(lib): implement strnlen secure and strcpy secure function" into integration
diff --git a/Makefile b/Makefile
index f457453..eca70bd 100644
--- a/Makefile
+++ b/Makefile
@@ -1021,6 +1021,14 @@
endif
endif
+# Enabling FEAT_MOPS requires access to hcrx_el2 registers which is
+# available only when FEAT_HCX is enabled.
+ifneq (${ENABLE_FEAT_MOPS},0)
+ ifeq (${ENABLE_FEAT_HCX},0)
+ $(error "ENABLE_FEAT_MOPS requires ENABLE_FEAT_HCX")
+ endif
+endif
+
# Enabling SVE for both the worlds typically requires the context
# management of SVE registers. The only exception being SPMC at S-EL2.
ifeq (${ENABLE_SVE_FOR_SWD}, 1)
@@ -1224,6 +1232,7 @@
HARDEN_SLS \
HW_ASSISTED_COHERENCY \
MEASURED_BOOT \
+ DISCRETE_TPM \
DICE_PROTECTION_ENVIRONMENT \
RMMD_ENABLE_EL3_TOKEN_SIGN \
DRTM_SUPPORT \
@@ -1410,6 +1419,7 @@
HW_ASSISTED_COHERENCY \
LOG_LEVEL \
MEASURED_BOOT \
+ DISCRETE_TPM \
DICE_PROTECTION_ENVIRONMENT \
DRTM_SUPPORT \
NS_TIMER_SWITCH \
@@ -1676,7 +1686,7 @@
# Add Secure Partition packages
ifeq (${NEED_SP_PKG},yes)
$(BUILD_PLAT)/sp_gen.mk: ${SP_MK_GEN} ${SP_LAYOUT_FILE} | $$(@D)/
- $(if $(host-poetry),$(q)poetry -q install)
+ $(if $(host-poetry),$(q)poetry -q install --no-root)
$(q)$(if $(host-poetry),poetry run )${PYTHON} "$<" "$@" $(filter-out $<,$^) $(BUILD_PLAT) ${COT} ${SP_DTS_LIST_FRAGMENT}
sp: $(DTBS) $(BUILD_PLAT)/sp_gen.mk $(SP_PKGS)
$(s)echo
diff --git a/changelog.yaml b/changelog.yaml
index 422b9da..3f06369 100644
--- a/changelog.yaml
+++ b/changelog.yaml
@@ -962,6 +962,9 @@
- drivers/scmi-msg
- scmi-msg
+ - title: TPM
+ scope: tpm
+
- title: UFS
scope: ufs
diff --git a/docs/components/rmm-el3-comms-spec.rst b/docs/components/rmm-el3-comms-spec.rst
index f1ca031..dfdabc6 100644
--- a/docs/components/rmm-el3-comms-spec.rst
+++ b/docs/components/rmm-el3-comms-spec.rst
@@ -52,8 +52,8 @@
- ``RES0``: Bit 31 of the version number is reserved 0 as to maintain
consistency with the versioning schemes used in other parts of RMM.
-This document specifies the 0.4 version of Boot Interface ABI and RMM-EL3
-services specification and the 0.4 version of the Boot Manifest.
+This document specifies the 0.5 version of Boot Interface ABI and RMM-EL3
+services specification and the 0.5 version of the Boot Manifest.
.. _rmm_el3_boot_interface:
@@ -671,6 +671,54 @@
``E_RMM_OK``,No errors detected
+RMM_MECID_KEY_UPDATE command
+============================
+
+This command updates the tweak for the encryption key/programs a new encryption key
+associated with a given MECID. After the execution of this command, all memory
+accesses associated with the MECID are encrypted/decrypted using the new key.
+This command is available from v0.5 of the RMM-EL3 interface.
+
+FID
+---
+
+``0xC40001B6``
+
+Input values
+------------
+
+.. csv-table:: Input values for RMM_MECID_KEY_UPDATE
+ :header: "Name", "Register", "Field", "Type", "Description"
+ :widths: 1 1 1 1 5
+
+ fid,x0,[63:0],UInt64,Command FID
+ mecid,x1,[15:0],UInt64,"mecid is a 16-bit value between 0 and 65,535 that identifies the MECID for which the encryption key is to be updated. Value has to be a valid MECID as per field MECIDWidthm1 read from MECIDR_EL2. Bits [63:16] must be 0."
+
+Output values
+-------------
+
+.. csv-table:: Output values for RMM_MECID_KEY_UPDATE
+ :header: "Name", "Register", "Field", "Type", "Description"
+ :widths: 1 1 1 1 5
+
+ Result,x0,[63:0],Error Code,Command return status. Valid for all opcodes listed in input values
+
+
+Failure conditions
+------------------
+
+The table below shows all the possible error codes returned in ``Result`` upon
+a failure. The errors are ordered by condition check.
+
+.. csv-table:: Failure conditions for RMM_MECID_KEY_UPDATE
+ :header: "ID", "Condition"
+ :widths: 1 5
+
+ ``E_RMM_INVAL``,"if mecid is invalid (larger than 65,535 or than the maximum MECID width, determined by MECIDR_EL2.MECIDWidthm1)"
+ ``E_RMM_UNK``,"An unknown error occurred whilst processing the command or the SMC is not present if interface version is <0.5"
+ ``E_RMM_OK``,No errors detected
+
+
RMM-EL3 world switch register save restore convention
_____________________________________________________
diff --git a/docs/design/cpu-specific-build-macros.rst b/docs/design/cpu-specific-build-macros.rst
index 67f29f0..6562139 100644
--- a/docs/design/cpu-specific-build-macros.rst
+++ b/docs/design/cpu-specific-build-macros.rst
@@ -956,6 +956,10 @@
Cortex-A510 CPU. This needs to be applied to revision r0p0, r0p1, r0p2,
r0p3, r1p0, r1p1 and r1p2. It is fixed in r1p3.
+- ``ERRATA_A510_2971420``: This applies erratum 2971420 workaround to
+ Cortex-A510 CPU. This needs to be applied to revisions r0p1, r0p2, r0p3,
+ r1p0, r1p1, r1p2 and r1p3 and is still open.
+
For Cortex-A520, the following errata build flags are defined :
- ``ERRATA_A520_2630792``: This applies errata 2630792 workaround to
@@ -1001,9 +1005,13 @@
Cortex-A715 CPU. This needs to be enabled for revisions r0p0, r1p0
and r1p1. It is fixed in r1p2.
+- ``ERRATA_A715_2804830``: This applies errata 2804830 workaround to
+ Cortex-A715 CPU. This needs to be enabled for revisions r0p0, r1p0,
+ r1p1 and r1p2. It is fixed in r1p3.
+
- ``ERRATA_A715_3699560``: This applies errata 3699560 workaround to
Cortex-A715 CPU. This needs to be enabled for revisions r0p0, r1p0,
- r1p2, r1p3. It is still open.
+ r1p2 and r1p3. It is still open.
For Cortex-A720, the following errata build flags are defined :
diff --git a/docs/design_documents/dtpm_drivers.rst b/docs/design_documents/dtpm_drivers.rst
new file mode 100644
index 0000000..324af03
--- /dev/null
+++ b/docs/design_documents/dtpm_drivers.rst
@@ -0,0 +1,119 @@
+Discrete TPM drivers
+====================
+
+This section focuses on the design and functionality of Discrete TPM drivers
+in |TF-A|. The |TPM| technology is designed to provide
+a dedicated, hardware-based solution for storing cryptographic keys and
+performing security-related operations.
+
+Discrete TPMs are separate, standalone hardware components that are physically
+isolated from the system's main processor. This isolation helps protect
+sensitive information, such as encryption keys and platform credentials, from
+being accessed or tampered with by malicious software or unauthorized users.
+When a Discrete TPM interface is implemented correctly, the risk of software
+based attacks is reduced, further reducing the attack surface.
+
+TPM measurements establish the security posture of a system and are used for
+attestation. Performing measurements using a TPM in TF-A is beneficial from
+a security standpoint because it ensures hardware-backed attestation earlier
+in the boot flow, reducing the risk of a compromised root of trust.
+
+The design implemented in TF-A supports multiple types of TPM hardware interfaces
+and hardware bus types in order to be compatible with different platforms.
+Platforms opt to use a specific messaging interface, such as |CRB| or |FIFO|,
+and a specific hardware bus interface, such as |I2C| or |SPI|.
+
+Driver architecture
+-------------------
+
+The Discrete TPM drivers are split up into four layers, each serving a distinct
+purpose in the overall architecture:
+
+ - **Command Layer**: This layer provides various TPM commands based on the
+ `TCG TPM 2.0 Library Specification`_. It allows a system to initialize the
+ TPM interface, perform a TPM startup, set up a locality for operations like
+ PCR extend and read, and release the locality when finished.
+ - **Interface Layer**: This layer handles sending and receiving TPM commands
+ via a specific TPM interface like FIFO or CRB. It also includes functions
+ such as getting information, requesting access, and relinquishing access,
+ tailored to the specific interface.
+ - **Link Layer**: Discrete TPMs may appear as a SPI, I2C, or memory mapped
+ device. The link layer maps the command passed from the interface layer to
+ the appropriate bus type. It includes hardware link read and write functions
+ that use the platform bus interface to transfer commands.
+ - **Platform Layer**: The platform layer implements the details of how to
+ communicate to the TPM chip for a specific platform. The link layer uses the
+ platform layer to read and write to the TPM.
+
+ .. note::
+ The command, interface, and link layers are implemented in common code in
+ TF-A. The platform layer is implemented in platform specific code.
+
+The following diagram illustrates the Discrete TPM driver stack for the Raspberry
+Pi 3 platform.
+
+|rpi3 dtpm driver stack|
+
+Header files
+^^^^^^^^^^^^
+- TPM Drivers: ``include/drivers/tpm``
+
+
+Source files
+^^^^^^^^^^^^
+- TPM Drivers: ``drivers/tpm``
+
+
+Build time config options
+-------------------------
+
+- ``MBOOT_TPM_HASH_ALG``: The hash algorithm to be used by the TPM, currently
+ the only supported algorithm is ``sha256``. As additional Discrete TPMs are
+ tested and integrated in TF-A, support for more algorithms will become
+ available.
+- ``DISCRETE_TPM``: Boolean flag to enable Discrete TPM support. Depending
+ on the selected TPM interface, the appropriate drivers will be built and
+ packaged into firmware.
+- ``TPM_INTERFACE``: This flag is required when ``DISCRETE_TPM=1``,
+ currently the only supported interface is ``FIFO_SPI``.
+ Ideally there should be four options:
+
+ .. code:: shell
+
+ FIFO_I2C
+ FIFO_SPI
+ FIFO_MMIO
+ CRB
+
+ .. note::
+ ``MBOOT_TPM_HASH_ALG`` will automatically overwrite ``MBOOT_EL_HASH_ALG``.
+ This is to ensure the event log and the TPM are using the same hash
+ algorithm.
+
+
+Discrete TPM Initialization
+---------------------------
+The TPM needs to be initialized based on the platform, the hardware interfaces
+need to be set up independently, and once they are setup, the TPM commands
+``tpm_interface_init()`` and subsequently ``tpm_startup()`` can be called.
+``tpm_startup()`` only needs to be called once after startup, or if the system
+is reset.
+
+An example of platform specific TPM hardware initialization for the rpi3 can be
+found in ``plat/rpi/rpi3/rpi3_bl1_setup.c`` and ``plat/rpi/rpi3/rpi3_bl1_mboot.c``
+
+
+Discrete TPM PCR Extend
+-----------------------
+Once the TPM is setup, the TPM ``pcr_extend`` operation can be used to extend
+hashes and store them in PCR 0.
+
+An example of ``pcr_extend`` that is used during rpi3 measured boot can be found
+ in ``plat/rpi/rpi3/rpi3_bl1_mboot.c`` and ``plat/rpi/rpi3/rpi3_bl2_mboot.c``.
+
+
+*Copyright (c) 2025, Arm Limited. All rights reserved.*
+
+.. |rpi3 dtpm driver stack| image::
+ ../resources/diagrams/rpi3_dtpm_driver.png
+.. _TCG TPM 2.0 Library Specification: https://trustedcomputinggroup.org/resource/tpm-library-specification/
diff --git a/docs/design_documents/index.rst b/docs/design_documents/index.rst
index f1d8386..11c1c5a 100644
--- a/docs/design_documents/index.rst
+++ b/docs/design_documents/index.rst
@@ -7,10 +7,12 @@
cmake_framework
measured_boot_poc
+ measured_boot_dtpm_poc
drtm_poc
rse
psci_osi_mode
measured_boot
+ dtpm_drivers
--------------
diff --git a/docs/design_documents/measured_boot.rst b/docs/design_documents/measured_boot.rst
index 005903e..1f76770 100644
--- a/docs/design_documents/measured_boot.rst
+++ b/docs/design_documents/measured_boot.rst
@@ -91,6 +91,14 @@
and the variable length crypto agile structure called TCG_PCR_EVENT2. Event
Log driver implemented in TF-A covers later part.
+#. Discrete TPM
+
+ A Discrete TPM (Trusted Platform Module) can be used alongside Event Log to
+ extend measurements and validate Measured Boot functionality. The use of a
+ Discrete TPM in TF-A to extend measurements of images and other critical data
+ allows for an additional layer of security. The TPM can be used to attest the
+ integrity of the Event Log.
+
#. |RSE|
It is one of the physical backends to extend the measurements. Please refer
@@ -229,7 +237,7 @@
--------------
-*Copyright (c) 2023, Arm Limited. All rights reserved.*
+*Copyright (c) 2023-2025, Arm Limited. All rights reserved.*
.. _Arm® Server Base Security Guide: https://developer.arm.com/documentation/den0086/latest
.. _TCG EFI Protocol Specification: https://trustedcomputinggroup.org/wp-content/uploads/EFI-Protocol-Specification-rev13-160330final.pdf
diff --git a/docs/design_documents/measured_boot_dtpm_poc.rst b/docs/design_documents/measured_boot_dtpm_poc.rst
new file mode 100644
index 0000000..63a12f2
--- /dev/null
+++ b/docs/design_documents/measured_boot_dtpm_poc.rst
@@ -0,0 +1,458 @@
+Measured Boot using a Discrete TPM (PoC)
+========================================
+
+Measured Boot is the process of cryptographically measuring the code and
+critical data used at boot time, for example using a TPM, so that the
+security state can be attested later.
+
+The current implementation of the driver included in |TF-A| supports several
+backends and each has a different means to store the measurements.
+This section focuses on the Discrete TPM backend, which stores measurements
+in a PCR within the TPM. This backend can be paired with the `TCG event log`_
+to provide attestation of the measurements stored in the event log. See
+details in :ref:`Measured Boot Design`.
+
+This section provides instructions to setup and build a proof of concept (PoC)
+that showcases the use of Measured Boot with a Discrete TPM interface.
+
+.. note::
+ The instructions given in this document are meant to build a PoC to
+ show how Measured Boot on TF-A can interact with a Discrete TPM interface.
+ This PoC is platform specific, and uses a SPI based Discrete TPM, the
+ Raspberry Pi communicates with the TPM via a GPIO pin bit-banged SPI interface.
+ For other platforms, different may be required to interface with the hardware
+ (e.g., different hardware communication protocols) and different TPM interfaces
+ (e.g., |FIFO| vs |CRB|).
+
+Components
+~~~~~~~~~~
+
+ - **Platform**: The PoC is developed on the Raspberry Pi 3 (rpi3), due to quick
+ driver development and the availability of GPIO pins to interface with a TPM
+ expansion module. Measured boot capabilities using the TCG Event Log are
+ ported to the Raspberry Pi 3 platform inside TF-A. This PoC specifically uses
+ the Raspberry Pi 3 Model B V1.2, but this PoC is compatible with other
+ Raspberry Pi 3 models.
+
+ - **Discrete TPM**: The TPM chip selected is a breakout board compatible with
+ the Raspberry Pi 3 GPIO pins. This PoC uses a |SPI| based LetsTrust TPM
+ breakout board equipped with a Infineon Optiga™ SLB 9670 TPM 2.0 chip. Link
+ to device: https://thepihut.com/products/letstrust-tpm-for-raspberry-pi
+
+ .. note::
+ If you have another TPM breakout board that uses the same
+ Infineon Optiga™ SLB 9670 TPM 2.0 SPI based chip, it will also work.
+ Ensure that the correct GPIO pins are utilized on the Raspberry Pi 3 to
+ avoid communication issues, and possible hardware failures.
+
+ - **TF-A TPM Drivers**: To interface with a physical (Discrete) TPM chip in
+ TF-A, the PoC uses TF-A drivers that provide the command, interface, link,
+ and platform layers required to send and receive data to and from the TPM.
+ The drivers are located in TFA, and not in a |SP|, so that they may be used
+ in early stages such as BL2, and in some cases, BL1. The design of the TPM
+ Drivers is documented here: :ref:`Discrete TPM drivers`.
+
+ - **U-boot BL33**: This PoC showcases measured boot up to BL33, and for
+ simplicity uses a U-boot image for BL33, so that the image is measured and
+ loaded. Currently U-boot does not have Discrete TPM support for the
+ Raspberry Pi 3 platform so the boot flow ends here.
+
+
+Building the PoC for the Raspberry Pi 3
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**Build instructions for U-Boot.bin for Raspberry Pi 3.**
+
+First, the build requires a BL33 firmware image that can be packaged and measured
+by TF-A.
+
+U-boot can be built for the Raspberry Pi 3, but there are some changes to be made
+to allow the build to succeed. First Clone U-boot and enter the repo.
+
+.. code:: shell
+
+ git clone https://github.com/u-boot/u-boot.git
+ cd u-boot
+
+Now to switch to a specific tag ``v2024.04`` for testing purposes, and then build
+the defconfig labelled ``rpi_3_b_plus_defconfig``.
+
+.. code:: shell
+
+ git checkout tags/v2024.04 -b tfa_dtpm_poc
+ make CROSS_COMPILE=aarch64-linux-gnu- rpi_3_b_plus_defconfig
+
+Lastly open the ``.config`` and change ``CONFIG_TEXT_BASE`` and
+``CONFIG_SYS_UBOOT_START`` to ``0x11000000`` to match the BL33 starting point.
+
+.. code:: shell
+
+ vim .config
+ CONFIG_TEXT_BASE=0x11000000
+ CONFIG_SYS_UBOOT_START=0x11000000
+
+To build the u-boot binary, use the following command.
+
+.. code:: shell
+
+ make CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc)
+
+**Build TF-A for Raspberry Pi 3 with Discrete TPM and Measured Boot.**
+
+Copy over the ``u-boot.bin`` file over to your TF-A working directory.
+
+.. code:: shell
+
+ cp /path/to/u-boot/build/u-boot.bin /path/to/tfa/u-boot.bin
+
+TF-A build command:
+
+.. code:: shell
+
+ CROSS_COMPILE=aarch64-linux-gnu- \
+ make PLAT=rpi3 \
+ RPI3_PRELOADED_DTB_BASE=0x200000 \
+ BL33=u-boot.bin \
+ SUPPORT_VFP=1 \
+ DEBUG=0 \
+ MEASURED_BOOT=1 \
+ DISCRETE_TPM=1 \
+ MBOOT_TPM_HASH_ALG=sha256 \
+ TPM_INTERFACE=FIFO_SPI \
+ MBEDTLS_DIR=/path/to/mbedtls/repo \
+ LOG_LEVEL=40 \
+ fip all
+
+This build command is similar to the one provided in the TF-A Raspberry Pi 3
+platform port, To learn more about the platform and its build options, visit
+:ref:`Raspberry Pi 3`.
+
+ - ``RPI3_PRELOADED_DTB_BASE`` is given a different address to accommodate the
+ larger BL1 and BL2 firmware sizes, this is to accommodate the TPM drivers
+ that are packaged in BL1 and BL2 for this PoC.
+ - ``BL33`` is the non trusted firmware, in this case the U-Boot binary built
+ earlier.
+ - ``SUPPORT_VFP`` is enabled, allows Vector Floating Point operations in EL3.
+ - ``MEASURED_BOOT`` is enabled to allow the Measured Boot flow.
+ - ``DISCRETE_TPM=1`` enables the build of Discrete TPM drivers.
+ - ``MBOOT_TPM_HASH_ALG=sha256`` sets the hash algorithm to sha256, this is
+ the only algorithm supported by both TF-A Measured Boot and the SLB 9670
+ TPM 2.0.
+ - ``TPM_INTERFACE=FIFO_SPI`` specifies the use of the FIFO SPI interface.
+ - ``MBEDTLS_DIR`` is the path to your local mbedtls repo.
+ - ``LOG_LEVEL=40`` ensures that eventlog is printed at the end of BL1 and BL2.
+
+
+**Hardware Setup:**
+
+ - **TPM Connection**: Connect the LetsTrust TPM board to GPIO pins 17 - 26 on
+ the 40-pin GPIO header on the Raspberry Pi board. The 2x5 header of the TPM
+ module must be aligned to the pins in a specific orientation, match the 3v3
+ and RST pins from the TPM board to pins 17 and 18 respectively on the
+ Raspberry Pi 3 header. See `rpi3 pinout`_.
+
+ - **Serial Console**: Establish a serial connection to the Raspberry Pi 3 to
+ view serial output during the boot sequence. The GND, TXD, and RXD pins,
+ which are labelled 6, 8, and 10 on the Raspberry Pi 3 header respectively,
+ are the required pins to establish a serial connection. The recommended way
+ to connect to the board from another system is to use a USB to serial TTL
+ cable to output the serial console in a easy manner.
+
+ - **SD Card Setup**: Format a SD Card as ``FAT32`` with a default Raspbian
+ installation that is similar to the default Raspberry Pi 3 boot partition,
+ this partition will utilize the default files installed in the root
+ directory with Rasbian such as:
+
+ ::
+
+ bcm2710-rpi3-b.dtb
+ bootcode.bin
+ config.txt
+ fixup.dat
+ start.elf
+
+ Open ``config.txt`` and overwrite the file with the following lines:
+
+ ::
+
+ arm_64bit=1
+ disable_commandline_tags=2
+ enable_uart=1
+ armstub=armstub8.bin
+ device_tree_address=0x200000
+ device_tree_end=0x210000
+
+ These configurations are required to enable uart, enable 64bit mode,
+ use the build TF binary, and the modified rpi3 device tree address
+ and size.
+
+ Copy ``armstub8.bin`` from the TF-A build path to the root folder of the
+ SD card.
+
+ The SD Card is now ready to be booted.
+
+Running the PoC for the Raspberry Pi 3
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Insert the SD Card into the Raspberry Pi 3 SD card port and boot the system.
+
+To access the serial console output from the Raspberry Pi 3 you can either:
+
+ - Follow `instructions`_ to use PuTTY to connect to Raspberry Pi 3 serial console.
+
+ - Use the linux ``screen`` command:
+
+ .. code:: shell
+
+ screen /dev/ttyUSB0 115200
+
+Once booted the output from the serial console will look like this:
+
+.. code:: shell
+
+ Raspberry Pi Bootcode
+
+ Read File: config.txt, 153
+
+ Read File: start.elf, 2975040 (bytes)
+
+ Read File: fixup.dat, 7265 (bytes)
+
+ MESS:00:00:01.170422:0: brfs: File read: /mfs/sd/config.txt
+ MESS:00:00:01.174630:0: brfs: File read: 153 bytes
+ MESS:00:00:01.211473:0: HDMI0:EDID error reading EDID block 0 attempt 0
+ MESS:00:00:01.217639:0: HDMI0:EDID error reading EDID block 0 attempt 1
+ MESS:00:00:01.223977:0: HDMI0:EDID error reading EDID block 0 attempt 2
+ MESS:00:00:01.230313:0: HDMI0:EDID error reading EDID block 0 attempt 3
+ MESS:00:00:01.236650:0: HDMI0:EDID error reading EDID block 0 attempt 4
+ MESS:00:00:01.242987:0: HDMI0:EDID error reading EDID block 0 attempt 5
+ MESS:00:00:01.249324:0: HDMI0:EDID error reading EDID block 0 attempt 6
+ MESS:00:00:01.255660:0: HDMI0:EDID error reading EDID block 0 attempt 7
+ MESS:00:00:01.261997:0: HDMI0:EDID error reading EDID block 0 attempt 8
+ MESS:00:00:01.268334:0: HDMI0:EDID error reading EDID block 0 attempt 9
+ MESS:00:00:01.274429:0: HDMI0:EDID giving up on reading EDID block 0
+ MESS:00:00:01.282647:0: brfs: File read: /mfs/sd/config.txt
+ MESS:00:00:01.286929:0: gpioman: gpioman_get_pin_num: pin LEDS_PWR_OK not defined
+ MESS:00:00:01.487295:0: gpioman: gpioman_get_pin_num: pin DISPLAY_DSI_PORT not defined
+ MESS:00:00:01.494853:0: gpioman: gpioman_get_pin_num: pin LEDS_PWR_OK not defined
+ MESS:00:00:01.500763:0: *** Restart logging
+ MESS:00:00:01.504638:0: brfs: File read: 153 bytes
+ MESS:00:00:01.510139:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 0
+ MESS:00:00:01.517254:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 1
+ MESS:00:00:01.524112:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 2
+ MESS:00:00:01.530970:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 3
+ MESS:00:00:01.537826:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 4
+ MESS:00:00:01.544685:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 5
+ MESS:00:00:01.551543:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 6
+ MESS:00:00:01.558399:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 7
+ MESS:00:00:01.565258:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 8
+ MESS:00:00:01.572116:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 9
+ MESS:00:00:01.578730:0: hdmi: HDMI0:EDID giving up on reading EDID block 0
+ MESS:00:00:01.584634:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 0
+ MESS:00:00:01.592427:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 1
+ MESS:00:00:01.599286:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 2
+ MESS:00:00:01.606142:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 3
+ MESS:00:00:01.613001:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 4
+ MESS:00:00:01.619858:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 5
+ MESS:00:00:01.626717:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 6
+ MESS:00:00:01.633575:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 7
+ MESS:00:00:01.640431:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 8
+ MESS:00:00:01.647288:0: hdmi: HDMI0:EDID error reading EDID block 0 attempt 9
+ MESS:00:00:01.653905:0: hdmi: HDMI0:EDID giving up on reading EDID block 0
+ MESS:00:00:01.659769:0: hdmi: HDMI:hdmi_get_state is deprecated, use hdmi_get_display_state instead
+ MESS:00:00:01.668264:0: HDMI0: hdmi_pixel_encoding: 162000000
+ MESS:00:00:01.673988:0: vec: vec_middleware_power_on: vec_base: 0x7e806000 rev-id 0x00002708 @ vec: 0x7e806100 @ 0x00000420 enc: 0x7e806060 @ 0x00000220 cgmsae: 0x7e80605c @ 0x00000000
+ MESS:00:00:01.880234:0: dtb_file 'bcm2710-rpi-3-b.dtb'
+ MESS:00:00:01.889713:0: brfs: File read: /mfs/sd/bcm2710-rpi-3-b.dtb
+ MESS:00:00:01.894375:0: Loaded 'bcm2710-rpi-3-b.dtb' to 0x200000 size 0x7cb2
+ MESS:00:00:01.915761:0: brfs: File read: 31922 bytes
+ MESS:00:00:02.007202:0: brfs: File read: /mfs/sd/config.txt
+ MESS:00:00:02.017277:0: brfs: File read: 153 bytes
+ MESS:00:00:02.020772:0: Failed to open command line file 'cmdline.txt'
+ MESS:00:00:02.042302:0: gpioman: gpioman_get_pin_num: pin EMMC_ENABLE not defined
+ MESS:00:00:02.398066:0: kernel=
+ MESS:00:00:02.455255:0: brfs: File read: /mfs/sd/armstub8.bin
+ MESS:00:00:02.459284:0: Loaded 'armstub8.bin' to 0x0 size 0xdbe74
+ MESS:00:00:02.465109:0: No compatible kernel found
+ MESS:00:00:02.469610:0: Device tree loaded to 0x200000 (size 0x823f)
+ MESS:00:00:02.476805:0: uart: Set PL011 baud rate to 103448.300000 Hz
+ MESS:00:00:02.483381:0: uart: Baud rate change done...
+ MESS:00:00:02.486793:0: uart: Baud rateNOTICE: Booting Trusted Firmware
+ NOTICE: BL1: v2.11.0(release):v2.11.0-187-g0cb1ddc9c-dirty
+ NOTICE: BL1: Built : 10:57:10, Jul 9 2024
+ INFO: BL1: RAM 0x100ee000 - 0x100f9000
+ INFO: Using crypto library 'mbed TLS'
+ NOTICE: TPM Chip: vendor-id 0xd1, device-id 0x0, revision-id: 0x16
+ NOTICE: rpi3: Detected: Raspberry Pi 3 Model B (1GB, Sony, UK) [0x00a02082]
+ INFO: BL1: Loading BL2
+ INFO: Loading image id=1 at address 0x100b4000
+ INFO: Image id=1 loaded: 0x100b4000 - 0x100c0281
+ INFO: TCG_EfiSpecIDEvent:
+ INFO: PCRIndex : 0
+ INFO: EventType : 3
+ INFO: Digest : 00
+ INFO: : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ INFO: : 00 00 00
+ INFO: EventSize : 33
+ INFO: Signature : Spec ID Event03
+ INFO: PlatformClass : 0
+ INFO: SpecVersion : 2.0.2
+ INFO: UintnSize : 1
+ INFO: NumberOfAlgorithms : 1
+ INFO: DigestSizes :
+ INFO: #0 AlgorithmId : SHA256
+ INFO: DigestSize : 32
+ INFO: VendorInfoSize : 0
+ INFO: PCR_Event2:
+ INFO: PCRIndex : 0
+ INFO: EventType : 3
+ INFO: Digests Count : 1
+ INFO: #0 AlgorithmId : SHA256
+ INFO: Digest : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ INFO: : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ INFO: EventSize : 17
+ INFO: Signature : StartupLocality
+ INFO: StartupLocality : 0
+ INFO: PCR_Event2:
+ INFO: PCRIndex : 0
+ INFO: EventType : 1
+ INFO: Digests Count : 1
+ INFO: #0 AlgorithmId : SHA256
+ INFO: Digest : 55 11 51 d8 8b 7f 41 d3 18 16 f2 e8 80 bf 80 fa
+ INFO: : b4 03 6d 96 4c a0 0a 98 45 cf 25 2f 1e a9 09 3e
+ INFO: EventSize : 5
+ INFO: Event : BL_2
+ NOTICE: BL1: Booting BL2
+ INFO: Entry point address = 0x100b4000
+ INFO: SPSR = 0x3c5
+ NOTICE: BL2: v2.11.0(release):v2.11.0-187-g0cb1ddc9c-dirty
+ NOTICE: BL2: Built : 10:56:39, Jul 9 2024
+ INFO: Using crypto library 'mbed TLS'
+ NOTICE: TPM Chip: vendor-id 0xd1, device-id 0x0, revision-id: 0x16
+ INFO: BL2: Doing platform setup
+ INFO: BL2: Loading image id 3
+ INFO: Loading image id=3 at address 0x100e0000
+ INFO: Image id=3 loaded: 0x100e0000 - 0x100e706b
+ INFO: BL2: Loading image id 5
+ INFO: Loading image id=5 at address 0x11000000
+ INFO: Image id=5 loaded: 0x11000000 - 0x110a8ad8
+ INFO: TCG_EfiSpecIDEvent:
+ INFO: PCRIndex : 0
+ INFO: EventType : 3
+ INFO: Digest : 00
+ INFO: : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ INFO: : 00 00 00
+ INFO: EventSize : 33
+ INFO: Signature : Spec ID Event03
+ INFO: PlatformClass : 0
+ INFO: SpecVersion : 2.0.2
+ INFO: UintnSize : 1
+ INFO: NumberOfAlgorithms : 1
+ INFO: DigestSizes :
+ INFO: #0 AlgorithmId : SHA256
+ INFO: DigestSize : 32
+ INFO: VendorInfoSize : 0
+ INFO: PCR_Event2:
+ INFO: PCRIndex : 0
+ INFO: EventType : 3
+ INFO: Digests Count : 1
+ INFO: #0 AlgorithmId : SHA256
+ INFO: Digest : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ INFO: : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ INFO: EventSize : 17
+ INFO: Signature : StartupLocality
+ INFO: StartupLocality : 0
+ INFO: PCR_Event2:
+ INFO: PCRIndex : 0
+ INFO: EventType : 1
+ INFO: Digests Count : 1
+ INFO: #0 AlgorithmId : SHA256
+ INFO: Digest : 55 11 51 d8 8b 7f 41 d3 18 16 f2 e8 80 bf 80 fa
+ INFO: : b4 03 6d 96 4c a0 0a 98 45 cf 25 2f 1e a9 09 3e
+ INFO: EventSize : 5
+ INFO: Event : BL_2
+ INFO: PCR_Event2:
+ INFO: PCRIndex : 0
+ INFO: EventType : 1
+ INFO: Digests Count : 1
+ INFO: #0 AlgorithmId : SHA256
+ INFO: Digest : f3 00 5c ed a2 12 8b 76 b7 82 da c5 28 c3 02 52
+ INFO: : 19 e4 3a 82 f2 3c ab 1e 0d 78 84 9c b5 fe e2 4f
+ INFO: EventSize : 14
+ INFO: Event : SECURE_RT_EL3
+ INFO: PCR_Event2:
+ INFO: PCRIndex : 0
+ INFO: EventType : 1
+ INFO: Digests Count : 1
+ INFO: #0 AlgorithmId : SHA256
+ INFO: Digest : 90 28 81 42 12 b7 9b ca aa 0c 40 76 33 5a 69 71
+ INFO: : b6 19 2b 90 f2 d2 69 b8 de 8e 6d 05 4d c2 73 f9
+ INFO: EventSize : 6
+ INFO: Event : BL_33
+ NOTICE: BL1: Booting BL31
+ INFO: Entry point address = 0x100e0000
+ INFO: SPSR = 0x3cd
+ NOTICE: BL31: v2.11.0(release):v2.11.0-187-g0cb1ddc9c-dirty
+ NOTICE: BL31: Built : 10:56:58, Jul 9 2024
+ INFO: rpi3: Checking DTB...
+ INFO: rpi3: Reserved 0x10000000 - 0x10100000 in DTB
+ INFO: BL31: Initializing runtime services
+ INFO: BL31: Preparing for EL3 exit to normal world
+ INFO: Entry point address = 0x11000000
+ INFO: SPSR = 0x3c9
+
+
+ U-Boot 2024.04-g84314330-dirty (Apr 23 2024 - 15:41:54 -0500)
+
+ DRAM: 948 MiB
+ RPI 3 Model B (0xa02082)
+ Core: 68 devices, 14 uclasses, devicetree: embed
+ MMC: mmc@7e202000: 0, mmc@7e300000: 1
+ Loading Environment from FAT... OK
+ In: serial,usbkbd
+ Out: serial,vidconsole
+ Err: serial,vidconsole
+ Net: No ethernet found.
+ starting USB...
+ Bus usb@7e980000: USB DWC2
+ scanning bus usb@7e980000 for devices...
+ Error: smsc95xx_eth No valid MAC address found.
+ 2 USB Device(s) found
+ scanning usb for storage devices... 0 Storage Device(s) found
+ Hit any key to stop autoboot: 2 1 0
+ Card did not respond to voltage select! : -110
+ No EFI system partition
+ No EFI system partition
+ Failed to persist EFI variables
+ No EFI system partition
+ Failed to persist EFI variables
+ No EFI system partition
+ Failed to persist EFI variables
+ Missing TPMv2 device for EFI_TCG_PROTOCOL
+ ** Booting bootflow '<NULL>' with efi_mgr
+ Loading Boot0000 'mmc 0' failed
+ EFI boot manager: Cannot load any image
+ Boot failed (err=-14)
+ Card did not respond to voltage select! : -110
+ No ethernet found.
+ No ethernet found.
+ U-Boot>
+
+
+Next steps for Discrete TPM and Measured Boot development
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In order to automatically validate the workings of the Discrete TPM, the creation
+of test cases that compare the eventlog image hashes with what is stored in PCR0
+are a great way to test the core functionality of the Discrete TPM in Measured Boot.
+
+Development of Discrete TPM drivers such as a reference FIFO |I2C|, MMIO, and CRB
+drivers has not started, these drivers will allow a larger number of platform
+to use a Discrete TPM in TF-A.
+
+*Copyright (c) 2025, Arm Limited. All rights reserved.*
+
+.. _TCG event log: https://trustedcomputinggroup.org/resource/tcg-efi-platform-specification/
+.. _rpi3 pinout: https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#gpio
+.. _instructions: https://www.circuitbasics.com/use-putty-to-access-the-raspberry-pi-terminal-from-a-computer/
+.. _workaround: https://github.com/mhomran/u-boot-rpi3-b-plus
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index 740f3a6..b5814bb 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -784,6 +784,20 @@
This option defaults to 0.
+- ``DISCRETE_TPM``: Boolean flag to include support for a Discrete TPM.
+
+ This option defaults to 0.
+
+- ``TPM_INTERFACE``: When ``DISCRETE_TPM=1``, this is a required flag to
+ select the TPM interface. Currently only one interface is supported:
+
+ ::
+
+ FIFO_SPI
+
+- ``MBOOT_TPM_HASH_ALG``: Build flag to select the TPM hash algorithm used during
+ Measured Boot. Currently only accepts ``sha256`` as a valid algorithm.
+
- ``MARCH_DIRECTIVE``: used to pass a -march option from the platform build
options to the compiler. An example usage:
diff --git a/docs/global_substitutions.txt b/docs/global_substitutions.txt
index 23a91cd..ecf6d63 100644
--- a/docs/global_substitutions.txt
+++ b/docs/global_substitutions.txt
@@ -6,6 +6,7 @@
.. |BTI| replace:: :term:`BTI`
.. |CoT| replace:: :term:`CoT`
.. |COT| replace:: :term:`COT`
+.. |CRB| replace:: :term:`CRB`
.. |CSS| replace:: :term:`CSS`
.. |CVE| replace:: :term:`CVE`
.. |DICE| replace:: :term:`DICE`
@@ -19,11 +20,13 @@
.. |FCONF| replace:: :term:`FCONF`
.. |FDT| replace:: :term:`FDT`
.. |FF-A| replace:: :term:`FF-A`
+.. |FIFO| replace:: :term:`FIFO`
.. |FIP| replace:: :term:`FIP`
.. |FVP| replace:: :term:`FVP`
.. |FWU| replace:: :term:`FWU`
.. |GIC| replace:: :term:`GIC`
.. |HES| replace:: :term:`HES`
+.. |I2C| replace:: :term:`I2C`
.. |ISA| replace:: :term:`ISA`
.. |Linaro| replace:: :term:`Linaro`
.. |MMU| replace:: :term:`MMU`
@@ -55,6 +58,7 @@
.. |SP| replace:: :term:`SP`
.. |SPD| replace:: :term:`SPD`
.. |SPM| replace:: :term:`SPM`
+.. |SPI| replace:: :term:`SPI`
.. |SRTM| replace:: :term:`SRTM`
.. |SSBS| replace:: :term:`SSBS`
.. |SVE| replace:: :term:`SVE`
diff --git a/docs/glossary.rst b/docs/glossary.rst
index 20ad21c..8bb35bc 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -36,6 +36,9 @@
CSS
Compute Sub-System
+ CRB
+ Command Response Buffer
+
CVE
Common Vulnerabilities and Exposures. A CVE document is commonly used to
describe a publicly-known security vulnerability.
@@ -88,6 +91,9 @@
FF-A
Firmware Framework for Arm A-profile
+ FIFO
+ First In, First Out
+
FIP
Firmware Image Package
@@ -103,6 +109,9 @@
HES
Arm CCA Hardware Enforced Security
+ I2C
+ Inter-Integrated Circuit Protocol
+
ISA
Instruction Set Architecture
@@ -211,6 +220,9 @@
SPM
Secure Partition Manager
+ SPI
+ Serial Peripheral Interface
+
SRTM
Static Root of Trust for Measurement
diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst
index 0f0dedd..327c67b 100644
--- a/docs/porting-guide.rst
+++ b/docs/porting-guide.rst
@@ -2350,6 +2350,24 @@
When ENABLE_RME is disabled, this function is not used.
+Function : plat_rmm_mecid_key_update() [when ENABLE_RME == 1]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : uint16_t
+ Return : int
+
+This function is invoked by BL31's RMMD when there is a request from the RMM
+monitor to update the tweak for the encryption key associated to a MECID.
+
+The first parameter (``uint16_t mecid``) contains the MECID for which the
+encryption key is to be updated.
+
+Return value is 0 upon success and -EFAULT otherwise.
+
+This function needs to be implemented by a platform if it enables RME.
+
Function : plat_rmmd_el3_token_sign_push_req() [mandatory when RMMD_ENABLE_EL3_TOKEN_SIGN == 1]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/resources/diagrams/rpi3_dtpm_driver.png b/docs/resources/diagrams/rpi3_dtpm_driver.png
new file mode 100644
index 0000000..36b1843
--- /dev/null
+++ b/docs/resources/diagrams/rpi3_dtpm_driver.png
Binary files differ
diff --git a/docs/threat_model/firmware_threat_model/threat_model.rst b/docs/threat_model/firmware_threat_model/threat_model.rst
index ae0219e..c0cc3be 100644
--- a/docs/threat_model/firmware_threat_model/threat_model.rst
+++ b/docs/threat_model/firmware_threat_model/threat_model.rst
@@ -928,6 +928,12 @@
Measured Boot implementation in |TF-A| is that it does not extend the
measurements into a |PCR| of a Discrete |TPM|, where measurements would
be securely stored and protected against tampering.
+ - Discrete |TPM|: Implemented in |TF-A| as a proof of concept, the Discrete
+ |TPM| is used alongside the existing TCG-compliant Event Log. This
+ Measured Boot implementation extends measurement hashes to a |PCR| in the
+ |TPM|, which provides a hardware-backed root of trust. The measurements in
+ the Event Log can now be hashed and compared to the value of the |PCR| to
+ determine if tampering of the Event Log has taken place.
- `CCA Measured Boot`_: Implemented by |TF-M|. Measurements are stored in
|HES| secure on-chip memory. |HES| implements protection against tampering
its on-chip memory. |HES| interface is available for BL1 and BL2.
@@ -942,6 +948,20 @@
to protect or threats to defend against that could compromise |TF-A| execution
environment's security.
+ When considering the implementation of Measured Boot using a TCG-compliant
+ Event Log backed by a discrete TPM, physical vulnerabilities come to mind.
+ Platforms have many different ways of integrating a discrete TPM, and these
+ implementations can be susceptible to man-in-the-middle attacks, where the
+ attacker intercepts the bus traffic between the discrete TPM and the host
+ machine. This can lead to PCR extend operations being modified, compromising
+ Measured Boot. This vulnerability requires physical access to the host machine.
+
+ TF-A does not provide any mitigations against these physical vulnerabilities,
+ it is the responsibility of the platform owners to address this based on their
+ specific threat model. Mitigation of this can be achieved through dedicated
+ hardware solutions, such as an encrypted AP/dTPM bus, or software-based
+ approaches designed to protect sensitive data such as parameter encryption.
+
There are general security assets and threats associated with remote/delegated
attestation. However, these are outside the |TF-A| security boundary and
should be dealt with by the appropriate agent in the platform/system.
@@ -1192,7 +1212,7 @@
--------------
-*Copyright (c) 2021-2024, Arm Limited. All rights reserved.*
+*Copyright (c) 2021-2025, Arm Limited. All rights reserved.*
.. _STRIDE threat analysis technique: https://docs.microsoft.com/en-us/azure/security/develop/threat-modeling-tool-threats#stride-model
diff --git a/drivers/gpio/gpio_spi.c b/drivers/gpio/gpio_spi.c
new file mode 100644
index 0000000..2913b41
--- /dev/null
+++ b/drivers/gpio/gpio_spi.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2025, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/gpio.h>
+#include <drivers/gpio_spi.h>
+#include <platform_def.h>
+
+static struct spi_plat gpio_spidev;
+
+static void gpio_spi_delay_us(void)
+{
+ udelay(gpio_spidev.gpio_data.spi_delay_us);
+}
+
+static int gpio_spi_miso(void)
+{
+ return gpio_get_value(gpio_spidev.gpio_data.miso_gpio);
+}
+
+static void gpio_spi_sclk(int bit)
+{
+ gpio_set_value(gpio_spidev.gpio_data.sclk_gpio, bit);
+}
+
+static void gpio_spi_mosi(int bit)
+{
+ gpio_set_value(gpio_spidev.gpio_data.mosi_gpio, bit);
+}
+
+static void gpio_spi_cs(int bit)
+{
+ gpio_set_value(gpio_spidev.gpio_data.cs_gpio, bit);
+}
+
+static void gpio_spi_start(void)
+{
+ gpio_spi_cs(1);
+ gpio_spi_sclk(0);
+ gpio_spi_cs(0);
+}
+
+static void gpio_spi_stop(void)
+{
+ gpio_spi_cs(1);
+}
+
+/* set sclk to a known state (0) before performing any further action */
+static void gpio_spi_get_access(void)
+{
+ gpio_spi_sclk(0);
+}
+
+static void xfer(unsigned int bytes, const void *out, void *in, int cpol, int cpha)
+{
+ for (unsigned int j = 0U; j < bytes; j++) {
+ unsigned char in_byte = 0U;
+ unsigned char out_byte = (out != NULL) ? *(const uint8_t *)out++ : 0xFF;
+
+ for (int i = 7; i >= 0; i--) {
+ if (cpha) {
+ gpio_spi_sclk(!cpol);
+ }
+
+ gpio_spi_mosi(!!(out_byte & (1 << i)));
+
+ gpio_spi_delay_us();
+ gpio_spi_sclk(cpha ? cpol : !cpol);
+ gpio_spi_delay_us();
+
+ in_byte |= gpio_spi_miso() << i;
+
+ if (!cpha) {
+ gpio_spi_sclk(cpol);
+ }
+ }
+
+ if (in != NULL) {
+ *(uint8_t *)in++ = in_byte;
+ }
+ }
+}
+
+static int gpio_spi_xfer(unsigned int bytes, const void *out, void *in)
+{
+ if ((out == NULL) && (in == NULL)) {
+ return -1;
+ }
+
+ switch (gpio_spidev.gpio_data.spi_mode) {
+ case 0:
+ xfer(bytes, out, in, 0, 0);
+ break;
+ case 1:
+ xfer(bytes, out, in, 0, 1);
+ break;
+ case 2:
+ xfer(bytes, out, in, 1, 0);
+ break;
+ case 3:
+ xfer(bytes, out, in, 1, 1);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+struct spi_ops gpio_spidev_ops = {
+ .get_access = gpio_spi_get_access,
+ .start = gpio_spi_start,
+ .stop = gpio_spi_stop,
+ .xfer = gpio_spi_xfer,
+};
+
+struct spi_plat *gpio_spi_init(struct gpio_spi_data *gpio_spi_data)
+{
+ gpio_spidev.gpio_data = *gpio_spi_data;
+ gpio_spidev.ops = &gpio_spidev_ops;
+
+ return &gpio_spidev;
+}
diff --git a/drivers/measured_boot/event_log/event_log.mk b/drivers/measured_boot/event_log/event_log.mk
index 5ea4c55..9e0d6c4 100644
--- a/drivers/measured_boot/event_log/event_log.mk
+++ b/drivers/measured_boot/event_log/event_log.mk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+# Copyright (c) 2020-2025, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -7,15 +7,20 @@
# Default log level to dump the event log (LOG_LEVEL_INFO)
EVENT_LOG_LEVEL ?= 40
-# Measured Boot hash algorithm.
-# SHA-256 (or stronger) is required for all devices that are TPM 2.0 compliant.
-ifdef TPM_HASH_ALG
- $(warning "TPM_HASH_ALG is deprecated. Please use MBOOT_EL_HASH_ALG instead.")
- MBOOT_EL_HASH_ALG := ${TPM_HASH_ALG}
+# When using a TPM, adopt the TPM's hash algorithm for
+# measurements through the Event Log mechanism, ensuring
+# the TPM uses the same algorithm for measurements and
+# extends the PCR accordingly, allowing for comparison
+# between PCR value and Event Log measurements required
+# for attestation.
+ifdef MBOOT_TPM_HASH_ALG
+ MBOOT_EL_HASH_ALG := ${MBOOT_TPM_HASH_ALG}
else
MBOOT_EL_HASH_ALG := sha256
endif
+# Measured Boot hash algorithm.
+# SHA-256 (or stronger) is required for all devices that are TPM 2.0 compliant.
ifeq (${MBOOT_EL_HASH_ALG}, sha512)
TPM_ALG_ID := TPM_ALG_SHA512
TCG_DIGEST_SIZE := 64U
diff --git a/drivers/tpm/tpm2.mk b/drivers/tpm/tpm2.mk
new file mode 100644
index 0000000..4418b97
--- /dev/null
+++ b/drivers/tpm/tpm2.mk
@@ -0,0 +1,26 @@
+#
+# Copyright (c) 2025, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+TPM2_SRC_DIR := drivers/tpm/
+
+TPM2_SOURCES := ${TPM2_SRC_DIR}tpm2_cmds.c \
+ ${TPM2_SRC_DIR}tpm2_chip.c
+
+# TPM Hash algorithm, used during Measured Boot
+# currently only accepts SHA-256
+ifeq (${MBOOT_TPM_HASH_ALG}, sha256)
+ TPM_ALG_ID := TPM_ALG_SHA256
+ TCG_DIGEST_SIZE := 32U
+else
+ $(error "The selected MBOOT_TPM_HASH_ALG is invalid.")
+endif #MBOOT_TPM_HASH_ALG
+
+ifeq (${TPM_INTERFACE}, FIFO_SPI)
+ TPM2_SOURCES += ${TPM2_SRC_DIR}tpm2_fifo.c \
+ ${TPM2_SRC_DIR}tpm2_fifo_spi.c
+else
+ $(error "The selected TPM_INTERFACE is invalid.")
+endif #TPM_INTERFACE
diff --git a/drivers/tpm/tpm2_chip.c b/drivers/tpm/tpm2_chip.c
new file mode 100644
index 0000000..537ce92
--- /dev/null
+++ b/drivers/tpm/tpm2_chip.c
@@ -0,0 +1,21 @@
+
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/tpm/tpm2_chip.h>
+
+/*
+ * TPM timeout values
+ * Reference: TCG PC Client Platform TPM Profile (PTP) Specification v1.05
+ */
+struct tpm_chip_data tpm_chip_data = {
+ .locality = -1,
+ .timeout_msec_a = 750,
+ .timeout_msec_b = 2000,
+ .timeout_msec_c = 200,
+ .timeout_msec_d = 30,
+ .address = 0,
+};
diff --git a/drivers/tpm/tpm2_cmds.c b/drivers/tpm/tpm2_cmds.c
new file mode 100644
index 0000000..b6422a8
--- /dev/null
+++ b/drivers/tpm/tpm2_cmds.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <lib/libc/endian.h>
+
+#include <drivers/delay_timer.h>
+#include <drivers/tpm/tpm2.h>
+#include <drivers/tpm/tpm2_chip.h>
+#include <drivers/tpm/tpm2_interface.h>
+
+#define CMD_SIZE_OFFSET 6
+
+#define SINGLE_BYTE 1
+#define TWO_BYTES 2
+#define FOUR_BYTES 4
+
+static struct interface_ops *interface;
+
+static int tpm_xfer(struct tpm_chip_data *chip_data, const tpm_cmd *send, tpm_cmd *receive)
+{
+ int ret;
+
+ ret = interface->send(chip_data, send);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = interface->receive(chip_data, receive);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return TPM_SUCCESS;
+}
+
+int tpm_interface_init(struct tpm_chip_data *chip_data, uint8_t locality)
+{
+ int err;
+
+ interface = tpm_interface_getops(chip_data, locality);
+
+ err = interface->request_access(chip_data, locality);
+ if (err != 0) {
+ return err;
+ }
+
+ return interface->get_info(chip_data, locality);
+}
+
+int tpm_interface_close(struct tpm_chip_data *chip_data, uint8_t locality)
+{
+ return interface->release_locality(chip_data, locality);
+}
+
+static int tpm_update_buffer(tpm_cmd *buf, uint32_t new_data, size_t new_len)
+{
+ int i, j, start;
+ uint32_t command_size;
+
+ union {
+ uint8_t var8;
+ uint16_t var16;
+ uint32_t var32;
+ uint8_t array[4];
+ } tpm_new_data;
+
+ command_size = be32toh(buf->header.cmd_size);
+
+ if (command_size + new_len > MAX_SIZE_CMDBUF) {
+ ERROR("%s: buf size exceeded, increase MAX_SIZE_CMDBUF\n",
+ __func__);
+ return TPM_INVALID_PARAM;
+ }
+ /*
+ * Subtract the cmd header size from the current command size
+ * so the data buffer is written to starting at index 0.
+ */
+ start = command_size - TPM_HEADER_SIZE;
+
+ /*
+ * The TPM, according to the TCG spec, processes data in BE byte order,
+ * in the case where the Host is LE, htobe correctly handles the byte order.
+ * When updating the buffer, keep in mind to only pass sizeof(new_data) or
+ * the variable type size for the new_len function parameter. This ensures
+ * there is only the possiblility of writing 1, 2, or 4 bytes to the buffer,
+ * and that the correct number of bytes are written to data[i].
+ */
+ if (new_len == SINGLE_BYTE) {
+ tpm_new_data.var8 = new_data & 0xFF;
+ } else if (new_len == TWO_BYTES) {
+ tpm_new_data.var16 = htobe16(new_data & 0xFFFF);
+ } else if (new_len == FOUR_BYTES) {
+ tpm_new_data.var32 = htobe32(new_data);
+ } else {
+ ERROR("%s: Invalid data length\n", __func__);
+ return TPM_INVALID_PARAM;
+ }
+
+ for (i = start, j = 0; i < start + new_len; i++, j++) {
+ buf->data[i] = tpm_new_data.array[j];
+ }
+ buf->header.cmd_size = htobe32(command_size + new_len);
+
+ return TPM_SUCCESS;
+}
+
+
+int tpm_startup(struct tpm_chip_data *chip_data, uint16_t mode)
+{
+ tpm_cmd startup_cmd, startup_response;
+ uint32_t tpm_rc;
+ int ret;
+
+ memset(&startup_cmd, 0, sizeof(startup_cmd));
+ memset(&startup_response, 0, sizeof(startup_response));
+
+ startup_cmd.header.tag = htobe16(TPM_ST_NO_SESSIONS);
+ startup_cmd.header.cmd_size = htobe32(sizeof(tpm_cmd_hdr));
+ startup_cmd.header.cmd_code = htobe32(TPM_CMD_STARTUP);
+
+ ret = tpm_update_buffer(&startup_cmd, mode, sizeof(mode));
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = tpm_xfer(chip_data, &startup_cmd, &startup_response);
+ if (ret < 0) {
+ return ret;
+ }
+
+ tpm_rc = be32toh(startup_response.header.cmd_code);
+ if (tpm_rc != TPM_RESPONSE_SUCCESS) {
+ ERROR("%s: response code contains error = %X\n", __func__, tpm_rc);
+ return TPM_ERR_RESPONSE;
+ }
+
+ return TPM_SUCCESS;
+}
+
+int tpm_pcr_extend(struct tpm_chip_data *chip_data, uint32_t index,
+ uint16_t algorithm, const uint8_t *digest,
+ uint32_t digest_len)
+{
+ tpm_cmd pcr_extend_cmd, pcr_extend_response;
+ uint32_t tpm_rc;
+ int ret;
+
+ memset(&pcr_extend_cmd, 0, sizeof(pcr_extend_cmd));
+ memset(&pcr_extend_response, 0, sizeof(pcr_extend_response));
+
+ if (digest == NULL) {
+ return TPM_INVALID_PARAM;
+ }
+ pcr_extend_cmd.header.tag = htobe16(TPM_ST_SESSIONS);
+ pcr_extend_cmd.header.cmd_size = htobe32(sizeof(tpm_cmd_hdr));
+ pcr_extend_cmd.header.cmd_code = htobe32(TPM_CMD_PCR_EXTEND);
+
+ /* handle (PCR Index)*/
+ ret = tpm_update_buffer(&pcr_extend_cmd, index, sizeof(index));
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* authorization size , session handle, nonce size, attributes*/
+ ret = tpm_update_buffer(&pcr_extend_cmd, TPM_MIN_AUTH_SIZE, sizeof(uint32_t));
+ if (ret < 0) {
+ return ret;
+ }
+ ret = tpm_update_buffer(&pcr_extend_cmd, TPM_RS_PW, sizeof(uint32_t));
+ if (ret < 0) {
+ return ret;
+ }
+ ret = tpm_update_buffer(&pcr_extend_cmd, TPM_ZERO_NONCE_SIZE, sizeof(uint16_t));
+ if (ret < 0) {
+ return ret;
+ }
+ ret = tpm_update_buffer(&pcr_extend_cmd, TPM_ATTRIBUTES_DISABLE, sizeof(uint8_t));
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* hmac/password size */
+ ret = tpm_update_buffer(&pcr_extend_cmd, TPM_ZERO_HMAC_SIZE, sizeof(uint16_t));
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* hashes count */
+ ret = tpm_update_buffer(&pcr_extend_cmd, TPM_SINGLE_HASH_COUNT, sizeof(uint32_t));
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* hash algorithm */
+ ret = tpm_update_buffer(&pcr_extend_cmd, algorithm, sizeof(algorithm));
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* digest */
+ for (int i = 0; i < digest_len; i++) {
+ ret = tpm_update_buffer(&pcr_extend_cmd, digest[i], sizeof(uint8_t));
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ ret = tpm_xfer(chip_data, &pcr_extend_cmd, &pcr_extend_response);
+ if (ret < 0) {
+ return ret;
+ }
+
+ tpm_rc = be32toh(pcr_extend_response.header.cmd_code);
+ if (tpm_rc != TPM_RESPONSE_SUCCESS) {
+ ERROR("%s: response code contains error = %X\n", __func__, tpm_rc);
+ return TPM_ERR_RESPONSE;
+ }
+
+ return TPM_SUCCESS;
+}
diff --git a/drivers/tpm/tpm2_fifo.c b/drivers/tpm/tpm2_fifo.c
new file mode 100644
index 0000000..7c4b9d8
--- /dev/null
+++ b/drivers/tpm/tpm2_fifo.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <lib/libc/endian.h>
+
+#include <drivers/delay_timer.h>
+#include <drivers/tpm/tpm2.h>
+#include <drivers/tpm/tpm2_chip.h>
+#include <drivers/tpm/tpm2_interface.h>
+
+#define LOCALITY_START_ADDRESS(x, y) \
+ ((uint16_t)(x->address + (0x1000 * y)))
+
+static int tpm2_get_info(struct tpm_chip_data *chip_data, uint8_t locality)
+{
+ uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, locality);
+ uint32_t vid_did;
+ uint8_t revision;
+ int err;
+
+ err = tpm2_fifo_read_chunk(tpm_base_addr + TPM_FIFO_REG_VENDID, DWORD, &vid_did);
+ if (err < 0) {
+ return err;
+ }
+
+ err = tpm2_fifo_read_byte(tpm_base_addr + TPM_FIFO_REG_REVID, &revision);
+ if (err < 0) {
+ return err;
+ }
+
+ INFO("TPM Chip: vendor-id 0x%x, device-id 0x%x, revision-id: 0x%x\n",
+ 0xFFFF & vid_did, vid_did >> 16, revision);
+
+ return TPM_SUCCESS;
+}
+
+static int tpm2_wait_reg_bits(uint16_t reg, uint8_t set, unsigned long timeout, uint8_t *status)
+{
+ int err;
+ uint64_t timeout_delay = timeout_init_us(timeout * 1000);
+
+ do {
+ err = tpm2_fifo_read_byte(reg, status);
+ if (err < 0) {
+ return err;
+ }
+ if ((*status & set) == set) {
+ return TPM_SUCCESS;
+ }
+ } while (!timeout_elapsed(timeout_delay));
+
+ return TPM_ERR_TIMEOUT;
+}
+
+static int tpm2_fifo_request_access(struct tpm_chip_data *chip_data, uint8_t locality)
+{
+ uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, locality);
+ uint8_t status;
+ int err;
+
+ err = tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_ACCESS, TPM_ACCESS_REQUEST_USE);
+ if (err < 0) {
+ return err;
+ }
+
+ err = tpm2_wait_reg_bits(tpm_base_addr + TPM_FIFO_REG_ACCESS,
+ TPM_ACCESS_ACTIVE_LOCALITY,
+ chip_data->timeout_msec_a, &status);
+ if (err == 0) {
+ chip_data->locality = locality;
+ return TPM_SUCCESS;
+ }
+
+ return err;
+}
+
+static int tpm2_fifo_release_locality(struct tpm_chip_data *chip_data, uint8_t locality)
+{
+ uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, locality);
+ uint8_t buf;
+ int err;
+
+ err = tpm2_fifo_read_byte(tpm_base_addr + TPM_FIFO_REG_ACCESS, &buf);
+ if (err < 0) {
+ return err;
+ }
+
+ if (buf & (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) {
+ return tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_ACCESS,
+ TPM_ACCESS_RELINQUISH_LOCALITY);
+ }
+
+ ERROR("%s: Unable to release locality\n", __func__);
+ return TPM_ERR_RESPONSE;
+}
+
+static int tpm2_fifo_prepare(struct tpm_chip_data *chip_data)
+{
+ uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, chip_data->locality);
+ uint8_t status;
+ int err;
+
+ err = tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_STATUS, TPM_STAT_COMMAND_READY);
+ if (err < 0) {
+ return err;
+ }
+
+ err = tpm2_wait_reg_bits(tpm_base_addr + TPM_FIFO_REG_STATUS,
+ TPM_STAT_COMMAND_READY,
+ chip_data->timeout_msec_b, &status);
+ if (err < 0) {
+ ERROR("%s: TPM Status Busy\n", __func__);
+ return err;
+ }
+
+ return TPM_SUCCESS;
+}
+
+static int tpm2_fifo_get_burstcount(struct tpm_chip_data *chip_data, uint16_t *burstcount)
+{
+ uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, chip_data->locality);
+ uint64_t timeout_delay = timeout_init_us(chip_data->timeout_msec_a * 1000);
+ int err;
+
+ if (burstcount == NULL) {
+ return TPM_INVALID_PARAM;
+ }
+
+ do {
+ uint8_t byte0, byte1;
+
+ err = tpm2_fifo_read_byte(tpm_base_addr + TPM_FIFO_REG_BURST_COUNT_LO, &byte0);
+ if (err < 0) {
+ return err;
+ }
+
+ err = tpm2_fifo_read_byte(tpm_base_addr + TPM_FIFO_REG_BURST_COUNT_HI, &byte1);
+ if (err < 0) {
+ return err;
+ }
+
+ *burstcount = (uint16_t)((byte1 << 8) + byte0);
+ if (*burstcount != 0U) {
+ return TPM_SUCCESS;
+ }
+ } while (!timeout_elapsed(timeout_delay));
+
+ return TPM_ERR_TIMEOUT;
+}
+
+static int tpm2_fifo_send(struct tpm_chip_data *chip_data, const tpm_cmd *buf)
+{
+ uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, chip_data->locality);
+ uint8_t status;
+ uint16_t burstcnt;
+ int err;
+ uint32_t len, index;
+
+ if (sizeof(buf->header) != TPM_HEADER_SIZE) {
+ ERROR("%s: invalid command header size.\n", __func__);
+ return TPM_INVALID_PARAM;
+ }
+
+ err = tpm2_fifo_read_byte(tpm_base_addr + TPM_FIFO_REG_STATUS, &status);
+ if (err < 0) {
+ return err;
+ }
+
+ if (!(status & TPM_STAT_COMMAND_READY)) {
+ err = tpm2_fifo_prepare(chip_data);
+ if (err < 0) {
+ return err;
+ }
+ }
+
+ /* write the command header to the TPM first */
+ const uint8_t *header_data = (const uint8_t *)&buf->header;
+
+ for (index = 0; index < TPM_HEADER_SIZE; index++) {
+ err = tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_DATA_FIFO,
+ header_data[index]);
+ if (err < 0) {
+ return err;
+ }
+ }
+
+ len = be32toh(buf->header.cmd_size);
+
+ while (index < len) {
+ err = tpm2_fifo_get_burstcount(chip_data, &burstcnt);
+ if (err < 0) {
+ return err;
+ }
+
+ for (; burstcnt > 0U && index < len; burstcnt--) {
+ err = tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_DATA_FIFO,
+ buf->data[index - TPM_HEADER_SIZE]);
+ if (err < 0) {
+ return err;
+ }
+ index++;
+ }
+ }
+
+ err = tpm2_wait_reg_bits(tpm_base_addr + TPM_FIFO_REG_STATUS,
+ TPM_STAT_VALID,
+ chip_data->timeout_msec_c,
+ &status);
+ if (err < 0) {
+ return err;
+ }
+
+ if (status & TPM_STAT_EXPECT) {
+ ERROR("%s: TPM is still expecting data after command buffer is sent\n", __func__);
+ return TPM_ERR_TRANSFER;
+ }
+
+ err = tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_STATUS, TPM_STAT_GO);
+ if (err < 0) {
+ return err;
+ }
+
+ return TPM_SUCCESS;
+}
+
+static int tpm2_fifo_read_data(struct tpm_chip_data *chip_data, tpm_cmd *buf,
+ uint16_t tpm_base_addr, uint8_t *status, int *size, int bytes_expected)
+{
+ int err, read_size, loop_index;
+ uint16_t burstcnt;
+ uint8_t *read_data;
+
+ if (bytes_expected == TPM_READ_HEADER) {
+ /* read the response header from the TPM first */
+ read_data = (uint8_t *)&buf->header;
+ read_size = TPM_HEADER_SIZE;
+ loop_index = *size;
+ } else {
+ /* process the rest of the mssg with bytes_expected */
+ read_data = buf->data;
+ read_size = bytes_expected;
+ loop_index = *size - TPM_HEADER_SIZE;
+ }
+
+ err = tpm2_wait_reg_bits(tpm_base_addr + TPM_FIFO_REG_STATUS,
+ TPM_STAT_AVAIL,
+ chip_data->timeout_msec_c,
+ status);
+ if (err < 0) {
+ return err;
+ }
+
+ while (*size < read_size) {
+ err = tpm2_fifo_get_burstcount(chip_data, &burstcnt);
+ if (err < 0) {
+ ERROR("%s: TPM burst count error\n", __func__);
+ return err;
+ }
+
+ for (; burstcnt > 0U && loop_index < read_size;
+ burstcnt--, loop_index++, (*size)++) {
+ err = tpm2_fifo_read_byte(
+ tpm_base_addr + TPM_FIFO_REG_DATA_FIFO,
+ (void *)&read_data[loop_index]);
+ if (err < 0) {
+ return err;
+ }
+ }
+ }
+
+ return TPM_SUCCESS;
+}
+
+static int tpm2_fifo_receive(struct tpm_chip_data *chip_data, tpm_cmd *buf)
+{
+ uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, chip_data->locality);
+ int size = 0, bytes_expected, err;
+ uint8_t status;
+
+ err = tpm2_fifo_read_data(chip_data, buf, tpm_base_addr, &status, &size, TPM_READ_HEADER);
+ if (err < 0) {
+ return err;
+ }
+
+ bytes_expected = be32toh(buf->header.cmd_size);
+ if (bytes_expected > sizeof(*buf)) {
+ ERROR("%s: tpm response buffer cannot store expected response\n", __func__);
+ return TPM_INVALID_PARAM;
+ }
+
+ if (size == bytes_expected) {
+ return size;
+ }
+
+ err = tpm2_fifo_read_data(chip_data, buf, tpm_base_addr, &status, &size, bytes_expected);
+ if (err < 0) {
+ return err;
+ }
+
+ if (size < bytes_expected) {
+ ERROR("%s: response buffer size is less than expected\n", __func__);
+ return TPM_ERR_RESPONSE;
+ }
+
+ return TPM_SUCCESS;
+}
+
+static interface_ops_t fifo_ops = {
+ .get_info = tpm2_get_info,
+ .send = tpm2_fifo_send,
+ .receive = tpm2_fifo_receive,
+ .request_access = tpm2_fifo_request_access,
+ .release_locality = tpm2_fifo_release_locality,
+};
+
+struct interface_ops *
+tpm_interface_getops(struct tpm_chip_data *chip_data, uint8_t locality)
+{
+ return &fifo_ops;
+}
diff --git a/drivers/tpm/tpm2_fifo_spi.c b/drivers/tpm/tpm2_fifo_spi.c
new file mode 100644
index 0000000..16d87d9
--- /dev/null
+++ b/drivers/tpm/tpm2_fifo_spi.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <drivers/gpio_spi.h>
+#include <drivers/tpm/tpm2.h>
+#include <drivers/tpm/tpm2_chip.h>
+#include <drivers/tpm/tpm2_interface.h>
+
+#define ENCODE_LIMIT 128
+#define CS_ASSERT_OFFSET 0xD4
+#define RETRY_COUNT 50
+
+#define TPM_READ false
+#define TPM_WRITE true
+
+extern struct spi_plat *spidev;
+
+static int tpm2_spi_transfer(const void *data_out, void *data_in, uint8_t len)
+{
+ return spidev->ops->xfer(len, data_out, data_in);
+}
+
+/*
+ * Reference: TCG PC Client Platform TPM Profile (PTP) Specification v1.05
+ */
+static int tpm2_spi_start_transaction(uint16_t tpm_reg, bool write, uint8_t len)
+{
+ int rc;
+ uint8_t header[4];
+ uint8_t header_response[4];
+ uint8_t zero = 0, byte;
+ int retries;
+
+ /* check to make sure len does not exceed the encoding limit */
+ if (len > ENCODE_LIMIT) {
+ return TPM_INVALID_PARAM;
+ }
+
+ /*
+ * 7.4.6 TPM SPI Bit protocol calls for the following header
+ * to be sent to the TPM at the start of every attempted read/write.
+ */
+
+ /* header[0] contains the r/w and the xfer size, if the msb is not
+ * set, the operation is write, if it is set then it is read.
+ * The size of the transfer is encoded, and must not overwrite
+ * the msb, therefore an ENCODE LIMIT of 128 is present.
+ */
+ header[0] = ((write) ? 0x00 : 0x80) | (len - 1);
+
+ /*
+ * header[1] contains the address offset 0xD4_xxxx as defined
+ * in the TPM spec, since the CS# is asserted.
+ */
+ header[1] = CS_ASSERT_OFFSET;
+
+ /*
+ * header[2] and header[3] contain the address of the register
+ * to be read/written.
+ */
+ header[2] = tpm_reg >> 8;
+ header[3] = tpm_reg;
+
+ rc = tpm2_spi_transfer(header, header_response, 4);
+ if (rc != 0) {
+ return TPM_ERR_TRANSFER;
+ }
+
+ /*
+ * 7.4.5 Flow Control defines a wait state in order to accommodate
+ * the TPM in case it needs to free its buffer.
+ */
+ if ((header_response[3] & 0x01) != 0U) {
+ return TPM_SUCCESS;
+ }
+
+ /*
+ * if the wait state over bit is not set in the initial header_response,
+ * poll for the wait state over by sending a zeroed byte, if the
+ * RETRY_COUNT is exceeded the transfer fails.
+ */
+ for (retries = RETRY_COUNT; retries > 0; retries--) {
+ rc = tpm2_spi_transfer(&zero, &byte, 1);
+ if (rc != 0) {
+ return TPM_ERR_TRANSFER;
+ }
+ if ((byte & 0x01) != 0U) {
+ return TPM_SUCCESS;
+ }
+ }
+
+ if (retries == 0) {
+ ERROR("%s: TPM Timeout\n", __func__);
+ return TPM_ERR_TIMEOUT;
+ }
+
+ return TPM_SUCCESS;
+}
+
+static void tpm2_spi_end_transaction(void)
+{
+ spidev->ops->stop();
+}
+
+static void tpm2_spi_init(void)
+{
+ spidev->ops->get_access();
+ spidev->ops->start();
+}
+
+static int tpm2_fifo_io(uint16_t tpm_reg, bool is_write, uint8_t len, void *val)
+{
+ int rc;
+
+ tpm2_spi_init();
+ rc = tpm2_spi_start_transaction(tpm_reg, is_write, len);
+ if (rc != 0) {
+ tpm2_spi_end_transaction();
+ return rc;
+ }
+
+ rc = tpm2_spi_transfer(
+ is_write ? val : NULL,
+ is_write ? NULL : val,
+ len);
+ if (rc != 0) {
+ tpm2_spi_end_transaction();
+ return rc;
+ }
+
+ tpm2_spi_end_transaction();
+
+ return TPM_SUCCESS;
+}
+
+int tpm2_fifo_write_byte(uint16_t tpm_reg, uint8_t val)
+{
+ return tpm2_fifo_io(tpm_reg, TPM_WRITE, BYTE, &val);
+}
+
+int tpm2_fifo_read_byte(uint16_t tpm_reg, uint8_t *val)
+{
+ return tpm2_fifo_io(tpm_reg, TPM_READ, BYTE, val);
+}
+
+int tpm2_fifo_read_chunk(uint16_t tpm_reg, uint8_t len, void *val)
+{
+ if ((len != BYTE) && (len != WORD) && (len != DWORD)) {
+ return TPM_INVALID_PARAM;
+ }
+
+ return tpm2_fifo_io(tpm_reg, TPM_READ, len, val);
+}
diff --git a/drivers/tpm/tpm2_slb9670/slb9670_gpio.c b/drivers/tpm/tpm2_slb9670/slb9670_gpio.c
new file mode 100644
index 0000000..993387d
--- /dev/null
+++ b/drivers/tpm/tpm2_slb9670/slb9670_gpio.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/delay_timer.h>
+#include <drivers/gpio.h>
+#include <drivers/tpm/tpm2_slb9670/slb9670_gpio.h>
+
+/*
+ * Infineon SLB9670 Chip Reset Parameters
+ */
+#define t_WRST 2 /* Warm Reset Time (us) */
+#define t_RSTIN 60 /* Reset Inactive Time (ms) */
+
+/*
+ * RPi3 GPIO pin configuration for TPM via bit-bang SPI
+ * References: https://pinout.xyz/pinout/spi
+ * - docs/design_documents/measured_boot_dtpm_poc.rst
+ */
+const struct gpio_spi_data tpm_rpi3_gpio_data = {
+ .cs_gpio = 7,
+ .sclk_gpio = 11,
+ .mosi_gpio = 10,
+ .miso_gpio = 9,
+ .reset_gpio = 24,
+ .spi_delay_us = 0,
+ .spi_mode = 0
+};
+
+/*
+ * When RST is asserted at certain points in time, then this
+ * triggers the TPM's security functions, in the case where
+ * multiple resets need to be asserted, there must be a wait
+ * of at least t_RSTIN between the resets
+ *
+ * In most cases this is not needed since RST is only being asserted
+ * once, ie for TPM initialization at the beginning of TFA.
+ */
+void tpm2_slb9670_reset_chip(struct gpio_spi_data *tpm_gpio_data)
+{
+ /*
+ * since we don't know the value of the pin before it was init to 1
+ * it is best to assume the state was 0, and account for that by
+ * adding an initial RST inactive delay
+ */
+ mdelay(t_RSTIN);
+ /* pull #RST pin to active low for 2us */
+ gpio_set_value(tpm_gpio_data->reset_gpio, 0);
+ udelay(t_WRST);
+ /* wait 60ms after warm reset before sending TPM commands */
+ gpio_set_value(tpm_gpio_data->reset_gpio, 1);
+ mdelay(t_RSTIN);
+}
+
+/*
+ * init GPIO pins for the Infineon slb9670 TPM
+ */
+void tpm2_slb9670_gpio_init(struct gpio_spi_data *tpm_gpio_data)
+{
+ gpio_set_value(tpm_gpio_data->cs_gpio, 1);
+ gpio_set_direction(tpm_gpio_data->cs_gpio, GPIO_DIR_OUT);
+
+ gpio_set_value(tpm_gpio_data->sclk_gpio, 0);
+ gpio_set_direction(tpm_gpio_data->sclk_gpio, GPIO_DIR_OUT);
+
+ gpio_set_value(tpm_gpio_data->mosi_gpio, 1);
+ gpio_set_direction(tpm_gpio_data->mosi_gpio, GPIO_DIR_OUT);
+
+ gpio_set_direction(tpm_gpio_data->miso_gpio, GPIO_DIR_IN);
+
+ gpio_set_value(tpm_gpio_data->reset_gpio, 1);
+ gpio_set_direction(tpm_gpio_data->reset_gpio, GPIO_DIR_OUT);
+}
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index 627416f..67fdead 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -1585,4 +1585,11 @@
#define CLUSTERPMCR_N_SHIFT U(11)
#define CLUSTERPMCR_N_MASK U(0x1f)
+/*******************************************************************************
+ * FEAT_MEC - Memory Encryption Contexts
+ ******************************************************************************/
+#define MECIDR_EL2 S3_4_C10_C8_7
+#define MECIDR_EL2_MECIDWidthm1_MASK U(0xf)
+#define MECIDR_EL2_MECIDWidthm1_SHIFT U(0)
+
#endif /* ARCH_H */
diff --git a/include/arch/aarch64/arch_helpers.h b/include/arch/aarch64/arch_helpers.h
index 7f87071..569182a 100644
--- a/include/arch/aarch64/arch_helpers.h
+++ b/include/arch/aarch64/arch_helpers.h
@@ -753,6 +753,9 @@
DEFINE_RENAME_SYSREG_RW_FUNCS(fpmr, FPMR)
+/* FEAT_MEC Registers */
+DEFINE_RENAME_SYSREG_READ_FUNC(mecidr_el2, MECIDR_EL2)
+
#define IS_IN_EL(x) \
(GET_EL(read_CurrentEl()) == MODE_EL##x)
diff --git a/include/drivers/gpio_spi.h b/include/drivers/gpio_spi.h
new file mode 100644
index 0000000..a926553
--- /dev/null
+++ b/include/drivers/gpio_spi.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GPIO_SPI_H
+#define GPIO_SPI_H
+
+#include <stdint.h>
+
+struct gpio_spi_data {
+ uint8_t cs_gpio, sclk_gpio, mosi_gpio, miso_gpio, reset_gpio;
+ uint32_t spi_delay_us;
+ unsigned int spi_mode;
+};
+
+struct spi_ops {
+ void (*get_access)(void);
+ void (*start)(void);
+ void (*stop)(void);
+ int (*xfer)(unsigned int bitlen, const void *dout, void *din);
+};
+
+struct spi_plat {
+ struct gpio_spi_data gpio_data;
+ const struct spi_ops *ops;
+};
+
+struct spi_plat *gpio_spi_init(struct gpio_spi_data *gpio_spi_data);
+
+#endif /* GPIO_SPI_H */
diff --git a/include/drivers/tpm/tpm2.h b/include/drivers/tpm/tpm2.h
new file mode 100644
index 0000000..c91acf8
--- /dev/null
+++ b/include/drivers/tpm/tpm2.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TPM2_H
+#define TPM2_H
+
+#include <assert.h>
+#include <endian.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <drivers/tpm/tpm2_chip.h>
+
+/* Return values */
+enum tpm_ret_value {
+ TPM_SUCCESS = 0,
+ TPM_ERR_RESPONSE = -1,
+ TPM_INVALID_PARAM = -2,
+ TPM_ERR_TIMEOUT = -3,
+ TPM_ERR_TRANSFER = -4,
+};
+
+/*
+ * TPM FIFO register space address offsets
+ */
+#define TPM_FIFO_REG_ACCESS 0x00
+#define TPM_FIFO_REG_INTR_ENABLE 0x08
+#define TPM_FIFO_REG_INTR_VECTOR 0x0C
+#define TPM_FIFO_REG_INTR_STS 0x10
+#define TPM_FIFO_REG_INTF_CAPS 0x14
+#define TPM_FIFO_REG_STATUS 0x18
+#define TPM_FIFO_REG_BURST_COUNT_LO 0x19
+#define TPM_FIFO_REG_BURST_COUNT_HI 0x20
+#define TPM_FIFO_REG_DATA_FIFO 0x24
+#define TPM_FIFO_REG_VENDID 0xF00
+#define TPM_FIFO_REG_DEVID 0xF02
+#define TPM_FIFO_REG_REVID 0xF04
+
+#define TPM_ST_NO_SESSIONS U(0x8001)
+#define TPM_ST_SESSIONS U(0x8002)
+
+#define TPM_SU_CLEAR U(0x0000)
+#define TPM_SU_STATE U(0x0001)
+
+#define TPM_MIN_AUTH_SIZE 9
+#define TPM_RS_PW 0x40000009
+#define TPM_ZERO_NONCE_SIZE 0
+#define TPM_ATTRIBUTES_DISABLE 0
+#define TPM_ZERO_HMAC_SIZE 0
+#define TPM_SINGLE_HASH_COUNT 1
+
+
+#define TPM_CMD_STARTUP U(0x0144)
+#define TPM_CMD_PCR_READ U(0x017E)
+#define TPM_CMD_PCR_EXTEND U(0x0182)
+
+#define TPM_RESPONSE_SUCCESS U(0x0000)
+
+#define TPM_ACCESS_ACTIVE_LOCALITY U(1 << 5)
+#define TPM_ACCESS_VALID U(1 << 7)
+#define TPM_ACCESS_RELINQUISH_LOCALITY U(1 << 5)
+#define TPM_ACCESS_REQUEST_USE U(1 << 1)
+#define TPM_ACCESS_REQUEST_PENDING U(1 << 2)
+
+#define TPM_STAT_VALID U(1 << 7)
+#define TPM_STAT_COMMAND_READY U(1 << 6)
+#define TPM_STAT_GO U(1 << 5)
+#define TPM_STAT_AVAIL U(1 << 4)
+#define TPM_STAT_EXPECT U(1 << 3)
+
+#define TPM_READ_HEADER -1
+
+#define TPM_HEADER_SIZE 10
+#define MAX_SIZE_CMDBUF 256
+#define MAX_CMD_DATA (MAX_SIZE_CMDBUF - TPM_HEADER_SIZE)
+
+#pragma pack(1)
+typedef struct tpm_cmd_hdr {
+ uint16_t tag;
+ uint32_t cmd_size;
+ uint32_t cmd_code;
+} tpm_cmd_hdr;
+
+typedef struct tpm_cmd {
+ tpm_cmd_hdr header;
+ uint8_t data[MAX_CMD_DATA];
+} tpm_cmd;
+#pragma pack()
+
+int tpm_interface_init(struct tpm_chip_data *chip_data, uint8_t locality);
+
+int tpm_interface_close(struct tpm_chip_data *chip_data, uint8_t locality);
+
+int tpm_startup(struct tpm_chip_data *chip_data, uint16_t mode);
+
+int tpm_pcr_extend(struct tpm_chip_data *chip_data, uint32_t index,
+ uint16_t algorithm, const uint8_t *digest,
+ uint32_t digest_len);
+
+#endif /* TPM2_H */
diff --git a/include/drivers/tpm/tpm2_chip.h b/include/drivers/tpm/tpm2_chip.h
new file mode 100644
index 0000000..ce052ad
--- /dev/null
+++ b/include/drivers/tpm/tpm2_chip.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifndef TPM2_CHIP_H
+#define TPM2_CHIP_H
+
+#define BYTE U(0x1)
+#define WORD U(0x2)
+#define DWORD U(0x4)
+
+struct tpm_chip_data {
+ uint8_t locality;
+ unsigned long timeout_msec_a, timeout_msec_b;
+ unsigned long timeout_msec_c, timeout_msec_d;
+ uint16_t address;
+};
+
+#endif /* TPM2_CHIP_H */
diff --git a/include/drivers/tpm/tpm2_interface.h b/include/drivers/tpm/tpm2_interface.h
new file mode 100644
index 0000000..6bfbf6c
--- /dev/null
+++ b/include/drivers/tpm/tpm2_interface.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TPM2_INTERFACE_H
+#define TPM2_INTERFACE_H
+
+#include "tpm2_chip.h"
+
+typedef struct interface_ops {
+ int (*get_info)(struct tpm_chip_data *chip_data, uint8_t locality);
+ int (*send)(struct tpm_chip_data *chip_data, const tpm_cmd *buf);
+ int (*receive)(struct tpm_chip_data *chip_data, tpm_cmd *buf);
+ int (*request_access)(struct tpm_chip_data *chip_data, uint8_t locality);
+ int (*release_locality)(struct tpm_chip_data *chip_data, uint8_t locality);
+} interface_ops_t;
+
+struct interface_ops *tpm_interface_getops(struct tpm_chip_data *chip_data, uint8_t locality);
+
+int tpm2_fifo_write_byte(uint16_t tpm_reg, uint8_t val);
+
+int tpm2_fifo_read_byte(uint16_t tpm_reg, uint8_t *val);
+
+int tpm2_fifo_read_chunk(uint16_t tpm_reg, uint8_t len, void *val);
+
+#endif /* TPM2_INTERFACE_H */
diff --git a/include/drivers/tpm/tpm2_slb9670/slb9670_gpio.h b/include/drivers/tpm/tpm2_slb9670/slb9670_gpio.h
new file mode 100644
index 0000000..59ae125
--- /dev/null
+++ b/include/drivers/tpm/tpm2_slb9670/slb9670_gpio.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "drivers/gpio_spi.h"
+
+#ifndef SLB9670_GPIO_H
+#define SLB9670_GPIO_H
+
+void tpm2_slb9670_reset_chip(struct gpio_spi_data *tpm_gpio_data);
+
+void tpm2_slb9670_gpio_init(struct gpio_spi_data *tpm_gpio_data);
+
+#endif /* SLB9670_GPIO_H */
diff --git a/include/lib/cpus/aarch64/cortex_a510.h b/include/lib/cpus/aarch64/cortex_a510.h
index 337aac3..fb09411 100644
--- a/include/lib/cpus/aarch64/cortex_a510.h
+++ b/include/lib/cpus/aarch64/cortex_a510.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2025, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -52,4 +52,12 @@
#define CORTEX_A510_CPUACTLR_EL1_DATA_CORRUPT_SHIFT U(18)
#define CORTEX_A510_CPUACTLR_EL1_DATA_CORRUPT_WIDTH U(1)
+#ifndef __ASSEMBLER__
+
+#if ERRATA_A510_2971420
+long check_erratum_cortex_a510_2971420(long cpu_rev);
+#endif
+
+#endif /* __ASSEMBLER__ */
+
#endif /* CORTEX_A510_H */
diff --git a/include/lib/cpus/aarch64/cortex_a715.h b/include/lib/cpus/aarch64/cortex_a715.h
index e9bd886..9980214 100644
--- a/include/lib/cpus/aarch64/cortex_a715.h
+++ b/include/lib/cpus/aarch64/cortex_a715.h
@@ -13,20 +13,14 @@
#define CORTEX_A715_BHB_LOOP_COUNT U(38)
/*******************************************************************************
- * CPU Auxiliary Control register 1 specific definitions.
+ * CPU Register Mappings
******************************************************************************/
+#define CORTEX_A715_CPUCFR_EL1 S3_0_C15_C0_0
#define CORTEX_A715_CPUACTLR_EL1 S3_0_C15_C1_0
-
-/*******************************************************************************
- * CPU Auxiliary Control register 2 specific definitions.
- ******************************************************************************/
#define CORTEX_A715_CPUACTLR2_EL1 S3_0_C15_C1_1
-
-/*******************************************************************************
- * CPU Extended Control register specific definitions
- ******************************************************************************/
+#define CORTEX_A715_CPUACTLR3_EL1 S3_0_C15_C1_2
#define CORTEX_A715_CPUECTLR_EL1 S3_0_C15_C1_4
-
+#define CORTEX_A715_CPUECTLR2_EL1 S3_0_C15_C1_5
#define CORTEX_A715_CPUPSELR_EL3 S3_6_C15_C8_0
#define CORTEX_A715_CPUPCR_EL3 S3_6_C15_C8_1
#define CORTEX_A715_CPUPOR_EL3 S3_6_C15_C8_2
diff --git a/include/lib/cpus/errata.h b/include/lib/cpus/errata.h
index 9eae276..8e28d46 100644
--- a/include/lib/cpus/errata.h
+++ b/include/lib/cpus/errata.h
@@ -67,10 +67,8 @@
}
#endif
-#if ERRATA_A520_2938996 || ERRATA_X4_2726228
-unsigned int check_if_affected_core(void);
-#endif
+bool check_if_trbe_disable_affected_core(void);
int check_wa_cve_2024_7881(void);
bool errata_ich_vmcr_el2_applies(void);
diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h
index b43f131..708cbcd 100644
--- a/include/plat/common/platform.h
+++ b/include/plat/common/platform.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2025, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -398,6 +398,7 @@
int plat_rmmd_el3_token_sign_pull_resp(struct el3_token_sign_response *resp);
size_t plat_rmmd_get_el3_rmm_shared_mem(uintptr_t *shared);
int plat_rmmd_load_manifest(struct rmm_manifest *manifest);
+int plat_rmmd_mecid_key_update(uint16_t mecid);
#endif
/*******************************************************************************
diff --git a/include/services/rmmd_svc.h b/include/services/rmmd_svc.h
index 0cc8628..8bf9319 100644
--- a/include/services/rmmd_svc.h
+++ b/include/services/rmmd_svc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2025, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -161,6 +161,18 @@
#define RMM_EL3_TOKEN_SIGN_PULL_RESP_OP U(2)
#define RMM_EL3_TOKEN_SIGN_GET_RAK_PUB_OP U(3)
+/* Starting RMM-EL3 interface version 0.5 */
+
+/*
+ * Function code to support update of MEC keys.
+ * The arguments of this SMC are:
+ * arg0 - Function ID.
+ * arg1 - MECID
+ * The return arguments are:
+ * ret0 - Status/Error
+ */
+#define RMM_MECID_KEY_UPDATE SMC64_RMMD_EL3_FID(U(6))
+
/* ECC Curve types for attest key generation */
#define ATTEST_KEY_CURVE_ECC_SECP384R1 U(0)
@@ -188,7 +200,7 @@
* Increase this when a bug is fixed, or a feature is added without
* breaking compatibility.
*/
-#define RMM_EL3_IFC_VERSION_MINOR (U(4))
+#define RMM_EL3_IFC_VERSION_MINOR (U(5))
#define RMM_EL3_INTERFACE_VERSION \
(((RMM_EL3_IFC_VERSION_MAJOR << 16) & 0x7FFFF) | \
diff --git a/lib/cpus/aarch64/cortex_a510.S b/lib/cpus/aarch64/cortex_a510.S
index 81a227b..6ec6742 100644
--- a/lib/cpus/aarch64/cortex_a510.S
+++ b/lib/cpus/aarch64/cortex_a510.S
@@ -178,6 +178,10 @@
ret
check_erratum_custom_end cortex_a510, ERRATUM(2313941)
+.global check_erratum_cortex_a510_2971420
+add_erratum_entry cortex_a510, ERRATUM(2971420), ERRATA_A510_2971420
+check_erratum_range cortex_a510, ERRATUM(2971420), CPU_REV(0, 1), CPU_REV(1, 3)
+
/* ----------------------------------------------------
* HW will do the cache maintenance while powering down
* ----------------------------------------------------
diff --git a/lib/cpus/aarch64/cortex_a715.S b/lib/cpus/aarch64/cortex_a715.S
index d9c0df2..d863cc5 100644
--- a/lib/cpus/aarch64/cortex_a715.S
+++ b/lib/cpus/aarch64/cortex_a715.S
@@ -119,6 +119,29 @@
check_erratum_ls cortex_a715, ERRATUM(2728106), CPU_REV(1, 1)
+workaround_reset_start cortex_a715, ERRATUM(2804830), ERRATA_A715_2804830
+ /* Workaround changes based on CORE_CACHE_PROTECTIONS field (bit 1) */
+ mrs x0, CORTEX_A715_CPUCFR_EL1
+ tbz x0, #1, wa_2804830_core_cache_prot_false
+
+ /* CORE_CACHE_PROTECTIONS==true */
+ sysreg_bit_set CORTEX_A715_CPUACTLR3_EL1, BIT(2)
+ sysreg_bit_set CORTEX_A715_CPUECTLR_EL1, BIT(23)
+ b wa_2804830_done
+
+ /* CORE_CACHE_PROTECTIONS==false */
+wa_2804830_core_cache_prot_false:
+ sysreg_bit_set CORTEX_A715_CPUECTLR2_EL1, BIT(7)
+
+wa_2804830_done:
+workaround_reset_end cortex_a715, ERRATUM(2804830)
+
+check_erratum_ls cortex_a715, ERRATUM(2804830), CPU_REV(1, 2)
+
+add_erratum_entry cortex_a715, ERRATUM(3699560), ERRATA_A715_3699560
+
+check_erratum_ls cortex_a715, ERRATUM(3699560), CPU_REV(1, 3)
+
workaround_reset_start cortex_a715, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
#if IMAGE_BL31
/*
@@ -131,10 +154,6 @@
check_erratum_chosen cortex_a715, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
-add_erratum_entry cortex_a715, ERRATUM(3699560), ERRATA_A715_3699560
-
-check_erratum_ls cortex_a715, ERRATUM(3699560), CPU_REV(1, 3)
-
cpu_reset_func_start cortex_a715
/* Disable speculative loads */
msr SSBS, xzr
diff --git a/lib/cpus/cpu-ops.mk b/lib/cpus/cpu-ops.mk
index 8136624..4cfa765 100644
--- a/lib/cpus/cpu-ops.mk
+++ b/lib/cpus/cpu-ops.mk
@@ -966,6 +966,11 @@
# Cortex-A510 cpu and is fixed in r1p3.
CPU_FLAG_LIST += ERRATA_A510_2684597
+# Flag to apply erratum 2971420 workaround during context switch. This erratum
+# applies to revisions r0p1, r0p2, r0p3, r1p0, r1p1, r1p2 and r1p3 of the
+# Cortex-A510 cpu and is still open.
+CPU_FLAG_LIST += ERRATA_A510_2971420
+
# Flag to apply erratum 2630792 workaround during reset. This erratum applies
# to revisions r0p0, r0p1 of the Cortex-A520 cpu and is still open.
CPU_FLAG_LIST += ERRATA_A520_2630792
@@ -1038,6 +1043,10 @@
# only to revision r0p0, r1p0 and r1p1. It is fixed in r1p2.
CPU_FLAG_LIST += ERRATA_A715_2728106
+# Flag to apply erratum 2804830 workaround during reset. This erratum applies
+# to revisions r0p0, r1p0, r1p1 and r1p2. It is fixed in r1p3.
+CPU_FLAG_LIST += ERRATA_A715_2804830
+
# Flag to apply erratum 3699560 workaround during context save/restore of
# ICH_VMCR_EL2 reg. This erratum applies to revisions r0p0, r1p0, r1p2, r1p3
# of the Cortex-A715 cpu and is still open.
diff --git a/lib/cpus/errata_common.c b/lib/cpus/errata_common.c
index a391430..0530647 100644
--- a/lib/cpus/errata_common.c
+++ b/lib/cpus/errata_common.c
@@ -9,6 +9,7 @@
#include <arch.h>
#include <arch_helpers.h>
#include <cortex_a75.h>
+#include <cortex_a510.h>
#include <cortex_a520.h>
#include <cortex_a710.h>
#include <cortex_a715.h>
@@ -25,21 +26,26 @@
#include <neoverse_n3.h>
#include <neoverse_v3.h>
-#if ERRATA_A520_2938996 || ERRATA_X4_2726228
-unsigned int check_if_affected_core(void)
+bool check_if_trbe_disable_affected_core(void)
{
- uint32_t midr_val = read_midr();
- long rev_var = cpu_get_rev_var();
-
- if (EXTRACT_PARTNUM(midr_val) == EXTRACT_PARTNUM(CORTEX_A520_MIDR)) {
- return check_erratum_cortex_a520_2938996(rev_var);
- } else if (EXTRACT_PARTNUM(midr_val) == EXTRACT_PARTNUM(CORTEX_X4_MIDR)) {
- return check_erratum_cortex_x4_2726228(rev_var);
+ switch (EXTRACT_PARTNUM(read_midr())) {
+#if ERRATA_A520_2938996
+ case EXTRACT_PARTNUM(CORTEX_A520_MIDR):
+ return check_erratum_cortex_a520_2938996(cpu_get_rev_var()) == ERRATA_APPLIES;
+#endif
+#if ERRATA_X4_2726228
+ case EXTRACT_PARTNUM(CORTEX_X4_MIDR):
+ return check_erratum_cortex_x4_2726228(cpu_get_rev_var()) == ERRATA_APPLIES;
+#endif
+#if ERRATA_A510_2971420
+ case EXTRACT_PARTNUM(CORTEX_A510_MIDR):
+ return check_erratum_cortex_a510_2971420(cpu_get_rev_var()) == ERRATA_APPLIES;
+#endif
+ default:
+ break;
}
-
- return ERRATA_NOT_APPLIES;
+ return false;
}
-#endif
#if ERRATA_A75_764081
bool errata_a75_764081_applies(void)
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
index c35aae9..f4fec42 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -905,7 +905,7 @@
sme_init_el2_unused();
}
- if (is_feat_mops_supported()) {
+ if (is_feat_mops_supported() && is_feat_hcx_supported()) {
write_hcrx_el2(read_hcrx_el2() | HCRX_EL2_MSCEn_BIT);
}
@@ -1673,13 +1673,11 @@
}
#endif
-#if ERRATA_A520_2938996 || ERRATA_X4_2726228
- if (check_if_affected_core() == ERRATA_APPLIES) {
+ if (check_if_trbe_disable_affected_core()) {
if (is_feat_trbe_supported()) {
trbe_disable(ctx);
}
}
-#endif
#if ENABLE_FEAT_TCR2 == FEAT_STATE_CHECK_ASYMMETRIC
el3_state_t *el3_state = get_el3state_ctx(ctx);
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index ec2aa1b..906e5d7 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -192,6 +192,9 @@
# Option to build TF with Measured Boot support
MEASURED_BOOT := 0
+# Option to build TF with Discrete TPM support
+DISCRETE_TPM := 0
+
# Option to enable the DICE Protection Environmnet as a Measured Boot backend
DICE_PROTECTION_ENVIRONMENT :=0
diff --git a/plat/amd/versal2/include/def.h b/plat/amd/versal2/include/def.h
index 938b118..9bef9d0 100644
--- a/plat/amd/versal2/include/def.h
+++ b/plat/amd/versal2/include/def.h
@@ -15,14 +15,14 @@
#define MAX_INTR_EL3 2U
/* List all consoles */
-#define VERSAL2_CONSOLE_ID_none 0
-#define VERSAL2_CONSOLE_ID_pl011 1
-#define VERSAL2_CONSOLE_ID_pl011_0 1
-#define VERSAL2_CONSOLE_ID_pl011_1 2
-#define VERSAL2_CONSOLE_ID_dcc 3
-#define VERSAL2_CONSOLE_ID_dtb 4
+#define CONSOLE_ID_none 0
+#define CONSOLE_ID_pl011 1
+#define CONSOLE_ID_pl011_0 1
+#define CONSOLE_ID_pl011_1 2
+#define CONSOLE_ID_dcc 3
+#define CONSOLE_ID_dtb 4
-#define CONSOLE_IS(con) (VERSAL2_CONSOLE_ID_ ## con == VERSAL2_CONSOLE)
+#define CONSOLE_IS(con) (CONSOLE_ID_ ## con == CONSOLE)
/* Runtime console */
#define RT_CONSOLE_ID_pl011 1
diff --git a/plat/amd/versal2/platform.mk b/plat/amd/versal2/platform.mk
index 489a063..7cd864e 100644
--- a/plat/amd/versal2/platform.mk
+++ b/plat/amd/versal2/platform.mk
@@ -71,13 +71,13 @@
USE_COHERENT_MEM := 0
HW_ASSISTED_COHERENCY := 1
-VERSAL2_CONSOLE ?= pl011
-ifeq (${VERSAL2_CONSOLE}, $(filter ${VERSAL2_CONSOLE},pl011 pl011_0 pl011_1 dcc dtb none))
+CONSOLE ?= pl011
+ifeq (${CONSOLE}, $(filter ${CONSOLE},pl011 pl011_0 pl011_1 dcc dtb none))
else
- $(error "Please define VERSAL2_CONSOLE")
+ $(error "Please define CONSOLE")
endif
-$(eval $(call add_define_val,VERSAL2_CONSOLE,VERSAL2_CONSOLE_ID_${VERSAL2_CONSOLE}))
+$(eval $(call add_define_val,CONSOLE,CONSOLE_ID_${CONSOLE}))
# Runtime console in default console in DEBUG build
ifeq ($(DEBUG), 1)
diff --git a/plat/arm/board/fvp/fvp_common.c b/plat/arm/board/fvp/fvp_common.c
index 7d76814..98d4bbc 100644
--- a/plat/arm/board/fvp/fvp_common.c
+++ b/plat/arm/board/fvp/fvp_common.c
@@ -7,6 +7,8 @@
#include <assert.h>
#include <string.h>
+#include <arch.h>
+#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/arm/cci.h>
#include <drivers/arm/ccn.h>
@@ -775,4 +777,16 @@
return 0;
}
+
+/*
+ * Update encryption key associated with @mecid.
+ */
+int plat_rmmd_mecid_key_update(uint16_t mecid)
+{
+ /*
+ * FVP does not provide an interface to change the encryption key associated
+ * with MECID. Hence always return success.
+ */
+ return 0;
+}
#endif /* ENABLE_RME */
diff --git a/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_common.c b/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_common.c
index 364bce1..b1ee5e6 100644
--- a/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_common.c
+++ b/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_common.c
@@ -187,6 +187,17 @@
return 0;
}
+/*
+ * Update encryption key associated with @mecid.
+ */
+int plat_rmmd_mecid_key_update(uint16_t mecid)
+{
+ /*
+ * TODO
+ */
+ return 0;
+}
+
int plat_rse_comms_init(void)
{
struct mhu_addr mhu_addresses;
diff --git a/plat/qemu/common/qemu_common.c b/plat/qemu/common/qemu_common.c
index a88297d..4a79a90 100644
--- a/plat/qemu/common/qemu_common.c
+++ b/plat/qemu/common/qemu_common.c
@@ -400,6 +400,18 @@
return 0;
}
+
+/*
+ * Update encryption key associated with @mecid.
+ */
+int plat_rmmd_mecid_key_update(uint16_t mecid)
+{
+ /*
+ * QEMU does not provide an interface to change the encryption key
+ * associated with MECID. Hence always return success.
+ */
+ return 0;
+}
#endif /* ENABLE_RME */
/**
diff --git a/plat/rpi/common/rpi3_common.c b/plat/rpi/common/rpi3_common.c
index 4e3c9f2..4908354 100644
--- a/plat/rpi/common/rpi3_common.c
+++ b/plat/rpi/common/rpi3_common.c
@@ -75,6 +75,9 @@
#endif
MAP_DEVICE0,
MAP_FIP,
+#if MEASURED_BOOT
+ RPI3_MAP_BL1_RW,
+#endif
MAP_NS_DRAM0,
#ifdef BL32_BASE
MAP_BL32_MEM,
diff --git a/plat/rpi/rpi3/include/platform_def.h b/plat/rpi/rpi3/include/platform_def.h
index 757c64a..eb2914a 100644
--- a/plat/rpi/rpi3/include/platform_def.h
+++ b/plat/rpi/rpi3/include/platform_def.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2025, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -172,6 +172,14 @@
#define BL1_RW_LIMIT (BL_RAM_BASE + BL_RAM_SIZE)
/*
+ * In order to access the TCG Event Log in BL2, we need to expose the BL1_RW region
+ * where the log resides.
+ */
+#define RPI3_MAP_BL1_RW MAP_REGION_FLAT(BL1_RW_BASE, \
+ BL1_RW_LIMIT - BL1_RW_BASE, \
+ MT_MEMORY | MT_RW | MT_SECURE)
+
+/*
* BL2 specific defines.
*
* Put BL2 just below BL31. BL2_BASE is calculated using the current BL2 debug
@@ -261,4 +269,15 @@
*/
#define SYS_COUNTER_FREQ_IN_TICKS ULL(19200000)
+/*
+ * TCG Event Log
+ */
+#define PLAT_ARM_EVENT_LOG_MAX_SIZE UL(0x400)
+
+/*
+ * NT_FW_CONFIG magic dram addr and max size
+ */
+#define PLAT_RPI3_DTO_BASE ULL(0x11530000)
+#define PLAT_RPI3_DTO_MAX_SIZE ULL(0x001000)
+
#endif /* PLATFORM_DEF_H */
diff --git a/plat/rpi/rpi3/include/rpi3_measured_boot.h b/plat/rpi/rpi3/include/rpi3_measured_boot.h
new file mode 100644
index 0000000..67ad479
--- /dev/null
+++ b/plat/rpi/rpi3/include/rpi3_measured_boot.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2025, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPI3_MEASURED_BOOT_H
+#define RPI3_MEASURED_BOOT_H
+
+#include <stdint.h>
+
+#include <arch_helpers.h>
+
+void rpi3_mboot_fetch_eventlog_info(uint8_t **eventlog_addr, size_t *eventlog_size);
+
+int rpi3_set_nt_fw_info(size_t log_size, uintptr_t *ns_log_addr);
+
+#endif /* RPI3_MEASURED_BOOT_H */
diff --git a/plat/rpi/rpi3/platform.mk b/plat/rpi/rpi3/platform.mk
index fc51bec..5297177 100644
--- a/plat/rpi/rpi3/platform.mk
+++ b/plat/rpi/rpi3/platform.mk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2013-2025, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -8,7 +8,8 @@
include lib/xlat_tables_v2/xlat_tables.mk
PLAT_INCLUDES := -Iplat/rpi/common/include \
- -Iplat/rpi/rpi3/include
+ -Iplat/rpi/rpi3/include \
+ -Iinclude/lib/libfdt
PLAT_BL_COMMON_SOURCES := drivers/ti/uart/aarch64/16550_console.S \
drivers/arm/pl011/aarch64/pl011_console.S \
@@ -20,6 +21,40 @@
plat/rpi/common/rpi3_console_dual.c \
${XLAT_TABLES_LIB_SRCS}
+ifeq (${DISCRETE_TPM},1)
+TPM2_MK := drivers/tpm/tpm2.mk
+$(info Including ${TPM2_MK})
+include ${TPM2_MK}
+endif
+
+ifeq (${TPM_INTERFACE},FIFO_SPI)
+PLAT_BL_COMMON_SOURCES += drivers/gpio/gpio_spi.c \
+ drivers/tpm/tpm2_slb9670/slb9670_gpio.c
+endif
+
+ifeq (${MEASURED_BOOT},1)
+MEASURED_BOOT_MK := drivers/measured_boot/event_log/event_log.mk
+$(info Including ${MEASURED_BOOT_MK})
+include ${MEASURED_BOOT_MK}
+
+PLAT_BL_COMMON_SOURCES += $(TPM2_SOURCES) \
+ ${EVENT_LOG_SOURCES}
+
+BL1_SOURCES += plat/rpi/rpi3/rpi3_bl1_mboot.c
+BL2_SOURCES += plat/rpi/rpi3/rpi3_bl2_mboot.c \
+ plat/rpi/rpi3/rpi3_dyn_cfg_helpers.c \
+ common/fdt_wrappers.c \
+ common/fdt_fixup.c
+
+CRYPTO_SOURCES := drivers/auth/crypto_mod.c
+
+BL1_SOURCES += ${CRYPTO_SOURCES}
+BL2_SOURCES += ${CRYPTO_SOURCES}
+
+include drivers/auth/mbedtls/mbedtls_crypto.mk
+
+endif
+
BL1_SOURCES += drivers/io/io_fip.c \
drivers/io/io_memmap.c \
drivers/io/io_storage.c \
diff --git a/plat/rpi/rpi3/rpi3_bl1_mboot.c b/plat/rpi/rpi3/rpi3_bl1_mboot.c
new file mode 100644
index 0000000..4294365
--- /dev/null
+++ b/plat/rpi/rpi3/rpi3_bl1_mboot.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdint.h>
+
+#include <common/desc_image_load.h>
+#include <common/ep_info.h>
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/gpio_spi.h>
+#include <drivers/measured_boot/event_log/event_log.h>
+#include <drivers/measured_boot/metadata.h>
+#include <drivers/tpm/tpm2.h>
+#include <drivers/tpm/tpm2_chip.h>
+#include <drivers/tpm/tpm2_slb9670/slb9670_gpio.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#include <rpi_shared.h>
+
+/* Event Log data */
+uint8_t event_log[PLAT_ARM_EVENT_LOG_MAX_SIZE];
+
+/* RPI3 table with platform specific image IDs, names and PCRs */
+const event_log_metadata_t rpi3_event_log_metadata[] = {
+ { FW_CONFIG_ID, MBOOT_FW_CONFIG_STRING, PCR_0 },
+ { TB_FW_CONFIG_ID, MBOOT_TB_FW_CONFIG_STRING, PCR_0 },
+ { BL2_IMAGE_ID, MBOOT_BL2_IMAGE_STRING, PCR_0 },
+
+ { EVLOG_INVALID_ID, NULL, (unsigned int)(-1) } /* Terminator */
+};
+
+#if DISCRETE_TPM
+extern struct tpm_chip_data tpm_chip_data;
+#if (TPM_INTERFACE == FIFO_SPI)
+extern struct gpio_spi_data tpm_rpi3_gpio_data;
+struct spi_plat *spidev;
+#endif
+
+static void rpi3_bl1_tpm_early_interface_setup(void)
+{
+#if (TPM_INTERFACE == FIFO_SPI)
+ tpm2_slb9670_gpio_init(&tpm_rpi3_gpio_data);
+
+ tpm2_slb9670_reset_chip(&tpm_rpi3_gpio_data);
+
+ spidev = gpio_spi_init(&tpm_rpi3_gpio_data);
+#endif
+}
+#endif
+
+void bl1_plat_mboot_init(void)
+{
+#if DISCRETE_TPM
+ int rc;
+
+ rpi3_bl1_tpm_early_interface_setup();
+ rc = tpm_interface_init(&tpm_chip_data, 0);
+ if (rc != 0) {
+ ERROR("BL1: TPM interface init failed\n");
+ panic();
+ }
+ rc = tpm_startup(&tpm_chip_data, TPM_SU_CLEAR);
+ if (rc != 0) {
+ ERROR("BL1: TPM Startup failed\n");
+ panic();
+ }
+#endif
+
+ event_log_init(event_log, event_log + sizeof(event_log));
+ event_log_write_header();
+}
+
+void bl1_plat_mboot_finish(void)
+{
+ size_t event_log_cur_size;
+ image_desc_t *image_desc;
+ entry_point_info_t *ep_info;
+
+ event_log_cur_size = event_log_get_cur_size(event_log);
+ image_desc = bl1_plat_get_image_desc(BL2_IMAGE_ID);
+ assert(image_desc != NULL);
+
+ /* Get the entry point info */
+ ep_info = &image_desc->ep_info;
+ ep_info->args.arg2 = (uint64_t) event_log;
+ ep_info->args.arg3 = (uint32_t) event_log_cur_size;
+
+#if DISCRETE_TPM
+ int rc;
+
+ /* relinquish control of TPM locality 0 and close interface */
+ rc = tpm_interface_close(&tpm_chip_data, 0);
+ if (rc != 0) {
+ ERROR("BL1: TPM interface close failed\n");
+ panic();
+ }
+#endif
+}
+
+int plat_mboot_measure_image(unsigned int image_id, image_info_t *image_data)
+{
+ int rc = 0;
+ unsigned char hash_data[CRYPTO_MD_MAX_SIZE];
+ const event_log_metadata_t *metadata_ptr = rpi3_event_log_metadata;
+
+ rc = event_log_measure(image_data->image_base, image_data->image_size, hash_data);
+ if (rc != 0) {
+ return rc;
+ }
+
+#if DISCRETE_TPM
+ rc = tpm_pcr_extend(&tpm_chip_data, 0, TPM_ALG_ID, hash_data, TCG_DIGEST_SIZE);
+ if (rc != 0) {
+ ERROR("BL1: TPM PCR-0 extend failed\n");
+ panic();
+ }
+#endif
+
+ while ((metadata_ptr->id != EVLOG_INVALID_ID) &&
+ (metadata_ptr->id != image_id)) {
+ metadata_ptr++;
+ }
+ assert(metadata_ptr->id != EVLOG_INVALID_ID);
+
+ event_log_record(hash_data, EV_POST_CODE, metadata_ptr);
+
+ /* Dump Event Log for user view */
+ dump_event_log((uint8_t *)event_log, event_log_get_cur_size(event_log));
+
+ return rc;
+}
diff --git a/plat/rpi/rpi3/rpi3_bl2_mboot.c b/plat/rpi/rpi3/rpi3_bl2_mboot.c
new file mode 100644
index 0000000..55c6923
--- /dev/null
+++ b/plat/rpi/rpi3/rpi3_bl2_mboot.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdint.h>
+
+#include "./include/rpi3_measured_boot.h"
+
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/gpio_spi.h>
+#include <drivers/measured_boot/event_log/event_log.h>
+#include <drivers/measured_boot/metadata.h>
+#include <drivers/tpm/tpm2.h>
+#include <drivers/tpm/tpm2_chip.h>
+#include <drivers/tpm/tpm2_slb9670/slb9670_gpio.h>
+#include <plat/common/common_def.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <tools_share/tbbr_oid.h>
+
+/* RPI3 table with platform specific image IDs, names and PCRs */
+const event_log_metadata_t rpi3_event_log_metadata[] = {
+ { BL31_IMAGE_ID, MBOOT_BL31_IMAGE_STRING, PCR_0 },
+ { BL33_IMAGE_ID, MBOOT_BL33_IMAGE_STRING, PCR_0 },
+ { NT_FW_CONFIG_ID, MBOOT_NT_FW_CONFIG_STRING, PCR_0 },
+
+ { EVLOG_INVALID_ID, NULL, (unsigned int)(-1) } /* Terminator */
+};
+
+#if DISCRETE_TPM
+extern struct tpm_chip_data tpm_chip_data;
+#if (TPM_INTERFACE == FIFO_SPI)
+extern struct gpio_spi_data tpm_rpi3_gpio_data;
+struct spi_plat *spidev;
+#endif
+
+static void rpi3_bl2_tpm_early_interface_setup(void)
+{
+#if (TPM_INTERFACE == FIFO_SPI)
+ tpm2_slb9670_gpio_init(&tpm_rpi3_gpio_data);
+
+ spidev = gpio_spi_init(&tpm_rpi3_gpio_data);
+#endif
+}
+#endif
+
+static uint8_t *event_log_start;
+static size_t event_log_size;
+
+void bl2_plat_mboot_init(void)
+{
+ uint8_t *bl2_event_log_start;
+ uint8_t *bl2_event_log_finish;
+
+#if DISCRETE_TPM
+ int rc;
+
+ rpi3_bl2_tpm_early_interface_setup();
+ rc = tpm_interface_init(&tpm_chip_data, 0);
+ if (rc != 0) {
+ ERROR("BL2: TPM interface init failed\n");
+ panic();
+ }
+#endif
+
+ rpi3_mboot_fetch_eventlog_info(&event_log_start, &event_log_size);
+ bl2_event_log_start = event_log_start + event_log_size;
+ bl2_event_log_finish = event_log_start + PLAT_ARM_EVENT_LOG_MAX_SIZE;
+ event_log_init(bl2_event_log_start, bl2_event_log_finish);
+}
+
+void bl2_plat_mboot_finish(void)
+{
+ int rc;
+
+ /* Event Log address in Non-Secure memory */
+ uintptr_t ns_log_addr;
+
+ /* Event Log filled size */
+ size_t event_log_cur_size;
+
+ event_log_cur_size = event_log_get_cur_size((uint8_t *)event_log_start);
+
+ /* write the eventlog addr and size to NT_FW_CONFIG TPM entry */
+ rc = rpi3_set_nt_fw_info(event_log_cur_size, &ns_log_addr);
+ if (rc != 0) {
+ ERROR("%s(): Unable to update %s_FW_CONFIG\n",
+ __func__, "NT");
+ /*
+ * fatal error due to Bl33 maintaining the assumption
+ * that the eventlog is successfully passed via
+ * NT_FW_CONFIG.
+ */
+ panic();
+ }
+
+ /* Copy Event Log to Non-secure memory */
+ (void)memcpy((void *)ns_log_addr, (const void *)event_log_start,
+ event_log_cur_size);
+
+ /* Ensure that the Event Log is visible in Non-secure memory */
+ flush_dcache_range(ns_log_addr, event_log_cur_size);
+
+ /* Dump Event Log for user view */
+ dump_event_log((uint8_t *)event_log_start, event_log_cur_size);
+
+#if DISCRETE_TPM
+ /* relinquish control of TPM locality 0 and close interface */
+ rc = tpm_interface_close(&tpm_chip_data, 0);
+ if (rc != 0) {
+ ERROR("BL2: TPM interface close failed\n");
+ panic();
+ }
+#endif
+}
+
+int plat_mboot_measure_image(unsigned int image_id, image_info_t *image_data)
+{
+ int rc = 0;
+
+ unsigned char hash_data[CRYPTO_MD_MAX_SIZE];
+ const event_log_metadata_t *metadata_ptr = rpi3_event_log_metadata;
+
+ /* Measure the payload with algorithm selected by EventLog driver */
+ rc = event_log_measure(image_data->image_base, image_data->image_size, hash_data);
+ if (rc != 0) {
+ return rc;
+ }
+
+#if DISCRETE_TPM
+ rc = tpm_pcr_extend(&tpm_chip_data, 0, TPM_ALG_ID, hash_data, TCG_DIGEST_SIZE);
+ if (rc != 0) {
+ ERROR("BL2: TPM PCR-0 extend failed\n");
+ panic();
+ }
+#endif
+
+ while ((metadata_ptr->id != EVLOG_INVALID_ID) &&
+ (metadata_ptr->id != image_id)) {
+ metadata_ptr++;
+ }
+ assert(metadata_ptr->id != EVLOG_INVALID_ID);
+
+ event_log_record(hash_data, EV_POST_CODE, metadata_ptr);
+
+ return rc;
+}
diff --git a/plat/rpi/rpi3/rpi3_bl2_setup.c b/plat/rpi/rpi3/rpi3_bl2_setup.c
index 80e4d8d..2f57b32 100644
--- a/plat/rpi/rpi3/rpi3_bl2_setup.c
+++ b/plat/rpi/rpi3/rpi3_bl2_setup.c
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2025, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
-#include <platform_def.h>
+#include "./include/rpi3_measured_boot.h"
#include <arch_helpers.h>
#include <common/bl_common.h>
@@ -18,6 +18,7 @@
#include <drivers/generic_delay_timer.h>
#include <drivers/rpi3/gpio/rpi3_gpio.h>
#include <drivers/rpi3/sdhost/rpi3_sdhost.h>
+#include <platform_def.h>
#include <rpi_shared.h>
@@ -27,6 +28,10 @@
/* Data structure which holds the MMC info */
static struct mmc_device_info mmc_info;
+/* Variables that hold the eventlog addr and size for use in BL2 Measured Boot */
+static uint8_t *event_log_start;
+static size_t event_log_size;
+
static void rpi3_sdhost_setup(void)
{
struct rpi3_sdhost_params params;
@@ -41,6 +46,12 @@
rpi3_sdhost_init(¶ms, &mmc_info);
}
+void rpi3_mboot_fetch_eventlog_info(uint8_t **eventlog_addr, size_t *eventlog_size)
+{
+ *eventlog_addr = event_log_start;
+ *eventlog_size = event_log_size;
+}
+
/*******************************************************************************
* BL1 has passed the extents of the trusted SRAM that should be visible to BL2
* in x0. This memory layout is sitting at the base of the free trusted SRAM.
@@ -67,6 +78,10 @@
/* Setup SDHost driver */
rpi3_sdhost_setup();
+ /* populate eventlog addr and size for use in bl2 mboot */
+ event_log_start = (uint8_t *)(uintptr_t)arg2;
+ event_log_size = arg3;
+
plat_rpi3_io_setup();
}
diff --git a/plat/rpi/rpi3/rpi3_dyn_cfg_helpers.c b/plat/rpi/rpi3/rpi3_dyn_cfg_helpers.c
new file mode 100644
index 0000000..7c2e6e7
--- /dev/null
+++ b/plat/rpi/rpi3/rpi3_dyn_cfg_helpers.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2025, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/desc_image_load.h>
+#include <common/fdt_wrappers.h>
+#include <libfdt.h>
+#include <platform_def.h>
+
+#define DTB_PROP_HW_LOG_ADDR "tpm_event_log_addr"
+#define DTB_PROP_HW_LOG_SIZE "tpm_event_log_size"
+
+static int rpi3_event_log_fdt_init_overlay(uintptr_t dt_base, int dt_size)
+{
+ int ret;
+ int offset;
+ void *dtb = (void *)dt_base;
+
+ ret = fdt_create_empty_tree(dtb, dt_size);
+ if (ret < 0) {
+ ERROR("cannot create empty dtb tree: %s\n",
+ fdt_strerror(ret));
+ return ret;
+ }
+
+ offset = fdt_path_offset(dtb, "/");
+ if (offset < 0) {
+ ERROR("cannot find root of the tree: %s\n",
+ fdt_strerror(offset));
+ return offset;
+ }
+
+ offset = fdt_add_subnode(dtb, offset, "fragment@0");
+ if (offset < 0) {
+ ERROR("cannot add fragment node: %s\n",
+ fdt_strerror(offset));
+ return offset;
+ }
+
+ ret = fdt_setprop_string(dtb, offset, "target-path", "/");
+ if (ret < 0) {
+ ERROR("cannot set target-path property: %s\n",
+ fdt_strerror(ret));
+ return ret;
+ }
+
+ offset = fdt_add_subnode(dtb, offset, "__overlay__");
+ if (offset < 0) {
+ ERROR("cannot add __overlay__ node: %s\n",
+ fdt_strerror(offset));
+ return ret;
+ }
+
+ offset = fdt_add_subnode(dtb, offset, "tpm_event_log");
+ if (offset < 0) {
+ ERROR("cannot add tpm_event_log node: %s\n",
+ fdt_strerror(offset));
+ return offset;
+ }
+
+ ret = fdt_setprop_string(dtb, offset, "compatible",
+ "arm,tpm_event_log");
+ if (ret < 0) {
+ ERROR("cannot set compatible property: %s\n",
+ fdt_strerror(ret));
+ return ret;
+ }
+
+ ret = fdt_setprop_u64(dtb, offset, "tpm_event_log_addr", 0);
+ if (ret < 0) {
+ ERROR("cannot set tpm_event_log_addr property: %s\n",
+ fdt_strerror(ret));
+ return ret;
+ }
+
+ ret = fdt_setprop_u32(dtb, offset, "tpm_event_log_size", 0);
+ if (ret < 0) {
+ ERROR("cannot set tpm_event_log_size property: %s\n",
+ fdt_strerror(ret));
+ return ret;
+ }
+
+ return ret;
+}
+
+/*
+ * Write the Event Log address and its size in the DTB.
+ *
+ * This function is supposed to be called only by BL2.
+ *
+ * Returns:
+ * 0 = success
+ * < 0 = error
+ */
+static int rpi3_set_event_log_info(uintptr_t config_base,
+ uintptr_t log_addr, size_t log_size)
+{
+ /* As libfdt uses void *, we can't avoid this cast */
+ void *dtb = (void *)config_base;
+ /* compatible is set based on the following tpm_tis_spi guidelines from
+ * https://www.kernel.org/doc/Documentation/devicetree/bindings
+ * /security/tpm/tpm_tis_spi.txt
+ */
+ const char *compatible_tpm = "arm,tpm_event_log";
+ uint64_t base = cpu_to_fdt64(log_addr);
+ uint32_t sz = cpu_to_fdt32(log_size);
+ int err, node;
+
+ err = fdt_open_into(dtb, dtb, PLAT_RPI3_DTO_MAX_SIZE);
+ if (err < 0) {
+ ERROR("Invalid Device Tree at %p: error %d\n", dtb, err);
+ return err;
+ }
+
+ /*
+ * Verify that the DTB is valid, before attempting to write to it,
+ * and get the DTB root node.
+ */
+
+ /* Check if the pointer to DT is correct */
+ err = fdt_check_header(dtb);
+ if (err < 0) {
+ WARN("Invalid DTB file passed\n");
+ return err;
+ }
+
+ /*
+ * Find the TPM node in device tree.
+ */
+ node = fdt_node_offset_by_compatible(dtb, -1, compatible_tpm);
+ if (node < 0) {
+ ERROR("The compatible property '%s' not%s", compatible_tpm,
+ " found in the config\n");
+ return node;
+ }
+
+ err = fdt_setprop(dtb, node, DTB_PROP_HW_LOG_ADDR, &base, 8);
+ if (err < 0) {
+ ERROR("Failed to add log addr err %d\n", err);
+ return err;
+ }
+
+ err = fdt_setprop(dtb, node, DTB_PROP_HW_LOG_SIZE, &sz, 4);
+ if (err < 0) {
+ ERROR("Failed to add log size err %d\n", err);
+ return err;
+ }
+
+ err = fdt_pack(dtb);
+ if (err < 0) {
+ ERROR("Failed to pack Device Tree at %p: error %d\n", dtb, err);
+ return err;
+ }
+
+ /*
+ * Ensure that the info written to the DTB is visible
+ * to other images.
+ */
+ flush_dcache_range(config_base, fdt_totalsize(dtb));
+
+ return err;
+}
+
+/*
+ * This function writes the Event Log address and its size
+ * in the RPi3 DTB.
+ *
+ * This function is supposed to be called only by BL2.
+ *
+ * Returns:
+ * 0 = success
+ * < 0 = error
+ */
+int rpi3_set_nt_fw_info(size_t log_size, uintptr_t *ns_log_addr)
+{
+ uintptr_t ns_addr;
+ int err;
+
+ assert(ns_log_addr != NULL);
+
+ ns_addr = PLAT_RPI3_DTO_BASE + PLAT_RPI3_DTO_MAX_SIZE;
+
+ rpi3_event_log_fdt_init_overlay(PLAT_RPI3_DTO_BASE,
+ PLAT_RPI3_DTO_MAX_SIZE);
+
+ /* Write the Event Log address and its size in the DTB */
+ err = rpi3_set_event_log_info(PLAT_RPI3_DTO_BASE,
+ ns_addr, log_size);
+
+ /* Return Event Log address in Non-secure memory */
+ *ns_log_addr = (err < 0) ? 0UL : ns_addr;
+ return err;
+}
diff --git a/services/std_svc/rmmd/rmmd_main.c b/services/std_svc/rmmd/rmmd_main.c
index 4ddf484..e94b048 100644
--- a/services/std_svc/rmmd/rmmd_main.c
+++ b/services/std_svc/rmmd/rmmd_main.c
@@ -470,6 +470,33 @@
return E_RMM_OK;
}
+/*
+ * Update encryption key associated with @mecid.
+ */
+static int rmmd_mecid_key_update(uint64_t mecid)
+{
+ uint64_t mecid_width, mecid_width_mask;
+ int ret;
+
+ /*
+ * Check whether the mecid parameter is at most MECIDR_EL2.MECIDWidthm1 + 1
+ * in length.
+ */
+ mecid_width = ((read_mecidr_el2() >> MECIDR_EL2_MECIDWidthm1_SHIFT) &
+ MECIDR_EL2_MECIDWidthm1_MASK) + 1;
+ mecid_width_mask = ((1 << mecid_width) - 1);
+ if ((mecid & ~mecid_width_mask) != 0U) {
+ return E_RMM_INVAL;
+ }
+
+ ret = plat_rmmd_mecid_key_update(mecid);
+
+ if (ret != 0) {
+ return E_RMM_UNK;
+ }
+ return E_RMM_OK;
+}
+
/*******************************************************************************
* This function handles RMM-EL3 interface SMCs
******************************************************************************/
@@ -519,6 +546,9 @@
VERBOSE("RMMD: running rmmd_rmm_sync_exit\n");
rmmd_rmm_sync_exit(x1);
+ case RMM_MECID_KEY_UPDATE:
+ ret = rmmd_mecid_key_update(x1);
+ SMC_RET1(handle, ret);
default:
WARN("RMMD: Unsupported RMM-EL3 call 0x%08x\n", smc_fid);
SMC_RET1(handle, SMC_UNK);
diff --git a/tools/nxp/create_pbl/Makefile b/tools/nxp/create_pbl/Makefile
index 965cc51..cd2ccc1 100644
--- a/tools/nxp/create_pbl/Makefile
+++ b/tools/nxp/create_pbl/Makefile
@@ -44,7 +44,7 @@
$(s)echo "Built $@ successfully"
$(s)echo
-%.o: %.c %.h Makefile
++${OBJECTS_1} ${OBJECTS_2}: %.o: %.c Makefile
$(s)echo " CC $<"
$(q)$(host-cc) -c ${CPPFLAGS} ${CFLAGS} ${INCLUDE_PATHS} $< -o $@