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 可以:

  1. 把 .img 文件映射为一个虚拟磁盘(如 /dev/loop0
  2. 自动识别并创建分区设备(如 /dev/loop0p1/dev/loop0p2
  3. 然后你就可以挂载其中的某个分区: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 和构建)
  1. 先将 .img 镜像文件映射为一个loop设备,挂载到 mnt/ 目录(通过 loop 设备和分区识别);
  2. 再把 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 环境能正常运行很多系统命令(比如 aptdpkgsystemctl 等),你需要把宿主系统的一些关键目录“绑定”进去:

sudo mount -o bind /proc rootfs/proc

提供进程信息(如 ps top apt等依赖)

sudo mount -o bind /sys rootfs/sys

提供内核和硬件信息(如 udevadm, systemd

sudo mount -o bind /dev rootfs/dev

提供设备节点(如 /dev/null, /dev/tty, /dev/sda等)

sudo mount --bind /dev/pts rootfs/dev/pts

提供伪终端支持(如 bash, ssh, screen等)

如果你不挂载 /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驱动##嵌入式软开##牛客在线求职答疑中心##牛客创作赏金赛#
全部评论

相关推荐

不愿透露姓名的神秘牛友
07-10 12:05
点赞 评论 收藏
分享
弦五Strings:他之所以会举报你代课是因为在这种人眼里正常上课就是正义代课就是邪恶,典型二极管思维,处理方法就是私下沟通,你就说你自己家里经济困难或者家里父母生病什么之类的,需要去打工挣钱,用尽孝的正义对冲他认为的上课的正义,他可能就妥协了。
我的实习日记
点赞 评论 收藏
分享
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务