카테고리 보관물: Linux

Raspberry Pi용 Qt5 Cross Compile

이 포스팅은 Qt5 5.15.11을 RPi5용으로 크로스 컴파일 하는 과정을 정리한 것이다. Build host는 Ubuntu 24.04이다.

Overview

2025년 12월 현재, Qt5가 RPi용 deb package 생성을 직접 지원하지는 않기 때문에 다소 복잡하고 번거롭긴 하지만, target인 Raspberry Pi OS의 image 파일을 빌드 호스트 머신에 loop device로 마운트 시켜서 크로스 컴파일을 수행하고 그 결과를 마운트된 공간에 설치하는 방식으로 이미지 파일(raspios.img)를 업데이트 시킨다. 이렇게 만들어진 이미지 파일을 RPi5용 SD card에 flash하면 Qt5가 포함된 이미지 파일을 사용할 수 있다.

Target RPi OS 이미지 준비

Raspberry Pi OS image 를 준비해서 개발 호스트에 마운트 시켜서, Qt5를 빌드하는데 필요한 패키지들을 설치한다. 이것은 cross compile중에 필요한 의존성을 해결하기 위한 과정이다.

필요한 모든 파일들을 모아둘 공간을 BASE_DIR라하고 그 아래에 Raspberry Pi OS image file을 마운트할 장소를 ROOTFS라고 정의한다. 그 외에 빌드에 필요한 환경변수들을 함께 정의해 주자.

# BASE_DIR: project에 필요한 데이터를 모아둘 파일경로
# ROOTFS: RPi image 파일을 마운트할 경로
export BASE_DIR=${PWD}
export ROOTFS=$BASE_DIR/rootfs
# QT_SRC_DIR: Qt5 소스코드를 보관
# QT_BUILD_DIR: Qt5 빌드 결과물을 보관
# QT_HOST: Qt5 호스트용 바이너리 위치
# QT_TARGET: Qt5 타겟용 바이너리 위치
export QT_BUILD_DIR=$BASE_DIR/qt5-build
export QT_SRC_DIR=$BASE_DIR
export QT_HOST=$BASE_DIR/qt5-host
export QT_TARGET=$BASE_DIR/qt5-rpi

Raspberry Pi OS의 image파일이 필요한데, 사용한 OS 이미지의 버전은 2025년 12월 현재의 최신 버전이다. 이 파일을 다운로드 받아서 raspios.img라는 이름으로 압축을 풀고, loop device로 설정해서 ROOTFS에 정의된 디렉토리 위치로 마운트 한다.

압축이 풀린 raspios.img 파일을 fdisk로 들여다 보면 두개의 파티션이 보이는데, 하나는 boot를 위한 파티션으로 p1에 있고 다른 하나는 우리가 Qt5를 빌드해서 설치할 rootfs인데, p2로 접근하면 된다. 아래의 예는 /dev/loop4로 설정된 loop device의 두번째 파티션 p2을 마운트 하는 것이다.

# Raspberry Pi OS 이미지를 다운로드
wget https://downloads.raspberrypi.com/raspios_arm64/images/raspios_arm64-2025-12-04/2025-12-04-raspios-trixie-arm64.img.xz
xzcat ./2025-12-04-raspios-trixie-arm64.img.xz > $BASE_DIR/raspios.img
# Loop device를 설정하고 ROOTFS 경로에 마운트
mkdir -p $ROOTFS
sudo losetup -Pf --show $BASE_DIR/raspios.img
/dev/loop4
# Root 파일 시스템 마운트
sudo mount /dev/loop4p2 $ROOTFS 

Root 파일 시스템이 마운트 되었다면 그 안에 있는 ARM binary를 QEMU로 실행할 수 있도록 update-binfmts를 설정한다. 호스트 머신에 있는 /dev, /proc/, /sys, /dev/pts를 ROOTFS에서 사용할 수 있도록 마운트 해주고 chroot을 실행하면 마치 ARM 시스템에 접속한 것 처럼 root shell(#)을 볼 수 있고, 관리자 권한으로 파일을 접근 할 수 있는 상태가 된다.

여기에서 수행하는 명령어 들은 ROOTFS에 적용되므로 결과 적으로 Raspberry Pi OS image가 업데이트 된다.

# QEMU ARM을 실행하기 위한 준비
sudo apt install qemu-user-static binfmt-support
sudo update-binfmts --enable qemu-aarch64
sudo cp /usr/bin/qemu-aarch64-static $ROOTFS/usr/bin/
# 파일시스템 바인딩
sudo mount --bind /dev  $ROOTFS/dev
sudo mount --bind /proc $ROOTFS/proc
sudo mount --bind /sys  $ROOTFS/sys
sudo mount --bind /dev/pts $ROOTFS/dev/pts
# Launch
sudo chroot $ROOTFS /usr/bin/qemu-aarch64-static /bin/bash

Qt5를 RPi용으로 컴파일하기 위해 필요한 의존성 패키지들을 설치해 준다. 참고로, RPi OS의 베이스 이미지는 이전에 데비안 Bookworm이었다가 Trixie로 얼마전에 업데이트 되었다.

# 한국에 있는 미러 서버를 소스 리스트에 등록
# 굳이 안해도 되지만 속도를 위해서 미러로 접속한다.
cat >> /etc/apt/sources.list << 'EOF'
deb http://ftp.kaist.ac.kr/debian trixie main contrib non-free non-free-firmware
deb http://ftp.kaist.ac.kr/debian trixie-updates main contrib non-free non-free-firmware
deb http://security.debian.org/debian-security trixie-security main contrib non-free non-free-firmware
EOF
# 의존성 패키지 설치
apt update
apt install -y \
    libgles-dev \
    libegl-dev \
    libgbm-dev \
    libdrm-dev \
    libinput-dev \
    libxkbcommon-dev \
    libx11-dev \
    libxext-dev \
    libxcb1-dev \
    libx11-xcb-dev \
    libxcb-glx0-dev \
    libxcb-util-dev \
    libxcb-xkb-dev \
    libxcb-xinerama0-dev \
    libxcb-cursor-dev \
    libxcb-keysyms1-dev \
    libxcb-render-util0-dev \
    libxcb-image0-dev \
    libxi-dev \
    libfontconfig1-dev \
    libfreetype6-dev \
    libpng-dev \
    libjpeg-dev \
    zlib1g-dev \
    libudev-dev \
    libdbus-1-dev \
    pkg-config \
    libxcb-shm0-dev \
    libxcb-xfixes0-dev \
    libxcb-randr0-dev \
    libxcb-render0-dev \
    libxcb-shape0-dev \
    libxcb-sync-dev \
    libxcb-icccm4-dev \
    libxkbcommon-x11-dev \
    libxfixes-dev \
    libxrandr-dev \
    libxrender-dev \
    libwayland-dev \
    libwayland-egl-backend-dev \
    wayland-protocols \
    libegl1-mesa-dev

필요한 패키지를 설치했으면 chroot을 종료하고 host의 디렉토리들을 unmount한다.

# Clean up
exit
sudo umount $ROOTFS/dev/pts
sudo umount $ROOTFS/dev
sudo umount $ROOTFS/proc
sudo umount $ROOTFS/sys

Qt5 Cross Compilation

컴파일을 수행할 Qt5의 소스코드를 다운로드 받는다. QT_SRC_DIR 경로에 소스코드를 풀어서 저장할 것이다.

# QT_SRC_DIR: Qt5의 소스코드를 저장할 경로
https://download.qt.io/archive/qt/5.15/5.15.11/single/qt-everywhere-opensource-src-5.15.11.tar.xz
tar xvf qt-everywhere-opensource-src-5.15.11.tar.xz -C $QT_SRC_DIR

devices 경로 아래에 새로운 디바이스 명으로 linux-aarch64-gnu-g++ 디렉토리를 생성하고 qmake.conf 파일을 생성한다.

# 디렉토리를 생성하고 qmake.conf 내용을 채운다.
mkdir -p $QT_SRC_DIR/qt-everywhere-src-5.15.11/qtbase/mkspecs/devices/linux-aarch64-gnu-g++
cat << 'EOF' > $QT_SRC_DIR/qt-everywhere-src-5.15.11/qtbase/mkspecs/devices/linux-aarch64-gnu-g++/qmake.conf
MAKEFILE_GENERATOR = UNIX
CONFIG += incremental
QMAKE_INCREMENTAL_STYLE = sublib
# Inherit standard Linux desktop flags (shared libs, version scripts, etc.)
include(../../linux-g++/qmake.conf)
# Cross-compile device
CONFIG += cross_compile
#############################################
# Target / Host Architecture
#############################################
QMAKE_TARGET_ARCH = aarch64
QMAKE_TARGET      = aarch64-linux-gnu
QMAKE_TARGET_CPU  = aarch64
QMAKE_HOST_ARCH   = x86_64
#############################################
# Cross Compiler Toolchain
#############################################
QMAKE_CC          = aarch64-linux-gnu-gcc
QMAKE_CXX         = aarch64-linux-gnu-g++
QMAKE_LINK        = aarch64-linux-gnu-g++
QMAKE_LINK_SHLIB  = aarch64-linux-gnu-g++
QMAKE_AR          = aarch64-linux-gnu-ar cqs
QMAKE_OBJCOPY     = aarch64-linux-gnu-objcopy
QMAKE_STRIP       = aarch64-linux-gnu-strip
# Make configure tests use the cross-compiler too
QMAKE_CONF_COMPILER = $$QMAKE_CXX
#############################################
# Sysroot
#############################################
QMAKE_CFLAGS      += --sysroot=$$[QT_SYSROOT]
QMAKE_CXXFLAGS    += --sysroot=$$[QT_SYSROOT]
QMAKE_LFLAGS      += --sysroot=$$[QT_SYSROOT]
#############################################
# Default Include / Lib paths in sysroot
#############################################
QMAKE_INCDIR += $$[QT_SYSROOT]/usr/include
QMAKE_LIBDIR += \
    $$[QT_SYSROOT]/usr/lib/aarch64-linux-gnu \
    $$[QT_SYSROOT]/lib/aarch64-linux-gnu
#############################################
# OpenGL ES 2.0 / EGL / GBM / DRM (Mesa)
#############################################
# GLES2
QMAKE_INCDIR_OPENGL_ES2 += \
    $$[QT_SYSROOT]/usr/include \
    $$[QT_SYSROOT]/usr/include/GLES2
QMAKE_LIBDIR_OPENGL_ES2 += $$[QT_SYSROOT]/usr/lib/aarch64-linux-gnu
QMAKE_LIBS_OPENGL_ES2   += -lGLESv2
# EGL
QMAKE_INCDIR_EGL += \
    $$[QT_SYSROOT]/usr/include \
    $$[QT_SYSROOT]/usr/include/EGL \
    $$[QT_SYSROOT]/usr/include/libdrm
QMAKE_LIBDIR_EGL += $$[QT_SYSROOT]/usr/lib/aarch64-linux-gnu
QMAKE_LIBS_EGL   += -lEGL
# GBM / DRM
QMAKE_LIBS_GBM   += -lgbm
QMAKE_LIBS_DRM   += -ldrm
QT_QPA_DEFAULT_PLATFORM = eglfs
load(qt_config)
EOF

그 다음으로 qplatformdefs.h 파일을 생성해 준다.

cat << 'EOF' > $QT_SRC_DIR/qt-everywhere-src-5.15.11/qtbase/mkspecs/devices/linux-aarch64-gnu-g++/qplatformdefs.h
#include "../../linux-g++/qplatformdefs.h"
EOF

이제 크로스 컴파일을 실행한다.

# Clean build를 위한 build directory 삭제
rm -rf $QT_BUILD_DIR
mkdir -p $QT_BUILD_DIR && cd $_
# 빌드 환경설정
$QT_SRC_DIR/qt-everywhere-src-5.15.11/configure \
    -opensource -confirm-license \
    -release \
    -device linux-aarch64-gnu-g++ \
    -device-option CROSS_COMPILE=aarch64-linux-gnu- \
    -sysroot "$ROOTFS" \
    -opengl es2 \
    -eglfs \
    -xcb \
    -skip qtwebengine \
    -nomake tests -nomake examples \
    -prefix /usr/local/qt5 \
    -extprefix "$QT_TARGET" \
    -hostprefix "$QT_HOST" \
    -make-tool "make"
# 크로스 컴파일 수행 및 설치
make -j `nproc`
make -j `nproc` install

컴파일이 완료되면 파일의 hard link, 모드, 소유권 등을 그대로 유지하면서 복사해야 하는데 rsync의 archiving 기능을 이용하면 이 부분을 수월하게 수행할 수 있으므로 이를 이용해서 ROOTFS에 컴파일 결과물을 복사하고, Qt5와 관련한 환경변수들을 파일에 만들어서 넣어 준다.

설치가 잘 되었다면 ROOTFS아래의 /usr/local/qt5에 필요한 Qt5관련 라이브러리와 파일들이 설치되었을 것이다.

# rsync로 파일 모드를 유지하면서 복사
sudo -E rsync -aH --info=progress2 $QT_BUILD_DIR/../qt5-rpi/ $ROOTFS/usr/local/qt5/
# 필요한 환경별수 설정: 부팅하면 자동 실행된다.
sudo -E tee $ROOTFS/etc/profile.d/qt5.sh << 'EOF'
export LD_LIBRARY_PATH=/usr/local/qt5/lib:$LD_LIBRARY_PATH
export QT_PLUGIN_PATH=/usr/local/qt5/plugins
export QT_QPA_PLATFORM=xcb
export QML2_IMPORT_PATH=/usr/local/qt5/qml
export PATH=/usr/local/qt5/bin:$PATH
EOF
sudo chmod +x $ROOTFS/etc/profile.d/qt5.sh

Clean Up

ROOTFS를 unmount하고 loop device를 해제한다.

sudo umount $ROOTFS
# Loop device /dev/loop4를 해제.
# 처음 losetup 할 때 출력되는 loop device의 경로명을 적어준다.
# 빌드 호스트에 따라 다를 수 있음.
sudo losetup -d /dev/loop4

동작 확인

이제 생성된 raspios.img 파일을 Raspberry Pi Imager의 custom image flash 기능을 이용해서 SD card에 이미지를 flash한다.

만약, 부팅 후에 필요하다면 아래의 XCB 관련 패키지들을 설치해 준다.

sudo apt install xorg xwayland libxcb1 libx11-6 libxext6

시험용으로 간단하게 만든 c++ testapp으로 동작을 확인했다.

yay – error while loading shared libraries: libalpm.so.xx

Arch Linux에서 yay를 실행하는데 libalpm.so를 로딩하지 못해서 죽는 경우가 생겼다. 검색해 보니 이런 경우가 종종 있는 모양이다. yay와 pacman 모두 ALPM(Arch Linux Package Management) Library에 의존하는데, packman에 의해 libalmp.so의 soname이 변경된 경우 yay가 이전 버전의 라이브러리를 로딩하지 못해 에러가 생길수 있다.

이 경우, yay는 libalpm.so.15를 참조하려다가 실패하고, pacman은 libalpm.so.16을 참조하고 있다. ldd로 봤을 때도 yay가 해당 라이브러리를 찾지 못하는 (“not found”) 상태임이 확인된다.

Arch Linux의 rolling release 특성상 이러한 종류의 문제는 이미 해결되어 있을 가능성이 높으므로 yay AUR을 빌드해서 다시 설치해 주는 것으로 대부분 해결할 수 있다.

# GitHub가 아닌 Arch AUR archive에서 clone
git clone https://aur.archlinux.org/yay.git
cd yay
# 빌드 후 인스톨 실행
makepkg -si

Raspberry Pi 5에 간단한 Linux 시스템 올리기

이 포스팅에서는 Raspberry pi 5(RPi5)에 아주 단순한 리눅스 시스템을 구성해서 부팅해 보는 과정을 다룬다. Ubuntu 24.04 개발환경에서 RPi5를 위한 u-boot, Linux, Busybox를 설정하고 부팅해 볼 것이다.

SD card 준비

SD card를 개발 호스트 머신에 삽입하고 lsblk 명령어로 연결된 디바이스들을 확인한다.

위의 예제에서 SD card는 mmclbk0이다. 저장공간의 크기를 통해 구분하거나 SD card를 삽입할 때 커널 메세지를 잘 보고 엉뚱한 디바이스를 지정하지 않도록 주의하자 실수하면 의도치 않게 시스템 정보를 날려 먹을 수도 있다.

파티션 생성

parted 명령어로 파티션을 생성한다. 부팅만을 위해는 첫번째 파티션인 256MiB짜리 FAT32만 설정해도 된다. 이 공간에 부팅에 관련된 boot loader, kernel, RAM disk image를 넣어주게 된다.

# MBR 설정을 위한 msdos label을 생성
sudo parted /dev/mmcblk0 mklabel msdos

# 파티션 두개(boot / data)를 만든다. ext4는 부팅과는 상관 없다.
sudo parted -a optimal /dev/mmcblk0 mkpart primary fat32 1MiB 256MiB
sudo parted -a optimal /dev/mmcblk0 mkpart primary ext4 256MiB 100%

# 파일 시스템을 생성한다.
sudo mkfs.vfat /dev/mmcblk0p1
sudo mkfs.ext4 /dev/mmcblk0p2

Kernel – Linux v6.12.58

LTS 커널 중에 2025년 11월 현재 가장 최신 버전인 v6.12.58을 골랐다. 딱히 특정한 버전을 사용해야 하는 것은 아니므로 안정적이라고 알려진 버전 중에 아무것이나 고르면된다.

Source code

GitHub를 통해서 코드를 받거나 Kernel Archive에서 tarball을 받아도 되는데, GtiHub는 히스토리를 다운로드 받는 것 때문에 생각보다 시간이 좀 걸렸다.

git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
cd linux
git checkout v6.12.58

Kernel Build

ARM64 CPU인 RPi5용 커널을 x86에서 빌드하기 위해서 cross compiler를 설치해야 한다.

sudo apt update
sudo apt install -y crossbuild-essential-arm64

Cross compile을 위해 ARCH와 CROSS_COMPILE 환경변수들을 아래와 같이 설정해 주고, make defconfig를 실행해서 .config 파일을 생성한다. 컴파일 타겟은 kernel image를 위한 Image, device tree blob을 위해 dtbs 그리고 kernel module들을 위한 modules를 지정해 주었다.

export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-

# Defconfig
make defconfig

# Compile
make -j `nproc` Image dtbs modules

빌드가 완료된 후에는 다음 두개의 파일이 잘 생성되어 있는지 확인한다.

# Linux kernel image
$ ls -l arch/arm64/boot/Image
-rw-rw-r-- 1 litcoder litcoder  arch/arm64/boot/Image

# BCM2712용 device tree blob
$ ls -l arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dtb
-rw-rw-r-- 1 litcoder litcoder  arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dtb

Boot loader – u-boot v2025.10

2025년 11월 현재 최신 버전인 tag v2025.10를 사용했다.

git clone https://github.com/u-boot/u-boot.git && cd $_
git checkout v2025.10

Compile

u-boot을 빌드하기 위해, 앞서 설정한 cross compiler외에도 파서 생성에 필요한 flex, bison과 GNU TLS를 위한 libgnutls28-dev를 설치해 주었다. 만약 24.04가 아닌 다른 버전을 사용하고 있다면 apt-cache search libgnutls 명령어로 대체 가능한 다른 패키지를 검색해 볼 수 있을 것이다.

sudo apt update
sudo apt install flex bison libgnutls28-dev

v2025.10 버전에서는 명시적으로 RPi5 이름이 붙은 defconfig 파일은 없고 대신에 rpi_arm64_defconfig를 사용하면 된다. ARCH와 CROSS_COMPILE 환경변수를 설정하고 컴파일한다.

export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-

# Defconfig PRi5
make rpi_arm64_defconfig

# Compile
make -j `nproc`

컴파일이 완료되면 아래와 같이 u-boot 관련 파일들이 생성되는데 이 중 u-boot.bin file이 생성된 부트로더 파일이다.

$ ls -l u-boot*
-rwxrwxr-x 1 litcoder litcoder  u-boot
-rw-rw-r-- 1 litcoder litcoder  u-boot-nodtb.bin
-rw-rw-r-- 1 litcoder litcoder  u-boot.bin # 부트로더 파일
-rw-rw-r-- 1 litcoder litcoder  u-boot.cfg
-rw-rw-r-- 1 litcoder litcoder  u-boot.dtb
-rw-rw-r-- 1 litcoder litcoder  u-boot.lds
-rw-rw-r-- 1 litcoder litcoder  u-boot.map
-rw-rw-r-- 1 litcoder litcoder  u-boot.srec
-rw-rw-r-- 1 litcoder litcoder  u-boot.sym

RootFS – Busybox 1_37_0

부트로더가 커널을 불러서 부팅까지 성공 했다면, 시스템 부팅의 후반 과정을 통해 필요한 데몬을 띄우거나 필요한 특수 파일 시스템을 구성하고 shell을 구동해서 명령어 입력이 가능한 상태로 만드는 일을 수행해야 하는데 이러한 정보를 담아두는 공간을 RootFS라고 한다. RootFS를 구성하는 여러가지 방법이 있으나, 여기에서는 가장 간단하게 Busybox를 이용해서 RAM disk image 형태로 만들어서 커널 부팅 이후의 과정을 수행하도록 한다.

Busybox git repository인 https://git.busybox.net/busybox 에서 필요한 버전을 tarball로 다운로드 받거나 git명령어로 받아서 소스 코드를 준비한다.

git clone https://git.busybox.net/busybox
cd busybox
git checkout 1_37_1

Compile

Cross compile을 위한 환경을 설정하고 make defconfig로 .config 파일을 생성한다.

export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-

make defconfig

생성된 .config 파일안에는 몇가지 설정이 있는데, 정적 링크를 위해 CONFIG_STATIC을 y로 설정해 주고 컴파일 오류를 방지 하기 위해 CONFIG_TC를 unset 해준다. 이 파일에서 보이듯이 기본 설치 디렉토리는 _install 디렉토리 이다.

# 생성된 .config 직접 편집
...
# not set -> y로 변경
CONFIG_STATIC=y
...
CONFIG_PREFIX="./_install"
...
# y -> not set으로 변경
#CONFIG_TC is not set

make oldconfig 후 컴파일 및 설치를 실행하면 _install directory안에 필요한 파일들이 설치된다.

make oldconfig
make -j `nproc`

# _install directory에 설치 파일 복사
# 주의: sudo를 쓰지 말것. 실수로 시스템이 망가지는 것을 막을 수 있음.
make install

RAM disk image 만들기

Busybox는 GNU coreutils처럼 기본적인 명령어들을 제공한다. 이러한 명령어들를 사용하기 위해서는 “busybox ls”와 같이 수행하고자 하는 명령어의 앞에 busybox를 입력해 주어야 하는데, /bin/sh가 /bin/busybox를 link하도록 하면 shell에 의해 자동적으로 이 부분이 수행 된다.

Linux kernel 부팅이 끝나고 나서 자동으로 init script가 불려지는 과정이 있는데, 이 내용을 포함한 RAM disk를 생성하는 과정을 아래와 같이 script로 만들어 두었다. 이 스크립트를 사용 하기 위해서는 위에서 설명한 busybox 관련 내용들을 make install까지 수행한 다음, export BUSYBOX_DIR=${PWD}로 환경변수를 설정해주고 스크립트를 수행하면 된다.

스크립트가 잘 수행되었다면 uInitrd 파일이 생성될 것이다.

설치 하기

RPi5의 ROM으 로드되면 FAT 파티션안에 있는 config.txt 파일의 내용을 읽어서 그 내용대로 수행해 준다. u-boot.bin 파일을 로드하기 위해 다음과 같이 config.txt file을 작성해 준다.

enable_uart=1
kernel=u-boot.bin
arm_64bit=1

bottfs라는 디렉토리를 하나 만들고 지금까지 생성한 모든 파일들을 한곳에 모아 둔다. 파일들의 내역은 다음과 같다.

$ ls -l ./bootfs
# 수동작성하는 설정파일
-rw-rw-r-- 1 litcoder litcoder  config.txt

# Kernel에서 복사
-rw-rw-r-- 1 litcoder litcoder  bcm2712-rpi-5-b.dtb
-rw-rw-r-- 1 litcoder litcoder  Image

# u-boot에서 복사
-rw-rw-r-- 1 litcoder litcoder  u-boot.bin

# Busybox에서 생성
-rw-rw-r-- 1 litcoder litcoder  uInitrd

SD card를 삽입하고 위의 파일들을 모두 첫번째 파티션인 FAT32로 복사해 준다.

mkdir -p ~/mnt
sudo mount /dev/mmcblk0p1 ~/mnt
sudo cp bootfs/* ~/mnt/
sudo umount ~/mnt

이제, SD card를 RPi5에 넣고 부팅을 시도하면 u-boot이 실행되고 부팅을 위한 카운트 다운이 실행되는데, 이 때 Enter key를 눌러서 u-boot> prompt를 띄운다.

printenv로 현재 환경변수들을 살펴보면 bcm2712-rpi-5-b.dtb의 경로가 잘못되어 있고, bootcmd가 설정되어 있지 않는 것을 볼 수 있다. 아래와 같이 설정해서 환경변수를 저장하면 이후로는 곧바로 부팅 할 수 있다.

setenv fdtfile bcm2712-rpi-5-b.dtb
setenv bootcmd "fatload mmc 0:1 ${kernel_addr_r} Image; fatload mmc 0:1 ${fdt_addr_r} ${fdtfile}; fatload mmc 0:1 ${ramdisk_addr_r} uInitrd; booti ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}"
saveenv

run bootcmd

참고로 변경한 u-boot 환경변수들을 모두 reset 하고 싶으면 아래의 명령어를 수행하면 된다.

env default -a
saveenv

부팅완료 후 root shell