Chapter 35D: Bootable SD and eMMC image layout¶
Chapters 31 and 35 got a root filesystem running over NFS. NFS is perfect for development, but a product needs local storage.
This chapter builds the storage layout you will use again and again:
SD/eMMC
p1 FAT32 boot files: zImage, DTB, optional initramfs
p2 ext4 root filesystem
p3 ext4 persistent data
The exact partition sizes change per product. The pattern does not.
35D.1 Why split boot, rootfs, and data?¶
Do not put everything in one writable ext4 partition.
Partition |
Mounted at |
Purpose |
|---|---|---|
Boot |
|
Files U-Boot reads: kernel, DTB, initramfs |
Rootfs |
|
Operating system files |
Data |
|
App config, logs, databases, user files |
This gives you clean boundaries:
You can replace the rootfs without erasing user data.
You can mount rootfs read-only later.
You can factory reset by clearing
/dataor the overlay partition.You can update boot files separately from application data.
35D.2 Use labels, not guessed device names¶
On one board, the SD card may appear as /dev/mmcblk0. On another boot path, eMMC may be /dev/mmcblk1.
Use filesystem labels:
root=LABEL=rootfs rootwait
Then the kernel searches for the partition labeled rootfs.
Create labels when formatting:
$ sudo mkfs.vfat -F 32 -n BOOT /dev/sdb1
$ sudo mkfs.ext4 -L rootfs /dev/sdb2
$ sudo mkfs.ext4 -L data /dev/sdb3
Labels make bootargs easier to read and harder to break.
35D.3 Manual image build¶
Manual partitioning is useful once. It teaches what the image builder later automates.
First, identify the target card:
$ lsblk -o NAME,SIZE,MODEL,TRAN,TYPE,MOUNTPOINTS
Assume the SD card is /dev/sdb. Replace this with the correct device on your host.
Create partitions:
$ sudo parted /dev/sdb --script \
mklabel msdos \
mkpart primary fat32 1MiB 129MiB \
set 1 boot on \
mkpart primary ext4 129MiB 641MiB \
mkpart primary ext4 641MiB 100%
Format:
$ sudo mkfs.vfat -F 32 -n BOOT /dev/sdb1
$ sudo mkfs.ext4 -L rootfs /dev/sdb2
$ sudo mkfs.ext4 -L data /dev/sdb3
Mount:
$ mkdir -p /tmp/imx6ull-card/boot /tmp/imx6ull-card/rootfs /tmp/imx6ull-card/data
$ sudo mount /dev/sdb1 /tmp/imx6ull-card/boot
$ sudo mount /dev/sdb2 /tmp/imx6ull-card/rootfs
$ sudo mount /dev/sdb3 /tmp/imx6ull-card/data
Copy boot files:
$ sudo cp ~/imx6ull/src/linux-v6.6/arch/arm/boot/zImage /tmp/imx6ull-card/boot/
$ sudo cp ~/imx6ull/src/linux-v6.6/arch/arm/boot/dts/nxp/imx/imx6ull-your-board.dtb \
/tmp/imx6ull-card/boot/
Install the rootfs:
$ sudo tar -xf ~/imx6ull/buildroot/output/images/rootfs.tar \
-C /tmp/imx6ull-card/rootfs
Create data directories:
$ sudo mkdir -p /tmp/imx6ull-card/data/myapp /tmp/imx6ull-card/data/log
Unmount:
$ sync
$ sudo umount /tmp/imx6ull-card/boot
$ sudo umount /tmp/imx6ull-card/rootfs
$ sudo umount /tmp/imx6ull-card/data
Now the card has a boot partition, rootfs partition, and data partition.
35D.4 Bootargs for local rootfs¶
In U-Boot:
=> setenv bootargs 'console=ttymxc0,115200 earlycon root=LABEL=rootfs rw rootwait'
=> fatload mmc 0:1 0x82000000 zImage
=> fatload mmc 0:1 0x83000000 imx6ull-your-board.dtb
=> bootz 0x82000000 - 0x83000000
Save it:
=> setenv bootcmd 'fatload mmc 0:1 0x82000000 zImage && fatload mmc 0:1 0x83000000 imx6ull-your-board.dtb && bootz 0x82000000 - 0x83000000'
=> saveenv
Use && so a failed load stops the boot.
35D.5 Mount /data¶
In the rootfs, add this to /etc/fstab:
LABEL=data /data ext4 defaults,noatime 0 2
Create the mountpoint:
$ sudo mkdir -p /tmp/imx6ull-card/rootfs/data
On target:
[root@pa-mini:~]# mount /data
[root@pa-mini:~]# touch /data/test
[root@pa-mini:~]# reboot
[root@pa-mini:~]# ls /data/test
If the file survives, persistent data works.
35D.6 Automate with genimage¶
Manual partitioning is not release engineering. For repeatable images, use genimage.
Buildroot can run genimage as a post-image step. The core file is genimage.cfg:
image sdcard.img {
hdimage {
}
partition boot {
partition-type = 0x0C
bootable = true
image = "boot.vfat"
size = 128M
}
partition rootfs {
partition-type = 0x83
image = "rootfs.ext4"
size = 512M
}
partition data {
partition-type = 0x83
size = 512M
}
}
image boot.vfat {
vfat {
files = {
"zImage",
"imx6ull-your-board.dtb"
}
}
size = 128M
}
The result is one flashable file:
$ sudo dd if=sdcard.img of=/dev/sdb bs=4M conv=fsync status=progress
Buildroot board directories usually keep this under:
board/myorg/myboard/genimage.cfg
Chapter 35E later uses that structure.
35D.7 Verify the card¶
Before booting, check:
$ lsblk -f /dev/sdb
NAME FSTYPE LABEL SIZE
sdb
├─sdb1 vfat BOOT 128M
├─sdb2 ext4 rootfs 512M
└─sdb3 ext4 data ...
After boot:
[root@pa-mini:~]# cat /proc/cmdline
[root@pa-mini:~]# findmnt /
[root@pa-mini:~]# findmnt /data
[root@pa-mini:~]# df -h
You want:
/mounted fromLABEL=rootfs,/datamounted fromLABEL=data,boot files loaded from the FAT partition.
35D.8 Key Notes¶
Boot files, the root filesystem and application data have different owners and update lifetimes. Separate partitions make those boundaries visible but do not by themselves provide rollback.
Partition identity and device enumeration are separate concerns. A label or PARTUUID can describe the intended root, while the selected init and kernel still need support for resolving that form.
The ROM boot region is outside the filesystem-level view. Image packaging must keep bootloader placement, partition tables and later filesystem writes from overlapping.
Root mounting depends on storage discovery and filesystem availability. A correct filename in U-Boot does not prove that the kernel can mount the selected root.
Service startup must follow the availability of persistent data. Otherwise an application can accidentally write into the underlying root directory instead of the intended data partition.
35D.9 Pitfalls¶
Writing the wrong
/dev/sdX. Always runlsblkbeforedd,parted, ormkfs.Using
/dev/mmcblk0p2in bootargs. It may change when boot source changes. PreferLABEL=orPARTUUID=.Forgetting
rootwait. MMC may not be ready when the kernel tries to mount root.Putting mutable app data in
/etc. Use/datafor runtime data.Mounting
/datatoo late. If your app starts before/datais mounted, it may create files on the rootfs instead.
Previous chapter: Chapter 35 - Buildroot
Next chapter: Chapter 35I - Boot from SPI NOR flash