从Ubuntu Base到可启动镜像:手把手教你制作、分区与烧录嵌入式Linux系统盘
从Ubuntu Base到可启动镜像:嵌入式Linux系统盘全流程实战指南
当你第一次将自制的Linux系统镜像成功烧录到SD卡,并看到设备屏幕上跳出登录提示符时,那种成就感是难以言喻的。不同于桌面Linux的安装,嵌入式系统开发需要我们从最基础的rootfs开始,一步步构建完整的可启动环境。本文将带你深入理解从Ubuntu Base制作到最终烧录的全过程,特别针对ARM架构设备如树莓派、Banana Pi等开发板。
1. 准备工作与环境搭建
在开始构建自定义rootfs之前,我们需要准备合适的工具链和工作环境。不同于x86架构的直观开发体验,ARM嵌入式开发往往需要在x86主机上交叉编译和准备系统镜像。
必备工具清单:
- qemu-user-static:用于在x86主机上模拟ARM执行环境
- debootstrap:Ubuntu官方提供的系统构建工具(可选)
- fdisk/parted:磁盘分区工具
- e2fsprogs:ext文件系统工具集
对于国内开发者,首先需要解决的是软件源访问速度问题。推荐使用阿里云或清华大学的Ubuntu ports镜像源,这将显著加快软件包下载速度。在/etc/apt/sources.list中替换默认源为:
deb http://mirrors.aliyun.com/ubuntu-ports/ xenial main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu-ports/ xenial main restricted universe multiverse注意:根据使用的Ubuntu Base版本不同(xenial/bionic/focal等),需要相应调整上述源中的发行版代号
2. 构建基础rootfs系统
Ubuntu Base是一个极简的rootfs,为我们提供了构建自定义镜像的起点。它去除了图形界面等非必要组件,非常适合嵌入式场景。
2.1 下载和解压Ubuntu Base
选择与目标设备架构匹配的Ubuntu Base版本至关重要。以Banana Pi R64(ARM64架构)为例:
wget http://cdimage.ubuntu.com/ubuntu-base/releases/20.04/release/ubuntu-base-20.04.3-base-arm64.tar.gz mkdir rootfs sudo tar -xpf ubuntu-base-20.04.3-base-arm64.tar.gz -C rootfs/解压完成后,我们需要设置chroot环境所需的支撑文件:
sudo cp /usr/bin/qemu-aarch64-static rootfs/usr/bin/ sudo cp -b /etc/resolv.conf rootfs/etc/2.2 配置基础系统环境
进入chroot环境前,我们需要准备一个自动化挂载脚本chroot-mount.sh:
#!/bin/bash MOUNT_DIR=$1 mount_ops() { sudo mount -t proc /proc ${MOUNT_DIR}proc sudo mount -t sysfs /sys ${MOUNT_DIR}sys sudo mount -o bind /dev ${MOUNT_DIR}dev sudo mount -o bind /dev/pts ${MOUNT_DIR}dev/pts } umount_ops() { sudo umount ${MOUNT_DIR}proc sudo umount ${MOUNT_DIR}sys sudo umount ${MOUNT_DIR}dev/pts sudo umount ${MOUNT_DIR}dev } case "$2" in -m) mount_ops ;; -u) umount_ops ;; *) echo "Usage: $0 [mount_dir] [-m|-u]" ;; esac使用这个脚本可以方便地进入和退出chroot环境:
sudo chroot rootfs /bin/bash3. 系统定制与软件安装
在chroot环境中,我们可以像在目标设备上一样操作系统,安装必要的软件包。
3.1 基础软件包安装
apt update apt install -y sudo ssh net-tools ethtool wireless-tools wpasupplicant apt install -y vim git build-essential python3对于需要图形界面的应用,可以安装轻量级桌面环境:
apt install -y --no-install-recommends xubuntu-core3.2 系统基础配置
设置主机名和时区:
echo "my-embedded-device" > /etc/hostname ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime创建普通用户并设置sudo权限:
useradd -m -s /bin/bash embedded-user passwd embedded-user usermod -aG sudo embedded-user配置网络服务(使用systemd-networkd):
cat > /etc/systemd/network/eth0.network <<EOF [Match] Name=eth0 [Network] DHCP=ipv4 EOF systemctl enable systemd-networkd4. 制作可启动镜像
有了完整的rootfs后,我们需要将其打包成可启动的磁盘镜像。
4.1 创建磁盘镜像文件
dd if=/dev/zero of=system.img bs=1M count=2048 sudo mkfs.ext4 system.img挂载镜像并复制rootfs内容:
mkdir tmp-mount sudo mount system.img tmp-mount sudo cp -a rootfs/* tmp-mount/ sudo umount tmp-mount检查并调整文件系统大小:
e2fsck -f system.img resize2fs -M system.img4.2 分区与引导配置
嵌入式设备通常需要特定的分区布局。以下是一个典型的分区方案:
| 分区 | 类型 | 大小 | 用途 |
|---|---|---|---|
| /dev/mmcblk0p1 | FAT32 | 256MB | 引导分区(存放内核、dtb、uEnv.txt) |
| /dev/mmcblk0p2 | ext4 | 剩余空间 | 根文件系统 |
使用fdisk创建分区表:
fdisk system.img <<EOF o n p 1 2048 +256M t c n p 2 526336 w EOF配置U-Boot环境变量(uEnv.txt):
bootargs=console=ttyS0,115200 root=/dev/mmcblk0p2 rootwait bootcmd=load mmc 0:1 ${kernel_addr_r} zImage; load mmc 0:1 ${fdt_addr_r} dtb; bootz ${kernel_addr_r} - ${fdt_addr_r}5. 烧录与启动测试
5.1 镜像烧录到SD卡
确定SD卡设备路径(如/dev/sdb)后:
sudo dd if=system.img of=/dev/sdb bs=4M status=progress sync警告:务必确认目标设备路径正确,错误的路径可能导致主机系统数据丢失
5.2 启动问题排查
常见启动问题及解决方法:
内核恐慌(Kernel panic):
- 检查内核与设备树的匹配性
- 确认root=参数指定的正确分区
- 验证文件系统完整性
卡在U-Boot阶段:
- 检查uEnv.txt语法是否正确
- 确认内核和设备树文件路径
- 使用U-Boot的printenv检查环境变量
根文件系统挂载失败:
- 检查rootfstype参数是否匹配实际文件系统
- 确认内核支持该文件系统(编译时配置)
- 尝试在U-Boot中手动挂载测试
调试技巧:
# 在U-Boot中测试文件读取 mmc dev 0 fatload mmc 0:1 ${loadaddr} zImage # 查看加载的文件大小 filesize6. 高级定制技巧
6.1 系统裁剪与优化
嵌入式系统往往需要精简以节省空间:
# 清理apt缓存 apt clean # 删除文档和不需要的本地化文件 find /usr/share/doc -depth -type f ! -name copyright | xargs rm || true find /usr/share/locale -maxdepth 1 -mindepth 1 -type d | grep -v en_US | xargs rm -rf使用systemd-analyze分析启动时间:
systemd-analyze systemd-analyze blame6.2 构建自动化脚本
将整个过程自动化可以大大提高效率。以下是一个简单的构建脚本框架:
#!/bin/bash set -e ROOTFS_DIR=./rootfs OUTPUT_IMG=system.img # 清理旧构建 [ -d "$ROOTFS_DIR" ] && sudo rm -rf "$ROOTFS_DIR" [ -f "$OUTPUT_IMG" ] && rm "$OUTPUT_IMG" # 下载和解压Ubuntu Base wget -c http://cdimage.ubuntu.com/ubuntu-base/releases/20.04/release/ubuntu-base-20.04.3-base-arm64.tar.gz mkdir "$ROOTFS_DIR" sudo tar -xpf ubuntu-base-20.04.3-base-arm64.tar.gz -C "$ROOTFS_DIR" # 设置chroot环境 sudo cp /usr/bin/qemu-aarch64-static "$ROOTFS_DIR/usr/bin" sudo cp -b /etc/resolv.conf "$ROOTFS_DIR/etc" # 进入chroot并安装软件 sudo chroot "$ROOTFS_DIR" /bin/bash <<CHROOT_EOF apt update apt install -y sudo ssh vim useradd -m -s /bin/bash user passwd user exit CHROOT_EOF # 创建镜像文件 dd if=/dev/zero of="$OUTPUT_IMG" bs=1M count=2048 sudo mkfs.ext4 "$OUTPUT_IMG" mkdir -p tmp-mount sudo mount "$OUTPUT_IMG" tmp-mount sudo cp -a "$ROOTFS_DIR"/* tmp-mount/ sudo umount tmp-mount在实际项目中,我通常会为不同的开发板维护不同的配置文件,使用同一个构建脚本配合不同的配置来生成针对特定硬件的镜像。这种方法显著减少了重复工作,特别是在需要频繁测试不同硬件配置时。
