flash manuale

Adesso puntiamo al flashare quello che abbiamo realizzato finora e vediamo se almeno qualcosa funziona. Apriamo quindi un progetto yocto, attiviamo il nostro layer e proviamo a buildare i recipe singolarmente, quindi:

bitbake u-boot
bitbake optee-os
bitbake trusted-firmware-a

Uno dei primi problemi è quello del COMPATIBLE_MACHINE. Yocto ci permette di definire per quali machine il nostro recipe (o .bbappend) ha senso di essere utilizzato. COMPATIBLE_MACHINE è una regex e per rendere la nostra machine compatibile ci basta usare:

*.bb
COMPATIBLE_MACHINE:append = "|stm32mp257f-dk"

Dopo aver risolto eventuali problemi nella build, i file che ci interessano sono:

  • TFA tmp/work/stm32mp257f_dk-poky-linux/trusted-firmware-a/2.10-stm32mp/image/firmware/tf-a-stm32mp257f-dk.stm32
  • FIP tmp/work/stm32mp257f_dk-poky-linux/trusted-firmware-a/2.10-stm32mp/image/firmware/fip.bin

Il layer meta-stm32mp2 che abbiamo realizzato finora è disponibile qui.

Adesso passiamo alla parte divertente. Per flashare la scheda esistono due modi principali:

  • sdcard
  • seriale

In entrambi i casi ci scontriamo con delle regole “hard-coded” definite dal ROM CODE, solitamente riguardo alla posizione e altre caratteristiche delle partizioni da cui viene caricato il bootloader.

Oltre al come flashare, dobbiamo anche decidere dove la scheda troverà i file necessari al boot. In sostanza dobbiamo decidere la tipologia di memoria flash che vogliamo utilizzare (sdcard, emmc, nand, nor, …)

Per informare il ROM code di quale processo vogliamo utilizzare per flash e boot, utilizziamo i boot switches della scheda: docs

Per il momento faremo il boot da scard, ma vediamo come flashare la scheda sia tramite sdcard, sia tramite seriale.

flash da sdcard

documentazione ST

Se la sdcard contiene una Global Positioning Table (GPT), il ROM code cerca le prime 2 partizioni che iniziano il proprio nome con fsbla oppure fsblm.

Se non trova la GPT, il ROM code cerca in delle posizioni fisse:

  • LBA0 per FSBL-M1
  • LBA640 per FSBL-M2
  • LBA1152 per FSBL-A1
  • LBA1664 per FSBL-A2

dove LBA indica Logical Block Addressing, quindi il numero di settore.

La dicitura fsbla, fsblm indica da quale core effettuare il boot, qundi core A35, core M33. La dicitura fsbla1, fsbla2 si riferisce invece alla eventuale ridondanza.

Utilizziamo il seguente script per formattare la sdcard utilizzando una GPT:

flasher.sh
23# demonstrate the sdcard flashing for stm32mp2
24#
25# minimal working setup to access uboot console 
26
27set -euo pipefail
28 
29DEVICE="${1:-}"
30TFA="${2:-}"
31FIP="${3:-}"
32 
33# Verify all 3 positional arguments are provided
34if [[ -z "$DEVICE" || -z "$TFA" || -z "$FIP" ]]; then
35    echo "Error: Missing required arguments." >&2
36    usage
37fi
38
39
40# FORMAT DEVICE
41sudo sgdisk --zap-all "$DEVICE"
42
43# ROM CODE REQUIREMENTS
44# TFA partition:
45# LABEL "fsbla" (first stage bootloader A35)
46# TYPE CODE GUID = 8DA63339-0007-60C0-C436-083AC8230908
47#
48# FIP partition
49# TYPE CODE GUID = 19D5DF83-11B0-457b-BE2C-7559C13142A5
50
51# sgdisk arguments
52#  -n --new=partnum:start:end
53#  -A (--attributes)
54#  -c (--change-name)
55#  -t (--typecode)
56#  -u (--partition-guid) 
57
58# TFA PARTITION
59sudo sgdisk \
60    -n 1:0:+512K \
61    -c 1:fsbla \
62    -t 1:8DA63339-0007-60C0-C436-083AC8230908 \
63    -u 1:R \
64    -p "$DEVICE"
65
66# FIP
67sudo sgdisk \
68    -n 2:0:+4M \
69    -c 2:fip \
70    -t 2:19d5df83-11b0-457b-be2c-7559c13142a5 \
71    -u 2:R \
72    -p "$DEVICE"
73
74# TFA CONTENTS
75sudo dd \
76    if=$TFA \
77    of=${DEVICE}1 \
78    bs=1M conv=fdatasync status=progress
79
80# FIP CONTENTS
81sudo dd \
82   if=$FIP \
83   of=${DEVICE}2 \
84   bs=1M conv=fdatasync status=progress

Adesso cambiamo i boot switches della scheda e usiamo il valore 1000 per informare il ROM code che vogliamo fare il boot del core A35 tramite sdcard.

flash da seriale

Il processo si basa sul protocollo USB DFU (Universal Serial Bus Device Firmware Upgrade), quindi abbiamo ampia scelta sui tool da utilizzare. Per comodità scegliamo di usare il tool da terminale STM32CubeProgrammer, in quanto implementa altre funzionalità specifiche per stm32mp2. L’installazione è descritta nella documentazione ST.

Per ulteriore comodità, al momento useremo un container per installare il tool.

La parte principale per l’uso del cube programmer è il file flashlayout.tsv che definisce quali partizioni creare e quali file flasharci dentro. La sintassi di questo file è descritta nella documentazione ST.

Per ottenere un risultato analogo al metodo precedente usiamo questo flashlayout:

flashlayout.tsv
#opt	PhaseId	Partition	Type		Device	Offset		Binary
-	0x01	fsbl-boot	Binary		none	0x00000000	tf-a-stm32mp257f-dk.stm32
-	0x02	fip-ddr		FIP		none	0x00000000	fip-ddr.bin
-	0x03	fip-boot	FIP		none	0x00000000	fip.bin
PD	0x04	fsbla		Binary		mmc0	0x00004400	tf-a-stm32mp257f-dk.stm32
PD	0x05	fip		FIP		mmc0	0x00104400	fip.bin

Un po’ di spiegazioni. La prima riga è commentata e indica solo i nomi dei campi.

Opt indica l’operazione da eseguire sulla partizione e può essere:

  • - per nessuna operazione
  • P per sovrascrivere (update)
  • PE per nessuna operazione (empty update)
  • PD per formattare e sovrascrivere (delete and update)
  • PDE per eliminare e lasciare vuota (delete and keep empty)

Name indica il nome della partizione e valgono le solite regole

Type è un enum associato al typecode GUID della partizione e al momento ci interessa sapere che:

  • Binary per GUID 8DA63339-0007-60C0-C436-083AC8230908
  • FIP per GUID 19D5DF83-11B0-457b-BE2C-7559C13142A5
  • FWU_MDATA per GUID 8A7A84A0-8387-40F6-AB41-A8B9A5A60D23

PhaseId è un codice che identifica la tipologia di partizione e anche il loro ordine. Per il bootloader esistono dei casi particolari:

  • 0x01 per TFA
  • 0x02 per il file di training DDR
  • 0x03 per FIP
  • 0xF* per comandi speciali

Device è un parametro che verrà utilizzato da UBOOT per capire su che dispositivo flashare la partizione:

  • none dedicato per caricare bootloader
  • mmcN indica l’istanza N di un mmc (mmc0=sdcard, mmc1=emmc)

Offset indica offset in byte all’interno della memoria flash, ma permette anche dei valori speciali:

  • boot1 per prima area boot della emcc
  • boot2 per seconda area boot della emcc

Binary indica il path relativo al file da flashare

Il file flashlayout definisce le partizioni che troveremo sulla memoria flash, ma anche delle partizioni dedicate al bootloader utilizzato per effettuare le operazioni di scrittura sulla flash. Questo è pressochè equivalente a quello che risiederà in flash, ma non è un vincolo che sia il medesimo. Per queste partizioni è necessario usare:

  • Opt = -
  • PhaseId dedicato
  • Type = Binary
  • Device = none
  • Offset = 0x0

Per poter essere eseguito anche da seriale, è necessario definire il simbolo STM32MP_USB_PROGRAMMER=1 nella compilazione del TFA, quindi nel recipe aggiungiamo:

trusted-firmware-a_%.bbappend
19EXTRA_OEMAKE:append = " STM32MP_USB_PROGRAMMER=1 "

Insomma è un grande insieme di regole arbitrarie, ma utili. Adesso flashiamo, quindi… Cambiamo i boot switches della scheda e usiamo il valore 0000 per fare un boot da seriale, permettendoci di usare il micro per flashare un’altra memoria.

Per flashare, da una generica cartella dir del tipo:

dir layout
workdir
├── tf-a-stm32mp257f-dk.stm32
├── fip.bin
└── flashlayout.tsv

cerchiamo la scheda tra i dispositivi collegati:

terminal
STM32_Programmer_CLI -l usb

eseguiamo il comando:

terminal
STM32_Programmer_CLI -c port=usb1 -w 

risultato finale

Collegandoci alla scheda tramite la porta seriale e riavviandola dovremmo vedere:

bootloader log
NOTICE:  CPU: STM32MP257FAK Rev.Y
NOTICE:  Model: STMicroelectronics STM32MP257F-DK Discovery Board
NOTICE:  Board: MB1605 Var1.0 Rev.C-01
NOTICE:  BL2: v2.10-stm32mp2-r2.0(release):v2.10-stm32mp-r2-dirty(cadc66f1)
NOTICE:  BL2: Built : 09:19:57, Jun  2 2025
NOTICE:  BL2: Booting BL31
NOTICE:  BL31: v2.10-stm32mp2-r2.0(release):v2.10-stm32mp-r2-dirty(cadc66f1)
NOTICE:  BL31: Built : 09:19:57, Jun  2 2025
I/TC: Early console on UART#2
I/TC: 
I/TC: Embedded DTB found
I/TC: OP-TEE version: 4.0.0-stm32mp-r2 (gcc version 13.4.0 (GCC)) #1 Thu May 4
I/TC: WARNING: This OP-TEE configuration might be insecure!                   
I/TC: WARNING: Please check https://optee.readthedocs.io/en/latest/architectul
I/TC: Primary CPU initializing                                                
I/TC: WARNING: All debug access are allowed                                   
I/TC: Override the OTP 124: 0 to 0x18db6                                      
I/TC: WARNING: Embeds insecure stm32mp_provisioning driver                    
I/TC: PMIC STPMIC REFID:2.@ V1.1                                              
I/TC: Platform stm32mp2: flavor PLATFORM_FLAVOR - DT stm32mp257f-dk.dts       
I/TC: OP-TEE ST profile: system_services                                      
[    0.000000] SCP-firmware 2.13.0-intree-optee-os-4.0.0-stm32mp-r2           
[    0.000000]                                                                
[    0.000000] [FWK] Module initialization complete!                          
I/TC: Primary CPU switching to normal world boot                              
I/TC: Reserved shared memory is disabled                                      
I/TC: Dynamic shared memory is enabled                                        
I/TC: Normal World virtualization support is disabled                         
I/TC: Asynchronous notifications are enabled                                  
                                                                              
                                                                              
U-Boot 2023.10-stm32mp-r2-rc8 (Jun 03 2025 - 07:35:36 +0000)                  
                                                                              
CPU: STM32MP257FAK Rev.Y                                                      
Model: STMicroelectronics STM32MP257F-DK Discovery Board                      
Board: stm32mp2 (st,stm32mp257f-dk)                                           
Board: MB1605 Var1.0 Rev.C-01                                                 
DRAM:  4 GiB                                                                  
optee optee: OP-TEE: revision 4.0 (a8dd87d4)                                  
I/TC: Reserved shared memory is disabled                                      
I/TC: Dynamic shared memory is enabled                                        
I/TC: Normal World virtualization support is disabled                         
I/TC: Asynchronous notifications are enabled                                  
Core:  419 devices, 42 uclasses, devicetree: board                            
WDT:   Started watchdog with servicing every 1000ms (32s timeout)             
NAND:  0 MiB                                                                  
MMC:   STM32 SD/MMC: 0, STM32 SD/MMC: 1                                       
Loading Environment from MMC... OK                                            
In:    serial                                                                 
Out:   serial                                                                 
Err:   serial                                                                 
Net:   eth0: eth1@482c0000                                                    
FWU metadata read failed                                                      
No EFI system partition                                                       
No EFI system partition                                                       
Failed to persist EFI variables                                               
Hit any key to stop autoboot:  0                                              
Boot over mmc0!                                                               
switch to partitions #0, OK                                                   
mmc0 is current device                                                        

E capiteremo dentro la console di uboot, dove potremo usare vari comandi:

uboot console
STM32MP> version                                                              
U-Boot 2023.10-stm32mp-r2-rc8 (Jun 03 2025 - 07:35:36 +0000)                  
aarch64-poky-linux-gcc (GCC) 13.4.0                                           
GNU ld (GNU Binutils) 2.42.0.20240723 

STM32MP> mmc list                                                             
STM32 SD/MMC: 0 (SD)                                                          
STM32 SD/MMC: 1 (eMMC)

Divertente no?