거의 6년만에 STM32MP 보드를 다시 하나 입수했다(이번에는 STM32MP257F-DK 보드다). 이번 시간 부터는 앞으로 몇차례에 걸쳐서, STM32MP257F-DK 보드 기반 embedded linux와 관련한 다양한 주제를 다뤄 보고자 한다. 이번이 그 네번째 시간이다. 😎
목차
8. Buildroot로 작업하기
9. Cortex-M33 CPU - Zephyr RTOS & STM32CubeIDE 기반 Application 돌려 보기
10. Application 돌려 보기 - WireGuard Rust, Qt6 Application, ROS
References
Keywords: STM32MP257F-DK, booting flow, u-boot, linux kernel, device tree, yocto project, Buildroot, Rust kernel module, STM32CubeIDE, Zephyr RTOS, PySide6
Embedded linux(echosystem)는 점점 더 복잡해져 가고 있다. 이중 삼중의 bootloader(거기에 TrustZone까지), device tree로 무장한 linux kernel, kernel에 합류한 Rust, build system의 대세 Yocto project ! 어느 하나 무시할 수 없는 것들 뿐이다. 이번 시간에는 Yocto project의 대체제인 Buildroot 환경에서 bootloader와 kernel 및 rootfs를 개발하는 내용을 다뤄 보고자 한다. 😋
비록 비인기 종목이지만 최선을 다한 선수들에게 박수를 ㅋㅋ
(Buildroot가 비록 Yocto project 보다는 비인기 종목(?) 이지만, 그래도 없어서는 안될 중요한 존재다 😍)
8. Buildroot로 작업하기
이번 장에서는 Buildroot를 이용하여 STM32MP257F-DK 보드용 image를 생성하는 방법과 개별 component(TF-A, OP-TEE, u-boot, kernel)를 별도로 build하는 방법을 살펴 보고자 한다. 😎
8.1 Buildroot 사용하기
이번 절에서는 STM32MP257F-DK 보드용 firmware image를 만들기 위하여, (5~7장에서 다뤘던) 조금은 거창한 Yocto project 대신 Buildroot를 사용해 보기로 한다.
다행히도 Buildroot에는 이미 stm32mp1 및 stm32mp2 계열의 보드를 지원하기 위한 확장 project가 마련되어 있다. 😍
참고로, 아래 그림은 Buildroot에 신규 보드를 추가하고자 할 경우에 예상되는 작업 내용을 대략적으로 정리해 본 것이다.
[그림 8.1.3] Buildroot 외부 확장 project - 신규 보드 추가시 대략적인 작업 과정
-------------------------------------------------------------------------
그럼, 지금부터 본격적으로 buildroot를 build해 보기로 하자.
<Ubuntu 22.04 LTS>
$ git clone -b st/2025.02.5 https://github.com/bootlin/buildroot.git
-> buildroot 2025.02.5 version을 내려 받는다.
$ git clone -b st/2025.02.5 https://github.com/bootlin/buildroot-external-st.git
-> stm32 boards용으로 확장 code를 제공하고 있어, 이를 사용하기로 한다.
$ cd buildroot
$ make BR2_EXTERNAL=../buildroot-external-st st_stm32mp257f_dk_defconfig
or
$ make BR2_EXTERNAL=../buildroot-external-st st_stm32mp257f_dk_demo_defconfig
-> OpenGL, Qt5, OP-TEE, WiF, Bluetooth, RAUC, Camera 등을 추가적으로 지원
-> squashfs file system 사용
$ make menuconfig
-> 필요한 설정을 추가하거나 변경해 본다.
$ make -j 16
or
$ make 2>&1 | tee build.log //build 과정을 파일로 저장해 보고 싶다면 ...
...
Allocating group tables: done
Writing inode tables: done
Creating journal (4096 blocks): done
Copying files into the device: done
Writing superblocks and filesystem accounting information: done
ln -sf rootfs.ext2 /mnt/hdd/workspace/ST/STM32MP257K_DK/BuildRoot/buildroot/output/images/rootfs.ext4
ln -snf /mnt/hdd/workspace/ST/STM32MP257K_DK/BuildRoot/buildroot/output/host/aarch64-buildroot-linux-gnu/sysroot /mnt/hdd/workspace/ST/STM32MP257K_DK/BuildRoot/buildroot/output/staging
>>> Executing post-image script /mnt/hdd/workspace/ST/STM32MP257K_DK/BuildRoot/buildroot-external-st/board/stmicroelectronics/common/generate-sdcard.sh
INFO: cmd: "mkdir -p "/mnt/hdd/workspace/ST/STM32MP257K_DK/BuildRoot/buildroot/output/build/genimage.tmp"" (stderr):
INFO: cmd: "rm -rf "/mnt/hdd/workspace/ST/STM32MP257K_DK/BuildRoot/buildroot/output/build/genimage.tmp"/*" (stderr):
INFO: cmd: "mkdir -p "/mnt/hdd/workspace/ST/STM32MP257K_DK/BuildRoot/buildroot/output/images"" (stderr):
INFO: hdimage(sdcard.img): adding primary partition 'fsbla' (in MBR) from 'tf-a-stm32mp257f-dk.stm32' ...
INFO: hdimage(sdcard.img): adding primary partition 'fip' (in MBR) from 'fip.bin' ...
INFO: hdimage(sdcard.img): adding primary partition 'u-boot-env' (in MBR) ...
INFO: hdimage(sdcard.img): adding primary partition 'rootfs' (in MBR) from 'rootfs.ext4' ...
INFO: hdimage(sdcard.img): adding primary partition '[MBR]' ...
INFO: hdimage(sdcard.img): adding primary partition '[GPT header]' ...
INFO: hdimage(sdcard.img): adding primary partition '[GPT array]' ...
INFO: hdimage(sdcard.img): adding primary partition '[GPT backup]' ...
INFO: hdimage(sdcard.img): writing GPT
INFO: hdimage(sdcard.img): writing protective MBR
INFO: hdimage(sdcard.img): writing MBR
INFO: cmd: "rm -rf "/mnt/hdd/workspace/ST/STM32MP257K_DK/BuildRoot/buildroot/output/build/genimage.tmp/"" (stderr):
>>> Executing post-image script /mnt/hdd/workspace/ST/STM32MP257K_DK/BuildRoot/buildroot-external-st/board/stmicroelectronics/common/generate-flashlayout.sh
아래 위치에 결과물이 생성된다.
$ cd output/images
$ tree .
.
├── Image.gz
├── bl2.bin
├── bl31.bin
├── fip-ddr-stm32mp257_dk_usb.bin
├── fip-stm32mp257_dk_usb.bin
├── fip.bin
├── flash.tsv
├── rootfs.ext2
├── rootfs.ext4 -> rootfs.ext2
├── sdcard.img
├── sdcard.img.bmap
├── sdcard.img.gz <---------------- 얘를 microSD에 설치하자.
├── stm32mp257f-dk.dtb
├── tee-header_v2.bin
├── tee-pageable_v2.bin
├── tee-pager_v2.bin
├── tee.bin
├── tf-a-stm32mp257_dk_usb.stm32
├── tf-a-stm32mp257f-dk.stm32
├── u-boot-nodtb.bin
└── u-boot.dtb
-----------------------------------------------------
Buildroot에서 하는 일을 대략적으로 정리해 보면 다음과 같다.
<buildroot의 build 절차 요약>
[1] ARM 웹사이트에서 미리 빌드된 ARM 컴파일러를 다운로드하여 설치하고, C 및 C++ 라이브러리를 대상 루트 파일 시스템 내에 설치한다.
[2] STMicroelectronics GitHub 저장소에서 Linux 커널 소스 코드를 다운로드하고, 제공된 구성 파일로 구성한 후 빌드한 Image.gz와 stm32mp257f-dk.dtb 파일을 output/images와 대상 루트 파일 시스템의 /boot 디렉터리에 설치한다. 또한 Linux 커널 모듈도 대상 루트 파일 시스템 내에 설치한다.
[3] STMicroelectronics GitHub 저장소에서 U-Boot 소스 코드를 다운로드하고, 구성 & 빌드한 후 u-boot-nodtb.bin와 u-boot.dtb 파일을 output/images에 설치한다.
[4] STMicroelectronics GitHub 저장소에서 OP-TEE와 TF-A 소스 코드를 다운로드하여 빌드한 후 결과 파일(tee*.bin, tf-a-*, fip*)을 output/images에 복사한다.
[5] 프로젝트 공식 웹사이트에서 Busybox 소스 코드를 다운로드하고, 구성하고, 빌드한 후 대상 루트 파일 시스템 내에 설치한다.
[6] 루트 파일 시스템 오버레이의 내용을 대상 루트 파일 시스템 내부에 복사한다.
[7] 루트 파일 시스템의 ext4 이미지를 생성하고 output/images/rootfs.ext4로 설치한다.
[그림 8.1.7] rootfs 생성 절차 [출처 - 참고문헌 15]
[8] support/scripts/genimage.sh 스크립트를 실행하여 최종 SD 카드 이미지인 output/images/sdcard.img를 생성한다.
-> buildroot-external-st/board/stmicroelectronics/common/generate-sdcard.sh
--> support/scripts/genimage.sh 호출
--> genimage.cfg 사용하여 sdcard.img 생성
[그림 8.1.8] buildroot-external-st/board/stmicroelectronics/stm32mp2/genimage.cfg
자, 그럼 이제부터 sdcard.img를 microSD card에 설치하고, 정상적으로 booting되는지를 확인해 보도록 하자. 먼저, microSD를 PC에 연결한 상태에서, 아래 명령을 실행하도록 한다.
$ gzip -dc ./sdcard.img.gz | sudo dd of=/dev/sdb bs=1M
-> file size가 크지 않아 곧 바로 write 된다.
0+3335 레코드 들어옴
0+3335 레코드 나감
109367296 bytes (109 MB, 104 MiB) copied, 7.72671 s, 14.2 MB/s
-----------------------------------------------------------------------
sdcard image 설치 후, fdisk 명령으로 /dev/sdb 파티션을 확인해 보니, 아래와 같이 4개의 파티션이 만들어진 것을 알 수가 있다.
$ sudo fdisk /dev/sdb
Welcome to fdisk (util-linux 2.37.2).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
GPT PMBR size mismatch (213607 != 31116287) will be corrected by write.
The backup GPT table is not on the end of the device. This problem will be corrected by write.
Command (m for help): p
Disk /dev/sdb: 14.84 GiB, 15931539456 bytes, 31116288 sectors
Disk model: STORAGE DEVICE
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: D45BC0F6-5FA6-4957-8AA1-55E3D362FDE3
Device Start End Sectors Size Type ................................................ (A)
/dev/sdb1 34 545 512 256K Linux filesystem
/dev/sdb2 546 8737 8192 4M Linux filesystem
/dev/sdb3 8738 8769 32 16K Linux filesystem
/dev/sdb4 8770 213569 204800 100M Linux filesystem
--------------------------------------------------------------------
같은 내용을 gparted 명령으로 확인해 보면 좀 더 많은 정보를 얻을 수가 있다.
[그림 8.1.9] gparted 명령 실행 모습
위의 그림을 기초로 할 때, 각각의 파티션이 어느 부분에 해당하는지가 명확해 진다.
<sdcard partition 정보>
partition 'fsbla' (in MBR) from 'tf-a-stm32mp257f-dk.stm32' ... //BL2(TF-A firmware)
partition 'fip' (in MBR) from 'fip.bin' ... //BL31(secure monitor), BL32(OP-TEE), BL33(u-boot)가 포함되어 있음.
partition 'u-boot-env' (in MBR) ... //u-boot ENV(환경 정보 저장) file
partition 'rootfs' (in MBR) from 'rootfs.ext4' ... //rootfs 저장용, 뿐만아니라 Image.gz, stm32mp257f-dk.dtb는 /boot에 위치함.
-------------------------------------------------------
이어서, Target board에 microSD를 다시 장착한 후, 전원을 켜 본다.
$ sudo minicom -D /dev/ttyACM0
-> OK, 정상적으로 부팅이 된다.
[그림 8.1.10] buildroot image 부팅 모습
만일 dd 명령으로 sdcard.img를 설치했음에도 불구하고, 부팅이 잘 안되는 경우에는 1장에서 소개한 STM32 Cube Programmer를 이용하여 설치해 주면 된다. 참고로, 이번에는 GUI 버젼 대신 CLI 버젼 즉, STM32_Programmer_CLI를 사용하여 설치를 진행해 보도록 하자.
1장에서 설명한 대로, boot switch를 <0 0 0 0> 상태로 만들고, USB-C cable과 5V/3A 전원 adapter를 연결한 상태에서 아래와 같은 명령을 실행하도록 한다.
STM32_Programmer_CLI -c port=usb1 -w flash.tsv
참고로, 아래 파일은 이때 필요한 flash.tsv file이다.
[그림 8.1.11] output/images/flash.tsv 모습
📌 tsv는 Tab-separated-values를 뜻한다. 즉, 각각의 field가 tab(\t)으로 구분되어 있는 파일이라는 얘기다.
$ sudo ~/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin/STM32_Programmer_CLI -c port=usb1 -w ./flash.tsv
-------------------------------------------------------------------
STM32CubeProgrammer v2.22.0
-------------------------------------------------------------------
USB speed : High Speed (480MBit/s)
Manuf. ID : STMicroelectronics
Product ID : DFU in HS Mode @Device ID /0x505, @Revision ID /0x2000
SN : 002E00434236501700363847
DFU protocol: 1.1
Board : --
Device ID : 0x505
Device name : STM32MP23xx/25xx
Device type : MPU
Revision ID : --
Device CPU : Cortex-A35
Start Embedded Flashing service
Opening and parsing file: tf-a-stm32mp257_dk_usb.stm32
Memory Programming ...
File : tf-a-stm32mp257_dk_usb.stm32
Size : 186.95 KB
Partition ID : 0x01
Download in Progress:
[==================================================] 100%
File download complete
Time elapsed during download operation: 00:00:01.210
RUNNING Program ...
PartID: :0x01
Reconnecting the device ...
USB speed : High Speed (480MBit/s)
Manuf. ID : STMicroelectronics
Product ID : DFU @Device ID /0x505, @Revision ID /0x0011, @Name /STM32MP257FAK Rev.Y,
SN : 002E00434236501700363847
DFU protocol: 1.1
Board : --
Device ID : 0x505
Device name : STM32MP257FAK Rev.Y
Device type : MPU
Device CPU : Cortex-A35
Start operation done successfully at partition 0x01
Opening and parsing file: fip-ddr-stm32mp257_dk_usb.bin
Memory Programming ...
File : fip-ddr-stm32mp257_dk_usb.bin
Size : 33.67 KB
Partition ID : 0x02
Download in Progress:
[==================================================] 100%
File download complete
Time elapsed during download operation: 00:00:00.023
RUNNING Program ...
PartID: :0x02
Reconnecting the device ...
USB speed : High Speed (480MBit/s)
Manuf. ID : STMicroelectronics
Product ID : DFU @Device ID /0x505, @Revision ID /0x0011, @Name /STM32MP257FAK Rev.Y,
SN : 002E00434236501700363847
DFU protocol: 1.1
Board : --
Device ID : 0x505
Device name : STM32MP257FAK Rev.Y
Device type : MPU
Device CPU : Cortex-A35
Start operation done successfully at partition 0x02
Opening and parsing file: fip-stm32mp257_dk_usb.bin
Memory Programming ...
File : fip-stm32mp257_dk_usb.bin
Size : 3.07 MB
Partition ID : 0x03
Download in Progress:
[==================================================] 100%
File download complete
Time elapsed during download operation: 00:00:02.061
RUNNING Program ...
PartID: :0x03
Reconnecting the device ...
USB speed : High Speed (480MBit/s)
Manuf. ID : STMicroelectronics
Product ID : USB download gadget@Device ID /0x505, @Revision ID /0x0011, @Name /STM32MP257FAK Rev.Y,
SN : 002E00434236501700363847
DFU protocol: 1.1
Board : --
Device ID : 0x505
Device name : STM32MP257FAK Rev.Y
Device type : MPU
Device CPU : Cortex-A35
Start operation done successfully at partition 0x03
Flashlayout Programming ...
[==================================================] 100%
Running Flashlayout Partition ...
Reconnecting the device ...
USB speed : High Speed (480MBit/s)
Manuf. ID : STMicroelectronics
Product ID : USB download gadget@Device ID /0x505, @Revision ID /0x0011, @Name /STM32MP257FAK Rev.Y,
SN : 002E00434236501700363847
DFU protocol: 1.1
Board : --
Device ID : 0x505
Device name : STM32MP257FAK Rev.Y
Device type : MPU
Device CPU : Cortex-A35
Flashlayout partition started successfully
Opening and parsing file: sdcard.img
Memory Programming ...
File : sdcard.img
Size : 104.30 MB
Partition ID : 0x10
Download in Progress:
[==================================================] 100%
File download complete
Time elapsed during download operation: 00:00:22.376
RUNNING Program ...
PartID: :0x10
Start operation done successfully at partition 0x10
Flashing service completed successfully
----------------------------------------------------------------------------
꽤나 복잡한 과정을 거쳐 설치가 진행되는 것을 알 수가 있다. 그렇다면, 위에서 진행되는 내용은 어떻게 설명될 수 있을까 ?
<STM32_Programmer_CLI의 대략적인 설치 절차 요약>
1) 아래 그림에서 확인할 수 있듯이, ROM code는 STM32 Cube Programmer를 통해 전달 받은 TF-A bootloader를 RAM 상에 적재(load)한 후, TF-A에게 제어권을 넘긴다.
-> ROM code는 기본적으로 USB port로 부터 들어오는 data를 읽어 RAM에 loading하는 기능이 포함되어 있다.
2) TF-A(usb용)는 USB port & STM32 Cube Programmer를 통해 fip-ddr-stm32mp257_dk_usb.bin image를 전달 받은 후, 그 안에서 u-boot SPL(예상)을 추출하여 RAM에 적재시킨 후, 제어권을 넘긴다.
3) u-boot SPL(usb용)은 주된 작업으로 RAM을 초기화하는 역할을 하게 되고, 이어서 STM32 Cube Programmer를 통해 fip-stm32mp257_dk_usb.bin를 전달 받는 후, 그 안에서 u-boot을 추출하여 RAM에 적재시킨 후, 역시 제어권을 넘긴다.
4) 마지막으로 u-boot(usb용)은 STM32 Cube Programmer를 통해 sdcard.img를 전달 받은 후, 이를 SDcard 물리 장치에 write(flash write)하게 된다.
[그림 8.1.12] sdcard.img 설치 과정 개요
📌 단, 위의 설명 및 그림에는 오류가 있을 수 있다.
이후, boot switch를 <1 0 0 0>으로 재 조정 후, 전원을 인가하여 부팅이 되는지를 확인해 본다.
-----------------------------------------
지금까지, Buildroot code를 내려 받아 STM32MP257F-DK board를 위한 image를 만든 후, microSD 카드에 설치 & 부팅하는 과정까지 살펴 보았다. 끝으로, Buildroot기반의 firmware image를 사용하는 STM32MP257F-DK board의 부팅 프로세스를 좀 더 구체적으로 요약해 보는 것으로 이번 절을 마무리하고자 한다. 💢
[그림 8.1.13] stm32mp2 booting flow [출처 - 참고문헌 17]
📌 위의 그림에서 BL31, BL33을 감싼 부분이 FIP(Firmware Image Package)에 해당한다.
1) STM32MP25 내장 ROM 코드는 이름이 fsbla로 시작하는 GPT 파티션을 찾고, 발견되면 해당 파티션의 내용을 STM32 내부 메모리에 로드하여 실행하게 되는데, 이것이 1단계 부트로더(TF-A)이다.
2) 이 1단계 부트로더는 SD 카드의 두 번째 파티션에서 2단계 부트로더를 로드하도록 하드코딩되어 있다. 따라서 외부 RAM을 초기화하고, 2단계 부트로더(u-boot)를 외부 RAM에 로드한 후 실행한다.
3) 2단계 부트로더(u-boot)는 추가적인 초기화를 수행한 후 부팅 가능으로 표시된 파티션(네 번째 파티션)을 찾는다. 그런 다음 /boot/extlinux/extlinux.conf 파일을 로드하여 커널과 디바이스 트리의 위치를 파악한다. 이후 커널과 디바이스 트리를 모두 로드하고, extlinux.conf 파일에 지정된 인수를 사용하여 커널을 시작한다.
[그림 8.1.14] /boot/extlinux/extlinux.conf 파일
참고로, /boot/extlinux/extlinux.conf 파일은 U-Boot에게 로드할 커널 이미지가 /boot/Image.gz이고, 사용할 dtb 파일이 /boot/stm32mp257f-dk.dtb이며, 부팅 시 Linux 커널에 인수로 root=PARTUUID=b26967be-18fb-40fe-9d9b-ae035fc4a1c5 rootwait console=ttySTM0,115200n8 문자열을 전달해야 함을 알려준다. 특히 root=PARTUUID=b26967be-18fb-40fe-9d9b-ae035fc4a1c5는 Linux 커널에 루트 파일 시스템의 위치(실제로 /dev/mmcblk0p4에 해당함)를 알려주는 중요한 부분이다.
4) 리눅스 커널은 루트 파일 시스템을 마운트할 때까지 실행되며, 루트 파일 시스템의 위치는 `root=PARTUUID=b26967be-18fb-40fe-9d9b-ae035fc4a1c5` 인수로 지정된다. 루트 파일 시스템을 마운트한 후, 커널은 첫 번째 사용자 공간 프로세스를 시작한다.
실행되는 첫 번째 사용자 공간 프로세스는 BusyBox로 구현된 `/sbin/init`이다. 이 프로세스는 몇 가지 서비스를 시작한 다음 로그인 프롬프트를 출력한다.
[그림 8.1.16] linux kernel 부팅 중, rootfs mount하는 모습
8.2 개별 component build 하기
이번 절에서는 Buildroot를 구성하는 주요 component 즉, TF-A, OP-TEE, u-boot, kernel 등을 직접 build한 후, 이를 토대로 booting image를 만들어 돌려보는 방법을 소개하도록 하겠다. 이번 절에서 소개하는 내용은 아래 문서를 기초로 하였다. 😍
아, 물론 buildroot build 과정에서 자동으로 download된 bootloader(tf-a, op-tee, u-boot), kernel 등을 사용할 수도 있겠지만, 여기에서는 외부 디렉토리(out-of-tree)에 개별 source code를 일일히 download하여 build하는 것을 원칙으로 한다.
<U-boot setup>
$ git clone https://github.com/STMicroelectronics/u-boot.git
$ cd u-boot
$ git checkout v2023.10-stm32mp-r1
$ git branch
* (HEAD v2023.10-stm32mp-r1 위치에서 분리됨)
v2023.10-stm32mp
$ export PATH=<YOUR_PATH>/buildroot/output/host/bin:$PATH
-> toolchain은 별도로 build하지 말고, 8.1 buildroot 절에서 만든 것을 이용하도록 하자.
$ aarch64-none-linux-gnu-gcc --version
aarch64-none-linux-gnu-gcc (Arm GNU Toolchain 14.2.Rel1 (Build arm-14.52)) 14.2.1 20241119
Copyright (C) 2024 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ export CROSS_COMPILE=aarch64-none-linux-gnu-
$ make stm32mp25_defconfig
#
# configuration written to .config
#
$ make menuconfig
-> Environment //uboot.env file안에 u-boot 환경 설정 정보를 저장하도록 설정을 변경하자.
-> [ ] Environment is not stored
-> [*] Environment is in a EXT4 filesystem
-> [ ] Environment in flash memory
-> [ ] Environment in an MMC devic
-> [ ] Environment is in SPI flash
-> [ ] Environment in a UBI volume
-> (mmc) Name of the block device for the environment
-> (0:3) Device and partition for where to store the environemt in EXT
-> (/uboot.env) Name of the EXT4 file to use for the environment (NEW)
$ make DEVICE_TREE=stm32mp257f-dk
...
CC net/tftp.o
AR net/built-in.o
LDS u-boot.lds
LD u-boot
OBJCOPY u-boot.srec
OBJCOPY u-boot-nodtb.bin
RELOC u-boot-nodtb.bin
DTC arch/arm/dts/stm32mp257f-dk.dtb
DTC arch/arm/dts/stm32mp257f-ev1.dtb
SHIPPED dts/dt.dtb
CAT u-boot-dtb.bin
COPY u-boot.bin
SYM u-boot.sym
COPY u-boot.dtb
OFCHK .config
<OP-TEE setup>
$ cd ..
$ git clone https://github.com/STMicroelectronics/optee_os.git
$ cd optee_os/
$ git checkout 4.0.0-stm32mp-r1
$ git branch
* (HEAD 4.0.0-stm32mp-r1 위치에서 분리됨)
4.0.0-stm32mp
$ make O=out \
CROSS_COMPILE=aarch64-none-linux-gnu- \
CROSS_COMPILE_core=aarch64-none-linux-gnu- \
CROSS_COMPILE_ta_arm64=aarch64-none-linux-gnu- \
CFG_ARM64_core=y \
CFG_USER_TA_TARGETS=ta_arm64 \
PLATFORM=stm32mp2 \
CFG_WITH_TUI=n \
all
...
LD out/ta/pkcs11/fd02c9da-306c-48c7-a49c-bbd827ae86ee.elf
OBJCOPY out/ta/pkcs11/fd02c9da-306c-48c7-a49c-bbd827ae86ee.stripped.elf
SIGN out/ta/pkcs11/fd02c9da-306c-48c7-a49c-bbd827ae86ee.ta
INSTALL out/export-ta_arm64/ta/fd02c9da-306c-48c7-a49c-bbd827ae86ee.ta
SIGN out/ta/remoteproc/80a4c275-0a47-4905-8285-1486a9771a08.ta
INSTALL out/export-ta_arm64/ta/80a4c275-0a47-4905-8285-1486a9771a08.ta
SIGN out/ta/stm32mp_nvmem/1a8342cc-81a5-4512-99fe-9e2b3e37d626.ta
INSTALL out/export-ta_arm64/ta/1a8342cc-81a5-4512-99fe-9e2b3e37d626.ta
CC out/ta/trusted_keys/entry.o
CC out/ta/trusted_keys/user_ta_header.o
CPP out/ta/trusted_keys/ta.lds
GEN out/ta/trusted_keys/dyn_list
UPD out/ta/trusted_keys/dyn_list
LD out/ta/trusted_keys/f04a0fe7-1f5d-4b9b-abf7-619b85b4ce8c.elf
OBJCOPY out/ta/trusted_keys/f04a0fe7-1f5d-4b9b-abf7-619b85b4ce8c.stripped.elf
SIGN out/ta/trusted_keys/f04a0fe7-1f5d-4b9b-abf7-619b85b4ce8c.ta
INSTALL out/export-ta_arm64/ta/f04a0fe7-1f5d-4b9b-abf7-619b85b4ce8c.ta
OBJDUMP out/ta/avb/023f8f1a-292a-432b-8fc4-de8471358067.dmp
CHK pkcs11-ta-verify-helpers
OBJDUMP out/ta/pkcs11/fd02c9da-306c-48c7-a49c-bbd827ae86ee.dmp
OBJDUMP out/ta/remoteproc/80a4c275-0a47-4905-8285-1486a9771a08.dmp
OBJDUMP out/ta/stm32mp_nvmem/1a8342cc-81a5-4512-99fe-9e2b3e37d626.dmp
OBJDUMP out/ta/trusted_keys/f04a0fe7-1f5d-4b9b-abf7-619b85b4ce8c.dmp
<TF-A setup>
$ cd ..
$ git clone https://github.com/STMicroelectronics/arm-trusted-firmware.git
$ cd arm-trusted-firmware/
$ git checkout v2.10-stm32mp-r1
$ git branch
* (HEAD v2.10-stm32mp-r1 위치에서 분리됨)
v2.10-stm32mp
$ make \
CROSS_COMPILE=aarch64-none-linux-gnu- \
PLAT=stm32mp2 ARM_ARCH_MAJOR=8 \
ARCH=aarch64 \
STM32MP_LPDDR4_TYPE=1 \
DTB_FILE_NAME=stm32mp257f-dk.dtb \
STM32MP_SDMMC=1 SPD=opteed \
BL32=../optee_os/out/core/tee-header_v2.bin \
BL32_EXTRA1=../optee_os/out/core/tee-pager_v2.bin \
BL32_EXTRA2=../optee_os/out/core/tee-pageable_v2.bin \
BL33=../u-boot/u-boot-nodtb.bin \
BL33_CFG=../u-boot/u-boot.dtb \
all fip
...
Built fiptool successfully
EL3 Runtime Firmware BL31: offset=0x1A0, size=0x136C8, cmdline="--soc-fw"
Secure Payload BL32 (Trusted OS): offset=0x13868, size=0x1C, cmdline="--tos-fw"
Secure Payload BL32 Extra1 (Trusted OS Extra1): offset=0x13884, size=0xF9558, cmdline="--tos-fw-extra1"
Non-Trusted Firmware BL33: offset=0x10CDDC, size=0x1C06D0, cmdline="--nt-fw"
FW_CONFIG: offset=0x2CD4AC, size=0x326, cmdline="--fw-config"
HW_CONFIG: offset=0x2CD7D2, size=0x1C5D0, cmdline="--hw-config"
SOC_FW_CONFIG: offset=0x2E9DA2, size=0x391A, cmdline="--soc-fw-config"
DDR_FW: offset=0x2ED6BC, size=0x8650, cmdline="--ddr-fw"
Built /mnt/hdd/workspace/ST/STM32MP257K_DK/BuildRoot/bootlin/arm-trusted-firmware/build/stm32mp2/release/fip.bin successfully
rm /mnt/hdd/workspace/ST/STM32MP257K_DK/BuildRoot/bootlin/arm-trusted-firmware/build/stm32mp2/release/stm32mp2-stm32mp257f-dk.o /mnt/hdd/workspace/ST/STM32MP257K_DK/BuildRoot/bootlin/arm-trusted-firmware/build/stm32mp2/release/tf-a-stm32mp257f-dk.bin /mnt/hdd/workspace/ST/STM32MP257K_DK/BuildRoot/bootlin/arm-trusted-firmware/build/stm32mp2/release/tf-a-stm32mp257f-dk.elf
TF-A firmware와 fip.bin은 아래 디렉토리에 생성된다.
$ cd build/stm32mp2/release
$ ls -l
drwxrwxr-x 3 chyi chyi 12288 3월 11 16:55 bl2
-rwxrwxr-x 1 chyi chyi 104563 3월 11 16:55 bl2.bin
drwxrwxr-x 3 chyi chyi 12288 3월 11 16:55 bl31
-rw-rw-r-- 1 chyi chyi 79560 3월 11 16:55 bl31.bin
drwxrwxr-x 2 chyi chyi 4096 3월 11 16:55 fdts
-rw-rw-r-- 1 chyi chyi 3104012 3월 11 16:55 fip.bin //OP-TEE, u-boot을 담고 있음.
drwxrwxr-x 2 chyi chyi 4096 3월 11 16:55 lib
drwxrwxr-x 2 chyi chyi 4096 3월 11 16:55 libc
drwxrwxr-x 2 chyi chyi 4096 3월 11 16:55 libfdt
drwxrwxr-x 2 chyi chyi 4096 3월 11 16:55 libwrapper
drwxrwxr-x 2 chyi chyi 4096 3월 11 16:55 romlib
-rw-rw-r-- 1 chyi chyi 1038 3월 11 16:55 stm32mp2.ld
-rw-rw-r-- 1 chyi chyi 2664 3월 11 16:55 stm32mp2.ld.d
-rw-rw-r-- 1 chyi chyi 2824 3월 11 16:55 tf-a-stm32mp257f-dk.map
-rw-rw-r-- 1 chyi chyi 189555 3월 11 16:55 tf-a-stm32mp257f-dk.stm32 //first stage bootloader(BL2)
여기까지의 과정을 거쳐, firmware image 파일이 준비되었으니, 이제 부터는 microSD card에 필요한 만큼의 partition을 만든 후, 각각의 위치에 원하는 firmware를 write해 보도록 하자.
<bootable microSD 만들기>
$ sudo dd if=/dev/zero of=/dev/sdb bs=1M count=128
-> microSD를 싹 밀고 다시 시작한다.
이번에는 fdisk 대신 parted를 사용하여 partition을 나누어 보도록 하자.
$ sudo parted /dev/sdb
GNU Parted 3.4
/dev/sdb 사용법
GNU Parted 사용을 환영합니다! 명령 목록을 보려면 ‘help’를 입력하십시오.
(parted) mklabel gpt
(parted) print
모델: Generic STORAGE DEVICE (scsi)
/dev/sdb 디스크: 15.9GB
섹터 크기(논리/실제): 512/B512B
분할 영역 테이블: gpt
디스크 플래그:
번호 시작 끝 크기 파일 시스템 이름 플래그
(parted) mkpart fsbla 34s 545s //sector 단위로 파티션을 만든다.
경고: 최적 성능을 목적으로 분할 영역 배치 과정에서 제대로 정렬하지 않았습니다: 34s % 2048s != 0s
무시/Ignore/취소/Cancel? I
(parted) mkpart fip 546s 8737s
경고: 최적 성능을 목적으로 분할 영역 배치 과정에서 제대로 정렬하지 않았습니다: 546s % 2048s != 0s
무시/Ignore/취소/Cancel? I
(parted) mkpart u-boot-env 8738s 8769s
경고: 최적 성능을 목적으로 분할 영역 배치 과정에서 제대로 정렬하지 않았습니다: 8738s % 2048s != 0s
무시/Ignore/취소/Cancel? I
(parted) mkpart rootfs 8770s 213569s
경고: 최적 성능을 목적으로 분할 영역 배치 과정에서 제대로 정렬하지 않았습니다: 8770s % 2048s != 0s
무시/Ignore/취소/Cancel? I
(parted) print
모델: Generic STORAGE DEVICE (scsi)
/dev/sdb 디스크: 15.9GB
섹터 크기(논리/실제): 512/B512B
분할 영역 테이블: gpt
디스크 플래그:
번호 시작 끝 크기 파일 시스템 이름 플래그
1 17.4kB 280kB 262kB fsbla
2 280kB 4474kB 4194kB fip
3 4474kB 4490kB 16.4kB u-boot-env
4 4490kB 109MB 105MB rootfs
(parted) quit
📌 위에서 사용한 sector 정보는 8.1절의 (A) 테이블 정보를 기초로 하였다.
------------------------------------------------------------------
$ sudo mkfs -t ext4 -L boot -O ^metadata_csum /dev/sdb3
mke2fs 1.46.5 (30-Dec-2021)
/dev/sdb3: Not enough space to build proposed filesystem while setting up superblock
$ cd arm-trusted-firmware/build/stm32mp2/release
$ sudo dd if=./tf-a-stm32mp257f-dk.stm32 of=/dev/sdb1 bs=1M conv=fdatasync
[sudo] chyi 암호:
0+1 레코드 들어옴
0+1 레코드 나감
189555 bytes (190 kB, 185 KiB) copied, 0.000169088 s, 1.1 GB/s
$ sudo dd if=./fip.bin of=/dev/sdb2 bs=1M conv=fdatasync
2+1 레코드 들어옴
2+1 레코드 나감
3104012 bytes (3.1 MB, 3.0 MiB) copied, 0.00217346 s, 1.4 GB/s
---------------------------------------------------------------
자, 이 상태에서 target board에 microSD를 다시 장착하고, TF-A -> OP-TEE -> u-boot까지 구동되는지를 확인해 본다.
$ sudo minicom -D /dev/ttyACM0
[그림 8.2.1] BL2(TF-A) -> BL33(u-boot) 구동 모습
--------------------------------------------------------------------------------------------------------------
이제 부터는 (마지막 단계로) kernel을 준비해 보도록 하자.
<kernel setup>
$ git clone https://github.com/torvalds/linux.git
$ cd linux
$ git remote add st https://github.com/STMicroelectronics/linux
$ git fetch st
$ git branch -r | grep st/
st/master
st/v4.19-stm32mp
st/v5.10-stm32mp
st/v5.15-stm32mp
st/v5.4-stm32mp
st/v6.1-stm32mp
st/v6.6-stm32mp
$ git checkout v6.6-stm32mp-r2
$ git branch
* (HEAD v6.6-stm32mp-r2 위치에서 분리됨)
master
$ export PATH=<YOUR_BUILDROOT>/buildroot/output/host/bin:$PATH
$ export ARCH=arm64
$ export CROSS_COMPILE=aarch64-none-linux-gnu-
다음으로 kernel config를 stm32mp257f-dk용에 맞게 일일히 조정해야 하지만, 매우 번거로운 작업이므로, buildroot or yocto project에서 사용했던 .config를 복사하여 사용하기로 한다. 😋
<buildroot or yocto에서 사용한 kernel config 재활용>
$ cp <YOUR_BUILDROOT>/buildroot/output/build/linux-custom/.config .
or
📌 yocto kernel의 config로 테스트해 보았는데, 부팅 중에 아래와 같이 kernel panic이 발생하는 문제가 있다. 😓
[ 5.074340] stm32-dwmac 482c0000.eth1: Using 32/32 bits DMA host/device width
[ 5.347547] etnaviv etnaviv: bound 48280000.gpu (ops gpu_ops [etnaviv])
E/TC:1 0 Panic at core/drivers/clk/clk-stm32mp25.c:2000 <clk_stm32_pll_init>
E/TC:1 0 TEE load address @ 0x82000000
E/TC:1 0 Call stack:
E/TC:1 0 0x82007f18
E/TC:1 0 0x82041e98
E/TC:1 0 0x82034a58
E/TC:1 0 0x82034d2c
E/TC:1 0 0x82030d2c
E/TC:1 0 0x82030d08
E/TC:1 0 0x82031294
E/TC:1 0 0x820734f8
E/TC:1 0 0x820699a4
E/TC:1 0 0x8206f3b4
-------------------------------------------------------------------
$ make menuconfig
-> kernel config가 제대로 구성되어 있는지 확인해 본다.
$ make -j 16
$ cd arch/arm64/boot
$ ls -la
-rw-rw-r-- 1 chyi chyi 152 3월 13 16:16 .Image.cmd
-rw-rw-r-- 1 chyi chyi 106 3월 13 16:16 .Image.gz.cmd
-rw-rw-r-- 1 chyi chyi 64 3월 12 13:26 .gitignore
-rw-rw-r-- 1 chyi chyi 25508352 3월 13 16:16 Image
-rw-rw-r-- 1 chyi chyi 11029469 3월 13 16:16 Image.gz
-rw-rw-r-- 1 chyi chyi 1373 3월 12 13:26 Makefile
drwxrwxr-x 36 chyi chyi 4096 3월 12 13:26 dts
-rwxrwxr-x 1 chyi chyi 1001 3월 12 13:26 install.sh
kernel modules을 별도의 디렉토리에 설치한다.
$ mkdir my_kernel_modules
$ make INSTALL_MOD_PATH=./my_kernel_modules/ modules_install
$ cd my_kernel_modules
$ tar modules-stm32mp2.tgz ./
$ ls -la
drwxrwxr-x 3 chyi chyi 4096 3월 13 16:28 lib
-rw-rw-r-- 1 chyi chyi 56002394 3월 13 16:30 modules-stm32mp2.tgz
새로 build한 kernel & modules, dtb 파일이 정상 동작하는지를 확인하기 위해서는 아래와 같이 3가지 방법을 사용할 수가 있다.
a) tftp booting & NFS mounting하여 확인하기
이와 관련한 사항은 이전 posting을 참고하기 바란다.
b) 앞서 만든 firmware를 적용한 새로운 sdcard.img 만들어 설치하기
tftp booting이 싫은 경우에는, 위에서 build한 결과물을 8.1절에서 만든 buildroot output 디렉토리로 복사하여 sdcard.img를 다시 만들어 설치하는 방법도 생각해 볼 수 있다. 즉,
$ cp tf-a-stm32mp257f-dk.stm32 <BUILDROOT>/output/images/
$ cp fip.bin <BUILDROOT>/output/images/
$ cp Image.gz <BUILDROOT>/output/images/
$ sudo mount -o loop rootfs.ext4 /mnt/my_rootfs
-> /mnt/my_rootfs에 필요한 파일 복사 후, unmount
$ cd <BUILDROOT>
$ make
-> <BUILDROOT>/output/images/sdcard.img.gz
c) 부팅 상태에서 kernel image, modules, dtb만 교체하여 시험하기
먼저, 아래 작업을 수행하기에 앞서서 buildroot ext4 file system의 기본 크기를 1024M으로 증가시켜 주기로 한다(modules.tar.gz 파일을 올리는데 문제가 있기 때문임).
$ scp arch/arm64/boot/Image.gz root@192.168.8.227:~/workspace
$ scp arch/arm64/boot/dts/st/stm32mp257f-dk.dtb root@192.168.8.227:~/workspace
$ scp my_kernel_modules/modules-stm32mp2.tgz root@192.168.8.227:~/workspace
<Target Board>
Target board로 복사한 내용을 system에 반영한 후, 재부팅하도록 하자.
$ cd workspace
$ cp -f ./Image.gz /boot
$ cp -f ./stm32mp257f-dk.dtb /boot
$ tar xvzf ./modules-stm32mp2.tgz -C /
$ sync; sync
$ depmod -a
-> depmod는 kernel module에 대한 의존성을 분석한 후, /lib/modules/6.6.116-xxx/modules.dep 파일을 새롭게 갱신시킨다.
$ reboot
참고로, depmod 명령을 추가하기 위해, 아래와 같이 (사전에) busybox 설정 변경을 해 주어야 한다.
$ make busybox-menuconfig
-> Linux Module Utilities
-> [*] depmod
$ sudo minicom -D /dev/ttyACM0
-> OK, 정상적으로 부팅된다. 😎
[그림 8.2.5] kernel & modules 교체 후, 부팅하는 모습
이제부터는 buildroot 환경에서 다양한 device driver or application을 돌려 볼 수 있는 준비가 되었다.
8.3 그 밖의 못다한 이야기
이번 절에서는 지난번 posting에서 미쳐 설명하지 못한 내용을 다뤄 보고자 한다.
[그림 8.3.1] 추가 기능 시험 관련 page
1) i2c device tree & device driver
-> 다른 board이기는 하지만, 이전 posting을 참조해 주기 바란다.
2) libgpiod와 GPIO
-> 다른 board이기는 하지만, 이전 posting을 참조해 주기 바란다.
3) STM32CubeMX로 device tree 만들기
4) WiFi
5) Bluetooth
6) Camera
7) ...
나머지 부분은 독자 여러분의 몫으로 남기며, 다음 장으로 넘어가 보기로 한다. 😋
To be continued...
References
[1] https://www.st.com/en/evaluation-tools/stm32mp257f-dk.html
[2] UM3385 - Discovery kit with STM32MP257F MPU - User manual, STMicroelectronics.
[3] Data brief - STM32MP257F-DK, STMicroelectronics.
[4] STM32MP251C/F STM32MP253C/F, STM32MP255C/F STM32MP257C/F Datasheet, STMicroelectronics.
[5] STM32MP257-DK schematic, STMicroelectronics.
[6] RM0457 Reference manual, STM32MP23/25xx advanced Arm®-based 32/64-bit MPUs
[7] https://wiki.st.com/stm32mpu/wiki/Getting_started/STM32MP2_boards/STM32MP257x-DK
[8] https://wiki.st.com/stm32mpu/wiki/STM32MP2_boot_chain_overview
[9] https://wiki.st.com/stm32mpu/wiki/STM32MPU_Distribution_Package
[10] https://wiki.st.com/stm32mpu/wiki/Category:Buildroot-based_Linux_embedded_software
-> STM32MP documents
[11] https://docs.yoctoproject.org/
-> yocto project manual
[12] https://github.com/bootlin/buildroot-external-st
[13] https://buildroot.org/downloads/manual/manual.html#customize
[14] https://tuxownia.pl/en/blog/buildroot-and-stm32mp257f-dk/
[15] https://bootlin.com/doc/training/buildroot/buildroot-slides.pdf
-> buildroot
[16] https://bootlin.com/doc/training/embedded-linux/embedded-linux-stm32mp2-labs.pdf
[17] https://bootlin.com/doc/training/embedded-linux/embedded-linux-slides.pdf
[19] https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-basic-system/
-> bootlin documents
[20] Mastering Embedded Linux Programming, Frank Vasquez, Chris Simmonds, Packt.
[21] https://uefi.org/specs/UEFI/2.10/05_GUID_Partition_Table_Format.html
[22] And Google and Gemini~
Slowboot





























