mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-16 01:24:27 +00:00
Merge changes from topic "dtpm_poc" into integration
* changes: feat(docs): update mboot threat model with dTPM docs(tpm): add design documentation for dTPM fix(rpi3): expose BL1_RW to BL2 map for mboot feat(rpi3): add dTPM backed measured boot feat(tpm): add Infineon SLB9670 GPIO SPI config feat(tpm): add tpm drivers and framework feat(io): add generic gpio spi bit-bang driver feat(rpi3): implement eventlog handoff to BL33 feat(rpi3): implement mboot for rpi3
This commit is contained in:
commit
7e84854015
33 changed files with 2399 additions and 13 deletions
2
Makefile
2
Makefile
|
@ -1232,6 +1232,7 @@ $(eval $(call assert_booleans,\
|
|||
HARDEN_SLS \
|
||||
HW_ASSISTED_COHERENCY \
|
||||
MEASURED_BOOT \
|
||||
DISCRETE_TPM \
|
||||
DICE_PROTECTION_ENVIRONMENT \
|
||||
RMMD_ENABLE_EL3_TOKEN_SIGN \
|
||||
DRTM_SUPPORT \
|
||||
|
@ -1418,6 +1419,7 @@ $(eval $(call add_defines,\
|
|||
HW_ASSISTED_COHERENCY \
|
||||
LOG_LEVEL \
|
||||
MEASURED_BOOT \
|
||||
DISCRETE_TPM \
|
||||
DICE_PROTECTION_ENVIRONMENT \
|
||||
DRTM_SUPPORT \
|
||||
NS_TIMER_SWITCH \
|
||||
|
|
|
@ -962,6 +962,9 @@ subsections:
|
|||
- drivers/scmi-msg
|
||||
- scmi-msg
|
||||
|
||||
- title: TPM
|
||||
scope: tpm
|
||||
|
||||
- title: UFS
|
||||
scope: ufs
|
||||
|
||||
|
|
119
docs/design_documents/dtpm_drivers.rst
Normal file
119
docs/design_documents/dtpm_drivers.rst
Normal file
|
@ -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/
|
|
@ -7,10 +7,12 @@ Design Documents
|
|||
|
||||
cmake_framework
|
||||
measured_boot_poc
|
||||
measured_boot_dtpm_poc
|
||||
drtm_poc
|
||||
rse
|
||||
psci_osi_mode
|
||||
measured_boot
|
||||
dtpm_drivers
|
||||
|
||||
--------------
|
||||
|
||||
|
|
|
@ -91,6 +91,14 @@ The Measured Boot implementation in TF-A supports:
|
|||
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 @@ Responsibilities of these platform interfaces are -
|
|||
|
||||
--------------
|
||||
|
||||
*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
|
||||
|
|
458
docs/design_documents/measured_boot_dtpm_poc.rst
Normal file
458
docs/design_documents/measured_boot_dtpm_poc.rst
Normal file
|
@ -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
|
|
@ -784,6 +784,20 @@ Common build options
|
|||
|
||||
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:
|
||||
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -36,6 +36,9 @@ You can find additional definitions in the `Arm Glossary`_.
|
|||
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 @@ You can find additional definitions in the `Arm Glossary`_.
|
|||
FF-A
|
||||
Firmware Framework for Arm A-profile
|
||||
|
||||
FIFO
|
||||
First In, First Out
|
||||
|
||||
FIP
|
||||
Firmware Image Package
|
||||
|
||||
|
@ -103,6 +109,9 @@ You can find additional definitions in the `Arm Glossary`_.
|
|||
HES
|
||||
Arm CCA Hardware Enforced Security
|
||||
|
||||
I2C
|
||||
Inter-Integrated Circuit Protocol
|
||||
|
||||
ISA
|
||||
Instruction Set Architecture
|
||||
|
||||
|
@ -211,6 +220,9 @@ You can find additional definitions in the `Arm Glossary`_.
|
|||
SPM
|
||||
Secure Partition Manager
|
||||
|
||||
SPI
|
||||
Serial Peripheral Interface
|
||||
|
||||
SRTM
|
||||
Static Root of Trust for Measurement
|
||||
|
||||
|
|
BIN
docs/resources/diagrams/rpi3_dtpm_driver.png
Normal file
BIN
docs/resources/diagrams/rpi3_dtpm_driver.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 56 KiB |
|
@ -928,6 +928,12 @@ nonetheless once execution has reached the runtime EL3 firmware.
|
|||
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 @@ nonetheless once execution has reached the runtime EL3 firmware.
|
|||
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 @@ Threats to be Mitigated by an External Agent Outside of TF-A
|
|||
|
||||
--------------
|
||||
|
||||
*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
|
||||
|
|
130
drivers/gpio/gpio_spi.c
Normal file
130
drivers/gpio/gpio_spi.c
Normal file
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
26
drivers/tpm/tpm2.mk
Normal file
26
drivers/tpm/tpm2.mk
Normal file
|
@ -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
|
21
drivers/tpm/tpm2_chip.c
Normal file
21
drivers/tpm/tpm2_chip.c
Normal file
|
@ -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,
|
||||
};
|
222
drivers/tpm/tpm2_cmds.c
Normal file
222
drivers/tpm/tpm2_cmds.c
Normal file
|
@ -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;
|
||||
}
|
322
drivers/tpm/tpm2_fifo.c
Normal file
322
drivers/tpm/tpm2_fifo.c
Normal file
|
@ -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;
|
||||
}
|
161
drivers/tpm/tpm2_fifo_spi.c
Normal file
161
drivers/tpm/tpm2_fifo_spi.c
Normal file
|
@ -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);
|
||||
}
|
75
drivers/tpm/tpm2_slb9670/slb9670_gpio.c
Normal file
75
drivers/tpm/tpm2_slb9670/slb9670_gpio.c
Normal file
|
@ -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);
|
||||
}
|
32
include/drivers/gpio_spi.h
Normal file
32
include/drivers/gpio_spi.h
Normal file
|
@ -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 */
|
103
include/drivers/tpm/tpm2.h
Normal file
103
include/drivers/tpm/tpm2.h
Normal file
|
@ -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 */
|
24
include/drivers/tpm/tpm2_chip.h
Normal file
24
include/drivers/tpm/tpm2_chip.h
Normal file
|
@ -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 */
|
28
include/drivers/tpm/tpm2_interface.h
Normal file
28
include/drivers/tpm/tpm2_interface.h
Normal file
|
@ -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 */
|
16
include/drivers/tpm/tpm2_slb9670/slb9670_gpio.h
Normal file
16
include/drivers/tpm/tpm2_slb9670/slb9670_gpio.h
Normal file
|
@ -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 */
|
|
@ -192,6 +192,9 @@ endif
|
|||
# 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
|
||||
|
||||
|
|
|
@ -75,6 +75,9 @@ static const mmap_region_t plat_rpi3_mmap[] = {
|
|||
#endif
|
||||
MAP_DEVICE0,
|
||||
MAP_FIP,
|
||||
#if MEASURED_BOOT
|
||||
RPI3_MAP_BL1_RW,
|
||||
#endif
|
||||
MAP_NS_DRAM0,
|
||||
#ifdef BL32_BASE
|
||||
MAP_BL32_MEM,
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
@ -171,6 +171,14 @@
|
|||
#define BL1_RW_BASE (BL1_RW_LIMIT - PLAT_MAX_BL1_RW_SIZE)
|
||||
#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.
|
||||
*
|
||||
|
@ -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 */
|
||||
|
|
18
plat/rpi/rpi3/include/rpi3_measured_boot.h
Normal file
18
plat/rpi/rpi3/include/rpi3_measured_boot.h
Normal file
|
@ -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 */
|
|
@ -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/libfdt/libfdt.mk
|
|||
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_BL_COMMON_SOURCES := drivers/ti/uart/aarch64/16550_console.S \
|
|||
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 \
|
||||
|
|
137
plat/rpi/rpi3/rpi3_bl1_mboot.c
Normal file
137
plat/rpi/rpi3/rpi3_bl1_mboot.c
Normal file
|
@ -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;
|
||||
}
|
151
plat/rpi/rpi3/rpi3_bl2_mboot.c
Normal file
151
plat/rpi/rpi3/rpi3_bl2_mboot.c
Normal file
|
@ -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;
|
||||
}
|
|
@ -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 @@ static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
|
|||
/* 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 @@ static void rpi3_sdhost_setup(void)
|
|||
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 @@ void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1,
|
|||
/* 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();
|
||||
}
|
||||
|
||||
|
|
198
plat/rpi/rpi3/rpi3_dyn_cfg_helpers.c
Normal file
198
plat/rpi/rpi3/rpi3_dyn_cfg_helpers.c
Normal file
|
@ -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;
|
||||
}
|
Loading…
Add table
Reference in a new issue