OPTEE

Per capire il motivo dell’ esistenza di OPTEE (Open Portable Trusted Execution Environment) dobbiamo prima parlare di Arm TrustZone, cioè il meccanismo hardware che permette di suddividere l’esecuzione della CPU in 2 ambienti isolati tra loro, il Secure World e il Normal World. L’intera memoria indirizzabile dalla CPU viene suddivisa in zone sicure o non sicure. La memoria indirizzabile, chiamata address space, è mappata fisicamente a varie periferiche, come UART, RAM DDR, SYSRAM e così via. Di conseguenza anche determinati applicativi e interrupt routine possono essere marcati come sicuri o non sicuri. La CPU viene inizializzata in Secure World dal codice ROM e TFA deve gestire il passaggio da questo al Normal World. Dietro questo processo si nascondono i meccanismi di CoT (Chain Of Trust), ma li affronteremo più avanti. Per il momento ci basta sapere che nella sua implementazione più semplice il TFA si autentica come elemento sicuro, avvia OPTEE come elemento sicuro e persistente in RAM DDR, carica UBOOT come elemento non sicuro e passa l’esecuzione a questo.

OPTEE viene chiamato Secure Monitor perchè sarà poi lui a gestire eventuali richieste dal Normal World al Secure World, ad esempio se un applicativo non sicuro vuole accedere a risorse sicure (come chiavi cifrate o alto).

Come visto per il TFA, cerchiamo di capire come configurare OPTEE basandoci su:

dal recipe originale

Notiamo subito che il progetto utilizza make e che vengono passate le seguenti variabili:

meta-arm/recipes-security/optee/optee-os.inc
23EXTRA_OEMAKE += " \
24    PLATFORM=${OPTEEMACHINE} \
25    CFG_${OPTEE_CORE}_core=y \
26    CROSS_COMPILE_core=${HOST_PREFIX} \
27    CROSS_COMPILE_ta_${OPTEE_ARCH}=${HOST_PREFIX} \
28    AFLAGS="${CFLAGS}" \
29    ta-targets=ta_${OPTEE_ARCH} \
30    O=${B} \
31"

e compilati con target all:

meta-arm/recipes-security/optee/optee-os.inc
43do_compile() {
44    oe_runmake -C ${S} all
45}

Le variabile bitbake che ci interessano sono:

  • OPTEEMACHINE
  • OPTEE_CORE
  • OPTEE_ARCH

Mentre quelle make che sarebbero da indagare sono:

  • PLATFORM
  • CFG_*_core
  • ta-targets

dalla documentazione

La documentazione più recente indica il supporto per la famiglia stm32mp1, ma non per stm32mp2, quindi è probabile che ST abbia dovuto fare un fork del progetto e i cambiamenti non siano ancora stati aggiunti in upstream. Potremmo leggere le procedure di porting, ma visto che non saremo noi a dover scrivere il codice c per supportare il processore per il momento passiamo a…

dai sorgenti

Nel Makefile principale si vede l’inclusione di core/core.mk e in questo l’utilizzo delle variabili ARCH e PLATFORM per individuare un make specifico per la piattaforma:

optee_os/core/core.mk
43arch-dir	:= core/arch/$(ARCH)
44platform-dir	:= $(arch-dir)/plat-$(PLATFORM)
45include $(platform-dir)/conf.mk
46include mk/config.mk
47# $(ARCH).mk also sets the compiler for the core module
48include core/arch/$(ARCH)/$(ARCH).mk
repo layout
optee_os
├── Makefile
├── ...
└── core 
     ├── ...
     └── arch
          ├── riscv
          └── arm
               ├── ...
               ├── dts
               │    ├── ...
               │    └── stm32mp257f-dk.dts
               └── plat-stm32mp2
                    ├── ...
                    └── conf.mk

In questo vediamo come viene definito il devicetree da utilizzare:

optee_os/core/arch/arm/plat-stm32mp2/conf.mk
16# Check if device-tree exist in OP-TEE source code, else search it in external
17# device tree repository
18ifeq ($(wildcard $(arch-dir)/dts/$(CFG_EMBED_DTB_SOURCE_FILE)),)
19# External device tree default path
20CFG_EXT_DTS ?= $(arch-dir)/dts/external-dt/optee

Come viene definito il modello di CPU:

optee_os/core/arch/arm/plat-stm32mp2/conf.mk
37# CFG_STM32MP2x switches are exclusive.
38# - CFG_STM32MP25 is enabled for STM32MP25x-* targets (default)
39# - CFG_STM32MP23 is enabled for STM32MP23x-* targets
40# - CFG_STM32MP21 is enabled for STM32MP21x-* targets
41# We try to guess the variant from the embedded DT source file name

Una menzione a diverse modalità di OPTEE:

optee_os/core/arch/arm/plat-stm32mp2/conf.mk
68# CFG_STM32MP_PROFILE selects the profile of the services embedded in OP-TEE
69CFG_STM32MP_PROFILE ?= secure_and_system_services
70
71ifeq ($(filter $(CFG_STM32MP_PROFILE),system_services secure_and_system_services),)
72$(error CFG_STM32MP_PROFILE shall be one of system_services or secure_and_system_services)
73endif
74
75ifeq ($(CFG_STM32MP_PROFILE),system_services)
76include $(platform-dir)/conf.disable-secure-services.mk
77endif

Una sfilza di configurazioni di default:

optee_os/core/arch/arm/plat-stm32mp2/conf.mk
68# Support DDR ranges up to 8GBytes (address range: 0x80000000 + DDR size)
69CFG_CORE_LARGE_PHYS_ADDR ?= y
70CFG_CORE_ARM64_PA_BITS ?= 34
71
72CFG_TEE_RAM_VA_SIZE ?= 0x400000
73CFG_CORE_HEAP_SIZE ?= 393216
74CFG_CORE_RESERVED_SHM ?= n

Per evitare problemi con l’ assegnazione di argomenti a make, dobbiamo controllare quali valori il recipe originale gli passa e come li assegna. Ad esempio:

meta-arm/recipes-security/optee/optee.inc
12OPTEEMACHINE ?= "${MACHINE}"
13OPTEE_ARCH:aarch64 = "arm64"
14OPTEE_CORE = "${@d.getVar('OPTEE_ARCH').upper()}"

che poi vengono passate alla variabile OEMAKE:

meta-arm/recipes-security/optee/optee.inc
22EXTRA_OEMAKE += " \
23    PLATFORM=${OPTEEMACHINE} \
24    CFG_${OPTEE_CORE}_core=y \
25    CROSS_COMPILE_core=${HOST_PREFIX} \
26    CROSS_COMPILE_ta_${OPTEE_ARCH}=${HOST_PREFIX} \
27    NOWERROR=1 \
28    ta-targets=ta_${OPTEE_ARCH} \
29    O=${B} \
30"

che causerà nel recipe:

meta-arm/recipes-security/optee/optee-os.inc
23EXTRA_OEMAKE += " \
24    PLATFORM=stm32mp257f-dk \
25    CFG_ARM64_core=y \
26    CROSS_COMPILE_core=${HOST_PREFIX} \
27    CROSS_COMPILE_ta_arm64=${HOST_PREFIX} \
28    AFLAGS="${CFLAGS}" \
29    ta-targets=ta_arm64 \
30    O=${B} \
31"

l’unico problema è che vogliamo PLATFORM=stm32mp2 in make quindi definiamo OPTEEMACHINE=stm32mp2 in yocto. Poi definiamo il modello preciso passando CFG_STM32MP25=y a make. Definiamo il devicetree passando CFG_EMBED_DTB_SOURCE_FILE=stm32mp257f-dk.dts a make. E per il momento passiamo CFG_STM32MP_PROFILE=system_services a make per disabilitare delle funzioni aggiuntive di cui possiamo fare a meno.

recipe finale

Otteniamo allora:

optee_os/core/arch/arm/plat-stm32mp2/conf.mk
68PV = "4.0.0-stm32mp"
69SRC_URI = "git://github.com/STMicroelectronics/optee_os.git;protocol=https;branch=4.0.0-stm32mp"
70SRCREV = "4.0.0-stm32mp-r2"
71
72
73OPTEEMACHINE = "stm32mp2"
74
75EXTRA_OEMAKE:append = " \
76    CFG_STM32MP25=y \
77    CFG_EMBED_DTB_SOURCE_FILE=stm32mp257f-dk.dts \
78    CFG_STM32MP_PROFILE=system_services \
79"