嵌入式 Linux 开发 8:部署 MTD 设备

MTD 与 Flash

Linux 工作站和服务器一般使用磁盘作为存储设备,而嵌入式 Linux 倾向使用 Flash 固态存储设备。
相比磁盘的“读”和“写”操作,Flash 还需要“擦除”,并且它还有写寿命(常见为 10 万次)。
为了更好地操作 Flash 设备 Linux 添加了 MTD 子系统(Memory Technology Device)。

MTD@Flash 和 磁盘块设备 的区别如下表所示

操作单位 操作 耗损均衡
MTD 擦除块 读/写/擦除 均匀分布写块
块设备 扇区 读/写 /

小窍门1
一般 MTD 设备指 Flash 芯片,常见的 SD/MMC CompactFlash USB闪存盘以及其他一些类似的设备更像传统的块设备(如磁盘)。

小窍门2
一般 Flash 分为 2 种类型 NOR 和 NAND,它们的区别如下表所示。

类别 容量 寻址单位 适合文件系统 管理坏块 性能
NOR 字节 JFFS2 / 写速度快
NAND YAFFS2 记录坏块 读速度快

内核支持 MTD

内核选项 MTD 功能
CONFIG_MTD 支持 MTD 子系统
CONFIG_MTD_CONCAT 将多个 MTD 设备或分区组合成单一文件系统
CONFIG_MTD_PARTITIONS 支持 MTD 分区
CONFIG_MTD_CHAR 通过 /dev/mtdN 和 /dev/mtdrN 操作 MTD 字符设备
CONFIG_MTD_BLOCK 通过 /dev/mtdblockN 操作 MTD 块设备
CONFIG_MTD_CMDLINE_PARTS 在命令行中传递分区信息

操作 MTD 分区

  • 查看 MTD 分区 cat /proc/mtd
  • 擦除 MTD 分区 flash_eraseall /dev/mtdX
  • 写 MTD 分区 NOR Flash flashcp /tmp/mtd.bin /dev/mtdX
  • 写 MTD 分区 NAND Flash nandwrite /tmp/image.bin /dev/mtdX
  • 读 MTD 分区 dd if=/dev/mtdX of=/tmp/mtd.bin

MTD 与文件系统

为了克服 Flash 自身的 2 个限制:擦除块耗时易导致断电丢失数据,写块有寿命限制。
支持它的文件系统一般需要具备:断电可靠性 和 耗损平衡(wear leveling 尽可能将数据均匀散布在 Flash 上)
常见的 MTD 文件系统包括:JFFS2 UBIFS YAFFS2 详情请链接Linux 文件系统类型

MTD 分区

和磁盘不同,不能使用 fdisk 之类的工具给 MTD 分区。

一般而言 MTD 分区有如下 3 种办法

  • 在内核命令行中定义分区表
  • 使用与具体板卡相关的映射驱动
  • 解析 Redboot TI_AR7 分区表

在 u-boot 引导的系统中使用方法 1 最简单;方法 2 需要修改 kernel 源代码并编译;方法 3 依赖特定的引导程序。

下面基于方法 1 给 MTD 分区
有一 128M NAND Flash 需要分成 5 个区,如下表所示

区块 分区 1 分区 2 分区 3 分区 4 分区 5
名称 u-boot kernel rootfs config log
大小 2M 20M 40M 2M 64M

按上面分区信息定义如下 u-boot 的参数,在启动时传递给内核,它会在 MTD 子系统中自动分区。

setenv bootargs 'noinitrd root=/dev/mtdblock2 rootfstype=yaffs2 rootflags=inband-tags console=ttyS0 rdinit=/sbin/init mem=64M mtdparts=nand0:2M(u-boot),20M(kernel),40M(rootfs),2M(config),-(log) ignore_loglevel'

启动 Linux 系统后,执行命令 cat /proc/mtd 即可查看 MTD 分区。

dev:    size   erasesize  name
mtd0: 00200000 00020000 "u-boot"
mtd1: 01400000 00020000 "kernel"
mtd2: 02800000 00020000 "rootfs"
mtd3: 00200000 00020000 "config"
mtd4: 04000000 00020000 "log"

编译与部署 MTD 工具

背景

为了升级 Linux 镜像,必然需要擦除/烧写 Flash,这是由 MTD 工具实现,它依赖 lzo libuuid 库。

编译 lzo 库

cd ${PRJROOT}/build-tools/lzo-2.09
./configure CC=${CROSS}-gcc --host=$CROSS --enable-shared
make
make prefix=$TARGET_PREFIX install

编译 libuuid 库

cd ${PRJROOT}/build-tools/libuuid-1.0.3
./configure --host=$CROSS
make
make prefix=$TARGET_PREFIX install

编译 MTD 工具

cd ${PRJROOT}/build-tools/mtd-utils
make CROSS="${CROSS}-" CFLAGS="-I ${TARGET_PREFIX}/include" LDFLAGS="-L ${TARGET_PREFIX}/lib"

部署 MTD 工具

cd $CROSS
MTD_TOOLS="./mtd_debug ./nandtest ./flash_erase ./nandwrite"
${CROSS}-strip $MTD_TOOLS
cp -vf $MTD_TOOLS <target_rootfs_dir>/usr/sbin/

大部分项目只需要上面 4 个 MTD 工具即可。幸运的是,它们只依赖 2 个库文件:libc(C 程序库) 和 ld(动态链接器)。
这 2 个库文件是基础软件(没有它们 Linux 几乎无法运行)。因此,不需要复制库文件到目标系统。

posted @ 2022-09-22 13:32  KevinAshton  阅读(719)  评论(0编辑  收藏  举报