Tüm eğitimler
TEKNİK REHBER GÖMÜLÜ LİNUX U-BOOT 2026

U-Boot —
Bootloader Anatomisi.

ROM'dan kernel'a — SPL zinciri, boot script, TFTP/NFS ve FIT image ile tam kontrol.

00 Boot sırası ve U-Boot'un yeri

Güç geldiği andan Linux çekirdeğinin kontrolü devralmasına kadar birden fazla yazılım katmanı sırayla çalışır.

Modern gömülü sistemlerde bootloader tek bir binary değildir. SoC'ların dahili SRAM'ı genellikle 256 KB ile birkaç MB arasında olduğundan, her şeyi ilk anda yüklemek mümkün değildir. Bu nedenle önyükleme birden fazla aşamaya bölünür.

  ROM Bootrom          SoC içi, değiştirilemez, üreticide yazılmış
       │                SRAM'ı hazırlar, boot medyasını tarar
       ▼
  SPL (MLO / spl.bin)  Secondary Program Loader — SRAM'da çalışır
       │                DDR'yi başlatır (training dahil)
       │                Gerçek U-Boot'u DDR'ye yükler
       ▼
  U-Boot               DDR'de çalışır, tam özellikli bootloader
       │                Ortam değişkenlerini okur
       │                Kernel, DTB, initrd yükler
       ▼
  Linux Kernel         DTB ile donanımı tanır, driver'ları probe eder
       ▼
  init / systemd       User-space ilk süreci
    

Neden birden fazla stage?

AM335x gibi bir SoC'da dahili SRAM genellikle 64 KB civarındadır. U-Boot'un tam binary'si ise 400–600 KB'a ulaşabilir. SPL bu engeli aşmak için vardır: minimal bir loader olarak SRAM'a sığar, DDR controller'ı başlatır ve sonra gerçek U-Boot'u büyük belleğe yükler. SPL kendi başına dosya sistemi, ağ veya USB gibi özelliklere ihtiyaç duymaz.

NOT

Bazı platformlarda SPL'nin önünde bir de FSBL (First Stage Boot Loader) yer alır. Xilinx Zynq'de FSBL, PL (FPGA) tarafını yapılandırır ve ardından SPL'yi başlatır. Katman sayısı platforma göre 2 ile 4 arasında değişebilir.

U-Boot vs diğer bootloader'lar

Bootloader Hedef Platform Özellik
U-Boot ARM, RISC-V, x86, MIPS, PowerPC Gömülü Linux'ta fiili standart; geniş board desteği
GRUB 2 x86 / x86-64 (EFI dahil) PC/sunucu; çoklu OS seçimi; UEFI Secure Boot
Barebox ARM ağırlıklı Daha temiz kod tabanı; U-Boot'tan etkilenmiş; endüstriyel
Coreboot x86 (Chromebook, sunucu) Donanım başlatmaya odaklı; payload olarak GRUB/SeaBIOS çalıştırır

U-Boot çıktı dosyaları

u-boot.binHam binary; bazı platformlarda doğrudan Flash'a yazılır.
u-boot.imgmkimage header'lı binary; U-Boot kendi kendini bu formatta yükleyebilir.
u-boot-dtb.imgU-Boot binary'si + board DTB birleştirilmiş; platform kendi DT'sini taşır.
MLOTI AM335x için SPL; FAT boot partition'ın ilk sektörlerine yazılır.
u-boot-sunxi-with-spl.binAllwinner SoC'lar için SPL + U-Boot birleşik binary; tek dd ile yazılır.

Bu bölümde

  • ROM → SPL → U-Boot → Kernel → init zincirinin her halkasının görevi
  • SRAM kısıtının SPL ihtiyacını nasıl doğurduğu
  • U-Boot, GRUB, Barebox ve Coreboot arasındaki farklar
  • Derleme çıktılarının (.bin, .img, MLO) platform bazındaki anlamı

01 U-Boot derleme

Kaynak koddan hedef board için binary üretmek; cross-compiler, defconfig ve Kconfig seçenekleri.

Kaynak kodu edinme

bash
# Resmi U-Boot deposu (DENX)
git clone https://source.denx.de/u-boot/u-boot.git
cd u-boot

# Kararlı bir etiket seç
git checkout v2024.10

Cross-compiler kurulumu

bash
# ARM 32-bit (gnueabihf = hard-float ABI)
sudo apt install gcc-arm-linux-gnueabihf

# Build ortamı için zorunlu değişkenler
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-

# ARM64 (Raspberry Pi 4, i.MX8 vb.)
sudo apt install gcc-aarch64-linux-gnu
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
DİKKAT

ARCH değişkeni ayarlanmazsa make, host mimarisini kullanır ve yanlış araç zincirine yönlenir. Her oturumda ya da Makefile içinde açıkça tanımla.

defconfig ve derleme

bash
# Raspberry Pi 4 için hazır konfigürasyon
make rpi_4_defconfig

# BeagleBone Black (TI AM335x)
make am335x_boneblack_defconfig

# Allwinner H3 (Orange Pi PC)
make orangepi_pc_defconfig

# Paralel derleme (nproc = CPU çekirdek sayısı)
make -j$(nproc)

# Çıktıları temizle
make distclean

Derleme çıktıları

DosyaPlatformAçıklama
u-boot.binGenelHam ELF-strip edilmiş binary
MLOTI AM335xSPL; FAT'a kopyalanır, ROM tarafından yüklenir
u-boot-sunxi-with-spl.binAllwinnerSPL + U-Boot birleşik; dd bs=1024 seek=8 ile SD'ye yazılır
u-boot.imgTI AM335xmkimage header'lı; MLO bu dosyayı yükler
u-boot-dtb.imgÇeşitliDT gömülü binary; CONFIG_OF_EMBED=y ile

Kconfig ile özellik seçimi

bash
# Etkileşimli menü (ncurses gerektirir)
make menuconfig

# Komut satırından tek seçenek değiştirme
./scripts/config --enable CONFIG_CMD_DHCP
./scripts/config --enable CONFIG_FIT
./scripts/config --set-val CONFIG_BOOTDELAY 3

# Mevcut konfigürasyonu doğrula
grep CONFIG_FIT .config
NOT

board'a özgü seçenekler genellikle configs/<board>_defconfig içinde önceden tanımlıdır. menuconfig sonrası make savedefconfig ile değişiklikleri minimal formatta geri kaydedebilirsin.

Bu bölümde

  • DENX deposundan kaynak edinme ve stabil etiket seçimi
  • ARCH ve CROSS_COMPILE zorunluluğu
  • defconfig → make -j$(nproc) derleme akışı
  • Platform bazında çıktı dosyası farklılıkları
  • menuconfig ve scripts/config ile feature toggle

02 U-Boot shell ve temel komutlar

UART konsolundan U-Boot prompt'una ulaşmak ve sık kullanılan komutları öğrenmek.

U-Boot başladığında bootdelay süresinde herhangi bir tuşa basılırsa otomatik boot durur ve interaktif shell açılır. Varsayılan UART ayarı 115200 baud, 8N1'dir.

Konsol bağlantısı

bash (host)
# minicom ile bağlan
minicom -D /dev/ttyUSB0 -b 115200

# picocom (daha hafif)
picocom -b 115200 /dev/ttyUSB0

# screen
screen /dev/ttyUSB0 115200

Ortam değişkeni komutları

U-Boot shell
# Tüm environment değişkenlerini listele
printenv

# Tek değişken
printenv bootargs

# Değişken tanımla (sadece RAM'de)
setenv myvar "hello world"

# Değişkeni kalıcı kaydet (flash/eMMC'ye)
saveenv

# Değişkeni sil
setenv myvar

Bellek komutları

U-Boot shell
# Belleği hex dump et (md = memory display)
# md.b = byte, md.w = word(16), md.l = long(32)
md.l 0x80000000 0x20   # 0x80000000'dan 32 long göster

# Belleğe yaz (mw = memory write)
mw.l 0x80000000 0xdeadbeef 1

# Board bilgisi (CPU, DRAM, clock)
bdinfo

Dosya yükleme komutları

U-Boot shell
# FAT partition'dan yükle (mmc 0:1 = ilk MMC, ilk partition)
fatload mmc 0:1 0x80000000 zImage

# ext4 partition'dan yükle
ext4load mmc 0:2 0x80000000 /boot/zImage

# TFTP ile ağdan yükle
setenv ipaddr 192.168.1.100
setenv serverip 192.168.1.1
tftp 0x80000000 zImage

# DHCP + TFTP tek adımda
dhcp 0x80000000 zImage

Yardım ve otomatik tamamlama

U-Boot shell
# Tüm komutları listele
help

# Komut için ayrıntılı yardım
help fatload
fatload ?         # alternatif sözdizimi

# Tab tuşu ile otomatik tamamlama
fat[TAB]          # → fatload, fatls, fatsize...
setenv boot[TAB]  # → bootcmd, bootargs, bootdelay...
NOT

U-Boot prompt'unda yukarı ok tuşu ile komut geçmişine erişilebilir. Bazı eski U-Boot sürümlerinde bu özellik CONFIG_CMDLINE_EDITING=y ile etkinleştirilmesi gerekir.

Bu bölümde

  • UART konsol bağlantısı: 115200 8N1, minicom / picocom
  • printenv, setenv, saveenv ile ortam değişkeni yönetimi
  • md / mw ile bellek erişimi
  • fatload, ext4load, tftp ile farklı kaynaklardan yükleme
  • help komutu ve Tab ile otomatik tamamlama

03 Environment değişkenleri ve bootargs

U-Boot'un davranışını yönlendiren değişkenler ve kernel'a aktarılan komut satırı parametreleri.

U-Boot environment'ı, power-on'dan boot'un sonuna kadar tüm davranışı yöneten anahtar-değer çiftleri topluluğudur. Bazı değişkenler özel anlam taşır ve U-Boot tarafından otomatik yorumlanır.

Temel özel değişkenler

bootcmdGüç açıldığında bootdelay sonunda otomatik çalışan komut. Tüm boot mantığının giriş noktası.
bootargsKernel'a geçirilen komut satırı parametreleri. /proc/cmdline olarak görünür.
bootdelaybootcmd çalışmadan önceki bekleme süresi (saniye). Ctrl+C ile otomatik boot durdurulur. -1 ile devre dışı bırakılır.
loadaddrVarsayılan dosya yükleme adresi. fatload gibi komutlarda adres belirtilmezse bu kullanılır.
fdtaddr / fdt_addrDevice tree binary (DTB) yükleme adresi. Kernel ile DTB arasında çakışma olmamalı.
ipaddrBoard'un IP adresi. TFTP/NFS boot için gerekli.
serveripTFTP sunucusunun IP adresi.
gatewayipVarsayılan ağ geçidi IP adresi.
netmaskAlt ağ maskesi. Varsayılan 255.255.255.0.

bootargs örnekleri

U-Boot shell
# Temel: seri konsol + eMMC rootfs
setenv bootargs "console=ttyS0,115200 root=/dev/mmcblk0p2 rootwait rw"

# NFS rootfs ile ağdan boot
setenv bootargs "console=ttyS0,115200 root=/dev/nfs \
  nfsroot=192.168.1.1:/srv/nfs/rootfs,v3 \
  ip=192.168.1.100:192.168.1.1:192.168.1.1:255.255.255.0::eth0:off \
  rw"

# initramfs ile (rootfs adres gömülü)
setenv bootargs "console=ttyAMA0,115200 rootfstype=tmpfs"

# Kernel debug modu
setenv bootargs "console=ttyS0,115200 root=/dev/mmcblk0p2 rootwait \
  loglevel=8 ignore_loglevel debug earlyprintk"

Environment depolama seçenekleri

DepolamaKconfigAçıklama
eMMC / SD (FAT)CONFIG_ENV_IS_IN_FATuboot.env dosyası olarak boot partition'da saklanır
eMMC / SD (raw)CONFIG_ENV_IS_IN_MMCBelirlenen offset'e raw yazılır; CONFIG_ENV_OFFSET ile ayarlanır
SPI NOR FlashCONFIG_ENV_IS_IN_SPI_FLASHFlash'ta sabit offset; CONFIG_ENV_SECT_SIZE dikkat
NAND FlashCONFIG_ENV_IS_IN_NANDBad-block aware; yedek kopya desteği mevcut
Yok (sadece derleme)CONFIG_ENV_IS_NOWHEREsaveenv çalışmaz; her boot varsayılan değerler
DİKKAT

Geliştirme sırasında saveenv'yi dikkatli kullan. Yanlış bootargs kaydedilirse cihaz her açılışta boot edemez hale gelebilir. Üretim ortamında environment'ı read-only bir bölümden yükleyip RAM'de değiştirmek daha güvenlidir.

Bu bölümde

  • bootcmd, bootargs, bootdelay — özel değişkenlerin işlevleri
  • loadaddr ve fdtaddr adres çakışması riski
  • Farklı rootfs senaryoları için bootargs örnekleri
  • FAT, raw MMC, SPI Flash, NAND depolama seçenekleri

04 Boot script (.cmd → .scr)

Karmaşık boot mantığını tekrar kullanılabilir bir script dosyasına taşı; koşullu dal ve değişken kontrolü.

bootcmd içine uzun komut zincirleri yazmak hem okunaksız hem de kırılgandır. Boot script yöntemi, boot.cmd metin dosyasını mkimage ile binary boot.scr'ye dönüştürür ve U-Boot bu dosyayı doğrudan çalıştırır.

Script derleme

bash (host)
# boot.cmd → boot.scr dönüşümü
mkimage -C none -A arm -T script -d boot.cmd boot.scr

# ARM64 için
mkimage -C none -A arm64 -T script -d boot.cmd boot.scr

# boot.scr'yi FAT partition'a kopyala
cp boot.scr /media/boot/

U-Boot'ta script çalıştırma

U-Boot shell
# boot.scr'yi yükle ve çalıştır
fatload mmc 0:1 ${loadaddr} boot.scr
source ${loadaddr}

# bootcmd olarak otomatikleştir
setenv bootcmd "fatload mmc 0:1 ${loadaddr} boot.scr; source ${loadaddr}"
saveenv

Tam boot script örneği

boot.cmd
# ── Adres tanımları ──────────────────────────────────
setenv kernel_addr  0x80008000
setenv dtb_addr     0x83000000
setenv initrd_addr  0x84000000

# ── Kernel komut satırı ──────────────────────────────
setenv bootargs "console=ttyS0,115200 root=/dev/mmcblk0p2 rootwait rw"

# ── Koşullu boot: önce TFTP dene, sonra MMC ──────────
if test -n ${serverip}; then
  echo "Network boot deneniyor..."
  if tftp ${kernel_addr} zImage; then
    tftp ${dtb_addr} my-board.dtb
    bootz ${kernel_addr} - ${dtb_addr}
  fi
fi

# ── MMC boot ─────────────────────────────────────────
echo "MMC boot..."
fatload mmc 0:1 ${kernel_addr}  zImage
fatload mmc 0:1 ${dtb_addr}    my-board.dtb
fatload mmc 0:1 ${initrd_addr} initrd.img

# bootz: zImage (ARM32) + DTB + initrd
bootz ${kernel_addr} ${initrd_addr} ${dtb_addr}

Script'te dosya varlığı kontrolü

boot.cmd
# FAT'ta dosya var mı?
if test -e mmc 0:1 /boot.scr; then
  fatload mmc 0:1 ${loadaddr} boot.scr
  source ${loadaddr}
fi

# env değişkeni boş mu?
if test -z ${fdt_file}; then
  setenv fdt_file my-board.dtb
fi
NOT

U-Boot script değişkenleri ${} sözdizimi kullanır. run <varname> komutu ise değişken içindeki komut dizisini çalıştırır — bu şekilde bootcmd içinde alt rutinler tanımlanabilir.

Bu bölümde

  • mkimage ile .cmd → .scr dönüşümü
  • source komutu ile script çalıştırma
  • Koşullu boot: TFTP önce, MMC yedek
  • test -e ile dosya varlığı, test -n/-z ile değişken kontrolü
  • bootz (ARM32 zImage) ile kernel başlatma

05 Network boot (TFTP + NFS)

Geliştirme sırasında her değişiklik için reflash gerekmez — kernel ve rootfs'i doğrudan ağdan yükle.

Network boot, gömülü Linux geliştirmenin en hızlı döngüsüdür. Kernel veya rootfs değiştiğinde yalnızca sunucu tarafı güncellenir; hedef cihaz yeniden başlatılınca yeni imajı ağdan çeker. Donanıma hiç dokunulmaz.

Host: TFTP sunucu kurulumu

bash (host)
# tftpd-hpa kur
sudo apt install tftpd-hpa

# /etc/default/tftpd-hpa
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/srv/tftp"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="--secure"

# Servisi başlat
sudo systemctl enable --now tftpd-hpa

# Kernel ve DTB'yi TFTP dizinine kopyala
cp arch/arm/boot/zImage /srv/tftp/
cp arch/arm/boot/dts/my-board.dtb /srv/tftp/

U-Boot'ta network boot

U-Boot shell
# Statik IP ayarla
setenv ipaddr    192.168.1.100
setenv serverip  192.168.1.1
setenv gatewayip 192.168.1.1
setenv netmask   255.255.255.0

# Alternatif: DHCP ile otomatik IP
dhcp

# Kernel indir
tftp ${loadaddr} zImage

# DTB indir
tftp ${fdt_addr} my-board.dtb

# NFS rootfs ile boot
setenv bootargs "console=ttyS0,115200 root=/dev/nfs \
  nfsroot=192.168.1.1:/srv/nfs/rootfs,v3,tcp \
  ip=dhcp rw"

bootz ${loadaddr} - ${fdt_addr}

Host: NFS sunucu kurulumu

bash (host)
# NFS sunucu kur
sudo apt install nfs-kernel-server

# /etc/exports dosyasına ekle
/srv/nfs/rootfs  192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash)

# Rootfs'i oluştur (Buildroot çıktısı gibi)
sudo tar xf rootfs.tar -C /srv/nfs/rootfs/

# Dışa aktar
sudo exportfs -ra
sudo systemctl enable --now nfs-kernel-server

netboot değişkeni ile tek komut

U-Boot shell
setenv netboot "dhcp; \
  tftp ${loadaddr} zImage; \
  tftp ${fdt_addr} my-board.dtb; \
  setenv bootargs console=ttyS0,115200 root=/dev/nfs \
    nfsroot=${serverip}:/srv/nfs/rootfs,v3 ip=dhcp rw; \
  bootz ${loadaddr} - ${fdt_addr}"

# Tek komutla network boot
run netboot

# Kalıcı kaydet
saveenv
DİKKAT

NFS v3 ile no_root_squash seçeneği geliştirme ortamında gereklidir; üretimde kullanma. Ayrıca host güvenlik duvarının 69/UDP (TFTP) ve 2049/TCP (NFS) portlarına izin verdiğinden emin ol.

Bu bölümde

  • tftpd-hpa kurulumu ve yapılandırması
  • dhcp / statik IP + tftp ile kernel ve DTB yükleme
  • NFS rootfs: /etc/exports, no_root_squash
  • netboot değişkeni ile tek adımlı geliştirme döngüsü

06 FIT image (Flattened Image Tree)

Kernel, DTB ve initrd'yi tek imzalanabilir dosyada birleştir; güvenli boot'un temel taşı.

FIT (Flattened Image Tree), mkimage tarafından oluşturulan ve içinde birden fazla alt imaj barındırabilen kapsayıcı bir formattır. Yapısı DTS/DTB formatına benzer; bir .its (Image Tree Source) dosyası ile tanımlanır ve dtc'ye benzer biçimde derlenir.

Tam .its dosyası örneği

my.its
/dts-v1/;

/ {
    description = "ARM Kernel + DTB + Ramdisk";
    #address-cells = <1>;

    images {
        kernel {
            description = "Linux Kernel";
            data = /incbin/("arch/arm/boot/zImage");
            type = "kernel";
            arch = "arm";
            os = "linux";
            compression = "none";
            load = <0x80008000>;
            entry = <0x80008000>;
        };

        fdt {
            description = "Device Tree";
            data = /incbin/("my-board.dtb");
            type = "flat_dt";
            arch = "arm";
            compression = "none";
        };

        ramdisk {
            description = "Initial Ramdisk";
            data = /incbin/("initrd.img");
            type = "ramdisk";
            arch = "arm";
            os = "linux";
            compression = "gzip";
        };
    };

    configurations {
        default = "conf-1";
        conf-1 {
            description = "Boot config 1";
            kernel = "kernel";
            fdt = "fdt";
            ramdisk = "ramdisk";
        };
    };
};

FIT image derleme ve yükleme

bash (host)
# .its → .fit binary oluştur
mkimage -f my.its my.fit

# İçeriği doğrula
mkimage -l my.fit
U-Boot shell
# FIT image'ı FAT'tan yükle ve boot et
fatload mmc 0:1 ${loadaddr} my.fit
bootm ${loadaddr}

# Belirli bir konfigürasyonu seç
bootm ${loadaddr}#conf-1

# TFTP ile FIT yükle
tftp ${loadaddr} my.fit
bootm ${loadaddr}

FIT ile imzalama

bash (host)
# RSA anahtar üret
mkdir keys
openssl genrsa -out keys/dev.key 2048

# X.509 sertifikası üret
openssl req -new -x509 -key keys/dev.key -out keys/dev.crt \
  -subj "/CN=Embedded Dev Key"

# FIT'i imzala ve public key'i U-Boot DTB'ye göm
mkimage -f my.its -K u-boot.dtb -k keys/ -F -r my.fit

# Public key gömülü U-Boot DTB ile yeniden derle
make EXT_DTB=u-boot.dtb
NOT

FIT imzalama için CONFIG_FIT_SIGNATURE=y ve CONFIG_RSA=y Kconfig seçenekleri etkin olmalıdır. Public key U-Boot DTB'sine gömüldükten sonra imzasız FIT image'lar reddedilir — bu güvenli boot zincirinin temel adımıdır.

Bu bölümde

  • FIT formatı: .its kaynak, mkimage ile derleme
  • Kernel + DTB + ramdisk tek dosyada; configurations bloğu
  • bootm ile FIT yükleme ve yapılandırma seçimi
  • RSA anahtar üretimi ve FIT imzalama süreci
  • CONFIG_FIT_SIGNATURE ve güvenli boot temeli

07 MMC / SD kart operasyonları

U-Boot'ta MMC/SD aygıtlarını listele, bölümleri incele ve doğrudan ham yazma yap.

U-Boot MMC subsystem'i hem SD kartları hem eMMC'yi destekler. Komutlarda mmc <dev>:<part> biçiminde device:partition çifti kullanılır. Device numaraları mmc list ile öğrenilir.

Cihaz yönetimi

U-Boot shell
# Tüm MMC/SD cihazlarını listele
mmc list

# Örnek çıktı:
mmc@fe320000: 0 (SD)
mmc@fe330000: 1 (eMMC)

# Aktif cihazı değiştir
mmc dev 0   # SD kart
mmc dev 1   # eMMC

# Cihaz bilgisi (kapasite, hız, bus genişliği)
mmc info

# Cihazı yeniden tara
mmc rescan

Partition listeleme

U-Boot shell
# FAT partition içeriğini listele (mmc 0, partition 1)
fatls mmc 0:1

# FAT'ta alt dizin
fatls mmc 0:1 /boot

# ext4 partition içeriğini listele
ext4ls mmc 0:2 /

# ext4'te /boot dizini
ext4ls mmc 0:2 /boot

# Partition tablosunu göster (MBR/GPT)
part list mmc 0

Dosya boyutu sorgulama

U-Boot shell
# Dosya boyutunu filesize değişkenine yaz
fatsize mmc 0:1 zImage
echo ${filesize}   # bayt cinsinden onaltılık

ext4size mmc 0:2 /boot/zImage

Ham sektör erişimi

U-Boot shell
# Ham okuma: sektör 0'dan 8 sektör oku (MBR kontrolü)
mmc read ${loadaddr} 0x0 0x8

# Bellekten MMC'ye ham yaz (DİKKATLİ!)
# mmc write   
mmc write ${loadaddr} 0x0 0x800   # 0x800 blok = 1 MB
DİKKAT

mmc write komutu doğrudan ham sektörlere yazar. Yanlış blok adresi veya sayımı partition tablosunu, dosya sistemini veya boot bölümünü kalıcı olarak bozabilir. Adres ve blok sayısını iki kez kontrol et.

Partition düzeni

PartitionTürİçerikTipik boyut
p1FAT32 (0xC)MLO, u-boot.img, boot.scr, zImage, *.dtb64–256 MB
p2ext4 (0x83)Linux rootfsKalan alan
Sektör 0MBR/rawAllwinner: u-boot-sunxi-with-spl.bin (offset 8 KB)8–1024 KB

Bu bölümde

  • mmc list / dev / info / rescan komutları
  • fatls, ext4ls ile partition içeriğini inceleme
  • part list ile MBR/GPT partition tablosu
  • mmc read / write ile ham sektör erişimi ve dikkat edilecekler
  • Tipik gömülü Linux SD kart partition düzeni

08 Güvenli boot ve imzalama

İmzasız kernel'ın çalışmasını engelle — RSA anahtarları, FIT imzalama ve U-Boot'a public key gömme.

Güvenli boot, bootloader'ın yalnızca belirli bir anahtarla imzalanmış imajları kabul etmesini sağlar. Amaç, yetkisiz veya değiştirilmiş kernel/initrd'nin yüklenmesinin önüne geçmektir. U-Boot'ta bu FIT imzalama mekanizması üzerine inşa edilir.

Gerekli Kconfig seçenekleri

.config / menuconfig
CONFIG_FIT=y
CONFIG_FIT_SIGNATURE=y
CONFIG_RSA=y
CONFIG_RSA_SOFTWARE_EXP=y
CONFIG_FIT_VERBOSE=y       # hata mesajları için yararlı
CONFIG_OF_CONTROL=y
CONFIG_SPL_FIT_SIGNATURE=y  # SPL de imzalama yapacaksa

Anahtar üretimi

bash (host)
# Anahtar dizini oluştur
mkdir -p keys

# RSA-2048 private key
openssl genrsa -out keys/dev.key 2048

# Self-signed sertifika (U-Boot public key için)
openssl req -batch -new -x509 \
  -key keys/dev.key \
  -out keys/dev.crt \
  -days 7300 \
  -subj "/CN=Embedded Secure Boot Key"

# Anahtar çiftini doğrula
openssl x509 -in keys/dev.crt -noout -text | grep Subject

İmzalı FIT image oluşturma

my-signed.its
/dts-v1/;

/ {
    description = "Signed Kernel Image";
    #address-cells = <1>;

    images {
        kernel {
            data = /incbin/("arch/arm/boot/zImage");
            type = "kernel";
            arch = "arm";
            os = "linux";
            compression = "none";
            load = <0x80008000>;
            entry = <0x80008000>;
            signature {
                algo = "sha256,rsa2048";
                key-name-hint = "dev";
            };
        };

        fdt {
            data = /incbin/("my-board.dtb");
            type = "flat_dt";
            arch = "arm";
            compression = "none";
        };
    };

    configurations {
        default = "conf-1";
        conf-1 {
            kernel = "kernel";
            fdt = "fdt";
            signature {
                algo = "sha256,rsa2048";
                key-name-hint = "dev";
                sign-images = "fdt", "kernel";
            };
        };
    };
};
bash (host)
# FIT oluştur ve imzala; public key'i u-boot.dtb'ye göm
mkimage -f my-signed.its \
  -K u-boot.dtb \
  -k keys/ \
  -F -r my-signed.fit

# U-Boot'u public key gömülü DTB ile yeniden derle
make EXT_DTB=u-boot.dtb

# İmzayı doğrula
mkimage -l my-signed.fit

Güvenli boot zinciri

  ROM                  SoC'a gömülü hash ile SPL'yi doğrular (OTP fuse)
     │
     ▼
  SPL                  ROM tarafından doğrulanmış
     │                 U-Boot FIT'ini yükler ve imzasını kontrol eder
     ▼
  U-Boot               Public key DTB'ye gömülü
     │                 Kernel FIT imzasını RSA ile doğrular
     │                 İmza hatalıysa → boot reddedilir
     ▼
  Kernel               Doğrulanmış imaj çalışır
     │
     ▼
  rootfs               dm-verity ile blok katmanında bütünlük
    
NOT

Tam güvenli boot için SoC'un OTP (One Time Programmable) fuse'larına SPL hash'ini yakmak gerekir. Bu adım platform bağımlıdır ve geri alınamaz. Geliştirme aşamasında fuse yakmadan FIT imzalama mekanizmasını test edebilirsin.

Bu bölümde

  • CONFIG_FIT_SIGNATURE, CONFIG_RSA — gerekli Kconfig seçenekleri
  • openssl ile RSA-2048 anahtar ve sertifika üretimi
  • signature node içeren .its dosyası yapısı
  • mkimage -K ile public key'i U-Boot DTB'ye gömme
  • ROM → SPL → U-Boot → Kernel güvenli boot zinciri

09 Pratik: QEMU ile test

Gerçek donanım olmadan U-Boot'u çalıştır, TFTP boot ve GDB ile debug yap.

QEMU, gerçek board'a ihtiyaç duymadan U-Boot'u test etmek için ideal ortamdır. Boot script geliştirme, FIT imzalama testi ve GDB ile adım adım hata ayıklama için kullanılır.

Kurulum

bash (host)
# ARM 32-bit ve 64-bit QEMU emülatörleri
sudo apt install qemu-system-arm qemu-system-aarch64

ARM32: vexpress-a9

bash (host)
# U-Boot'u vexpress-a9 defconfig ile derle
make vexpress_ca9x4_defconfig
make -j$(nproc)

# QEMU'da çalıştır (stdio üzerinden UART)
qemu-system-arm \
  -M vexpress-a9 \
  -kernel u-boot.bin \
  -serial stdio \
  -nographic

SD kart emülasyonu

bash (host)
# 1 GB SD imajı oluştur
dd if=/dev/zero of=sd.img bs=1M count=1024

# Partition tablosu oluştur
parted sd.img mklabel msdos
parted sd.img mkpart primary fat32 1MiB 64MiB
parted sd.img mkpart primary ext4 64MiB 100%

# Loop device üzerinden formatla
sudo losetup -f --show --partscan sd.img
# → /dev/loop0
sudo mkfs.fat -F32 /dev/loop0p1
sudo mkfs.ext4 /dev/loop0p2

# SD imajı ile QEMU
qemu-system-arm \
  -M vexpress-a9 \
  -kernel u-boot.bin \
  -drive file=sd.img,format=raw,if=sd \
  -serial stdio \
  -nographic

TFTP ağ emülasyonu

bash (host)
# QEMU user-mode networking + TFTP
# QEMU host = 10.0.2.2, guest = 10.0.2.15
qemu-system-arm \
  -M vexpress-a9 \
  -kernel u-boot.bin \
  -netdev user,id=net0,tftp=/srv/tftp \
  -device virtio-net,netdev=net0 \
  -serial stdio \
  -nographic

# U-Boot'ta (QEMU içinde):
setenv ipaddr   10.0.2.15
setenv serverip 10.0.2.2
tftp 0x60000000 zImage

ARM64: Raspberry Pi 3

bash (host)
# ARM64 U-Boot derle
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
make rpi_3_defconfig
make -j$(nproc)

# QEMU aarch64 raspi3b emülasyonu
qemu-system-aarch64 \
  -M raspi3b \
  -kernel u-boot.bin \
  -serial stdio \
  -nographic

GDB ile debug

bash (host)
# Terminal 1: QEMU'yu GDB stub ile başlat
# -s → GDB stub port 1234, -S → başlangıçta bekle
qemu-system-arm \
  -M vexpress-a9 \
  -kernel u-boot.bin \
  -serial stdio \
  -nographic \
  -s -S

# Terminal 2: GDB ile bağlan
arm-linux-gnueabihf-gdb u-boot

# GDB komutları:
(gdb) target remote :1234
(gdb) break board_init_f
(gdb) continue
(gdb) info registers
(gdb) x/10i $pc    # PC konumundan 10 instruction
NOT

QEMU'da -nographic kullanılınca Ctrl+A X ile çıkılır (Ctrl+C değil). UART çıktısı stdio'ya yönlendirilir; ayrı bir pencere açmak için -serial telnet:localhost:5555,server ve başka bir terminalde telnet localhost 5555 kullanılabilir.

Bu bölümde

  • qemu-system-arm ile vexpress-a9 ve ARM64 raspi3b emülasyonu
  • dd + parted + losetup ile SD kart imajı hazırlama
  • QEMU user-mode networking ile TFTP boot (10.0.2.2)
  • -s -S ile GDB stub başlatma ve remote debugging
  • arm-linux-gnueabihf-gdb ile U-Boot'a breakpoint koyma