跳转至

制作根文件系统

本项目默认生成适用于 NAND Flash 的 UBIFS 根文件系统。本文介绍 NAND Flash 和 NOR Flash 两种启动介质对应的根文件系统制作方法,包括分区配置、镜像打包和烧录文件准备。

适用平台:Hi3516CV608 / Hi3516CV610。

前置条件:已按默认配置完成 OpenHarmony(OHOS)编译。

不同启动介质使用的文件系统格式、打包工具和分区配置如下。介质相关约束统一列于第 7 节“注意事项”。

对比项 NAND(SPI NAND) NOR(SPI NOR)
默认支持情况 默认编译产物可直接使用 需按本文调整配置并生成镜像
根文件系统 UBIFS JFFS2
打包工具 mkubiimg.sh(内部调用 mkfs.ubifs 和 ubinize) fakeroot mkfs.jffs2
擦除块 128K 64K
默认分区布局(608 / 610) 37M / 203M 15M / ≈46M

编译产物目录(下文记作 $OUT):

ohos/out/hispark_<chip>/ipcamera_hispark_<chip>_linux/
├── boot_image.bin           # U-Boot
├── uImage                   # kernel + dtb
├── rootfs/                  # 已完成 BusyBox 后处理的根目录,包含内核模块、动态库和初始化脚本
├── nand_env.bin             # NAND 用
├── nand_burn_table.xml      # NAND 用
├── rootfs_<chip>.ubifs      # NAND 用(实际烧录的镜像)
└── rootfs_<chip>_64k.jffs2  # NOR 使用,需单独生成

1. NAND 根文件系统配置

NAND 编译产物可直接使用,通常无需调整;更换 NAND 芯片时,需补充芯片表项并重新编译。相关注意事项见第 7.1 节。

1.1 CV608

配置项 配置值 来源
分区布局 512K(boot),512K(env),4M(kernel),32M(rootfs) = 37M env_text/hi3516cv608/nand_env.txt
bootcmd nand read 0x41000000 0x100000 0x400000; bootm 0x41000000 同上
bootargs 关键段 root=ubi0:ubifs rootfstype=ubifs rw ubi.mtd=3 mtdparts=nand:... 同上
rootfs 镜像 rootfs_hi3516cv608.ubifs,实测 4.75MiB $OUT
烧录表 ohos/device/soc/hisilicon/hi3516cv608/burn/nand_burn_table.xml,rootfs 分区 Length=0x2000000(32M) 静态文件

1.2 CV610

配置项 配置值 来源
分区布局 512K(boot),512K(env),4M(kernel),198M(rootfs) = 203M env_text/hi3516cv610/nand_env.txt
bootcmd 与 CV608 相同 同上
bootargs 关键段 与 CV608 相同,内存参数为 mem=56M(CV608 为 mem=32m) 同上
rootfs 镜像 rootfs_hi3516cv610_2k_128k_198M.ubifs,实测 39MiB $OUT
烧录表 ohos/device/soc/hisilicon/hi3516cv610/burn/nand_burn_table.xml,rootfs 分区 Length=0xC600000(198M) 静态文件

2. NOR 根文件系统配置

使用 NOR 启动时,需调整内核命令行配置(仅 CV608)、生成环境变量镜像和烧录表,并打包 JFFS2 根文件系统镜像。

2.1 容量评估

NOR 使用 JFFS2 根文件系统,其镜像大小小于 UBIFS 镜像,但 NOR 芯片容量也较小。实测结果如下:

平台 JFFS2 镜像实测大小 最小容量需求(boot + env + kernel + rootfs) 结论
CV608 2.60MiB 512K+512K+3.17M+2.60M ≈ 6.77M 8MB 及以上可用
CV610 32.42MiB 512K+512K+3.66M+32.42M ≈ 37.1M 32MB 容量不足
  • CV608:使用 8MB 芯片时,按 4M kernel 分区配置,rootfs 分区可分配 3M,镜像约占该分区的 87%。此配置下 JFFS2 垃圾回收较为频繁,建议使用 16MB 及以上容量的芯片。
  • CV610:完整 rootfs 镜像约为 32.42MiB,32MB NOR 芯片无法容纳。可根据产品需求裁剪未使用的内核模块和动态库,选用 64MB 及以上容量的 NOR 芯片,或使用 NAND。选用 64MB 及以上容量的 NOR 芯片时,需补充芯片表项并启用 4 字节地址模式。

2.2 CV608 NOR 配置步骤

步骤一:调整内核命令行配置

CV608 的内核 defconfig 启用了 CONFIG_CMDLINE_FORCE=y,且 CONFIG_CMDLINE 使用 NAND 启动参数。启动时,early_init_dt_scan_chosen() 中的 #elif defined(CONFIG_CMDLINE_FORCE) 分支(位于 drivers/of/fdt.c:1067)会使用该配置覆盖 U-Boot 传入的 bootargs。因此,仅将环境变量修改为 JFFS2 参数后,内核仍会尝试挂载 ubi0,导致 NOR 启动失败,需同步修改内核命令行配置。

将以下两个文件第 26 行的 CONFIG_CMDLINE 修改为与 env_text/hi3516cv608/nor_env.txt 中 bootargs 完全一致的值:

ohos/kernel/linux/config/linux-5.10/arch/arm/configs/.hispark_hi3516cv608_small_defconfig.orig   # 第 26 行
ohos/kernel/linux/config/linux-5.10/arch/arm/configs/hispark_hi3516cv608_small_defconfig          # 第 26 行

两个文件需同步修改。.orig 文件是 scripts/build_ohos.sh:475-481 使用的备份基线,overlay_case_defconfig() 会在每轮构建时据此还原 defconfig;仅修改后者会被覆盖。修改完成后,重新编译 uImage。

步骤二:根据芯片容量配置分区

修改 env_text/hi3516cv608/nor_env.txt。使用 8MB 芯片时,将 rootfs 分区配置为 3M,即 ...,4M(kernel),3M(rootfs);使用 16MB 及以上容量的芯片时,可保留以下 10M rootfs 分区配置:

bootargs=... rw root=/dev/mtdblock3 rootfstype=jffs2 mtdparts=sfc:512K(boot),512K(env),4M(kernel),10M(rootfs)

步骤三:生成镜像并准备烧录文件

按第 3 节生成环境变量镜像和烧录表,按第 4.1 节打包 JFFS2 镜像,再按第 5.1 节准备并检查烧录文件。

2.3 CV610 NOR 配置步骤

CV610 的内核配置为 CONFIG_CMDLINE="",且未启用 CONFIG_CMDLINE_FORCE,可直接使用 U-Boot 传入的 bootargs,无需执行第 2.2 节的内核命令行修改步骤。容量方面需使用 64MB 芯片,容量评估见第 2.1 节。

步骤一:根据芯片容量配置分区

修改 env_text/hi3516cv610/nor_env.txt。使用 64MB 芯片时,可将 rootfs 分区配置为 59M:

bootargs=... rw root=/dev/mtdblock3 rootfstype=jffs2 mtdparts=sfc:512K(boot),512K(env),4M(kernel),59M(rootfs)

步骤二:生成镜像并准备烧录文件

按第 3 节生成环境变量镜像和烧录表,按第 4.1 节打包 JFFS2 镜像,再按第 5.1 节准备并检查烧录文件。

3. 生成 NOR 环境变量镜像和烧录表

从工程根目录 hi_aiot_solution/ 执行以下命令:

CHIP=hi3516cv608        # 或 hi3516cv610
cd sdk/Hi3516CV610/boards/dmeb/tools/pc/uboot_env
make ENVTXT=$PWD/env_text/$CHIP/nor_env.txt
mv env.bin nor_env.bin && mv burn_table.xml nor_burn_table.xml

make 依次调用 mkenvimage -s 0x40000 -o env.bin <env.txt> 生成环境变量镜像,并调用 python3 scripts/env2burn.py <env.txt> burn_table.xml,根据 mtdparts=sfc:... 生成烧录表。调整分区时,修改 mtdparts 并重新执行 make 即可生成烧录表,无需手动编写 XML。生成后,检查烧录表引用的镜像文件名:

grep -o 'SelectFile="[^"]*"' nor_burn_table.xml

烧录表中的 SelectFile 应与实际镜像文件名一致,命名约束见第 7.2 节。

4. 打包根文件系统

两种介质均使用 $OUT/rootfs 作为打包源目录。该目录已完成 BusyBox 后处理,包含内核模块、动态库和初始化脚本。两种介质使用的源目录内容相同,打包工具和参数不同。

4.1 NOR:生成 JFFS2 镜像

cd ohos/out/hispark_<chip>/ipcamera_hispark_<chip>_linux/
fakeroot mkfs.jffs2 -U -d ./rootfs -l -e 0x10000 -o rootfs_<chip>_64k.jffs2
参数 含义
fakeroot 使 -U 对文件属主和权限的设置生效;在编译主机上以普通用户直接执行时,可能记录错误的属主
mkfs.jffs2 由 mtd-utils 提供;可通过 apt install mtd-utils fakeroot 安装所需工具
-d ./rootfs 源目录,即 $OUT/rootfs
-l 小端(ARM)
-e 0x10000 擦除块大小为 64K,必须与芯片实际值一致,否则板端挂载失败;见第 7.2 节
-U 将所有文件的属主和属组统一设置为 root:root
-o rootfs_<chip>_64k.jffs2 输出文件名,应与烧录表中的引用一致

打包后,检查镜像大小和文件头。镜像大小应小于 rootfs 分区容量,容量评估见第 2.1 节。

ls -l rootfs_<chip>_64k.jffs2
xxd -l 2 rootfs_<chip>_64k.jffs2

4.2 NAND:生成 UBIFS 镜像

NAND 镜像制作分为两个阶段:先使用 mkfs.ubifs 生成文件系统镜像,再使用 ubinize 根据 NAND 物理参数生成可烧录的 UBI 镜像。SDK 通过 sdk/Hi3516CV610/boards/dmeb/tools/pc/ubi_sh/mkubiimg.sh 封装上述流程;OHOS 构建流程使用内容相同的 scripts/ohos/mkubiimg.sh。

cd ohos/out/hispark_<chip>/ipcamera_hispark_<chip>_linux/
./mkubiimg.sh <chip> 2k 128k rootfs <rootfs分区大小> pc

CV608 和 CV610 的命令示例如下:

# CV608:rootfs 分区 32M(对应 nand_env.txt 的 32M(rootfs))
./mkubiimg.sh hi3516cv608 2k 128k rootfs 32M pc

# CV610:rootfs 分区 198M(对应 nand_env.txt 的 198M(rootfs))
./mkubiimg.sh hi3516cv610 2k 128k rootfs 198M pc
位置 含义
mkubiimg.sh 在 $OUT 目录下执行;若脚本不存在,可从 scripts/ohos/mkubiimg.sh 复制
第 1 个 <chip> 芯片名称,用于生成输出文件名:rootfs_<chip>.ubifs
第 2 个 2k NAND 页大小,当前两种 NAND 芯片均为 2K,以 -m 2048 传入 mkfs.ubifs
第 3 个 128k NAND 块大小,以 -p 131072 传入 ubinize
第 4 个 rootfs 源目录($OUT/rootfs)
第 5 个 32M/198M rootfs 分区大小,必须与 nand_env.txt 中 mtdparts 的 rootfs 分区大小一致
第 6 个 pc 工具路径占位参数;通过 PATH 查找 mkfs.ubifs 和 ubinize 时,可传入任意值

调用脚本时需提供全部 6 个参数。以 32M rootfs 分区为例,脚本内部处理流程等价于:

# 1) 计算逻辑擦除块:LEB = 块大小 - 页大小 × 2 = 128K - 2×2K = 126976 (0x1F000)
# 2) 根据 LEB 和最大 LEB 数(分区大小 / 块大小 = 32M/128K = 256)生成 UBIFS 镜像
mkfs.ubifs -F -d rootfs -m 2048 -e 126976 -c 256 -o rootfs_<chip>_2k_128k_<size>.ubiimg

# 3) 生成 ubinize 配置:单卷、动态卷、autoresize
#    [ubifs-volumn] mode=ubi / vol_type=dynamic / vol_name=ubifs / vol_flags=autoresize
# 4) 按物理参数打包成可烧写的 UBI 镜像
ubinize -o rootfs_<chip>.ubifs -m 2048 -p 131072 rootfs_<chip>_2k_128k_<size>.ubicfg

输出文件为 rootfs_<chip>.ubifs,中间文件 .ubiimg 和 .ubicfg 默认会被删除。打包后检查镜像大小和文件头:

ls -l rootfs_<chip>.ubifs            # 应小于分区大小;自动扩容机制见第 7.1 节
xxd -l 4 rootfs_<chip>.ubifs         # 前 4 字节应为 UBI#(0x55424923)

打包后,按第 7.1 节核对镜像文件名与烧录表中的 SelectFile。

5. 烧录文件清单

5.1 NOR

分区 文件 分区容量 来源
boot boot_image.bin 512KB 编译产物;未支持的芯片型号需补充表项后重新编译
env nor_env.bin 512KB 按第 3 节生成
kernel uImage 4MB 编译产物;CV608 需先完成第 2.2 节的内核命令行配置
rootfs rootfs_<chip>_64k.jffs2 见第 2.2、2.3 节 第 4.1 节打包

烧录表 nor_burn_table.xml 如下,默认分区总容量为 15M;小容量芯片以实际生成的烧录表为准。

<Partition_Info>
<Part Sel="1" PartitionName="boot" FlashType="spi" FileSystem="none" Start="0x0" Length="0x80000" SelectFile="boot_image.bin" />
<Part Sel="1" PartitionName="env" FlashType="spi" FileSystem="none" Start="0x80000" Length="0x80000" SelectFile="nor_env.bin" />
<Part Sel="1" PartitionName="kernel" FlashType="spi" FileSystem="none" Start="0x100000" Length="0x400000" SelectFile="uImage" />
<Part Sel="1" PartitionName="rootfs" FlashType="spi" FileSystem="none" Start="0x500000" Length="0xa00000" SelectFile="rootfs_hi3516cv608_64k.jffs2" />
</Partition_Info>

将环境变量镜像和烧录表复制到编译产物目录,并执行烧录配置检查:

cp ../../../../sdk/Hi3516CV610/boards/dmeb/tools/pc/uboot_env/{nor_env.bin,nor_burn_table.xml} .
bash tools/burn/check_config.sh <镜像目录> NOR

5.2 NAND

分区 文件 分区容量 来源
boot boot_image.bin 512KB 编译产物
env nand_env.bin 512KB 编译产物
kernel uImage 4MB 编译产物
rootfs 608:rootfs_hi3516cv608.ubifs
610:rootfs_hi3516cv610_2k_128k_198M.ubifs
608:32MB
610:198MB
第 4.2 节打包

使用 ohos/device/soc/hisilicon/<chip>/burn/nand_burn_table.xml 作为烧录表(使用要求见第 7.1 节),并执行烧录配置检查:

bash tools/burn/check_config.sh <镜像目录> NAND

6. 常见问题与处理方法

现象 介质 原因与处理
can't find in the ID table !!! + Failed to initialize SPI flash NOR U-Boot NOR 芯片表未包含该型号,按第 7.2 节补充表项并重新编译 U-Boot
内核 unrecognized JEDEC id bytes、/proc/mtd 为空 NOR 内核 SPI NOR 芯片表未包含该 ID,按第 7.2 节补充表项
CV608 配置 NOR 环境变量后,内核仍尝试挂载 ubi0 NOR CONFIG_CMDLINE_FORCE=y 覆盖了 bootargs,按第 2.2 节步骤一处理后重新编译 uImage
JFFS2 挂载失败或回读校验失败 NOR 常见原因为 -e 与芯片擦除块大小不一致,需核对 /proc/mtd,并同步调整镜像文件名与烧录表
烧录时提示镜像超出分区 NOR 镜像大于 rootfs 分区,按第 2.1 节重新评估容量,并按第 3 节重新生成相关文件
内核启动停滞或无法找到根文件系统 NOR rootfs 不再是第 4 个分区,或 bootcmd 中 kernel 的偏移、长度与烧录表不一致
大于 16MB 的芯片启动失败,U-Boot 报地址模式错误 NOR 表项 addrcycle 与 FMC 启动地址模式不匹配
板端权限异常或应用无法启动 两者 JFFS2 打包时未使用 -U 及 fakeroot
saveenv 报错或环境变量丢失 NOR 芯片擦除块大于 CONFIG_ENV_SECT_SIZE(64K),需调整该配置并重新编译 U-Boot
mkubiimg.sh 仅输出用法说明,未生成镜像 NAND 参数数量不符合要求(需提供 6 个,见第 4.2 节);脚本以状态码 0 退出,需检查目标文件是否生成
UBIFS 挂载失败或无法找到 ubi0 NAND 页大小、块大小与芯片不一致,或分区大小超出芯片容量;按第 4.2 节核对
烧录表 SelectFile 为空或指向不存在的文件 NAND 使用 env2burn.py 重新生成了 NAND 烧录表,或镜像文件名与烧录表不一致;见第 7.1 节

7. 注意事项

7.1 NAND 注意事项

  • 烧录表来源与文件名一致性:使用 ohos/device/soc/hisilicon/<chip>/burn/nand_burn_table.xml,不得通过 env2burn.py 重新生成 NAND 烧录表。该静态烧录表已与实际文件名保持一致,也可手动调整 SelectFile。CV610 静态烧录表引用的文件名为 rootfs_hi3516cv610_2k_128k_198M.ubifs,可能与手动打包生成的 rootfs_<chip>.ubifs 不同,需在打包后按烧录表统一文件名,否则烧录时无法找到文件。OHOS 构建脚本 scripts/build_ohos.sh:673-681 中的 align_rootfs_image_name() 用于完成此项处理。
  • 镜像大小与分区容量:UBIFS 对应卷配置了 autoresize,首次挂载时会自动扩展至可用分区空间。因此,镜像大小明显小于分区容量属于正常情况。例如,CV608 的镜像约为 4.75MiB,而 rootfs 分区为 32M。不应仅依据镜像大小缩减分区。
  • 页大小与块大小:打包参数必须与实际 NAND 芯片一致。当前两种 NAND 芯片均使用 2K 页和 128K 擦除块,对应第 4.2 节命令中的 2k 128k。

7.2 NOR 注意事项

  • 擦除块大小:mkfs.jffs2 -e 必须与芯片实际擦除块大小一致。当前 SDK 未启用 CONFIG_MTD_SPI_NOR_USE_4K_SECTORS,本文配置使用 64K 擦除块,对应 -e 0x10000。可通过板端 cat /proc/mtd 核对 erasesize 列,其值应为 00010000;U-Boot 的 sf probe 输出也会包含块大小信息,例如 Block:64KB Chip:16MB Name:"..."。
  • 芯片支持范围:新增芯片型号时,应核对 U-Boot 和内核中的芯片表项。U-Boot 表位于 drivers/mtd/spi/fmc100/fmc_spi_nor_ids.c,内核表位于 drivers/mtd/spi-nor/gigadevice.c。适配修改可参考 apps/cv610_ev_board/samples/fastboot/nor_fastboot/patch/uboot_flash_adapter.patch。
  • 根文件系统分区序号:rootfs 必须为第 4 个分区。挂载参数固定为 root=/dev/mtdblock3,增加或删除分区会导致设备编号与挂载参数不匹配。
  • kernel 分区与读取参数一致性:修改 kernel 分区长度后,必须同步修改 bootcmd。例如,sf read 0x41000000 0x100000 0x400000 中第三个参数为 kernel 读取长度;扩大分区后未同步调整该参数,会导致 uImage 被截断。涉及 U-Boot 编译配置的修改应写入 defconfig 后重新编译,不能仅修改临时 .config,因为 u-boot/Makefile 的 all 目标会先执行 distclean 并重新生成配置。
  • MTD 设备名称:mtdparts=sfc: 的前缀来自设备树节点名称。不得修改 hi3516cv6xx-demb.dts 中 &sfc { sfc@0 {...} } 的节点名称,否则无法生成分区。
  • 环境变量擦除范围:CONFIG_ENV_SECT_SIZE=0x10000 表示 SPI 环境变量使用 64K 擦除范围。芯片要求的最小擦除块更大时,需相应调整此配置并重新编译 U-Boot。
  • 镜像文件命名:烧录表生成脚本使用固定的 NOR 文件名 rootfs_<chip>_64k.jffs2,不会根据 mkfs.jffs2 -e 参数调整文件名。使用非 64K 擦除块时,应同步调整镜像文件名或烧录表中的 SelectFile,确保引用一致。