00 eMMC nedir?
eMMC (embedded MultiMediaCard), NAND flash bellek ve kontrolcüsünü tek bir BGA paketinde birleştiren, JEDEC JESD84 standardıyla tanımlanmış yönetilen depolama birimidir.
NAND flash ve yönetilen depolama
Ham NAND flash ile çalışmak son derece karmaşıktır: bozuk blok yönetimi, wear leveling, ECC (Error Correction Code) ve write endurance tümü yazılım katmanında çözülmelidir. eMMC, tüm bu düşük seviyeli sorumluluğu iç kontrolcüde gizleyerek sisteme standart bir MMC/SD arayüzü sunar. Geliştirici dosya sistemi yazma/okuma işlemleri yaparken; sayfa programlama, blok silme, ECC ve wear leveling eMMC içinde otomatik yürütülür.
Depolama teknolojisi karşılaştırması
| Özellik | Ham NAND | eMMC | SD Kart | NVMe SSD |
|---|---|---|---|---|
| Arayüz | Paralel/SPI | MMC (HS400) | SD/SPI | PCIe/NVMe |
| Hız (seq r) | ~100 MB/s | 250–300 MB/s | 10–100 MB/s | 2–7 GB/s |
| Entegrasyon | MTD/UBIFS gerekir | Block device doğrudan | Block device | Block device |
| Boot desteği | Manuel | Boot0/Boot1 hardwired | Card detect gerekir | NVMe boot |
| RPMB | Yok | Standart | Yok | Yok (genelde) |
| Endurance | pSLC: 100K cycle | MLC: 3K–10K cycle | Düşük | TLC: 3K cycle |
| Maliyet | Düşük | Orta | Düşük | Yüksek |
JEDEC JESD84 standardı
JESD84-B51 (eMMC 5.1) standardı; HS400 (400 MB/s), enhanced strobe modu, packed commands, command queuing ve gelişmiş sağlık registerları gibi özellikleri tanımlar. Çoğu modern SoC (i.MX8, RK3568, AM625) HS400 destekler.
01 Fiziksel yapı ve registerlar
eMMC'nin iç yapısını anlamak; boot partition seçimi, write protection ve kapasite hesaplama için gereklidir.
Mantıksal bölge yapısı
eMMC Fiziksel Yapısı
┌────────────────────────────────────────┐
│ User Data Area │ ← normal disk bölümler
│ (mmcblk0 — GPT/MBR bölümleme) │
├──────────────┬─────────────────────────┤
│ Boot Area 1 │ Boot Area 2 │ ← mmcblk0boot0 / mmcblk0boot1
│ (mmcblk0boot0) (mmcblk0boot1) │ U-Boot buraya yazılır
├──────────────┴─────────────────────────┤
│ RPMB (Replay Protected Memory Block) │ ← mmcblk0rpmb
│ (TEE / güvenli depolama) │
└────────────────────────────────────────┘
Önemli registerlar
EXT_CSD register haritası (önemli ofsetler)
| Ofset | Alan | Açıklama |
|---|---|---|
| 196 | BOOT_PARTITION_ENABLE | Hangi boot alanından önyükleneceği (boot0/boot1/user) |
| 179 | PARTITION_CONFIG | Boot partition access ve bus seçimi |
| 241 | BOOT_SIZE_MULTI | Boot partition boyutu = değer × 128 KB |
| 267 | PRE_EOL_INFO | Ömür sonu uyarısı (0x01=normal, 0x02=warning, 0x03=urgent) |
| 268 | DEVICE_LIFE_TIME_EST_A | Type A (SLC) yıpranma tahmini — %10 adımlarla 0–100% |
| 269 | DEVICE_LIFE_TIME_EST_B | Type B (MLC) yıpranma tahmini — %10 adımlarla 0–100% |
# EXT_CSD registerını oku ve parse et
mmc extcsd read /dev/mmcblk0 | grep -E "BOOT|LIFE|EOL"
# Çıktı örneği:
# Boot Partition Size [BOOT_SIZE_MULTI]: 0x10
# Boot configuration bytes [PARTITION_CONFIG]: 0x48
# pre-EOL information [PRE_EOL_INFO]: 0x01
# Device life time estimation type A [DEVICE_LIFE_TIME_EST_TYP_A]: 0x01
02 GPT bölümleme
eMMC user data alanı, tıpkı bir SATA disk gibi GPT veya MBR bölüm tablosuyla yönetilir. Gömülü sistemlerde GPT tercih edilir.
Neden GPT?
MBR 4 birincil bölümle sınırlıdır ve 2 TB üstü diskleri desteklemez. GPT 128 bölüme kadar destek sunar, birincil ve yedek bölüm tablosu içerir ve her bölüme GUID ile benzersiz kimlik verir.
sgdisk ile bölümleme
#!/bin/bash
# Üretim bölümleme scripti
DEVICE=/dev/mmcblk0
# Mevcut bölüm tablosunu sil
sgdisk --zap-all $DEVICE
# Bölümleri oluştur
# U-Boot env (2 MB, offset 1 MB'dan başla — bootloader raw için yer)
sgdisk --new=1:2048:6143 --typecode=1:8300 --change-name=1:"uboot-env" $DEVICE
# Boot: kernel + DTB + initramfs (64 MB)
sgdisk --new=2:6144:137215 --typecode=2:0700 --change-name=2:"boot" $DEVICE
# RootFS A (512 MB — squashfs)
sgdisk --new=3:137216:1185791 --typecode=3:8300 --change-name=3:"rootfs-a" $DEVICE
# RootFS B (512 MB — A/B güncelleme)
sgdisk --new=4:1185792:2234367 --typecode=4:8300 --change-name=4:"rootfs-b" $DEVICE
# Data (kalan alan)
sgdisk --new=5:2234368:0 --typecode=5:8300 --change-name=5:"data" $DEVICE
# Bölüm tablosunu yazdır
sgdisk --print $DEVICE
# Kernel bölüm tablosunu güncelle
partprobe $DEVICE || partx -u $DEVICE
Bölüm düzeni
| Bölüm | Başlangıç | Boyut | İçerik | FS |
|---|---|---|---|---|
| mmcblk0p1 | 2048 (1 MB) | 2 MB | U-Boot env | Raw |
| mmcblk0p2 | 6144 (3 MB) | 64 MB | Kernel, DTB, initrd | FAT32 |
| mmcblk0p3 | 137216 | 512 MB | RootFS A (squashfs) | SquashFS |
| mmcblk0p4 | 1185792 | 512 MB | RootFS B (squashfs) | SquashFS |
| mmcblk0p5 | 2234368 | Kalan | Kalıcı data + overlay | ext4 |
eMMC'de ilk 1 MB (LBA 0–2047) bootloader için ayrılır ve bölüm tablosuna dahil edilmez. U-Boot çoğunlukla mmcblk0boot0'a yazılır; ancak bazı SoC tasarımları U-Boot'u user data alanının başına ham olarak yazar. Hedef boardunuzun boot flow diyagramını inceleyin.
03 Boot partitions
eMMC'nin iki adet 128 KB'nın katları şeklinde boyutlandırılmış özel boot alanı (boot0 / boot1) mevcuttur. SoC ROM kodu doğrudan bu alanlardan önyükleme yapabilir.
Boot partition erişimini etkinleştirme
# Boot0'ı erişilebilir yap
echo 0 > /sys/class/block/mmcblk0boot0/force_ro
# Boot1'i erişilebilir yap
echo 0 > /sys/class/block/mmcblk0boot1/force_ro
U-Boot'u boot0'a yazma
#!/bin/bash
# U-Boot'u eMMC boot0 partition'a yaz
UBOOT_BIN=/tmp/u-boot.imx # i.MX8 formatı
BOOT0=/dev/mmcblk0boot0
# Write protect'i kaldır
echo 0 > /sys/class/block/mmcblk0boot0/force_ro
# Yazma (i.MX8 için offset 0, bazı SoC'lar 512 byte offset ister)
dd if=$UBOOT_BIN of=$BOOT0 bs=512 seek=0 conv=fsync status=progress
# Write protect'i geri aç
echo 1 > /sys/class/block/mmcblk0boot0/force_ro
echo "U-Boot yazıldı: $(stat -c %s $UBOOT_BIN) byte"
BOOT_PARTITION_ENABLE ayarlama
# mmc-utils ile boot0'dan önyüklemeyi etkinleştir
# PARTITION_CONFIG[5:3] = 001 = boot0
mmc bootpart enable 1 1 /dev/mmcblk0
# Argümanlar: boot_partition(1=boot0) boot_ack(1=etkin) device
# Mevcut ayarı doğrula
mmc extcsd read /dev/mmcblk0 | grep "Boot configuration"
# Boot configuration bytes [PARTITION_CONFIG]: 0x48
# 0x48 = 0100 1000: boot0 enabled, boot ACK enabled
Boot partition boyutu
# Boot partition boyutunu hesapla
mmc extcsd read /dev/mmcblk0 | grep "BOOT_SIZE_MULTI"
# Boot Partition Size [BOOT_SIZE_MULTI]: 0x10
# Boyut = 0x10 * 128KB = 16 * 128KB = 2MB
# Doğrula
blockdev --getsize64 /dev/mmcblk0boot0
# 4194304 = 4 MB (bazı cihazlarda 2× BOOT_SIZE_MULTI)
04 RPMB — Replay Protected Memory Block
RPMB, eMMC içinde kriptografik kimlik doğrulama kullanan özel bir bellek bölgesidir. Güvenli sayaç, cihaz kimliği ve güvenli boot durumu saklamak için kullanılır.
RPMB güvenlik modeli
TEE (Güvenli Dünya) Normal Dünya
| |
HMAC-SHA256 mmc ioctl
anahtarı bilir (sadece RPMB erişimi)
| |
+------- eMMC RPMB ------+
|
256-byte veri bloğu
+ write counter
+ MAC doğrulama
RPMB anahtar provisioning
#!/bin/bash
# RPMB anahtarını ilk kez yaz (bir kez yapılır — geri alınamaz!)
# Anahtar 32 byte HMAC-SHA256 anahtarı
# Donanımdan türetilmiş anahtar (örnek — gerçekte TEE/HSM'den gelir)
KEY_HEX="0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"
# rpmb-tool veya mmc rpmb write-key kullan
mmc rpmb write-key /dev/mmcblk0rpmb /dev/mmcblk0 <<< "$KEY_HEX"
# Ya da rpmb-tool (daha güvenilir TEE entegrasyonu)
# rpmb_tool --key $KEY_HEX program /dev/mmcblk0
RPMB okuma/yazma (mmc-utils)
# RPMB'ye 256-byte veri yaz (blok 0)
echo -n "secure_data_here_padded_to_256b" | \
mmc rpmb write-block /dev/mmcblk0rpmb /dev/mmcblk0 0x00 -
# RPMB'den veri oku
mmc rpmb read-block /dev/mmcblk0rpmb /dev/mmcblk0 0x00 1 -
RPMB anahtarı eMMC'ye bir kez yazılır ve değiştirilemez. Aynı anahtar yedek olarak güvenli depolamada (HSM, TEE persistent storage) tutulmalıdır. RPMB'nin asıl amacı yüksek kapasiteli veri depolama değil; write counter ile replay saldırısına karşı dayanıklı küçük güvenli değer saklamaktır (örn: rollback counter, device binding key).
05 mmc-utils araçları
mmc-utils paketi, EXT_CSD okuma, boot partition yönetimi, sağlık sorgulama ve düşük seviyeli eMMC yapılandırması için temel CLI araçlarını sunar.
Temel komutlar
# EXT_CSD tüm alanları oku
mmc extcsd read /dev/mmcblk0
# eMMC durumu sorgula
mmc status get /dev/mmcblk0
# Çıktı: READY_FOR_DATA=1, CURRENT_STATE=Transfer, ...
# Cihaz bilgisi (CID, CSD)
mmc info /dev/mmcblk0
# Boot bus ayarlarını göster
mmc bootbus get /dev/mmcblk0
# Boot bus genişliği ayarla (x8, SDR, DDR)
mmc bootbus set /dev/mmcblk0 x8 sdr normal
Güvenli silme işlemleri
# Belirli LBA aralığını sil (DISCARD — hızlı, veri geri alınabilir)
mmc erase /dev/mmcblk0 0 8192
# Güvenli silme (SECURE ERASE — yavaş, NAND hücrelerini fiziksel sıfırlar)
mmc erase --secure /dev/mmcblk0 0 8192
# Tüm cihazı güvenli sil (üretim sonrası temizleme)
mmc sanitize /dev/mmcblk0
Write Protect (WP) yönetimi
# WP grup boyutunu öğren
mmc extcsd read /dev/mmcblk0 | grep "Write protect group size"
# Boot partition kalıcı write protect
mmc writeprotect boot set /dev/mmcblk0
# User area belirli bölge WP
mmc writeprotect user set pwron /dev/mmcblk0 0 8192
# pwron = power-on WP (her açılışta aktif)
# perm = kalıcı WP (değiştirilemez)
# temp = geçici WP
06 Sağlık izleme
eMMC JESD84-B51 standardı, cihaz ömrü ve wear durumunu izlemek için EXT_CSD içinde birkaç sağlık alanı tanımlar.
Temel sağlık alanları
#!/bin/bash
# eMMC sağlık raporu scripti
DEVICE=${1:-/dev/mmcblk0}
echo "=== eMMC Sağlık Raporu: $DEVICE ==="
EXTCSD=$(mmc extcsd read $DEVICE 2>/dev/null)
# PRE_EOL_INFO
EOL=$(echo "$EXTCSD" | grep "PRE_EOL_INFO" | grep -oP '0x[0-9a-fA-F]+' | tail -1)
case $EOL in
0x00) EOL_STATUS="Undefined" ;;
0x01) EOL_STATUS="Normal — kullanım %0-80" ;;
0x02) EOL_STATUS="WARNING — kullanım %80-90" ;;
0x03) EOL_STATUS="URGENT — kullanım >%90, değiştirin!" ;;
*) EOL_STATUS="Bilinmiyor: $EOL" ;;
esac
echo "Pre-EOL Info: $EOL_STATUS"
# LIFE TIME EST A/B
LIFE_A=$(echo "$EXTCSD" | grep "DEVICE_LIFE_TIME_EST_TYP_A" | grep -oP '0x[0-9a-fA-F]+' | tail -1)
LIFE_B=$(echo "$EXTCSD" | grep "DEVICE_LIFE_TIME_EST_TYP_B" | grep -oP '0x[0-9a-fA-F]+' | tail -1)
echo "Life Time Est Type A (SLC): $((16#${LIFE_A#0x} * 10))% tüketildi"
echo "Life Time Est Type B (MLC): $((16#${LIFE_B#0x} * 10))% tüketildi"
Sağlık alanı yorumlama tablosu
| Değer | PRE_EOL_INFO | LIFE_TIME_EST |
|---|---|---|
| 0x00 | Tanımsız | Tanımsız |
| 0x01 | Normal | %0–10 kullanıldı |
| 0x02 | Uyarı (SLC kopyaları tükeniyor) | %10–20 kullanıldı |
| 0x03 | Acil (cihazı değiştirin) | %20–30 kullanıldı |
| 0x0A | — | %90–100 kullanıldı |
| 0x0B | — | >%100 (aşılmış!) |
Sistemd sağlık izleme servisi
# /etc/systemd/system/emmc-health-check.service
[Unit]
Description=eMMC Health Monitor
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/usr/sbin/emmc-health-report.sh
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
---
# /etc/systemd/system/emmc-health-check.timer
[Unit]
Description=eMMC Health Check — günlük
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
07 Wear leveling ve tuning
eMMC iç wear leveling algoritması otomatik çalışır; ancak host tarafında scheduler, fstrim ve ext4 seçenekleri ek optimizasyon sağlar.
I/O Scheduler seçimi
eMMC managed storage olduğundan, iç kontrolcü komut sıralamasını kendisi yapar. Host scheduler'ın ek maliyet getirmemesi için mq-deadline veya none tercih edilir.
# Mevcut scheduler'ı gör
cat /sys/block/mmcblk0/queue/scheduler
# [mq-deadline] none kyber bfq
# mq-deadline olarak ayarla
echo mq-deadline > /sys/block/mmcblk0/queue/scheduler
# Udev kuralı ile kalıcı yap:
# /etc/udev/rules.d/60-mmc-scheduler.rules
ACTION=="add|change", KERNEL=="mmcblk[0-9]", \
ATTR{queue/rotational}=="0", \
ATTR{queue/scheduler}="mq-deadline"
ext4 tuning
# ext4 data bölümünü flash için optimize et
# Zaten oluşturulmuş bölümde:
tune2fs -o journal_data_writeback /dev/mmcblk0p5
tune2fs -O ^has_journal /dev/mmcblk0p5 # journal'ı kapat (kritik veri yoksa)
tune2fs -E discard /dev/mmcblk0p5 # TRIM/DISCARD etkinleştir
# fstab mount seçenekleri:
# /dev/mmcblk0p5 /data ext4 noatime,nodiratime,discard,data=writeback 0 2
fstrim ile düzenli TRIM
# Manuel trim
fstrim -v /data
# /data: 256 MiB (268435456 bytes) trimmed
# Systemd timer ile haftalık trim
systemctl enable fstrim.timer
systemctl start fstrim.timer
# fstrim.timer ne kadar sıklıkla çalışıyor?
systemctl cat fstrim.timer | grep OnCalendar
# OnCalendar=weekly
eMMC'de discard mount seçeneği her silme işleminde eMMC'ye DISCARD komutu gönderir. Bu, sık yazma/silme işlemlerinde performans düşüşüne neden olabilir. Bunun yerine periyodik fstrim (ör: gece yarısı) daha dengeli bir yaklaşımdır.
Yazma I/O'yu azaltma stratejileri
08 Pratik: Üretim eMMC provision scripti
Üretim hattında her cihaza uygulanacak eksiksiz provision scripti: bölümleme, imaj yazma, boot partition yapılandırması ve RPMB anahtar programlama.
Tam provision scripti
#!/bin/bash
# production-provision.sh — Üretim eMMC Provision
# Kullanım: ./production-provision.sh /dev/mmcblk0 images/
set -euo pipefail
DEVICE=${1:?Cihaz gerekli: /dev/mmcblk0}
IMG_DIR=${2:?İmaj dizini gerekli}
LOG=/var/log/provision-$(date +%Y%m%d-%H%M%S).log
log() { echo "[$(date '+%T')] $*" | tee -a $LOG; }
log "=== Üretim Provision Başlıyor: $DEVICE ==="
# 1. Eski bölüm tablosunu temizle
log "Bölüm tablosu temizleniyor..."
sgdisk --zap-all $DEVICE
# 2. GPT bölümleme
log "GPT bölümleri oluşturuluyor..."
sgdisk \
--new=1:2048:6143 --change-name=1:"uboot-env" \
--new=2:6144:137215 --change-name=2:"boot" \
--new=3:137216:1185791 --change-name=3:"rootfs-a" \
--new=4:1185792:2234367 --change-name=4:"rootfs-b" \
--new=5:2234368:0 --change-name=5:"data" \
$DEVICE
partprobe $DEVICE
sleep 1
# 3. Boot filesystem
log "Boot bölümü formatlanıyor..."
mkfs.vfat -F 32 -n "BOOT" ${DEVICE}p2
# 4. Data bölümü
log "Data bölümü formatlanıyor..."
mkfs.ext4 -L data -O ^has_journal -E discard ${DEVICE}p5
# 5. Boot partitionları aç, U-Boot yaz
log "U-Boot boot0'a yazılıyor..."
echo 0 > /sys/class/block/$(basename ${DEVICE})boot0/force_ro
dd if=$IMG_DIR/u-boot.imx of=${DEVICE}boot0 bs=512 seek=0 conv=fsync
echo 1 > /sys/class/block/$(basename ${DEVICE})boot0/force_ro
# 6. Boot partition etkinleştir
log "Boot partition etkinleştiriliyor..."
mmc bootpart enable 1 1 $DEVICE
# 7. Kernel + DTB boot bölümüne kopyala
log "Kernel ve DTB kopyalanıyor..."
MNT=$(mktemp -d)
mount ${DEVICE}p2 $MNT
cp $IMG_DIR/Image $MNT/
cp $IMG_DIR/*.dtb $MNT/
cp $IMG_DIR/initramfs.cpio.gz $MNT/ 2>/dev/null || true
umount $MNT
# 8. RootFS A'ya squashfs yaz
log "RootFS A yazılıyor..."
dd if=$IMG_DIR/rootfs.squashfs of=${DEVICE}p3 bs=4M conv=fsync status=progress
# 9. RootFS B'ye aynısını yaz (başlangıç senkron)
log "RootFS B (kopya) yazılıyor..."
dd if=$IMG_DIR/rootfs.squashfs of=${DEVICE}p4 bs=4M conv=fsync status=progress
# 10. RPMB anahtar provision (varsa)
if [ -f "$IMG_DIR/rpmb.key" ]; then
log "RPMB anahtarı programlanıyor..."
mmc rpmb write-key ${DEVICE}rpmb $DEVICE < $IMG_DIR/rpmb.key
fi
# 11. Doğrulama
log "=== Provision Doğrulama ==="
sgdisk --print $DEVICE | tee -a $LOG
mmc extcsd read $DEVICE | grep -E "Boot|PARTITION_CONFIG" | tee -a $LOG
log "=== PROVISION TAMAMLANDI ==="
echo "Log: $LOG"
Provision sonrası sağlık kontrolü
#!/bin/bash
# post-provision-check.sh
DEVICE=${1:-/dev/mmcblk0}
echo "Bölüm düzeni:"
lsblk $DEVICE -o NAME,SIZE,FSTYPE,LABEL,MOUNTPOINT
echo ""
echo "eMMC sağlık:"
mmc extcsd read $DEVICE | grep -E "PRE_EOL|LIFE_TIME|BOOT_SIZE"
echo ""
echo "Boot partition:"
mmc bootpart get $DEVICE
eMMC, ham NAND'ın tüm düşük seviyeli karmaşıklığını soyutlayan yönetilen bir depolama standardıdır. Üretim kaliteli sistemlerde; GPT bölümleme, boot0 kullanımı, RPMB key provisioning ve düzenli sağlık izleme birlikte ele alınmalıdır. mmc-utils bu işlemlerin tamamını komut satırından gerçekleştirmenizi sağlar.