ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

飞腾E2000/D2000双系统镜像制作指南:Buildroot+debootstrap实战

飞腾E2000/D2000双系统镜像制作指南:Buildroot+debootstrap实战 做飞腾 E2000/D2000 这块板子的系统镜像我前后折腾了差不多两周。核心需求很明确同一块存储介质上既能跑 Ubuntu 做图形展示和人机交互又能切到 Debian 跑服务类和后台任务而且整个编译流程要可复现、可进版本管理。最后定下来的方案就是用 Buildroot 2022.02 统一管理 U-Boot 和内核rootfs 部分用 debootstrap 灌装发行版原生根文件系统再用 extlinux 引导菜单把两个系统串起来。今天把这套编译指南完整写出来包括选型思路、关键配置、完整命令和我实际踩过的坑给正在做飞腾 E2000/D2000 适配的朋友一个可以直接抄作业的参考。这篇内容适合几类人看刚拿到飞腾 E2000/D2000 评估板、正在搭编译环境的嵌入式工程师想从手工交叉编译切换到 Buildroot 做工程化构建的开发者以及需要在同一硬件上做多发行版引导、做产线镜像或故障回滚方案的同学。我先说设计思路再拆解核心配置最后给实操流程和问题排查按这个顺序讲透。1. 整体设计为什么用Buildroot 2022.02做飞腾E2000/D2000的系统底座1.1 选型逻辑Buildroot、LTS版本与飞腾平台的历史问题飞腾 E2000 和 D2000 都是 ARMv8 架构但这不代表你能随便拿一个 aarch64 的 U-Boot 和内核就能启动。E2000 是四核低功耗设计面向工控、金融终端、电力设备这类场景D2000 是八核桌面和边缘服务器级别内存控制器、PCIe 控制器、启动流程都有差异。最麻烦的是 U-Boot 里的 DDR 参数和板级初始化代码不同板卡必须用匹配的 defconfig错一个都开不了机。在工具链选型上我对比过三条路直接手工交叉编译、Yocto、Buildroot。手工编译飞腾内核其实不复杂三条命令能编完但问题在于 U-Boot、内核、设备树、rootfs 之间的版本对应关系没有统一管理换个人换个宿主机器环境就漂移了产线上没法学。Yocto 能提供完整的发行版式构建能力Ubuntu/Debian 的 debootstrap rootfs 它也能接可 bitbake 的学习曲线太长一个 recipe 的依赖就能折腾一上午对团队里做板卡适配的同事极不友好。Buildroot 正好在中间一条 make 命令完成工具链、U-Boot、内核、文件系统的构建配置文件全部文本化扔进 git 就能复现。Buildroot 2022.02 这个版本的选择也有讲究。2022.02 是 LTS 分支官方维护周期长Bug 修复会持续跟进对于产品基线来说这是很关键的指标。它自带的工具链版本、内核版本和 U-Boot 版本经过了一整套联合测试彼此之间的兼容性比你自己随意拼版本高得多。实际用下来这个版本对飞腾 E2000 和 D2000 的适配比较成熟内核默认配置能覆盖大部分板载外设省去了一堆裁剪工作。我不用最新版本原因很简单嵌入式系统镜像讲究稳定一个新版本引入的改动可能影响整个 BSP没必要为了追新给自己挖坑。1.2 双系统镜像的分区布局与引导思路这次设计核心是一个引导层、两套根文件系统。存储介质上用四个分区第一个分区是 boot 分区放内核 Image、设备树 dtb 和 extlinux.conf第二个分区是 Ubuntu 的 rootfs第三个分区是 Debian 的 rootfs第四个分区做数据交换和日志存储。这样设计的优势很明显两个系统共用一个内核和引导层维护成本低系统的用户数据和系统分区分离重刷系统不会动业务数据以后想加第三个系统只要再分一个区、在 extlinux.conf 里加一条 label不用改引导层。引导方式我选的是 U-Boot 的 distro boot 机制配合 extlinux.conf。U-Boot 启动时会扫描所有可启动设备找到 boot 分区下的 extlinux/extlinux.conf读取里面的菜单配置。extlinux.conf 的好处是可以用文本文件管理多个启动项每个 label 对应该系统的内核、设备树和启动参数。板子上电后串口终端会显示菜单默认进入 Ubuntu5 秒不操作自动加载默认项手动干预时按上下键切换。这个交互体验在开发调试阶段非常爽比每次改 U-Boot 环境变量去手动 setenv bootcmd 要直观太多。分区表我用的 MBR 而不是 GPT原因是飞腾平台的 U-Boot 有些版本对 GPT 的识别有问题MBR 兼容性最好。要是你的存储介质超过 2TB再考虑 GPT但大多数 E2000 评估板接 eMMC 或 SD 卡容量根本到不了这个量级。每个分区的类型、大小和挂载点我后面在第 3 章实操部分给完整命令。1.3 用Buildroot统一管理U-Boot与内核rootfs交给发行版生态很多人第一次接触这个方案会问Buildroot 不是能直接生成整个文件系统吗为什么还要用 debootstrap 单独做 Ubuntu/Debian 的 rootfs原因在于发行版生态。Buildroot 的 rootfs 是基于 busybox 的精简系统装个 Python 都要自己加包、自己处理依赖做嵌入式小系统没问题但要把这块板子当桌面或服务器用缺的包太多了。Ubuntu 和 Debian 的软件源里有现成的全套软件apt 安装依赖自动解决内核模块也能用 DKMS 动态编译这是 busybox 生态比不了的。所以这次方案把两者做了分工Buildroot 只负责交叉编译 U-Boot 和内核保证引导层稳定可控rootfs 直接用 debootstrap 从发行版源灌装原生系统保证软件生态完整。两个系统可以是不同发行版也可以是同一个发行版的不同版本灵活性很高。我这次构建是在 Ubuntu 22.04 宿主机上完成的交叉编译目标架构是 aarch64。整个过程和标题里“从 Ubuntu 到 Debian”的对应关系是宿主机是 Ubuntu产物里同时包含 Ubuntu 和 Debian 两套目标系统镜像。整个工作流可以用一句话概括在一个干净的 Ubuntu 环境里用 Buildroot 构建飞腾平台的 U-Boot 和内核用 debootstrap 构建两个发行版的 rootfs最后用分区工具和引导菜单把它们组合成一张可启动的存储卡。2. 核心细节解析与关键配置2.1 交叉编译工具链选型外部Linaro还是Buildroot内置Buildroot 默认会自动构建一套交叉编译工具链这是最省事的方式。它会根据你选的 C 库版本glibc、musl 或 uClibc自动下载源码编译出完整的 aarch64 工具链然后用它来编译 U-Boot 和内核。好处是整个工具链的生命周期都在 Buildroot 管理下版本完全可控编译出来的二进制和 rootfs 的 C 库兼容性最好。缺点是首次构建要多花大概 15 分钟编译工具链不过这个成本是一次性的后面编译内核就快了。也可以选择外部工具链比如 Linaro 或 ARM 官方提供的 aarch64-linux-gnu- 系列或者宿主机 apt 安装的 gcc-aarch64-linux-gnu。外部工具链的优势是省去 Buildroot 内部工具链的编译时间但版本一致性差一些宿主机上的 gcc 版本随时间会变换了机器可能就不一样了这对“可复现构建”来说是隐患。我的建议是如果你是个人开发、图快可以用外部工具链如果你要交付产线或团队协作务必用 Buildroot 内置工具链。这次项目我选的是内置工具链配置如下BR2_TOOLCHAIN_BUILDROOTy BR2_TOOLCHAIN_BUILDROOT_GLIBCygcc 版本和内核版本匹配问题Buildroot 在 LTS 分支里已经处理好了你不用管。实际用下来内置工具链编译飞腾内核大概 15 分钟加上 U-Boot 也就多几分钟完全可以接受。2.2 内核配置与设备树飞腾平台需要特别注意的项飞腾 E2000 和 D2000 的内核配置核心点是开启 ARM64 全特性支持但有些选项必须针对板卡裁剪。我给输出说明的比较方便的设备树路径是arch/arm64/boot/dts/phytium/目录下不同板卡有不同的 dts 文件比如phytium,e2000.dts和phytium,d2000.dts。Buildroot 里通过BR2_LINUX_KERNEL_INTREE_DTS_NAME指定要编译的设备树名字它会自动把编译出来的 dtb 放到 output 目录。内核配置用 defconfig 而不是 menuconfig 手工改原因是要进 git 管理。Buildroot 支持BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE指定一个内核 defconfig 文件这个文件可以由飞腾官方 BSP 包提供也可以自己从当前内核的 config 导出。第一版建议直接用飞腾 BSP 里的配置启动成功后再逐步裁剪不要一开始就自己精简。特别是这几个配置项容易出问题CONFIG_EFI和CONFIG_EFI_STUB如果 U-Boot 用 UEFI 方式引导内核必须开启但我这次用 distro boot 直接引导 Image可以不开CONFIG_PHYTIUM如果有和CONFIG_ARM64_VA_BITSARM64 大页和虚拟地址宽度飞腾平台的 DDR 容量决定了该选多少存储控制器驱动E2000 的 SD/MMC 控制器、SATA 控制器必须编进内核而不是模块否则 rootfs 起不来串口驱动飞腾平台早期调试全靠串口CONFIG_SERIAL_AMBA_PL011这类驱动务必确认开启设备树的 clock 和 pinctrl 节点如果配置错了最常见的问题就是串口没输出或者 SD 卡不识别。遇到这类问题先用 U-Boot 的md命令读寄存器确认硬件地址再对比 dts 里的 reg 属性这个排查方法我在第 4 章详细说。2.3 rootfs灌装debootstrap qemu-user-static的正确姿势rootfs 是整个流程里最有技术含量的一步核心工具是 debootstrap。debootstrap 能从一个最小的包集合开始从 Ubuntu 或 Debian 的源里拉取安装一个完整的根文件系统。因为在 x86 宿主机上装的是 ARM64 的 rootfs必须配合 qemu-user-static 做指令集模拟否则 chroot 进 rootfs 之后所有命令都无法执行。以 Debian 12bookworm为例灌装命令大概是sudo debootstrap --archarm64 --foreign bookworm rootfs-debian \ http://mirrors.tuna.tsinghua.edu.cn/debian/加上--foreign是关键它告诉 debootstrap 只下载包并解压不执行 rootfs 里的任何程序。因为此时还没有 qemu 模拟环境直接执行会报 “cannot execute binary file”。解压完成后需要把 qemu-aarch64-static 复制进 rootfssudo cp /usr/bin/qemu-aarch64-static rootfs-debian/usr/bin/然后再用 chroot 完成第二阶段的配置。Ubuntu 的操作方式类似区别只是源不同。Ubuntu 22.04 用的是jammy套件源地址换成合适的 Ubuntu 镜像源。rootfs 灌装完成之后还要做几件收尾事设 root 密码、装基础工具vim、curl、networkmanager 等、配置网络、清理缓存。这些步骤我会在第 3 章的实操命令里全部写出来。2.4 分区、文件系统与引导参数设计分区的类型和大小直接影响后期维护体验。我这次用的分区方案分区大小文件系统挂载点说明/dev/mmcblk0p1512MBext4/boot内核、dtb、extlinux.conf/dev/mmcblk0p24GBext4/ (Ubuntu)Ubuntu 22.04 rootfs/dev/mmcblk0p34GBext4/ (Debian)Debian 12 rootfs/dev/mmcblk0p4剩余ext4/data数据分区boot 分区用 ext4 而不是 vfat原因是 vfat 对符号链接支持不好而内核和设备树文件名有时候会带软链接ext4 省心。如果要兼容 Windows 读取那另说但对嵌入式板卡来说用不到。引导参数这块最基础的几个参数是consolettyAMA0,115200 root/dev/mmcblk0p2 rw rootwaitconsole指定串口终端飞腾平台常见的调试串口是 ttyAMA0但不同板卡可能不同要看原理图。root指定根分区设备名rootwait必须加否则内核在存储设备初始化完成前去挂根会直接 panic。还有一个更稳的做法是用 PARTUUID 代替设备名设备名在不同启动介质下可能变化PARTUUID 是分区唯一的不会变。生成和确认 PARTUUID 的方法在第 3 章烧录部分会写。3. 实操过程与核心环节实现3.1 构建环境准备与依赖安装构建环境建议用一台干净的 Ubuntu 20.04 或 22.04 宿主内存至少 8GB磁盘剩余空间 30GB 以上。先安装 Buildroot 构建要用的依赖包sudo apt update sudo apt install -y build-essential gcc g make cmake flex bison \ libncurses-dev libssl-dev libelf-dev bc u-boot-tools python3 \ git wget cpio unzip rsyncrootfs 灌装还需要 debootstrap 和 qemu 用户态模拟sudo apt install -y debootstrap qemu-user-static parted dosfstools注意 qemu-user-static 这个包装好后会在/usr/bin/下生成qemu-aarch64-static同时注册 binfmt_misc 的 ARM64 格式关联。装完可以用update-binfmts --display确认是否注册成功这步漏了后面 debootstrap 第二阶段一定报错。3.2 Buildroot的defconfig配置完整流程下载 Buildroot 并切换到 2022.02 版本git clone https://gitlab.com/buildroot.org/buildroot.git cd buildroot git checkout 2022.02这里要说明一下Buildroot 官方仓库地址是 gitlab.comGitHub 上也有镜像但官方仓库更新最及时。2022.02 这个 tag 是 LTS 版本的发布点。接下来创建自定义 defconfig。Buildroot 的配置入口是make menuconfig但它生成的是.config不方便直接进 git。正确的做法是先把配置通过 menuconfig 调整好再执行make savedefconfigBuildroot 会生成一个精简的defconfig文件把它放到 Buildroot 源码根目录并重命名成你的板级配置名。这个defconfig文件就是你的构建基线可以提交到 git。我这次针对飞腾 E2000 的完整 defconfig 关键部分如下BR2_aarch64y BR2_cortex_a72y BR2_ARM_FPU_VFPV4y BR2_TOOLCHAIN_BUILDROOT_GLIBCy BR2_LINUX_KERNELy BR2_LINUX_KERNEL_CUSTOM_GITy BR2_LINUX_KERNEL_CUSTOM_REPO_URLhttps://gitee.com/phytium-linux/kernel.git BR2_LINUX_KERNEL_CUSTOM_REPO_VERSIONlinux-5.10.y BR2_LINUX_KERNEL_USE_CUSTOM_CONFIGy BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILEboard/phytium/e2000/linux.config BR2_LINUX_KERNEL_INTREE_DTS_NAMEphytium/phytium-e2000 BR2_TARGET_UBOOTy BR2_TARGET_UBOOT_CUSTOM_GITy BR2_TARGET_UBOOT_CUSTOM_REPO_URLhttps://gitee.com/phytium-linux/u-boot.git BR2_TARGET_UBOOT_CUSTOM_REPO_VERSIONv2021.04-phytium BR2_TARGET_UBOOT_BOARD_DEFCONFIGevb_emmc BR2_PACKAGE_HOST_GENIMAGEy这里有几个点需要特别说明。第一内核和 U-Boot 的仓库地址要根据你们 BSP 拿到的实际仓库改飞腾生态不同时期的 BSP 包对应的仓库路径不一样不要直接照抄。第二BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE指向的内核配置文件可以直接用 BSP 里提供的也可以自己make ARCHarm64 defconfig后导出来。第三BR2_TARGET_UBOOT_BOARD_DEFCONFIG必须是你的板卡在 U-Boot 源码configs/目录下真实存在的 defconfig 文件E2000 的 eMMC 启动板一般是evb_emmc_defconfig或类似命名D2000 的 SATA/NVMe 启动板则可能是d2000_sata_defconfig。配置写好后执行make phytium_e2000_defconfig这条命令会把defconfig展开成完整的.config接下来就能编译了。3.3 编译U-Boot、内核与整个镜像的完整命令编译过程是一条命令make -j$(nproc)$(nproc) 自动使用宿主机所有核心数并行编译。首次构建因为有工具链编译耗时较长我实测在 8 核 16 线程的机器上大概 30 分钟其中工具链编译占一半。第二次开始因为工具链和下载的源码包都在缓存里基本 10 分钟就能出产物。构建完成后检查output/images/目录ls -lh output/images/正常情况下会有这些文件u-boot.binU-Boot 二进制ImageARM64 内核镜像phytium-e2000.dtb设备树名字取决于你配置的 dts 名称rootfs.ext2、rootfs.ext4Buildroot 自带的 rootfs这里用不到但会生成这里要提醒一下Buildroot 默认会尝试生成它自己的根文件系统镜像即使你根本不需要它。如果不想让它在 rootfs 构建上浪费时间可以在配置里去掉BR2_TARGET_ROOTFS_EXT2相关的选项。不过留着也无所谓编译时间成本很低有时候还能用来做最小系统调试。编译通过的判断标准是看到类似于 Finalizing target directory和 Generating root filesystem image的日志输出且没有任何 error。如果中间失败不要慌先用make clean清理再重新执行多数情况是网络问题导致源码包下载失败。单独构建某个组件也有用要重编内核make linux-rebuild重编 U-Bootmake uboot-rebuild。改过内核配置后这两个命令非常实用。3.4 制作Ubuntu与Debian根文件系统先做 Ubuntu 22.04 的 rootfs这一步和 Debian 基本一致差异只在发行版代号和软件源sudo debootstrap --archarm64 --foreign jammy rootfs-ubuntu \ http://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/Ubuntu ARM64 的源必须是ubuntu-ports不能是普通的ubuntu源这是个很容易踩的坑。Debian 则用sudo debootstrap --archarm64 --foreign bookworm rootfs-debian \ http://mirrors.tuna.tsinghua.edu.cn/debian/--foreign参数的含义我在 2.3 节说过这里再强调一次必须加。不加的话debootstrap 在执行第二阶段时会调用 rootfs 内的dpkg而那是 ARM64 的二进制宿主 x86 直接报 “cannot execute binary file”。加完第一阶段解压后复制 qemu 模拟器进去sudo cp /usr/bin/qemu-aarch64-static rootfs-ubuntu/usr/bin/ sudo cp /usr/bin/qemu-aarch64-static rootfs-debian/usr/bin/然后进入 chroot 环境执行第二阶段sudo chroot rootfs-ubuntu /debootstrap/debootstrap --second-stage sudo chroot rootfs-debian /debootstrap/debootstrap --second-stage第二阶段做完rootfs 就是一个可用的基本系统了。接下来进入 chroot 做系统初始化sudo chroot rootfs-ubuntu export LANGC echo ubuntu-2204 /etc/hostname echo 127.0.0.1 localhost /etc/hosts passwd root apt update apt install -y vim curl net-tools network-manager sudo exitDebian 的初始化命令完全一样只是 hostname 改了。有一个小细节chroot 环境默认没有挂载/proc和/dev有些软件安装脚本会访问它们导致警告或失败。比较稳妥的做法是先挂载再 chrootsudo mount --bind /proc rootfs-ubuntu/proc sudo mount --bind /sys rootfs-ubuntu/sys sudo mount --bind /dev rootfs-ubuntu/dev用完再卸载。我一开始懒得挂结果 apt 安装 systemd 的 postinst 脚本报警告虽然最终能装上但心里不踏实。挂载一下也就几秒钟的事。rootfs 做完之后建议打个 tar 包存档sudo tar -czf ubuntu-rootfs.tar.gz -C rootfs-ubuntu .以后每次做镜像直接解压这个 tar 包就行不用重新跑 debootstrap能节省大量时间。3.5 镜像烧录与上板启动验证把 SD 卡或 eMMC 接到宿主机lsblk确认设备名假设是/dev/sdb。先清空分区表再重建sudo parted /dev/sdb mklabel msdos sudo parted /dev/sdb mkpart primary ext4 1MiB 513MiB sudo parted /dev/sdb mkpart primary ext4 513MiB 4609MiB sudo parted /dev/sdb mkpart primary ext4 4609MiB 8705MiB sudo parted /dev/sdb mkpart primary ext4 8705MiB 100%注意这些数字是按分区大小换算的实际大小根据你的存储介质容量调整。分区建好后格式化sudo mkfs.ext4 /dev/sdb1 sudo mkfs.ext4 /dev/sdb2 sudo mkfs.ext4 /dev/sdb3 sudo mkfs.ext4 /dev/sdb4挂载并复制文件mkdir -p /mnt/boot /mnt/ubuntu /mnt/debian sudo mount /dev/sdb1 /mnt/boot sudo mount /dev/sdb2 /mnt/ubuntu sudo mount /dev/sdb3 /mnt/debian sudo cp output/images/Image /mnt/boot/ sudo cp output/images/phytium-e2000.dtb /mnt/boot/ sudo tar -xzf ubuntu-rootfs.tar.gz -C /mnt/ubuntu sudo tar -xzf debian-rootfs.tar.gz -C /mnt/debian接下来创建 extlinux.conf。这个文件决定 U-Boot 启动时的菜单timeout 50 default Ubuntu menu title Phytium Boot Menu label Ubuntu menu label Ubuntu 22.04 LTS (ARM64) kernel /Image fdt /phytium-e2000.dtb append consolettyAMA0,115200 root/dev/mmcblk0p2 rw rootwait label Debian menu label Debian 12 (ARM64) kernel /Image fdt /phytium-e2000.dtb append consolettyAMA0,115200 root/dev/mmcblk0p3 rw rootwait把 extlinux.conf 放到/mnt/boot/extlinux/目录sudo mkdir -p /mnt/boot/extlinux sudo cp extlinux.conf /mnt/boot/extlinux/同步并卸载sync sudo umount /mnt/boot /mnt/ubuntu /mnt/debian还需要把 U-Boot 烧到启动介质的前面。这一步要非常小心写错设备会毁掉整个盘。E2000 的 eMMC 启动板一般把 U-Boot 写到偏移量 1MiB 处不同板卡可能不同BSP 手册会写sudo dd ifoutput/images/u-boot.bin of/dev/sdb bs1k seek1 convfsyncD2000 如果走 SATA 或 NVMeU-Boot 的烧写方式可能不一样有的是写到 SPI Nor Flash有的是写到盘的最前面按 BSP 文档操作。烧完后插到板子上接串口线上电串口终端应能看到 U-Boot 日志然后出现启动菜单。选择 Ubuntu 或 Debian能走到登录提示符整个过程就算通了。启动参数里如果用 PARTUUID 替代设备名可以用blkid查询各分区的 PARTUUIDsudo blkid /dev/sdb2 /dev/sdb3然后把 extlinux.conf 里的root/dev/mmcblk0p2改成rootPARTUUIDxxxx。这个改动能避免多存储设备枚举顺序变化带来的挂根失败问题。4. 常见问题与排查技巧实录4.1 debootstrap阶段失败排查debootstrap 第一个高频问题是 “Failed to get release file”。大多是网络问题或者软件源路径不对。Ubuntu 要用 ubuntu-ports 源Debian 用 debian 源这个搞反了必然 404。另外建议把源换成国内镜像直接访问官方源在国内环境下经常超时尤其 debootstrap 又要下载几百个包网络不稳定就前功尽弃。第二个高频问题是在--second-stage时报 “Cannot execute binary file”。原因就是没把 qemu-aarch64-static 复制进 rootfs 的/usr/bin/或者 binfmt_misc 没有正确注册。检查方式update-binfmts --display | grep qemu-aarch64如果没有输出执行sudo update-binfmts --enable qemu-aarch64或者直接重新安装 qemu-user-static 并重启 binfmt 服务。还有一个容易被忽略的点chroot 进去后apt update报 GPG 错误原因是 debootstrap 只装了基础包gnupg 没装。先apt install gnupg再apt update就好了。4.2 U-Boot启动系统失败排查U-Boot 阶段的失败最典型的是两种找不到启动介质或者找到介质但加载内核失败。“No bootable device” 这类提示先确认 U-Boot 是否烧对了偏移量eMMC 烧在 1MiB、SPI Nor 烧在 0SD 卡可能也要偏移。就像前面说的这个偏移量在 BSP 文档里有不同板子不一样。其次确认extlinux/extlinux.conf是否放在 boot 分区的正确路径U-Boot 会按/extlinux/extlinux.conf或/boot/extlinux/extlinux.conf的路径找放错位置就识别不到。“Error loading kernel” 则说明 extlinux.conf 找到了但 Image 文件路径不对或内核镜像格式不被支持。飞腾平台用的是 ARM64 的Image格式不是zImageU-Boot 需要开启对Image格式的支持。如果 U-Boot 编译时没有打开对应配置会报 “Wrong Image Format”。遇到这种情况回到 U-Boot 源码确认 CONFIG_CMD_BOOTI 和 CONFIG_ARM64 这些配置打开了重新编一版 U-Boot。还有一个常见情况是内核启动过程中没有任何输出死得无声无息。优先查console参数是不是 ttyAMA0波特率是不是 115200。如果板子的调试串口是 ttyAMA1你写成 ttyAMA0内核日志就全部不见了。先用 U-Boot 的printenv console看看 U-Boot 用的串口然后对齐内核启动参数。4.3 rootfs启动后的运行问题与调优能登录系统但是网络不通大概率是缺少网卡固件或驱动。飞腾 E2000/D2000 板载网卡可能走的是 PCIe 外接或 SoC 内部 MAC对应的内核驱动和 firmware 首先要确认内核配置里打开了其次检查 Debian/Ubuntu 的 non-free 固件包是否安装。Debian 12 需要加 non-free-firmware 组件注Debian 12 开始固件仓库的名字是 non-free-firmwareDebian 11 及更早是 non-free。很多网卡识别不了就是缺这个。另一个高频问题是 systemd 启动卡在 90 秒再往下走。这个基本上是 fstab 里的某个挂载项找不到设备。debootstrap 生成的 rootfs 里 fstab 文件可能根本不存在或者内容里有UUID指向一个不存在的分区。我习惯的做法是在 chroot 阶段就写好 fstab只挂载根分区和 /data 分区用 PARTUUID 指定设备。写好后用systemctl status查哪个单元超时基本一查一个准。还有个细节Ubuntu 22.04 默认没有启用 sshd如果你需要无头操作记得apt install openssh-server并设置开机自启。Debian 12 也一样。另外 locale 问题很烦人不装 locale 的话终端里中文乱码、apt 警告、部分软件运行异常。进了 chroot 后dpkg-reconfigure locales勾选 en_US.UTF-8 和 zh_CN.UTF-8然后update-locale设置默认值一劳永逸。首次启动默认没有图形界面如果需要 Ubuntu 桌面用 tasksel 安装 ubuntu-desktopDebian 则apt install task-kde-desktop或task-xfce-desktop。但注意 E2000 上跑桌面GPU 驱动要适配好我在一块 E2000 板子上实测自研 GPU 在标准内核下只有 framebuffer 输出桌面能起来但流畅度一般。D2000 搭配独立显卡会好很多。4.4 问题速查表现象可能原因快速排查方法解决方案debootstrap 报 404发行版代号或源路径错误手工 curl 源地址Ubuntu 用 ubuntu-portsDebian 用 debianchroot 后不能执行命令qemu-aarch64-static 缺失update-binfmts --display复制 qemu 到 rootfs/usr/binU-Boot 找不到启动设备U-Boot 烧写位置错误dd 检查前 1MiB 内容按 BSP 手册重烧到正确偏移内核加载失败Image 格式不支持U-Boot 下 booti 测试开启 CONFIG_CMD_BOOTI 重编 U-Boot内核无任何输出console 参数错误printenv console 对比修改启动参数串口号卡在 Waiting for root device根分区设备名不对blkid 查看实际设备用 PARTUUID 替代设备名systemd 启动卡 90 秒fstab 挂载项失效systemctl status 查超时清理 fstab用 PARTUUID网卡不识别内核驱动或固件缺失lspci / dmesg装 firmware 包编译对应驱动apt update GPG 错误缺 gnupgdpkg -l gnupgchroot 内先 apt install gnupg4.5 多系统引导联动的进一步优化做多系统镜像不只是把两套 rootfs 塞进一张卡引导菜单更合理的设计是把选择权交给使用场景。比如默认引导 Ubuntu但在启动参数里加一个环境变量控制默认项或者把 Debian 的 label 命名和版本号对应起来方便后续维护。我用下来最实用的做法是给两个系统分配独立的内核 Image 文件比如Image-ubuntu和Image-debian这样即使两个系统需要不同的内核版本也能通过 extlinux.conf 分别指定不用重新做整个镜像。内核和 dtb 的升级也变成了单纯的 boot 分区文件替换对产线维护来说太方便了。另外如果你要在同一条 U-Boot 环境变量里实现“板子一上电就默认进 Debian但长按某个键进 Ubuntu”可以把启动参数default通过 U-Boot 的bootargs动态传入或者用setenv boot_default Debian配合 extlinux 的 label 匹配。这些玩法不改变编译流程只是引导层的策略调整等你基础镜像完成后可以自由发挥。5. 一点个人的体会这次编译工作最大的收获是彻底理解了“工具链版本一致性”在嵌入式系统里的分量。早期我也习惯用宿主机自带的 gcc 交叉编译编内核没问题但遇到 glibc 版本和 rootfs 不匹配就抓瞎反复定位问题花的时间比重新构建还多。后来老老实实让 Buildroot 自己管工具链这些麻烦事基本消失了。还有一个小技巧分享给大家不要每次做镜像都从头跑 debootstraprootfs 打好包之后存一个 tar.gz 基线后续所有板子都从基线展开再定制效率和一致性都很高。我这次做完 Ubuntu 和 Debian 两套基线包之后给第二块板子做适配只花了半天时间基本就是调调设备树和启动参数。这也解释了为什么我在文章里反复强调文本化配置、版本管理这些事——嵌入式开发里能复现的方案才是好方案单次成功只能说明运气不错。
返回列表