LV05-06-系统烧写-02-img镜像文件

本文主要是系统烧写——创建一个img文件烧写到sd卡中的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。

点击查看使用工具及版本
PC端开发环境 Windows Windows11
Ubuntu Ubuntu20.04.2的64位版本
VMware® Workstation 17 Pro 17.6.0 build-24238078
终端软件 MobaXterm(Professional Edition v23.0 Build 5042 (license))
Win32DiskImager Win32DiskImager v1.0
Linux开发板环境 Linux开发板 正点原子 i.MX6ULL Linux 阿尔法开发板
uboot NXP官方提供的uboot,使用的uboot版本为U-Boot 2019.04
linux内核 linux-4.19.71(NXP官方提供)
点击查看本文参考资料
分类 网址 说明
官方网站 https://www.arm.com/ ARM官方网站,在这里我们可以找到Cotex-Mx以及ARMVx的一些文档
https://www.nxp.com.cn/ NXP官方网站
https://www.nxpic.org.cn/NXP 官方社区
https://u-boot.readthedocs.io/en/latest/u-boot官网
https://www.kernel.org/linux内核官网
点击查看相关文件下载
分类 网址 说明
NXP https://github.com/nxp-imx NXP imx开发资源GitHub组织,里边会有u-boot和linux内核的仓库
nxp-imx/linux-imx/releases/tag/v4.19.71 NXP linux内核仓库tags中的v4.19.71
nxp-imx/uboot-imx/releases/tag/rel_imx_4.19.35_1.1.0 NXP u-boot仓库tags中的rel_imx_4.19.35_1.1.0
I.MX6ULL i.MX 6ULL Applications Processors for Industrial Products I.MX6ULL 芯片手册(datasheet,可以在线查看)
i.MX 6ULL Applications ProcessorReference Manual I.MX6ULL 参考手册(下载后才能查看,需要登录NXP官网)
Source Code https://elixir.bootlin.com/linux/latest/source linux kernel源码
https://elixir.bootlin.com/u-boot/latest/source uboot源码

这里只是看到有一些img文件,想要尝试一下,但是最后发现其实并不比直接烧写SD卡来的块,而且做出来的img文件可能比要更大,但是在有些场景是很实用的。

一、img镜像文件

1. 什么是磁盘镜像文件?

磁盘镜像文件能够完整地存储一个磁盘的内容和结构,不仅适用于 CD 或 DVD,还可以用于各种存储设备,包括磁带驱动器、硬盘、固态硬盘、U 盘,甚至软盘都可以转化成磁盘镜像文件。

磁盘镜像文件有许多用途,包括备份、操作系统分发、虚拟化和存档等。在 Windows、Linux 和 macOS 等主流操作系统中,许多常见的磁盘镜像格式都受到原生支持。

2. 常见磁盘镜像格式

磁盘镜像文件具有广泛的应用领域,涵盖了不同类型的存储需求,包括存档只读存储器(ROM)和专为虚拟机设计的特殊镜像格式等。目前,有大约 150 多种不同的镜像格式可供选择。尽管许多格式在功能上存在重叠,有时可以互相替代使用,但最常被使用和推荐的仍然是 ISO、BIN/CUE 和 IMG 这几种。

2.1 ISO镜像格式

ISO 是目前最流行的磁盘镜像格式之一,主要用于存储使用 ISO 9660 文件系统的光盘。它包含了从磁盘起始位置一直到末尾的所有扇区,因此 ISO 磁盘镜像文件与其复制的原始磁盘完全相同,是逐扇区的原始驱动器复制,没有进行任何压缩处理。

ISO 格式的核心理念是以数字方式精确复制原始光盘,然后使用生成的磁盘镜像文件来刻录出一张与原始光盘完全相同的新光盘。这使得使用 ISO 格式刻录的光盘可以成为原始光盘的完美副本,从而方便、可靠地保存和共享数据。

ISO 格式在 Windows、Linux 和 macOS 等主流操作系统上都受到原生支持,通常用于分发软件和操作系统。然而,它在处理音频 CD 的「复制保护」方面存在一些限制,因此不太适合用于处理音频 CD。

大多数公开分发的操作系统,包括 Windows 和 Linux,都以 ISO 镜像文件的形式进行共享。除了分发程序和操作系统之外,ISO 还是备份旧光盘的理想选择。这种多功能性使得 ISO 成为许多用户的首选格式。

2.2 BIN 和 CUE 镜像格式

BIN 和 CUE 文件看似是两种不同的磁盘镜像格式,但实际上它们是相辅相成的:

  • BIN 文件是整个光盘的二进制副本,包含了要刻录到光盘上的数据。
  • CUE 文件是一个纯文本文件,包含定义光盘轨道设置的元数据。

这种组合使得它们成为处理光盘数据的强大工具,特别适合用于保留和复制光盘内容。

BIN/CUE 镜像是原始光盘的完整复制,包括了复制保护、错误校正、曲目列表、多轨道以及任何系统特定信息。这种格式能够完整保留原始光盘的所有特性,从复制保护到多轨道音频,都是原封不动的复制,使其成为备份和复制光盘的最佳选择。

要使用 BIN/CUE镜像,需要同时拥有这两个文件。BIN 文件包含原始数据,CUE 文件包含组织这些数据的元信息。在大多数情况下,BIN 文件和 CUE 文件必须同时存在,特别是要将 BIN 镜像刻录到光盘上时。这种文件组合的结构允许精确地还原原始光盘的内容和结构,确保复制的准确性和完整性。

从现有 BIN 文件生成 CUE 文件非常简单,但无法反过来从 CUE 文件生成 BIN 文件。CUE 文件只有元信息,不包含实际数据。

BIN/CUE 格式的设计初衷是为了克服 ISO 格式在音频「复制保护」方面的限制。它是一种强大的磁盘镜像格式,特别适用于需要维护完整性和无限制访问的应用场景。BIN 文件包含了完整的二进制数据,包括音频和数据轨道,而 CUE 文件提供了关于如何组织这些数据的详细指令。

2.3 IMG 镜像格式

IMG 格式的使用不如 ISO、BIN/CUE 或 DMG(macOS 使用的磁盘映像格式)那么广泛。它最初是为了备份软盘而创建的,通过复制目标磁盘每个扇区的位来工作。虽然不如其他格式流行,但对于特定用途(如软盘备份)来说,IMG 格式仍然具有独特的价值。

除了备份软盘,IMG 格式还可以用于存储各种内容。然而,随着软盘和软驱逐渐退出历史舞台,IMG 文件的主要用途已经转向创建硬盘镜像。需要注意的是,IMG 格式生成的文件大小始终是 512 字节的整数倍,因为它遵循了软盘的 512 字节扇区大小标准。这一特性可能在处理未来高容量硬盘或固态硬盘时变得不太合适,因此在选择 IMG 格式时需要谨慎考虑其局限性。

IMG 文件与 ISO 文件在功能上非常相似,主要区别在于:

  • ISO 文件只有一种标准格式
  • IMG 镜像可以是压缩或未压缩的

这种灵活性使得 IMG 格式在特定情况下更具优势,用户可以根据需要选择压缩或未压缩选项。但两者在存储光盘、分发系统等方面基本相同,但 IMG 增加的压缩选项为用户提供了更多选择。

未经压缩的 IMG 镜像与 ISO 镜像之间的差异并不大,甚至可以直接将 IMG 扩展名更改为 ISO,它仍然可以正常工作,或者将其转换为 VHD 文件以在 VirtualBox中使用;但是,压缩过的 IMG 会删除一些元数据以减小文件大小,因此不能与 ISO 文件互换使用。这一点需要特别注意,在处理 IMG 和 ISO 格式时,需要确保正确的文件互操作性。

2.4 三种格式对比

ISO 格式 BIN/CUE 格式 IMG 格式
扇区大小 2048 字节 4096 字节 512 字节
原生操作系统支持 是(Windows、Linux 和 macOS)
限制 不支持复制保护 不支持复制保护
最佳用途 备份无复制保护的光盘
分发程序和操作系统 备份或复制带有复制保护的光盘 备份或刻录光盘

3. 这里为什么用img

我们可以img文件可以简单理解为一个磁盘,可以存放二进制数据,可以进行分区,可以建立文件系统等操作。这个img文件的扇区大小刚好与SD卡扇区大小一致,也许就是这个原因吧,我们可以将uboot、kernel、dtb和rootfs做成一个img文件,然后通过工具烧录到sd卡中。

4. imx6ull的img镜像分区

其实这里的镜像分区与前面我们的sd卡是一致的:

image-20241112222116357

也就是:

image-20241110172120026

我们就按这个来做一个img文件。

二、制作img文件

基本步骤

(1)使用dd 命令,根据固件的大小建立一个合适的 img 空文件。

(2)对 img 文件进行分区。

(3)用dd命令创建烧写u-boot。

(4)用losetup命令将 img 文件虚拟成循环块设备 /dev/loopx ,并用将虚拟出的循环块设备分区并格式化。

(5)创建挂载点,然后建立文件系统并且 mount 上来 。

(6)使用文件复制命令cp将 zImage dtb rootfs 放到指定的文件系统分区 。

(7)取消挂载,复制文件,烧录到 SD 卡。

注意:这里创建的时候img文件大小小和最后生成的img文件的大小好像不太一样,具体我还不清楚是为什么,后面知道了再更新吧。

1. 安装工具

下面这些工具中,好像就用到了parted和kpartx,另外两个好像没啥用,感觉不装应该也行。

1
sudo apt-get install dosfstools dump parted kpartx

2. 准备文件

2.1 创建工作目录

1
2
3
4
mkdir ~/imx6ull_img
cd ~/imx6ull_img
mkdir BOOT # 这个文件夹用于挂载内核的分区
mkdir rootfs # 这个文件夹用于挂载文件系统分区
image-20241112222622058

2.1 准备文件

我们需要以下文件:

image-20241112223124738

就是这里的这些:release · 苏木/imx6ull-alpha-release - 码云 - 开源中国 (gitee.com)

3. 开始制作img文件

3.1 创建空白ing文件

我们首先创建一个空白的img文件,创建多大?我们不可能直接创建一个2G的吧,这个其实我们可以根据上面分分区起情况和文件大小计算一下。前面uboot和kernel、dtb的大小已经知道了,现在我们看一下根文件系统,我们创建个临时目录解压一下:

image-20241112223525481

可以看到大概13M,所以就是:

image-20241112223603145

所以我们粗略创建一个1M+1M+70M+30M=102M,抹个零,100M吧,后面随着各个部分增大,我们可以再创建新的:

1
dd if=/dev/zero of=imx6ull-sys.img bs=1024 count=102400 && sync
image-20241112223922385
1
2
3
4
5
if=文件名:输入文件名,默认为标准输入。即指定源文件。
of=文件名:输出文件名,默认为标准输出。即指定目的文件。
bs=bytes:同时设置读入/输出的块大小为bytes个字节。这里也可以是1K,1M等,主要是计算大小用。
count=blocks:仅拷贝blocks个块,块大小等于1 bs(一次读入bytes个字节,)指定的字节数。
/dev/zero:“零”设备,可以无限的提供空字符(0x00,ASCII代码NUL)。

到这里我们的空镜像文件就已经创建好了。可以看到创建的文件大小为100M。

3.2 对img文件分区

3.2.1 parted命令简介

通常我们用的比较多的分区工具是fdisk命令,但由于fdisk只支持MBR分区,MBR分区表最大支撑2T的磁盘,所以无法划分大于2T的分区。而parted工具可以划分单个分区大于2T的GPT格式的分区,也可以划分普通的MBR分区。

parted命令是由GNU组织开发的一款功能强大的磁盘分区和分区大小调整工具。parted在使用过程中有两种方式,一种是直接以非交互的方式,一种是像fdisk一样进入菜单界面进行操作。

3.2.2 parted命令说明

1
2
3
4
SYNOPSIS
parted [options] [device [command [options...]...]]
# 其实就是
parted [选项] [设备 [命令 [参数]...]...]

操作命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    parted交互命令	                            说 明
check NUMBER 做一次简单的文件系统检测
cp [FROM-DEVICE] FROM-NUMBER TO-NUMBER 复制文件系统到另一个分区
help [COMMAND] 显示所有的命令帮助
mklabel,mktable LABEL-TYPE 创建新的磁盘卷标(分区表) "gpt", "msdos"等
mkfs NUMBER FS-TYPE 在分区上建立文件系统
mkpart PART-TYPE [FS-TYPE] START END 创建一个分区
mkpartfs PART-TYPE FS-TYPE START END 创建分区,并建立文件系统
move NUMBER START END 移动分区
name NUMBER NAME 给分区命名
print [devices|free|list,all|NUMBER] 显示分区表、活动设备、空闲空间、所有分区
quit 退出
rescue START END 修复丢失的分区
resize NUMBER START END 修改分区大小
rm NUMBER 删除分区
select DEVICE 选择需要编辑的设备
set NUMBER FLAG STATE 改变分区标记
toggle [NUMBER [FLAG]] 切换分区表的状态
unit UNIT 设置默认的单位
Version 显示版本

这里主要要了解两个交互命令:

  • mklabel
1
mklabel,mktable LABEL-TYPE

这个命令是创建新的磁盘卷标(分区表), “gpt”, “msdos”等,一般就选这个msdos就可以了。大于2T的分区的话可以用gpt。

  • mkpart
1
2
mkpart PART-TYPE [FS-TYPE] START END	创建一个分区
mkpartfs PART-TYPE FS-TYPE START END 创建分区,并建立文件系统

这个命令主要是创建分区,这里的START和END就是起始和结束的地址,他们用什么单位?我们可以看一下man手册:

1
2
unit unit
Set unit as the unit to use when displaying locations and sizes, and for interpreting those given by the user when not suffixed with an explicit unit. unit can be one of "s" (sectors), "B"(bytes), "kB", "MB", "MiB", "GB", "GiB", "TB", "TiB", "%" (percentage of device size), "cyl" (cylinders), "chs" (cylinders, heads, sectors), or "compact" (megabytes for input, and a human-friendlyform for output).

3.2.3 非交互方式分区

3.2.3.1 字节为单位的示例
1
2
3
4
5
# 以大小来划分起始和结束点
sudo parted imx6ull-sys.img mklabel msdos
sudo parted imx6ull-sys.img mkpart primary fat32 1M 64M
sudo parted imx6ull-sys.img mkpart primary ext4 64M 100%
sync
  • fat32:文件系统类型为 fat32 这是内核设备树的文件系统。

  • 1M:这个表示内核设备树扇区的起始地址(注意不是实际地址,扇区地址x扇区大小=实际地址),这个分区紧跟在 1M 的 u-boot 空间后面。

  • 64M:内核设备树扇区的结束地址=扇区起始地址+扇区大小-1。

  • ext4 :文件系统为 ext4,这是根文件系统的分区。

  • 64M:文件系统的扇区起始地址。

  • 100%为文件系统的结束地址剩余内存,也可以不填。

image-20241112225756009

我们来看一下分区情况:

1
parted imx6ull-sys.img print
image-20241112225833253
3.2.1.2 扇区示例
1
2
3
4
5
# 以扇区来划分起始结束点
sudo parted imx6ull-sys.img mklabel msdos
sudo parted imx6ull-sys.img mkpart primary fat32 2048s 133119s # s就表示扇区
sudo parted imx6ull-sys.img mkpart primary ext4 133120s 100%
sync

划分结果如下:

image-20241113075040753

3.2.4 parted命令交互方式

image-20241112230006270

这里就不演示了,按照说明进行就可以了。

3.2.5 fdisk命令

也可以使用fdisk命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
sumu@sumu-virtual-machine:~/imx6ull_img$ fdisk imx6ull-sys.img

欢迎使用 fdisk (util-linux 2.34)。
更改将停留在内存中,直到您决定将更改写入磁盘。
使用写入命令前请三思。


命令(输入 m 获取帮助): p
Disk imx6ull-sys.img:100 MiB,104857600 字节,204800 个扇区
单元:扇区 / 1 * 512 = 512 字节
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节
磁盘标签类型:dos
磁盘标识符:0x040d9807

命令(输入 m 获取帮助): n
分区类型
p 主分区 (0个主分区,0个扩展分区,4空闲)
e 扩展分区 (逻辑分区容器)
选择 (默认 p): p
分区号 (1-4, 默认 1): 1
第一个扇区 (2048-204799, 默认 2048):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-204799, 默认 204799): +64M

创建了一个新分区 1,类型为“Linux”,大小为 64 MiB。

命令(输入 m 获取帮助): n
分区类型
p 主分区 (1个主分区,0个扩展分区,3空闲)
e 扩展分区 (逻辑分区容器)
选择 (默认 p): p
分区号 (2-4, 默认 2): 2
第一个扇区 (133120-204799, 默认 133120):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (133120-204799, 默认 204799):

创建了一个新分区 2,类型为“Linux”,大小为 35 MiB。

命令(输入 m 获取帮助): p
Disk imx6ull-sys.img:100 MiB,104857600 字节,204800 个扇区
单元:扇区 / 1 * 512 = 512 字节
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节
磁盘标签类型:dos
磁盘标识符:0x040d9807

设备 启动 起点 末尾 扇区 大小 Id 类型
imx6ull-sys.img1 2048 133119 131072 64M 83 Linux
imx6ull-sys.img2 133120 204799 71680 35M 83 Linux

命令(输入 m 获取帮助): w
分区表已调整。
正在同步磁盘。

3.3 烧写uboot

1
sudo dd if=u-boot-dtb.imx of=imx6ull-sys.img bs=1024 seek=1 conv=notrunc,sync
image-20241112232304325

3.4 将img文件虚拟成块设备

3.4.1 losetup命令

我们先来看一下losetup命令,主要还是查看手册。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
SYNOPSIS
Get info:
losetup [loopdev]
losetup -l [-a]
losetup -j file [-o offset]
Detach a loop device:
losetup -d loopdev...
Detach all associated loop devices:
losetup -D
Set up a loop device:
losetup [-o offset] [--sizelimit size] [--sector-size size]
[-Pr] [--show] -f|loopdev file
Resize a loop device:
losetup -c loopdev

losetup(Loop device setup)命令在Linux操作系统中用于设置和控制循环设备。循环设备是一种伪设备,它使文件可以作为块设备进行访问。如果只给出了loopdev参数,那么将显示相应循环设备的状态。

换句话说,就是现在这里有一个文件,循环设备可以把这个文件虚拟成块设备(block device),比如sd卡,以便模拟整个文件系统,这样用户可以将其看作是硬盘驱动器,光驱或软驱等设备,并挂入当作目录来使用。

3.4.2 常用命令

  • 列出所有已使用的循环设备
1
2
losetup -a 
losetup -l
image-20241113190543343
  • 查找第一个未使用的循环设备
1
losetup -f
image-20241113190638678
  • 分离循环设备
1
sudo losetup -d /dev/loopx
  • 创建循环设备,就是将自己的文件和循环设备建立连接
1
sudo losetup /dev/loopx loopfile

3.4.3 虚拟我们的img文件

接下来就是把我们的img文件虚拟成块设备。首先来看一下使用一个被占用的循环设备会怎么样:

1
sudo losetup /dev/loop0 imx6ull-sys.img

这里的loop0如果被占用:

image-20241112230925392

这里会显示设备或者资源繁忙,这个时候我们可以查找一下空闲的第一个循环设备:

1
sudo losetup -f
image-20241112230827387

然后我们重新虚拟一下:

1
sudo losetup /dev/loop13 imx6ull-sys.img
image-20241112231016227

3.5 创建虚拟的块设备分区映射

我们刚才对img文件进行了分区,我们后面操作需要挂载分区,可是挂载的时候要有一个节点,我们来看一下:

image-20241113191522225

我们挂载试一下:

1
sudo mount /dev/loop13 BOOT
image-20241113191859111

发现是失败的,因为我们并没有格式化,它并没有文件系统,那怎么办?就要用到kpartx这个命令啦。

3.5.1 kpartx命令简介

还是先看man手册:

1
2
SYNOPSIS
kpartx [-a|-d|-u|-l] [-r] [-p] [-f] [-g] [-s|-n] [-v] wholedisk

这个命令可以从分区表创建设备映射。这个工具源自util-linux的partx,它读取指定设备上的分区表,并在检测到的分区段上创建设备映射。

3.5.2 创建虚拟块设备分区映射

命令格式为:

1
sudo kpartx -av /dev/loopx

这里就是:

1
sudo kpartx -av /dev/loop13
image-20241112231152529

被分区后的设备节点在/dev/mapper/路径下:

1
ls /dev/mapper/
image-20241112231259367

3.6 格式化分区

1
2
3
sudo mkfs.vfat -F 32 /dev/mapper/loop13p1
sudo mkfs.ext4 /dev/mapper/loop13p2
sync
image-20241112231412768

然后我们可以看一下格式化情况,我们直接看这个img文件:

1
parted imx6ull-sys.img print
image-20241113075659755

这里的大小可能有点和其他图不太对应,主要是因为这时候来重新分区的。

3.7 写入相关文件

3.7.1 挂载分区

1
2
sudo mount /dev/mapper/loop13p1 BOOT
sudo mount /dev/mapper/loop13p2 rootfs
image-20241112231628700

3.7.2 拷贝kernel、dtb和rootfs

  • (1)拷贝相关文件到对应目录
1
2
sudo cp zImage imx6ull-alpha-emmc.dtb BOOT
sudo cp rootfs.tar.bz2 rootfs
image-20241112231822209
  • (2)解压根文件系统
1
2
3
cd rootfs
sudo tar jxf rootfs.tar.bz2
sudo tar xf rootfs.tar
image-20241112232017363

3.7.3 卸载分区

1
2
sudo umount BOOT
sudo umount rootfs

3.8 卸载还原虚拟分区

1
2
sudo kpartx -dv /dev/loop13
sudo losetup -d /dev/loop13
image-20241112232428538

三、烧写到SD卡

1. ubuntu

ubuntu下我们可以使用dd命令烧写:

1
sudo dd if=imx6ull-sys.img of=/dev/sdc conv=fsync

2. windows

windows下用这个软件:Win32 Disk Imager download | SourceForge.net

image-20241113205706699

这个没啥好说的,在windows下烧写这个img文件还是很快的。

参考资料:

比较 ISO、BIN/CUE 和 IMG,常见磁盘映像文件解析 (sysgeek.cn)

制作imx6ull Linux系统的img镜像文件(emmc烧录 )_制造 img imx6ull-CSDN博客

制作imx6ull Linux系统的img镜像_imx6ull emmc img 生成-CSDN博客

shell脚本将uboot zImage 和文件系统打包成为一个img系统镜像_如何把uboot 内核 文件系统打包-CSDN博客