LAN966x TFA_CTL
LAN966x TFA_CTL
SoC Resources
Using the PSCI/SMCCC interface available in Linux along with the
mchp_tfa_ctl
driver, it is possible to control the following
features of TFA firmware:
-
Secure JTAG
-
Firmware encryption with BSSK key
See also PSCI documentation
Kernel configurations
Following kernel config options should be enabled to use TFA_CTL interface
-
CONFIG_MCHP_TFA_CTL
- tfa_ctl driver config option.
The option is enabled by default.
The option will select these related kernel options
-
CONFIG_ARM_PSCI
-
CONFIG_CRYPTO_SHA256
Devicetree Configuration
There is no device tree node for the driver itself, but it requires that the psci node is present.
/ { ... psci { compatible = "arm,psci-1.0"; method = "smc"; }; ... };
Using the TFA_CTL driver
First, you should ensure you have booted a Linux kernel with the
mchp_tfa_ctl
driver. You can do so by grepping the dmesg
kernel log and/or querying sysfs:
# dmesg | grep tfa_ctl [ 0.148936] tfa_ctl: PSCI driver v.0.0.0 # ls -l /sys/class/misc/tfa_ctl/ total 0 -r--r--r-- 1 root root 4096 Jan 1 00:01 dev -rw-r--r-- 1 root root 0 Jan 1 00:01 fw_bind --w------- 1 root root 0 Jan 1 00:01 fw_bind_trigger drwxr-xr-x 2 root root 0 Jan 1 00:01 power --w------- 1 root root 32 Jan 1 00:01 sjtag_key -r--r--r-- 1 root root 8 Jan 1 00:01 sjtag_status --w------- 1 root root 0 Jan 1 00:01 sjtag_unlock lrwxrwxrwx 1 root root 0 Jan 1 00:01 subsystem -> ../../../../class/misc -rw-r--r-- 1 root root 4096 Jan 1 00:01 uevent
Controlling SJTAG
A good place to start is to ensure that SJTAG is enabled. You can do
so by reading the sjtag_status
file. It contains the two SJTAG
registers: CTL
and INT_STATUS
:
# od -t x4 /sys/class/misc/tfa_ctl/sjtag_status 0000000 0000024d 00000000 0000010
Here, the 0x24d value (b'001001001101') is a typical value for when SJTAG is enabled in mode 1. Refer to the register list for details.
To do a proper unlock, you must provide the (binary) 32-byte SJTAG key
in the write-only file sjtag_key
. The default value is all zeroes.
After writing the key, you can trigger an unlock by writing (anything)
to the sjtag_unlock
file, as below. The return value from the
write signal the result of the unlock operation.
# cd /tmp # dd if=/dev/zero of=key count=1 bs=32 1+0 records in 1+0 records out # dd if=key of=/sys/class/misc/tfa_ctl/sjtag_key 0+1 records in 0+1 records out # echo 1 > /sys/class/misc/tfa_ctl/sjtag_unlock # # od -t x4 /sys/class/misc/tfa_ctl/sjtag_status 0000000 00000847 00000000 0000010
After unlocking, the value 0x847 indicates that the SJTAG is now unlocked. You should now be able to attach a JTAG interface.
Firmware Binding
In this context Firmware Binding descibes the operation of taking a
firmware image encrypted with the SSK
key, decrypting and
re-encrypting with the BSSK
instead. As the BSSK
is a
device-local, unique key, this ensures that the firmware cannot be
reproduced. (Note that the BSSK
is derived from the HUK
key).
The firmware binding process is able to use OTP emulation data, if this is deployed. If not, the binding will use the OTP data directly.
Firmware binding requires the SSK
and BSSK
for decryption and
encryption. These may be any binary value (32 bytes long).
The firmware binding is done using a sysfs file as holding bay for the image, and a sysfs to trigger the actual bind operation.
The commands below illustrate taking an SSK
encrypted image off
the MMC and re-encrypting with the BSSK
key.
# cd /tmp # dd if=/dev/mmcblk0p1 of=data sha256sum data dd if=data of=/sys/class/misc/tfa_ctl/fw_bind bs=1k echo 1 > /sys/class/misc/tfa_ctl/fw_bind_trigger dd if=/sys/class/misc/tfa_ctl/fw_bind of=bound bs=1k 2048+0 records in 2048+0 records out # sha256sum data sha256sum bound 559a603550297e47a83fa2a9a42c4cb3216e8588d68ae488dc511abc6025ca88 data # dd if=data of=/sys/class/misc/tfa_ctl/fw_bind bs=1k 1024+0 records in 1024+0 records out # echo 1 > /sys/class/misc/tfa_ctl/fw_bind_trigger # dd if=/sys/class/misc/tfa_ctl/fw_bind of=bound bs=1k 1024+0 records in 1024+0 records out # sha256sum bound 41d6f577e343c81cbd05552c8bc2408e99815d41683e98873acedbe7b8f197ca bound
As can be seen, the firmware binding will not change the size of the image, but it will change the image data.
After a successful operation, the image may now be written to the boot media of choice.
If the operation fails, the fw_bind_trigger
write will fail. The
kernel log will provide information about the problem.
# echo 1 > /sys/class/misc/tfa_ctl/fw_bind_trigger sh: write error: Input/output error # dmesg | tail -1 [ 3357.425863] misc tfa_ctl: tfa_ctl: Bind failed: 0xffffffec
The error codes are described here:
0xfffffff0 |
FW_FIP_HDR |
Header check of FIP failed |
0xffffffef |
FW_FIP_ALIGN |
FIP needs to be produced with FIP_ALIGN |
0xffffffee |
FW_FIP_INCOMPLETE |
FIP is incomplete (truncated, garbled) |
0xffffffed |
FW_TOC_TERM_MISSING |
FIP does not have a ToC terminator entry |
0xffffffec |
FW_NOT_SSK_ENCRYPTED |
FIP must be encrypted with SSK |
0xffffffeb |
FW_SSK_FAILURE |
Failed to obtain SSK key |
0xffffffea |
FW_DECRYPT |
Failed to decrypt FIP image |
0xffffffe9 |
FW_BSSK_FAILURE |
Failed to obtain BSSK key |
0xffffffe8 |
FW_ENCRYPT |
Failed to encrypt FIP image |
The firmware image use memory resources until purged from the
fw_bind sysfs file. The purge is done by writing an empty image to
the file.
|
# dd if=/dev/null of=/sys/class/misc/tfa_ctl/fw_bind 0+0 records in 0+0 records out