Flash Storage trong Linux kernel: MTD và MMC¶
Trang này mô tả cách Linux kernel tổ chức code và giao diện cho bộ nhớ flash, gồm các subsystem liên quan, cách khai báo trong device tree, các node trong /dev và cách mount rootfs. Phần cứng (cell, NOR/NAND, ECC, eMMC) được trình bày tại Flash: NOR, NAND và eMMC; so sánh và cách chọn loại bộ nhớ cho board xem Chọn bộ nhớ non-volatile cho hệ nhúng.
Tổng quan: MTD và MMC¶
| Raw flash (NOR, raw NAND, SPI NAND) | Managed NAND (eMMC, SD card) | |
|---|---|---|
| Subsystem | MTD | MMC + block layer |
| Ai lo ECC, bad block, wear leveling | Kernel (driver NAND, UBI) | Controller trong chip |
| Node chính | /dev/mtdN, /dev/ubiX_Y |
/dev/mmcblkN, /dev/mmcblkNpM |
| Filesystem | UBIFS, JFFS2, squashfs | ext4, f2fs |
MTD subsystem¶
MTD (Memory Technology Device) là lớp trừu tượng cho flash thô, cung cấp ba thao tác đọc, ghi và xóa theo erase block. Code nằm trong drivers/mtd/:
| Thư mục | Nội dung |
|---|---|
drivers/mtd/ |
MTD core, phân vùng, char device mtdchar, mtdblock |
drivers/mtd/spi-nor/ |
SPI NOR core; controller QSPI/OSPI cung cấp thao tác qua spi-mem (xem SPI Subsystem) |
drivers/mtd/nand/raw/ |
Raw NAND core và driver NAND controller của từng SoC |
drivers/mtd/nand/spi/ |
SPI NAND |
drivers/mtd/ubi/ |
UBI |
Node trong /dev:
/dev/mtdN: char device, dùng cho các công cụ đọc, ghi, xóa (flash_erase,nandwrite). Có thêm/dev/mtdNrochỉ đọc./dev/mtdblockN: block device chỉ nên dùng để đọc hoặc mount filesystem chỉ đọc (squashfs). Không có wear leveling, nên không dùng để ghi thường xuyên.
Phân vùng MTD¶
Phân vùng thường được khai báo trong device tree, bên trong node của chip flash:
&qspi {
flash@0 {
compatible = "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <50000000>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "boot";
reg = <0x000000 0x100000>;
read-only;
};
partition@100000 {
label = "env";
reg = <0x100000 0x020000>;
};
partition@120000 {
label = "rootfs";
reg = <0x120000 0xee0000>;
};
};
};
};
Cũng có thể truyền phân vùng qua kernel command line, ví dụ mtdparts=spi0.0:1M(boot)ro,128k(env),-(rootfs). Cách này thuận tiện khi bootloader (U-Boot) đã quản lý bảng phân vùng.
UBI và UBIFS¶
Trên raw NAND, ghi trực tiếp lên MTD không có wear leveling và bad block management. UBI (Unsorted Block Images) chạy trên một phân vùng MTD để đảm nhận các chức năng này, và chia phân vùng thành các volume (/dev/ubiX_Y). UBIFS là filesystem chạy trên một UBI volume.
ubiformat /dev/mtd2 # chuẩn bị phân vùng cho UBI, giữ lại erase counter
ubiattach /dev/ubi_ctrl -m 2 # gắn mtd2 thành ubi0
ubimkvol /dev/ubi0 -N rootfs -m # tạo volume "rootfs" chiếm toàn bộ dung lượng còn lại
mount -t ubifs ubi0:rootfs /mnt
Với phân vùng đã dùng UBI, nên dùng ubiformat thay cho flash_erase để không mất erase counter mà UBI dùng cho wear leveling.
MMC subsystem¶
MMC subsystem điều khiển eMMC, SD card và SDIO. Code nằm trong drivers/mmc/:
| Thư mục | Nội dung |
|---|---|
drivers/mmc/core/ |
Khởi tạo thẻ, quản lý bus, driver block (block.c) |
drivers/mmc/host/ |
Driver host controller: sdhci-* (SDHCI chuẩn), dw_mmc* (Synopsys)... |
Khai báo host controller trong device tree, ví dụ một eMMC 8-bit:
Node trong /dev:
/dev/mmcblkN: toàn bộ vùng dữ liệu (user area);/dev/mmcblkNpMlà các phân vùng trong bảng MBR/GPT./dev/mmcblkNboot0,boot1: boot partition của eMMC, mặc định chỉ đọc. Cho phép ghi bằng lệnhecho 0 > /sys/block/mmcblk0boot0/force_ro./dev/mmcblkNrpmb: vùng RPMB, truy cập quammc-utilshoặc TEE.
Mount rootfs từ flash¶
Rootfs được chỉ định qua kernel command line (xem Kernel Command Line):
| Rootfs nằm trên | Tham số |
|---|---|
| eMMC, phân vùng 2 | root=/dev/mmcblk0p2 rootfstype=ext4 rootwait |
UBIFS trên phân vùng MTD tên rootfs |
ubi.mtd=rootfs root=ubi0:rootfs rootfstype=ubifs |
| squashfs trên NOR, phân vùng MTD số 3 | root=/dev/mtdblock3 rootfstype=squashfs ro |
rootwait là cần thiết với eMMC và SD card, do thiết bị có thể được phát hiện muộn hơn thời điểm kernel tìm rootfs.
Kiểm tra và debug¶
cat /proc/mtd # danh sách phân vùng MTD, kích thước, erase size
mtdinfo -a # chi tiết từng MTD device (mtd-utils)
cat /sys/class/mtd/mtd0/{type,erasesize,writesize,oobsize}
ubinfo -a # UBI device và volume
lsblk /dev/mmcblk0 # eMMC và các phân vùng
cat /sys/block/mmcblk0/device/{name,type}
cat /sys/kernel/debug/mmc0/ios # clock, bus width, timing đang dùng (debugfs)
mmc extcsd read /dev/mmcblk0 # thanh ghi EXT_CSD (mmc-utils)
dmesg | grep -i -E "mtd|ubi|mmc"