HOWTO: build ATF (Trusted Firmware ARM) and OPTEE for RK3588 March 10, 2025 | 6 min Read

HOWTO: build ATF (Trusted Firmware ARM) and OPTEE for RK3588

HOWTO: build ATF (Trusted Firmware ARM) and OPTEE for RK3588

To better implement the protection of digital assets in embedded systems, we have chosen the RK3588 as the prototype platform. Firstly, the RK3588 is backed by an increasingly mature open-source ecosystem. Thanks to the continuous efforts of Collabora and the open-source community over the past two years, the RK3588 has achieved a nearly complete ecosystem with support for key components such as U-Boot, Linux kernel, NPU driver, ATF. In the meanwhile, the maintainer team of The Dogecoin Foundation has joined in supporting OP-TEE and completing key features of the hardware-based chain of trust and root of trust, such as OTP (One-Time Programmable) and HUK (Hardware Unique Key). Although open-source does not equal to security, its transparency benefits the security in either security audits and vulnerability hunting, thereby providing a solid foundation for the protection of digital assets.

Secondly, this SoC not only possesses excellent general computing performance but also must implement security extensions for MMU, similar to TZASC (TrustZone Address Space Controller). Such a design effectively isolates permissions across different software layers, preventing security risks revealed in analyses like tzram-audit, and ensuring strict isolation between various security zones within the system, thus providing robust hardware-level protection for sensitive assets.

Thirdly, the RK3588 is equipped with a 6 TOPS NPU (Neural Processing Unit), which offers strong support for edge AI in embedded applications. For private AI application scenarios, such as assisting in crypto trading decisions and building secure, real-time knowledge bases, the high-performance NPU of the RK3588 can achieve efficient data processing and intelligent analysis, thereby promoting the deep application of AI in areas such as secure communication and digital asset management.

the boot process of Rockchip

See https://opensource.rock-chips.com/wiki_Boot_option , When booting from the SD card, the code in the SOC’s built-in ROM can use the first 16MiB of the SD card as ROM (therefore, other partitions are located after 16MiB).

The boot code outside of the SOC is mainly divided into two stages, located after 32KiB (64 sectors) and 8MiB (16384 sectors), respectively. The first stage is primarily responsible for memory initialization, while the second stage includes the ARM Trusted Firmware (ATF), TEE, and bootloader. U-Boot can be responsible for generating both of these stages

propritary code

The first stage of U-Boot consists of TPL and SPL, but the source code for memory initialization of the RK3588 has not been made public; only binary blobs are available. https://github.com/rockchip-linux/rkbin/blob/master/bin/rk35/rk3588_ddr_lp4_2112MHz_lp5_2400MHz_v1.18.bin , When combined with u-boot-spl.bin, it can still form a usable first stage.

Build ATF

$ make CROSS_COMPILE=aarch64-linux-gnu- PLAT=rk3588 DEBUG=1 SPD=opteed clean
$ make CROSS_COMPILE=aarch64-linux-gnu- PLAT=rk3588 DEBUG=1 SPD=opteed

Copy or link build/rk3588/debug/bl31/bl31.elf to rk3588/bl31.elf in the u-boot directory.

Build optee_os

$ make   CROSS_COMPILE64=aarch64-linux-gnu-   PLATFORM=rockchip PLATFORM_FLAVOR=rk3588   CFG_ARM64_core=y   CFG_USER_TA_TARGETS=ta_arm64   CFG_DT=y CFG_CORE_ARM64_PA_BITS=<ram-bits> clean
$ make   CROSS_COMPILE64=aarch64-linux-gnu-   PLATFORM=rockchip PLATFORM_FLAVOR=rk3588   CFG_ARM64_core=y   CFG_USER_TA_TARGETS=ta_arm64   CFG_DT=y CFG_CORE_ARM64_PA_BITS=<ram-bits>

Where ram-bits is the number of binary bits representing the actual size of memory in bytes.

Copy or link out/arm-plat-rockchip/core/tee.bin to rk3588/tee.bin in the u-boot directory.

Build u-boot

Download the aforementioned memory initialization blob and copy it to rk3588/ddr.bin in the u-boot directory.

$ make ARCH=arm CROSS_COMPILE=aarch64-linux-gnu- rock5a-rk3588s_defconfig
$ make ARCH=arm CROSS_COMPILE=aarch64-linux-gnu- ROCKCHIP_TPL=rk3588/ddr.bin BL31=rk3588/bl31.elf TEE=rk3588/tee.bin
$ mkimage -T rksd -n rk3588 -d rk3588/ddr.bin:spl/u-boot-spl.bin idbloader.img

Noted that the combination method using cat(1) in https://opensource.rock-chips.com/wiki_Boot_option#The_Pre-bootloader.28IDBLoader.29 cannot generate a usable first stage; instead, mkimage is needed to combine the two parts.

Writing

idbloader.img is the first stage, and u-boot.itb is the second stage. Writing both to the specified locations on the SD card will create a usable bootloader:

# dd if=idbloader.img of=/dev/sdX seek=64
# dd if=u-boot.itb of=/dev/sdX seek=16384

/dev/sdX is SD card.

Boot log

U-Boot SPL 2025.04-rc3-00023-g6ae0a578de67 (Mar 03 2025 - 11:46:06 +0800)
Trying to boot from MMC2
## Checking hash(es) for config config-1 ... OK
## Checking hash(es) for Image atf-1 ... sha256+ OK
....
....
....
NOTICE:  BL31: v2.12.0(debug):v2.12.0-617-ga8a5d39d6
NOTICE:  BL31: Built : 16:15:14, Mar  6 2025
INFO:    GICv3 without legacy support detected.
INFO:    ARM GICv3 driver initialized in EL3
INFO:    Maximum SPI INTID supported: 511
INFO:    BL31: Initializing runtime services
INFO:    BL31: cortex_a55: CPU workaround for erratum 1530923 was applied
INFO:    BL31: Initializing BL32
I/TC: 
I/TC: No non-secure external DT
I/TC: OP-TEE version: 4.5.0-87-g873f5f6c7 (gcc version 14.2.0 (Debian 14.2.0-12)) #1 Tue Feb 25 03:51:56 UTC 2025 aarch64
I/TC: WARNING: This OP-TEE configuration might be insecure!
I/TC: WARNING: Please check https://optee.readthedocs.io/en/latest/architecture/porting_guidelines.html
I/TC: Primary CPU initializing
I/TC: GIC redistributor base address not provided
I/TC: Assuming default GIC group status and modifier
I/TC: Primary CPU switching to normal world boot
INFO:    BL31: Preparing for EL3 exit to normal world
INFO:    Entry point address = 0xa00000
INFO:    SPSR = 0x3c9
NOT_SUPPORTED: A Firmware Framework implementation does not exist


U-Boot 2025.04-rc3-00023-g6ae0a578de67 (Mar 06 2025 - 16:16:43 +0800)

Model: Radxa ROCK 5A
SoC:   RK3588S
DRAM:  8 GiB
NOT_SUPPORTED: A Firmware Framework implementation does not exist
I/TC: Reserved shared memory is enabled
I/TC: Dynamic shared memory is disabled
I/TC: Normal World virtualization support is disabled
I/TC: Asynchronous notifications are disabled
optee optee: OP-TEE capabilities mismatch
Core:  344 devices, 32 uclasses, devicetree: separate
MMC:   mmc@fe2c0000: 1, mmc@fe2e0000: 0
Loading Environment from nowhere... OK
In:    serial@feb50000
Out:   serial@feb50000
Err:   serial@feb50000
Model: Radxa ROCK 5A
SoC:   RK3588S
Net:   eth0: ethernet@fe1c0000
Hit any key to stop autoboot:  2  1  0 
Scanning for bootflows in all bootdevs
Seq  Method       State   Uclass    Part  Name                      Filename
---  -----------  ------  --------  ----  ------------------------  ----------------
Scanning global bootmeth 'efi_mgr':
Card did not respond to voltage select! : -110
Cannot persist EFI variables without system partition
  0  efi_mgr      ready   (none)       0  <NULL>                    
** Booting bootflow '<NULL>' with efi_mgr
Loading Boot0000 'mmc 1' failed
EFI boot manager: Cannot load any image
Boot failed (err=-14)
Scanning bootdev '[email protected]':
  1  extlinux     ready   mmc          3  [email protected] /boot/extlinux/extlinux.conf
** Booting bootflow '[email protected]_3' with extlinux
U-Boot menu
1:	Debian GNU/Linux 12 (bookworm) 6.1.43-20-rk2312
2:	Debian GNU/Linux 12 (bookworm) 6.1.43-20-rk2312 (rescue target)
Enter choice: 1:	Debian GNU/Linux 12 (bookworm) 6.1.43-20-rk2312
Retrieving file: /boot/vmlinuz-6.1.43-20-rk2312
Retrieving file: /boot/initrd.img-6.1.43-20-rk2312
append: root=UUID=3f7cc3b2-4026-493b-bc46-ee2668d25bcc console=ttyFIQ0,1500000n8 iomem=relaxed quiet splash loglevel=4 rw earlycon consoleblank=0 console=tty1 coherent_pool=2M irqchip.gicv3_pseudo_nmi=0 cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory swapaccount=1
Retrieving file: /usr/lib/linux-image-6.1.43-20-rk2312/rockchip/rk3588s-rock-5a.dtb
## Flattened Device Tree blob at 12000000
   Booting using the fdt blob at 0x12000000
Working FDT set to 12000000
   Loading Ramdisk to ebeef000, end eceaeda5 ... OK
   Loading Device Tree to 00000000ebeb2000, end 00000000ebeee8a8 ... OK
Working FDT set to ebeb2000

Starting kernel ...

I/TC: Secondary CPU 1 initializing
I/TC: Secondary CPU 1 switching to normal world boot
I/TC: Secondary CPU 2 initializing
I/TC: Secondary CPU 2 switching to normal world boot
I/TC: Secondary CPU 3 initializing
I/TC: Secondary CPU 3 switching to normal world boot
I/TC: Secondary CPU 4 initializing
...
...
...
[   19.295224] rk-pcie fe190000.pcie: PCIe Link Fail, LTSSM is 0x3, hw_retries=1
[   20.330335] rk-pcie fe190000.pcie: failed to initialize host

Debian GNU/Linux 12 rock-5a ttyFIQ0

rock-5a login: 

TODO

  • Verification of TZASC
  • OTP and eFuses
  • Data encryption based on HUK and user-defined seeds
  • Compartmentation for bootflow (VaultBoot) and runtime TAs
  • Further assessment, trade-off of anti-rollback, RPMB, use-case, etc.