嵌入式 Linux 系统移植与 SD 卡量产镜像制作

嵌入式 Linux 系统移植与 SD 卡量产镜像制作 目录1. 项目目标2. 整个系统启动流程理解3. 整体流程概览五步走3.1 存储分区规划以32GB SD卡为例3.2 Uboot启动流程设计上电自动运行3.3 修改Uboot源码并编译3.4 制作完整镜像文件.img3.5 烧录到目标SD卡工厂操作3.6 启动后的额外挂载自动化脚本1. 项目目标将已经调试好的嵌入式 Linux 系统Uboot Linux Kernel Device Tree Rootfs制作成一个完整 SD 卡镜像文件交付给工厂进行批量烧写。最终产物imx6ull.img工厂拿到这个文件后SD卡 ↓ 烧写 imx6ull.img ↓ 上电 ↓ 自动启动Linux系统2. 整个系统启动流程理解一个嵌入式 Linux 开机过程上电 | BootROM | 读取SD卡中的Uboot Uboot启动 | 加载Linux内核 | 加载设备树DTB | 设置启动参数bootargs Linux Kernel启动 | 挂载Rootfs 用户空间启动 | Linux系统运行3. 整体流程概览五步走规划存储布局– 决定SD卡上每个分区放什么多大。配置Uboot启动参数– 让上电后自动加载内核和文件系统。编译并烧写新的Uboot– 把配置写进代码生成新的Uboot二进制。打包所有文件成一个镜像– 将Uboot、内核、设备树、根文件系统按分区布局打包成单一文件。烧录与验证– 用工具把镜像烧进SD卡上电测试。3.1 存储分区规划以32GB SD卡为例分区大小格式存放内容第1分区FAT~50MBFAT32Uboot二进制u-boot.imx、内核镜像zImage、设备树.dtb、可选的initrdramdisk.gz第2分区EXT4~150MBEXT4根文件系统即完整的Linux系统文件如/bin,/etc,/lib,/usr等剩余空间未分配或后续使用—留给用户数据或其他分区忽略为什么这么分第1分区用FAT因为Uboot可以轻松读取FAT分区来加载内核和设备树。第2分区用EXT4作为根文件系统稳定且支持读写。3.2 Uboot启动流程设计上电自动运行Uboot引导加载程序启动后需要自动完成三件事设置启动参数bootargs– 告诉内核根文件系统在哪里、控制台串口参数等。从SD卡第1分区加载内核zImage和设备树.dtb到内存。启动内核bootz命令内核随后挂载第2分区作为根文件系统。关键环境变量解释新手勿怕只需知道它们控制启动行为bootdelay– 倒计时秒数超时后自动执行bootcmd中的命令。bootcmd– 倒计时结束后自动执行的命令。bootargs– 传递给内核的启动参数例如 root 路径、控制台、文件系统类型。load– 从存储设备加载文件到内存指定地址。bootz– 启动ARM Linux内核的命令。run负责执行一个环境变量里预先写好的命令脚本它可以包含一条或多条load、setenv、bootz等命令。设计的启动命令序列简化版1. 设置 bootargsroot/dev/mmcblk0p2 rw rootfstypeext4 init/linuxrc consolettymxc0,115200 2. 加载内核load mmc 0:1 0x80800000 zImage 3. 加载设备树load mmc 0:1 0x83000000 imx6ull-mmc-npi.dtb 4. 启动内核bootz 0x80800000 - 0x83000000注mmc 0:1表示第0个MMC设备即SD卡的第1个分区。3.3 修改Uboot源码并编译我们需要把上述启动命令固化到Uboot源码中这样生成的Uboot二进制自带这些配置。在Uboot源码目录下找到板级配置文件例如include/configs/mx6ullfire.h添加或修改以下宏定义bootdelay2\0 \ args_sd_bootsetenv bootargs consolettymxc0,115200 root/dev/mmcblk0p2 rw rootfstypeext4 init/linuxrc\0 \ bootcmd_mmcxload mmc 0:1 0x80800000 zImage;load mmc 0:1 0x83000000 imx6ull-mmc-npi.dtb;run args_sd_boot;bootz 0x80800000 - 0x83000000;\0 \ bootcmdrun bootcmd_mmcx\0然后重新编译Uboot得到新的u-boot.imx文件。3.4 制作完整镜像文件.img将以上所有文件按分区布局打包成一个镜像文件例如imx6ull.img。常用工具是dd配合分区表如使用fdisk或sgdisk创建分区再逐个写入数据。简化制作流程假设你有一张已分区的SD卡并已将各文件拷入对应分区将该脚本设为可执行并添加到启动项即可烧录完成后将SD卡插入开发板上电即可自动启动系统。3.6 启动后的额外挂载自动化脚本为了方便后期更新内核和调试可以在根文件系统中加入一个开机自启动脚本如/etc/init.d/auto_mount.sh自动挂载NFS共享目录和SD卡的第1分区FAT分区以便拷贝新内核或设备树。示例脚本内容#!/bin/sh # 设置IP如果需要 ifconfig eth0 192.168.10.50 # 挂载NFS共享目录开发机共享文件夹 mount -t nfs -o nolock 192.168.10.100:/home/rocky/ebf/shared /opt # 挂载SD卡第一个分区FAT到/mnt方便更新内核 mount -t vfat /dev/mmcblk0p1 /mnt使用dd将整个SD卡包括分区表导出为镜像文件这样得到的imx6ull.img就是完整的量产镜像。sudo dd if/dev/sdb ofimx6ull.img bs4M statusprogress3.5 烧录到目标SD卡工厂操作工厂会使用两种方式之一使用dd命令在Linux烧录机sudo dd ifimx6ull.img of/dev/sdX bs4M statusprogress oflagsync其中/dev/sdX是SD卡设备注意不要选错。使用专用烧录工具如Win32DiskImager或厂家提供的工具直接选择.img文件烧录。3.6 shell脚本参考一定要注意是自己的loop 不一定是loop0# 创建两个目录用于挂载镜像的分区 mkdir -p sd/boot sd/root # 生成一个 200MB 的空白镜像文件bs512, count409600 200MiB # 其中约 50MB 给 boot 分区150MB 给 rootfs 分区 dd if/dev/zero of./imx6ull.img bs512 count409600 # 在镜像上创建 MS-DOSMBR分区表 sudo parted imx6ull.img --script -- mklabel msdos # 创建第一个分区FAT32用于 /boot # 起始于 2048 扇区为了对齐2048*5121MB结束于 104447 扇区 # 大小约为 (104447 - 2048 1) * 512 ≈ 50MB sudo parted imx6ull.img --script -- mkpart primary fat32 2048s 104447s # 创建第二个分区ext4用于根文件系统 # 起始于 104448 扇区结束于最后一个可用扇区-1 sudo parted imx6ull.img --script -- mkpart primary ext4 104448s -1 # 将镜像文件关联到第一个可用的 loop 设备并显示设备名如 /dev/loop0 sudo losetup -f --show imx6ull.img # 为 loop 设备创建分区映射生成 /dev/mapper/loop0p1 和 loop0p2 sudo kpartx -va /dev/loop0 # 格式化第一个分区为 vfatFAT32 sudo mkfs.vfat /dev/mapper/loop0p1 # 格式化第二个分区为 ext4 sudo mkfs.ext4 /dev/mapper/loop0p2 # 挂载两个分区到先前创建的目录 sudo mount /dev/mapper/loop0p1 ./sd/boot/ sudo mount /dev/mapper/loop0p2 ./sd/root/ # 将 U-Boot 镜像u-boot-dtb.imx写入镜像的偏移 2 个扇区处跳过前 1KB # 因为 i.MX6ULL 从偏移 1KB即第 2 个 block处加载 U-Boot #U-Boot 不是放在SD卡分区里面的文件而是放在SD卡最前面的固定裸地址区域i.MX6ULL芯片上电后会直接#去这个位置找它。 sudo dd if/opt/out/u-boot-dtb.imx of/dev/loop0 bs512 seek2 convfsync # 复制启动相关文件内核、设备树等到 boot 分区 sudo cp ./all/boot/* ./sd/boot/ # 复制根文件系统内容到 rootfs 分区保留属性-a 表示归档模式 sudo cp -a ./all/rootfs/* ./sd/root/ # 卸载两个分区 sudo umount ./sd/boot/ ./sd/root/ # 移除分区映射 sudo kpartx -d /dev/loop0 # 释放 loop 设备 sudo losetup -d /dev/loop0 # 提示打包开始压缩镜像使用 xz 格式减少体积 echo 正在打包,需要一定时间,请勿中断 xz -zf ./imx6ull.img # 清理临时目录这里删除的是 ./gxa但脚本中并未创建该目录可能是用户失误或额外清理 rm -rf ./gxa ---------------------------------------备用 # 创建两个目录用于挂载镜像的分区 mkdir -p sd/boot sd/root # 创建 200MB 镜像 dd if/dev/zero of./imx6ull.img bs512 count409600 # 创建 MBR 分区表 sudo parted imx6ull.img --script -- mklabel msdos # 创建 boot 分区 sudo parted imx6ull.img --script -- mkpart primary fat32 2048s 104447s # 创建 rootfs 分区 sudo parted imx6ull.img --script -- mkpart primary ext4 104448s -1 # 绑定 loop LOOP$(sudo losetup -f --show imx6ull.img) echo 使用设备: $LOOP # 创建分区映射 sudo kpartx -av $LOOP # 获取分区设备名字 PART1/dev/mapper/$(basename $LOOP)p1 PART2/dev/mapper/$(basename $LOOP)p2 echo boot分区: $PART1 echo root分区: $PART2 # 格式化 sudo mkfs.vfat $PART1 sudo mkfs.ext4 $PART2 # 挂载 sudo mount $PART1 ./sd/boot/ sudo mount $PART2 ./sd/root/ # 写入 U-Boot sudo dd if/home/xingxinliao/ebf/out/u-boot-dtb.imx of$LOOP bs512 seek2 convfsync # 拷贝 boot 文件 sudo cp /home/xingxinliao/ebf/out/* ./sd/boot/ # 拷贝 rootfs sudo cp -a /home/xingxinliao/ebf/rootsfs/* ./sd/root/ # 卸载 sudo umount ./sd/boot/ sudo umount ./sd/root/ # 删除分区映射 sudo kpartx -d $LOOP # 释放 loop sudo losetup -d $LOOP echo 正在打包,需要一定时间,请勿中断 xz -zf ./imx6ull.img rm -rf ./gxa3.7 shell脚本语法解析参考dd就是复制可以复制磁盘可以复制分区可以按指定大小复制数据块可以制作镜像文件dd if/dev/zero of./imx6ull.img bs512 count409600的作用就是创建一个200MB大小的空白SD卡镜像文件imx6ull.img。dd if输入文件 of输出文件if/dev/zero of输入0输出到of./imx6ull.img