news 2026/8/17 21:41:24

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
嵌入式 Linux 系统移植与 SD 卡量产镜像制作

目录

1. 项目目标

2. 整个系统启动流程理解

3. 整体流程概览(五步走)

3.1 存储分区规划(以32GB SD卡为例)

3.2 Uboot启动流程设计(上电自动运行)

3.3 修改Uboot源码并编译

3.4 制作完整镜像文件(.img)

3.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. 整体流程概览(五步走)

  1. 规划存储布局– 决定SD卡上每个分区放什么,多大。

  2. 配置Uboot启动参数– 让上电后自动加载内核和文件系统。

  3. 编译并烧写新的Uboot– 把配置写进代码,生成新的Uboot二进制。

  4. 打包所有文件成一个镜像– 将Uboot、内核、设备树、根文件系统按分区布局打包成单一文件。

  5. 烧录与验证– 用工具把镜像烧进SD卡,上电测试。

3.1 存储分区规划(以32GB SD卡为例)

分区大小格式存放内容
第1分区(FAT)~50MBFAT32Uboot二进制(u-boot.imx)、内核镜像(zImage)、设备树(.dtb)、可选的initrd(ramdisk.gz
第2分区(EXT4)~150MBEXT4根文件系统(即完整的Linux系统文件,如/bin,/etc,/lib,/usr等)
剩余空间未分配或后续使用留给用户数据或其他分区(忽略)

为什么这么分?

  • 第1分区用FAT,因为Uboot可以轻松读取FAT分区来加载内核和设备树。

  • 第2分区用EXT4作为根文件系统,稳定且支持读写。

3.2 Uboot启动流程设计(上电自动运行)

Uboot(引导加载程序)启动后,需要自动完成三件事:

  1. 设置启动参数(bootargs)– 告诉内核根文件系统在哪里、控制台串口参数等。

  2. 从SD卡第1分区加载内核(zImage)和设备树(.dtb)到内存

  3. 启动内核(bootz命令),内核随后挂载第2分区作为根文件系统。

关键环境变量解释(新手勿怕,只需知道它们控制启动行为):

  • bootdelay– 倒计时秒数,超时后自动执行bootcmd中的命令。

  • bootcmd– 倒计时结束后自动执行的命令。

  • bootargs– 传递给内核的启动参数(例如 root 路径、控制台、文件系统类型)。

  • load– 从存储设备加载文件到内存指定地址。

  • bootz– 启动ARM Linux内核的命令。

  • run:负责执行一个环境变量里预先写好的命令脚本(它可以包含一条或多条loadsetenvbootz等命令)。

设计的启动命令序列(简化版)

1. 设置 bootargs:root=/dev/mmcblk0p2 rw rootfstype=ext4 init=/linuxrc console=ttymxc0,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),添加或修改以下宏定义:

"bootdelay=2\0" \ "args_sd_boot=setenv bootargs console=ttymxc0,115200 root=/dev/mmcblk0p2 rw rootfstype=ext4 init=/linuxrc\0" \ "bootcmd_mmcx=load mmc 0:1 0x80800000 zImage;load mmc 0:1 0x83000000 imx6ull-mmc-npi.dtb;run args_sd_boot;bootz 0x80800000 - 0x83000000;\0" \ "bootcmd=run bootcmd_mmcx\0"

然后重新编译Uboot,得到新的u-boot.imx文件。

3.4 制作完整镜像文件(.img)

将以上所有文件按分区布局打包成一个镜像文件(例如imx6ull.img)。
常用工具是dd配合分区表(如使用fdisksgdisk创建分区,再逐个写入数据)。

简化制作流程(假设你有一张已分区的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 of=imx6ull.img bs=4M status=progress

    3.5 烧录到目标SD卡(工厂操作)

    工厂会使用两种方式之一:

  • 使用dd命令(在Linux烧录机):

    sudo dd if=imx6ull.img of=/dev/sdX bs=4M status=progress oflag=sync

    其中/dev/sdX是SD卡设备(注意不要选错)。

  • 使用专用烧录工具(如Win32DiskImager或厂家提供的工具),直接选择.img文件烧录。

3.6 shell脚本参考

一定要注意是自己的loop 不一定是loop0

# 创建两个目录用于挂载镜像的分区 mkdir -p sd/boot sd/root # 生成一个 200MB 的空白镜像文件(bs=512, count=409600 => 200MiB) # 其中约 50MB 给 boot 分区,150MB 给 rootfs 分区 dd if=/dev/zero of=./imx6ull.img bs=512 count=409600 # 在镜像上创建 MS-DOS(MBR)分区表 sudo parted imx6ull.img --script -- mklabel msdos # 创建第一个分区(FAT32),用于 /boot # 起始于 2048 扇区(为了对齐,2048*512=1MB),结束于 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 # 格式化第一个分区为 vfat(FAT32) 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 bs=512 seek=2 conv=fsync # 复制启动相关文件(内核、设备树等)到 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 bs=512 count=409600 # 创建 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 bs=512 seek=2 conv=fsync # 拷贝 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 ./gxa

3.7 shell脚本语法解析参考

dd就是复制

  • 可以复制磁盘
  • 可以复制分区
  • 可以按指定大小复制数据块
  • 可以制作镜像文件

dd if=/dev/zero of=./imx6ull.img bs=512 count=409600的作用就是:创建一个200MB大小的空白SD卡镜像文件imx6ull.img

dd if=输入文件 of=输出文件

if=/dev/zero of输入0

输出到of=./imx6ull.img

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/17 21:39:59

移动端设备标识码全解析:从IMEI到UUID的合规实践指南

1. 项目概述:为什么我们需要关注移动端设备标识码?在移动应用开发和运营的日常工作中,无论是进行用户行为分析、精准广告投放、反作弊风控,还是实现简单的设备登录态管理,我们几乎每天都会和一堆以“ID”结尾的字符串打…

作者头像 李华
网站建设 2026/8/17 21:39:27

DTU上传数据一定要公网IP吗?

4G DTU上传数据不一定需要公网IP,更不强制需要固定公网IP。在绝大多数“串口设备→DTU→中心服务器/云平台”的采集上报场景中,DTU作为客户端主动向外发起连接,自身使用运营商分配的动态内网IP即可稳定传输;只有服务器/云平台侧需…

作者头像 李华
网站建设 2026/8/17 21:38:44

UVa 701 The Archeologist‘s Dilemma

题目描述 考古学家发现一些墙壁上的数字链,左侧数字总是完整的,右侧部分常因侵蚀而缺失。她注意到所有完整数字都是 222 的幂,因此需要验证这一假设。给定一个正整数 NNN,要求找到最小的正整数指数 EEE,使得 2E2^E2E 的…

作者头像 李华