kernel 构建 ubuntu deb(2)loop设备挂载/bring up/EFI构建
0.loop
0.1什么是loop设备?
Loop 设备:是 Linux 系统中的一种特殊块设备,它允许你将一个普通的文件(比如 .img
镜像文件)当作一个“虚拟磁盘”来使用。无需真实硬件即可模拟磁盘操作
你可以把 loop 设备想象成一个“虚拟硬盘适配器”:
- 你有一个
.img
文件,它其实是一个完整的磁盘镜像。 - 你不能直接访问里面的分区或文件系统。
- 通过
losetup
把这个文件“插入”到一个 loop 设备(比如/dev/loop0
)中,系统就会把它当作一个真实的磁盘来看待。 - 然后你就可以像操作真实硬盘一样,对它进行挂载、读写等操作。
0.2 不能直接用 mount
挂载 .img
文件模拟硬件吗?
不能直接挂载包含多个分区的磁盘镜像文件,必须借助 loop 设备。
1)如果你有一个只包含文件系统的镜像(比如 rootfs.ext4
),你可以直接挂载它:sudo mount rootfs.ext4 /mnt
2)如果你有一个完整的磁盘镜像(比如 .img
文件),它通常包含:
- MBR 或 GPT 分区表
- 多个分区(如 boot、rootfs、EFI 等)
0.3 为什么需要loop设备?
使用 losetup --partscan
可以:
- 把
.img
文件映射为一个虚拟磁盘(如/dev/loop0
) - 自动识别并创建分区设备(如
/dev/loop0p1
,/dev/loop0p2
) - 然后你就可以挂载其中的某个分区:sudo mount /dev/loop0p1 /mnt
镜像类型 | 是否需要loop设备 | 是否能直接挂载 |
单一文件系统(如 ext4) | ❌ 不需要 | ✅ 可以 |
完整磁盘镜像(含分区表) | ✅ 需要 | ❌ 不可以 |
1.Kernel Build
进入kernel目录,对config/image/module进行编译,并拉出所需设备树
Kernel Build产物:
.config
Image
modules/lib/modules/<kernel_version>
xxx.dtb
2.脚本编译deb
将kernel产物变成deb,下一节详解
3.rootfs build
rootfs: root filse system根文件系统,linux系统启动后挂载的第一个文件系统
启动流程:内核加载 → 挂载 rootfs → 运行 rootfs 中的初始化程序(如 systemd
)→ 初始化系统服务 → 完成启动。
3.1下载并解压Ubuntu
sudo wget https://cdimage.ubuntu.com/ubuntu-server/noble/daily-preinstalled/current/noble-preinstalled-server-arm64.img.xz sudo 7z x noble-preinstalled-server-arm64.img.xz
3.2挂载镜像并提取根文件系统
sudo losetup --show --sector-size 4096 --partscan --find noble-preinstalled-server-arm64.img 使用 losetup 创建 loop 设备,启用分区扫描 sudo mkdir rootfs mnt sudo mount /dev/loopXp1 mnt sudo cp -rap mnt/* rootfs/ sudo umount mnt sudo losetup -d /dev/loopX noble-preinstalled-server-arm64.img │ ▼ losetup + --partscan │ ▼ /dev/loopXp1 ←(识别出的分区) │ ▼ mount 到 mnt/ │ ▼ cp -rap mnt/* → rootfs/ ←(用于 chroot 和构建)
- 先将
.img
镜像文件映射为一个loop设备,挂载到mnt/
目录(通过 loop 设备和分区识别); - 再把
mnt/
中的内容复制到rootfs/
目录中,用于后续的 chroot 或打包操作。
又是一个小问题,为什么不能省略mnt这一步,直接将img内容放到rootfs中?回答两个问题
不能直接复制 .img
到 rootfs/
的原因:
1. .img
是一个磁盘镜像文件,不是普通的文件夹
- 它包含了分区表(MBR 或 GPT)和多个分区(如 boot 分区、rootfs 分区等)。
- 你不能直接用
cp
或rsync
复制.img
的内容,因为系统无法“看见”里面的文件系统。
2. 必须通过挂载才能访问里面的文件
- 你需要先用
losetup
把.img
映射为一个 loop 设备(比如/dev/loop0
); - 然后通过
--partscan
识别出里面的分区(比如/dev/loop0p1
); - 再挂载某个分区(比如 rootfs 分区)到
mnt/
; - 最后才能访问并复制里面的文件。
为什么要复制到 rootfs/
?
复制到 rootfs/
是为了:
- 构建一个可修改的根文件系统,你可以在里面安装软件、修改配置;
- 进入 chroot 环境,模拟目标系统;
- 最终打包成新的镜像或烧录到设备上。
直接在挂载点 mnt/
上操作虽然也可以,但不够灵活,也不利于后续打包或清理。
3.3准备内核和固件
sudo cp linux-kernel-xxx-arm64 rootfs/ sudo cp linux-firmware-xxx+noble_arm64.deb rootfs/
3.4配置DNS/挂载必要的系统目录
sudo rm -rf rootfs/etc/resolv.conf sudo cp -L /etc/resolv.conf rootfs/etc/ sudo mount -o bind /proc rootfs/proc sudo mount -o bind /sys rootfs/sys sudo mount -o bind /dev rootfs/dev sudo mount --bind /dev/pts rootfs/dev/pts
问题,为什么需要bind mount?
为了使用chroot进入另一个系统环境
背景:什么是 chroot
?
chroot rootfs/
会把当前 shell 的根目录(/
)切换到 rootfs/
,让你像是在一个独立的系统中操作。但这个环境默认是“空的”,它无法访问宿主系统的内核接口、设备、进程信息等。
bind mount 的作用
为了让 chroot
环境能正常运行很多系统命令(比如 apt
, dpkg
, systemctl
等),你需要把宿主系统的一些关键目录“绑定”进去:
| 提供进程信息(如 |
| 提供内核和硬件信息(如 |
| 提供设备节点(如 |
| 提供伪终端支持(如 |
如果你不挂载 /proc
,在 chroot 中运行 apt update
会报错:
E: Could not open file /proc/filesystems - open (2: No such file or directory)
3.5 进入chroot环境并配置系统
1.进入chroot sudo chroot rootfs/ 2.添加用户并安装内核和固件 adduser lx usermod -aG sudo lx dpkg -i linux-firmware-xxx+noble_arm64.deb dpkg -i linux-kernel-xxx-arm64.deb 3.设置 grub 启动项,指定设备树、内核、initrd 及启动参数。 tee /boot/grub.cfg <<EOF # grub 配置内容, 这里面的内容就是上一节里面的内容 EOF 4.安装桌面环境和网络工具 apt update && apt install ubuntu-desktop-minimal network-manager iw net-tools 5.退出chroot exit 6. 卸载挂载的系统目录 sudo umount rootfs/dev/pts sudo umount rootfs/dev sudo umount rootfs/sys sudo umount rootfs/proc sudo umount rootfs 7.创建最终镜像 sudo truncate -s 6G ubuntu.img sudo mkfs.ext4 ubuntu.img sudo mount -o loop ubuntu.img mnt/ sudo cp -rap rootfs/* mnt/ sudo umount mnt 流程图 [空文件] → truncate → [6GB 空镜像] ↓ mkfs.ext4 格式化(在空文件上创建ext4文件系统) ↓ mount -o loop → mnt/ ↓ cp -rap rootfs/* → mnt/ ↓ umount mnt/ ↓ [ubuntu.img] ← 完整的 rootfs 镜像
3.6 EFI System Partition Construction(arm64环境下执行)
UEFI 是 EFI 的“正式标准版”,EFI 是它的前身。现代计算机系统启动时使用的固件接口
[UEFI 固件]
↓
[读取 EFI 分区(FAT32)]
↓
[加载 bootloader(如 GRUB)]
↓
[启动操作系统(Linux/Windows)]
sudo apt-get install grub2-common 安装grub工具 dd if=/dev/zero of=efiesp.bin bs=1M count=200 创建一个名为efiesp.bin的200MB空白镜像文件 losetup -fP efiesp.bin loop_device=$(losetup -a | grep "efiesp.bin" | cut -d ':' -f 1) 将镜像文件映射为loop设备,并提取设备名称 mkfs.vfat -F 32 $loop_device UEFI 固件要求 ESP 分区必须是 FAT32 格式。 mount $loop_device mnt 将 loop 设备挂载到 mnt/ 目录,准备写入引导文件 mkdir -p mnt/boot grub-install --target=arm64-efi --efi-directory=mnt/ --boot-directory=mnt/boot --removable 指定架构/挂载点/grub配置文件/生成默认启动文件bootaa64.efi 在一个挂载好的 EFI System Partition(ESP)目录中安装 ARM64 架构的 GRUB 引导程序 安装后的目录 mnt/ ├── EFI/ │ └── BOOT/ │ └── BOOTAA64.EFI ← GRUB 引导程序/主启动文件(UEFI 固件会默认加载它) ├── boot/ │ ├── grub/ │ │ └── *.mod ← GRUB 模块 │ └── grub.cfg ← GRUB 配置文件(你手动创建) tee -a mnt/boot/grub/grub.cfg <<EOF set root=(hd0,gpt13) set prefix=($root)/boot configfile $prefix/grub.cfg EOF 设置启动分区为(hd0,gpt13)/设置grub的前置路径/然后从前置路径加载真正的配置文件/boot/grub.cfg $ umount mnt $ losetup -d $loop_device#嵌入式##linux驱动##嵌入式软开##牛客在线求职答疑中心##牛客创作赏金赛#