Over the past few years, we have been contributing to the OP-TEE project the support for the Microchip SAMA5D2 processor family, and we also helped with enabling OP-TEE on the Microchip SAMA7 processor family.
In this blog post, we propose a quick introduction to OP-TEE and then detail a few changes that have been
done to add support for Microchip SAMA5 processors to the OP-TEE project.
Principle
ARM Trustzone is a technology that defines various methods to achieve system-wide hardware-enforced isolation, built into the CPU. Basically, the CPU can execute in two modes (Normal and Secure). When executing in normal world (NW), the CPU has access to a restricted set of peripherals and memory, while when executing in the secure world (SW), the CPU has full access to the peripherals and memory. Switching from the normal world to the secure world is possible using the SMC (Secure Monitor Call) instruction. In a typical embedded Linux scenario, the Linux kernel and user-space will run in the normal world, while OP-TEE will be running in the secure world.
When in secure mode, peripherals configured as secure will only be accessible by the secure world. The peripherals and memory partitioning is done using the Matrix bus on the SAMA5D2. If the normal world tries to access a secure peripheral, access will be denied and an interrupt will signal it to the secure world via the Matrix bus.
Memories can also be split in multiple SW/NW areas to protect secure world memories. This is typically used to secure the OP-TEE execution memory zone.
SAMA5 Bootchain
Limiting the attack surface starts by reducing the amount of code that executes in the secure world. This involve booting OP-TEE as soon as possible to avoid U-Boot accessing critical peripherals. In order to do that, the Microchip SAMA5 bootchain has been reworked, as illustrated below:
In the previous bootchain, everything was running in the secure world: ROM code, first stable bootloader (at91bootstrap), second stage bootloader (U-Boot) and Linux system.
We modified the at91bootstrap so that it can load both U-Boot and OP-TEE. Once at91bootstrap has done its job, it passes control over to OP-TEE, and passes to OP-TEE the address at which U-Boot was loaded. OP-TEE then does its initialization, switches to normal world and passes control over to U-Boot. Thanks to this, U-Boot and everything after it (including Linux of course) runs in the normal world.
Memory map
OP-TEE itself needs to be stored in memory, so a dedicated area of the RAM is reserved for OP-TEE and made inaccessible to the normal world. On SAMA5 platforms, we have chosen to place OP-TEE at the start of RAM, i.e at 0x2000000
, as this allows to be compatible with all platforms regardless of the amount of available RAM.
However, this required adjusting U-Boot, as U-Boot uses a function called get_dram_size()
to calculate the amount of available RAM, and this function was trying to access the memory from its start to calculate its size. And of course, accessing the start of RAM was no longer allowed: it is now reserved for the secure world, and U-Boot runs in normal world. In order to avoid that, the SAMA5 U-Boot RAM detection was switched to use the Device Tree memory
node. This allows to easily modify the Device Tree to exclude OP-TEE memory area. U-Boot will then load Linux at the beginning of the memory area described in the Device Tree.
Peripherals
Getting OP-TEE to work on a new platform mainly involves writing drivers for the peripherals that will be made only accessible by the secure world, and for which the control will be delegated to OP-TEE. In the following sections, we will look at 3 specific SAMA5 peripherals for which we have enabled support in OP-TEE.
Clock support
One peripheral that is very often delegated to the secure world is the clock controller: we can’t let a normal world operating system manipulate the configuration of clocks. Therefore, we added support for the clock controller in the SAMA5D2. As part of this work, we actually implemented and contributed a brand new generic clock framework to OP-TEE, which until now was missing (every platform was coming up with its own mechanism, which we felt was far from ideal).
The clocks managed by OP-TEE are accessible from the normal world operating system (Linux) using a protocol called SCMI.
From the Linux Device Tree perspective, the following description allows Linux to contact the SCMI server present in OP-TEE to be able to control clocks:
reserved-memory { scmi0_shmem: scmi0_shmem@21400000 { no-map; reg = <0x21400000 0x80>; }; }; firmware { scmi0 { compatible = "arm,scmi-smc"; shmem = <&scmi0_shmem>; arm,smc-id = <0x2000200>; scmi0_clock: scmi0_clock@14 { #clock-cells = <0x01>; reg = <0x14>; }; }; };
All clock definitions in the Linux Device Tree are modified to use a new phandle referencing the scmi0_clock
.
Power management support
Another aspect that is often delegated to the secure world are power management operations, which are then exposed to the normal world operating system using another interface called PSCI. We therefore implemented support for reset, shutdown, suspend and CPU idle for SAMA5 in OP-TEE.
From the Linux Device Tree perspective, a PSCI node allows Linux to communicate with the secure world to benefit from those features:
psci { sys_reset = <0x84000009>; sys_poweroff = <0x84000008>; cpu_on = <0x84000003>; cpu_off = <0x84000002>; cpu_suspend = <0x84000001>; method = "smc"; compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci"; };
NVMEM support
A last peripheral we wanted to highlight is the Microchip Secure Fuse Controller (SFC). It provides a unique DIE ID and a Hardware Unique Key (HUK) which can be used to perform cryptographic operations in OP-TEE. In order to support this SFC, we first contributed a NVMEM framework to OP-TEE, modeled after the similar subsystem in the Linux kernel. Then, we contributed a driver specific to the Microchip SFC, which is used from the OP-TEE Device Tree perspective as follows:
sfc: sfc@f804c000 { compatible = "atmel,sama5d2-sfc"; reg = <0xf804c000 0x64>; read-only; status = "disabled"; secure-status = "okay"; #address-cells = <1>; #size-cells = <1>; sfc_dr0: cell@20 { reg = <0x20 0x20>; }; sfc_dr1: cell@24 { reg = <0x24 0x20>; }; }; die_id: die_id { compatible = "optee,nvmem-die-id"; nvmem-cells = <&sfc_dr0>; nvmem-cell-names = "die_id"; }; huk: huk { compatible = "optee,nvmem-huk"; nvmem-cells = <&sfc_dr1>; nvmem-cell-names = "hw_unique_key"; };
Current status and future work
Currently, the OP-TEE support for SAMA5D2 is able to drive following peripherals:
- Clocks: clock framework, DT support in the clock framework, fixed clock driver, Microchip clock drivers
- TRNG: Microchip TRNG driver
- Secure Interrupt Controller: Microchip SAIC driver
- Shutdown Controller: Microchip Shutdown Controller driver
- Reset Controller: Microchip reset controller driver
- Suspend support: SAMA5 suspend/resume support code
- Watchdog driver: Watchdog SMC interface to normal world, Microchip Watchdog driver
- RTC controller: Pseudo Trusted Application exposing OP-TEE RTC devices to the normal world, Microchip RTC driver
- Intrusion detection: PIOBU driver
- NVMEM: API for nvmem controllers, Microchip Secure Fuse Controller driver, NVMEM DIE ID driver, NVMEM hardware unique key driver
- GPIO: also provided by the PIOBU driver
- I2C: Microchip I2C controller driver
Here is how we progressively added the SAMA5 support to OP-TEE:
- In OP-TEE 3.15, the existing rudimentary support for SAMA5 in OP-TEE was reworked to be functional, and OP-TEE was moved to the start of the RAM
- In OP-TEE 3.16, a generic clock framework was added, many clock drivers for SAMA5 were added as part of this framework, Device Tree files for SAMA5D2 Xplained and SAMA5D27 SOM1 were added, drivers for the Random Number Generator, for the reset controller were added, and initial support for PSCI was implemented
- In OP-TEE 3.17, suspend/resume support was implemented, a driver for the SAIC interrupt controller was added, a watchdog interface to the normal world was added together with a driver for the Microchip watchdog, an RTC API was added as well together with a driver for the Microchip RTC
- In OP-TEE 3.18, a driver for the Microchip PIOBU was added, as well as a timer clock driver, and several improvements to the suspend/resume support were made
- In OP-TEE 3.20, several more peripherals were set as secure only, and a few fixes were integrated
- In OP-TEE 3.21, a Device Tree for the SAMA7D27 WLSOM1 was added, some clock driver improvements were contributed
- In OP-TEE 3.22, a simple framework to handle I2C devices was added, as well as a driver for the Microchip I2C controller. The SCMI server was implemented, using the generic clock framework previously introduced, a GPIO framework and Microchip GPIO and pin-muxing drivers were added
- In OP-TEE 4.0.0, we enabled building SAMA5D27 platform build testing in the OP-TEE CI
- In OP-TEE 4.1.0, a NVMEM subsystem was contributed, with a driver for the Microchip Secure Fuse Controller
- In OPTEE 4.2.0, support for the hardware unique key and die ID was added, using the NVMEM subsystem previously contributed
In total we so far contributed 169 commits to the OP-TEE project to contribute this SAMA5 support.
In terms of future work: we are currently implementing an OP-TEE driver for the MCP16502 PMIC used on WLSOM1 and SOM1 EVK, and we are also supporting Microchip to fix SAMA5D2 regressions and to enable SAMA7G5 support.