新闻详情

新闻详情

首页 / 资讯中心 / 详情

用Ubuntu Base 20.04从零构建ARM开发板根文件系统

发布时间:2026/10/4 2:21:40来源:尧图网络
用Ubuntu Base 20.04从零构建ARM开发板根文件系统
很多玩开发板的朋友大概率都遇到过这种尴尬官方烧录的根文件系统要么塞满了用不上的桌面组件要么精简到连apt都没有改起来处处受限。我自己拿到新板子的习惯是先给它配一套自己掌控的根文件系统而 Ubuntu Base 20.04 一直是我在 ARM 平台上的首选。它不是完整的 Ubuntu而是官方发布的最小化基础层包含了核心库、busybox 工具集和 APT 包管理能力正好适合在 ARM 开发板上按需组合。这篇文章就把我这几年来反复折腾的完整流程写下来从下载解压、chroot 配置到部署上板最后附上我确实踩过的问题清单希望能帮你少走点弯路。1. 为什么要自己打造根文件系统而不是用厂家镜像1.1 Ubuntu Base 20.04与完整Ubuntu、官方rootfs的差异很多开发板出厂自带的 rootfs 是厂商基于某个发行版裁剪出来的。它的优点是开箱即用但缺点也很明显——你不知道里面被改过什么不知道安装的库是哪个版本更不敢随便升级。用 Ubuntu Base 20.04 自己拼一套最大的优势是“底子非常干净且弹性大”。它本质上是一个标准化的基础目录树里面包含/bin、/sbin、/lib、/etc、/usr等目录额外带了dpkg和apt。也就是说你拿到的是一个可以被apt管理的最小系统想装什么就装什么。这里要区别一个概念Ubuntu Base 不是 Ubuntu Server 的精简版也不是桌面版的安装镜像。它的压缩包通常只有几十 MB解压后基础占用在 200MB 到 400MB 左右视目标架构而定。相比之下完整桌面版动不动几个 GB对还没有进入量产验证阶段的开发板来说既浪费存储也拖慢启动和调试速度。开发者真正需要的是“从虚到实”的能力先跑起内核和基础用户空间再针对当前板卡的外设、工具链、应用库做增量安装。Ubuntu Base 刚好提供了这个起点。1.2 它适合哪些板子和场景先说适用范围。只要是官方 Linux 内核能正常启动、厂商或社区提供了对应设备树和 bootloader 的 ARM 板子基本都可以用它来做 rootfs。常见的有 i.MX6ULL、Zynq、树莓派、RK35 系列等。我试过在 64 位 ARMv8 和 32 位 ARMv7 板卡上分别放arm64和armhf的 Ubuntu Base过程几乎一样区别只是下载包的不同。适合的场景主要有三类一是做工业产品开发想把文件系统完全掌握在自己手里方便后续做 OTA 和版本管理二是做嵌入式软件调试希望有一个接近 PC 的开发环境能够通过 apt 快速安装 gdb、build-essential、网络工具三是做学习研究想真正理解 Linux 启动过程中 rootfs 扮演的角色。它不适合的场景也有比如你只需要一个只读的、没有任何包管理的 mini rootfs那直接上 BusyBox 更合适又比如要跑桌面环境那建议直接用厂商桌面镜像自己从 Base 开始组装桌面图形栈的成本会比较高。2. 从零开始下载、分区、解压rootfs到SD卡2.1 主机环境与分区规划在开始之前先准备一台 Ubuntu 主机版本不用太挑剔18.04 以上就行我用的是 20.04 x86_64。如果你不是 Ubuntu 主机也可以但下面涉及chroot到 ARM rootfs 的步骤会受架构影响最好用 qemu-user-static 来模拟这是另一个话题了。接着准备目标存储介质。绝大多数开发板先从 SD 卡启动所以我把一张 16GB 的 SD 卡作为例子。使用lsblk查看设备名我这里是/dev/sdb。注意操作前确认没有分区被挂载否则后面全是写入错误。分区规划建议第一个分区FAT32256MB用作 boot 分区存放内核和设备树。第二个分区ext4剩余空间用作 rootfs。为什么 boot 分区用 FAT32因为很多 ARM 板卡的 bootloaderU-Boot从 FAT/ext4 读取内核时对 FAT 的兼容性最好。后续如果你的板载 eMMC 启动方式不同分区结构也要跟着调整但思路是一样的。2.2 下载官方Ubuntu Base 20.04压缩包Ubuntu Base 的官方发布页在 cdimage.ubuntu.com路径通常是ubuntu-base/releases/20.04/release/。你需要根据开发板 CPU 架构选择文件64 位 ARM 开发板ubuntu-base-20.04.x-base-arm64.tar.gz32 位 ARM 开发板ubuntu-base-20.04.x-base-armhf.tar.gz我在 Xilinx ZynqMP 平台用过 arm64在 i.MX6ULL 平台用的是 armhf。下载时可以这样wget http://cdimage.ubuntu.com/ubuntu-base/releases/20.04/release/ubuntu-base-20.04.5-base-arm64.tar.gz版本号里的20.04.x会随时间更新你可以直接打开发布页看最新的点版本。下载完成后最好校验一下 SHA256sha256sum ubuntu-base-20.04.5-base-arm64.tar.gz去官网核对校验和。这一步看着多余但对于要部署到量产设备上的文件系统还是别省。2.3 解压到目标分区的正确姿势接下来把 SD 卡分区并格式化。假设 SD 卡是/dev/sdbsudo fdisk /dev/sdb在 fdisk 里输入n新建分区第一个分区设置大小256M类型选ef再n新建第二个分区类型默认 Linux。写盘后sudo mkfs.vfat -F 32 /dev/sdb1 sudo mkfs.ext4 -F /dev/sdb2格式化完成后挂载 rootfs 分区sudo mkdir -p /mnt/rootfs sudo mount /dev/sdb2 /mnt/rootfs然后解压 Ubuntu Basesudo tar xzvf ubuntu-base-20.04.5-base-arm64.tar.gz -C /mnt/rootfs这里必须用tar解压而不是直接复制文件原因很简单压缩包里的/bin/busybox、/lib下的软链接以及各种文件权限位普通复制很可能丢失。用tar且在 root 用户下操作能最大程度保留原始属性。解压完成后你能看到/mnt/rootfs/etc、/mnt/rootfs/lib等目录这就说明成功了一小半。3. 进入rootfs内部完成第一轮定制3.1 chroot环境的挂载与进入刚解压出来的 Ubuntu Base 还不能直接启动需要先进入内部做一些初始化。在 x86 主机上 chroot 进 ARM rootfs有一个关键点内核为 ARM 架构但当前主机的内核是 x86直接chroot不会成功。两种办法一是把 SD 卡放到 ARM 板子上通过板子本身的 Linux 环境进入 chroot二是在 x86 主机上用qemu-aarch64-static模拟 ARM 用户态。我这里更推荐在 ARM 板子上操作因为很多板卡出厂就带一个能用的 Linux 环境。如果只能 x86 主机操作需要安装 qemu-user-staticsudo apt install qemu-user-static sudo cp /usr/bin/qemu-aarch64-static /mnt/rootfs/usr/bin/然后挂载必要目录sudo mount -t proc /proc /mnt/rootfs/proc sudo mount --rbind /dev /mnt/rootfs/dev sudo mount --rbind /sys /mnt/rootfs/sys sudo mount --rbind /run /mnt/rootfs/run--rbind是为了让 chroot 环境里的程序访问设备节点、sysfs 和运行状态。缺了这些后面在 rootfs 里配置网卡、启动服务时都会碰到奇怪的问题。接着sudo chroot /mnt/rootfs /bin/bash看到roothost:/#之类的提示符就算进入 rootfs 内部了。3.2 配置APT源、DNS和基础工具Ubuntu Base 默认的 apt 源指向 Ubuntu 官方源但 ARM 平台的软件源和 x86 平台不同。对 Ubuntu 20.04 来说镜像路径应该是ports.ubuntu.com/ubuntu-ports而不是archive.ubuntu.com/ubuntu。我用以下内容覆盖/etc/apt/sources.listdeb http://ports.ubuntu.com/ubuntu-ports focal main restricted universe multiverse deb http://ports.ubuntu.com/ubuntu-ports focal-updates main restricted universe multiverse deb http://ports.ubuntu.com/ubuntu-ports focal-security main restricted universe multiverse写完源之后先配置 DNS。etc/resolv.conf在 Base 包里面通常是空的需要写入echo nameserver 8.8.8.8 /etc/resolv.conf echo nameserver 114.114.114.114 /etc/resolv.conf然后apt update apt install ifupdown net-tools openssh-server python3 vim sudo locales udev kmod这一步是必须的。Base 系统里没有网络管理工具如果漏装net-tools你连ip addr都执行不了。udev和kmod对很多板子至关重要它们负责设备节点创建设备节点和加载内核模块。安装完成后建议顺手安装locales并生成 UTF-8 语言环境避免后续程序输出乱码。3.3 串口登录服务不同板卡要改的设备节点开发板调试最常用的通道是串口。Ubuntu Base 默认可能只开了 tty1而嵌入式板卡的串口通常对应ttyS0、ttymxc0、ttyAMA0这样的设备节点。为了让系统启动后在串口上自动弹出登录提示符需要启用 systemd 的 serial-getty 服务。以 i.MX6ULL 的ttymxc0为例ln -s /lib/systemd/system/serial-getty.service \ /etc/systemd/system/getty.target.wants/serial-gettyttymxc0.service如果板卡用的是ttyPS0或ttyS0把命令里的设备名替换掉就行。ZynqMP 平台一般是ttyPS0树莓派默认是/dev/ttyAMA0或/dev/ttyS0。启用之后还需要确认波特率通常 U-Boot 和内核 console 参数是 115200systemd 默认会从内核参数继承所以你先改内核 cmdline 里的consolettymxc0,115200getty 基本就能跟上来。3.4 用户、密码、主机名、fstab、网络工具的初始化接下来设置基础身份信息。直接使用 root 登录虽然在开发阶段方便但不建议长期这样干。我一般先设置 root 密码再创建一个普通用户echo root:your_root_password | chpasswd useradd -m -s /bin/bash ubuntu echo ubuntu:your_user_password | chpasswd echo ubuntu ALL(ALL) NOPASSWD:ALL /etc/sudoers.d/ubuntu主机名改成板卡项目名echo armdev /etc/hostname echo 127.0.0.1 localhost armdev /etc/hosts然后是/etc/fstab。这个文件很重要很多启动问题都出在它身上。以 SD 卡启动为例rootfs 在第二个分区可以这样写/dev/mmcblk0p2 / ext4 defaults,noatime 0 1 /dev/mmcblk0p1 /boot vfat defaults 0 0 tmpfs /tmp tmpfs defaults 0 0注意不同的板卡存储控制器的设备名不同有的叫mmcblk0有的叫sda。这一项必须跟你的内核和设备树对应。如果写错系统启动到挂载根文件系统时会直接卡住。网络方面如果只是临时调试可以装一个dhclient启动后手动dhclient eth0获取 IP。期望开机自动联网的建议安装systemd-networkd并写一个简单的.network配置文件。4. 部署到开发板boot分区、引导参数与同步落盘4.1 理解boot分区与rootfs分区的协作关系很多第一次做 rootfs 的人会忽略 boot 分区的必要性。基于 ARM 的 Linux 系统通常分为两层bootloader 和内核。bootloader如 U-Boot存放在板载 SPI Flash 或者 SD 卡起始位置内核镜像zImage/Image和设备树.dtb存放在 boot 分区。rootfs 分区存放用户空间文件。为什么要分开一是 bootloader 读取 FAT 分区里的单个文件相对容易二是升级 rootfs 时不需要动 boot 区降低变砖风险。我在实际项目中会把编译生成的内核和设备树直接拷到/dev/sdb1然后确保 rootfs 分区里已经有正确的内容。这里有个细节很多板卡的 U-Boot 默认环境变量会写死内核从 mmc 0:1 加载rootfs 从 mmc 0:2 挂载。你的分区编号必须对应好。4.2 修改uEnv.txt/extlinux/cmdline的关键参数不同的 U-Boot 版本和板卡内核引导参数的存放位置不一样。最常见的三种uEnv.txt文件写在 boot 分区里被 U-Boot 读取。extlinux/extlinux.conf文件通过 U-Boot 的 DISTRO 启动脚本加载。U-Boot 环境变量里的bootargs字符串。以 i.MX6ULL 的 uEnv.txt 为例bootargsconsolettymxc0,115200 root/dev/mmcblk0p2 rootwait rw loadaddr0x83000000 fdtaddr0x83000000 loadkernelfatload mmc 0:1 ${loadaddr} zImage loadfdtfatload mmc 0:1 ${fdtaddr} imx6ull-14x14-evk.dtb bootbootz ${loadaddr} - ${fdtaddr}这里面有几个参数必须要理解consolettymxc0,115200内核日志输出到哪个串口、多少波特率。填错了会误以为系统没启动。root/dev/mmcblk0p2根文件系统所在分区。很多开发板启动失败就是因为这里还保留了厂商默认的 root/dev/mmcblk1p2 之类的值。rootwait等待根设备出现。设备树和内核加载过程比 rootfs 慢没加的话内核可能找不到根设备。rw以可读写方式挂载根文件系统。有些方案为了安全默认是ro你后面想改文件内容总是失败。如果用的是 NXP 的 Yocto 体系可能还会看到rootPARTUUID...这是另一个可行方式但人工维护时直接写设备节点更直观。ZynqMP 平台通常把 bootargs 写在 U-Boot 环境变量里思路是一样的。4.3 卸载前为什么要反复sync这是我在常见问题里看到最多、也最容易忽略的一步。嵌入式开发中直接断电、拔 SD 卡是常态但这不是好习惯。Linux 有缓存机制你用cp写入文件数据不一定立刻落盘而是先停留在 page cache 里。如果此时直接断电或卸载分区就会出现 rootfs 元数据损坏轻则文件丢失重则启动时出现 VFS 错误。正确的做法是sync sudo umount /mnt/rootfssync的作用是把缓存中的数据主动刷到磁盘。如果你要频繁在 rootfs 和 SD 卡之间拷贝比如交替修改内核、设备树、应用我建议每次回写文件后都执行一次。不要嫌麻烦量产的板子出现启动不了多半就是 rootfs 损坏而那往往是省了一次 sync 换来的。5. 常见问题排查手册都是实际踩过的坑5.1 VFS报错与Kernel panic根设备路径和驱动问题启动日志里如果出现类似VFS: Cannot open root device mmcblk0p2 or unknown-block(179,2) Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(179,2)不要慌。这个错误说明内核已经运行但挂载 rootfs 失败。可能原因有三个第一cmdline 里的root参数和实际分区不匹配第二rootfs 分区格式不对或者 rootfs 文件没有真正写进分区第三内核缺少对应存储控制器的驱动。排查顺序也按这个来。先确认分区在 U-Boot 下执行mmc list、mmc dev和mmc part看看实际分区编号。然后确认 rootfs把 SD 卡插回读卡器mount /dev/sdb2 /mnt/rootfs看看/mnt/rootfs/bin和/etc是否存在。如果分区内容没问题多半是内核配置问题。很多人用厂商默认内核忘记打开 storage driver 对应的 device tree 节点导致内核看不到 SD 卡或 eMMC。这就得回来检查设备树而不是折腾 rootfs。5.2 DNS解析失败、apt update拉不回来不是网络的问题现象是开发板能 ping 通路由器 IP但apt update报错Could not resolve ports.ubuntu.com这说明网络链路通了但 DNS 配置缺失。Ubuntu Base 的/etc/resolv.conf默认是空的而我见过不少人把 DNS 写在/etc/network/interfaces里结果发现 systemd-resolved 没启动或者根本就没装。最简单的临时方案是echo nameserver 8.8.8.8 /etc/resolv.conf想一劳永逸建议安装resolvconf或启用systemd-resolved。不过嵌入式板卡为了轻量更妥当的做法是给你的网络接口配置静态 DNS。比如用systemd-networkd在/etc/systemd/network/20-wired.network里[Network] DHCPyes DNS8.8.8.8 DNS114.114.114.114改完重启系统或者networkctl reload。这个坑的麻烦之处在于它不像网线断开那么直观总让人误以为是 apt 源坏了。5.3 串口无输出或乱码从波特率到getty服务开发板串口完全没有输出的情况我至少遇到过三次。第一次是console参数写错了设备名内核日志去了另一个串口。第二次是波特率不匹配终端软件设成 9600内核却是 115200屏幕上全是乱码。第三次最阴间内核和文件系统串口参数都对但到启动后期 getty 没有在对应设备上起服务。排查方法先把波特率统一成 1152008N1无流控。然后检查 bootargs 里console是否和板卡实际调试串口一致。有的板子丝印标明 “DEBUG UART”它的设备节点可能是ttyS0也可能要通过设备树 alias 来确定。启动到用户空间后执行systemctl list-units | grep getty看有没有serial-gettyttymxc0.service。如果没启动检查 3.3 节里的软链接是否存在。还有一种情况U-Boot 里设置了stdinserial但 rootfs 里的/etc/inittab对 systemd 系统不起作用别在那边找。5.4 开发板屏幕终端中文显示乱码locale与字体缺一不可如果你用 i.MX6ULL 这类带屏幕的板卡在终端里输出中文时看到一堆方框或者乱码第一反应往往是“字符集没设置”。但填了LANGen_US.UTF-8后仍然乱码那就要检查两样东西locale 和终端字体。Ubuntu Base 默认没有生成完整的 locale 数据。需要执行apt install locales locale-gen en_US.UTF-8 zh_CN.UTF-8 update-locale LANGen_US.UTF-8注意先安装 locales再生成语言环境。如果你直接改/etc/default/locale而不执行locale-gen很多程序不会生效。至于方块字通常是终端没有中文字体。framebuffer 终端不像 X11 下自动渲染字体需要你往 rootfs 里放一个点阵或多字节字体比如kbd包里的字体文件或者用fbterm配合中文字体。如果只是远程 SSH 连接后显示乱码那多半是终端模拟器的编码没有设为 UTF-8rootfs 反而没问题。5.5 文件系统变成只读或者写入很慢不只是sync的锅开发过程中常碰到的另一个现象touch /test报Read-only file system。原因可能是启动参数里没有rw也可能是 ext4 文件系统检测到异常自动以只读方式挂载。先执行mount -o remount,rw /看能不能恢复。能恢复说明只是当前挂载参数问题把这个参数写进 bootargs。如果仍然只读多半是文件系统损坏需要拔卡在主机上跑fsck.ext4 /dev/sdb2。实际项目里突然断电导致 ext4 变为只读的案例非常多这也是我前面强调 sync 的原因。写入慢则是另一类问题SD 卡质量、降频模式、没有使用noatime挂载选项都会有影响。SD 卡在长期 debug 过程中性能下降建议换一张高速卡同时确认/etc/fstab里写的是defaults,noatime避免每次访问文件都更新 atime 元数据。最后再分享一个我个人的习惯。每次做完 rootfs 修改我不会急着拔卡上板而是先在主机端把 rootfs 完整做一次tar.gz备份。这样即使板子上把文件系统折腾坏了也能在几分钟内恢复到一个干净状态。Ubuntu Base 20.04 这套流程我已经在不同板卡上重复了不下十次熟练之后从下载到上板大概半小时。真碰上问题兜底方案永远比临时排查更可靠。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

服务器添加记录下载次数功能 2026/10/4 2:37:55

服务器添加记录下载次数功能

wordpress--------javascript---------django-----------------保存到文件这就是全部技术路线

阅读更多 →
基础知识课 第二十三课:什么是半桥整流和全桥整流 2026/10/4 2:37:16

基础知识课 第二十三课:什么是半桥整流和全桥整流

想了解半桥和全桥,先了解半波整流和全波整流, 半桥和全桥是用不同方式去实现了全波整流;下面详细介绍 半波整流 将交流电转换为脉动直流电,但它只利用输入交流电的半个周期(正半周或负半周),而将另一个半周完全抑制掉,半波整流波形图如下图: 优缺点 优点 电路结构极…

阅读更多 →
【深度学习新浪潮】AI 研发周报 | 2026 年第 39 周(9.27 – 10.3) 2026/10/4 2:35:26

【深度学习新浪潮】AI 研发周报 | 2026 年第 39 周(9.27 – 10.3)

本周关键词:自主 Agent 产品化 Dots 与 Muse 同台 Gemini 4 防越狱 Agent 安全平台 物理 AI 资本热 能力安全双轮 在连续两周"模型降价潮 + 开源逆袭"(第 37、38 周)之后,本周 AI 领域的叙事重心明显转向三条清晰的主线:自主 Agent 从概念原型走向可交付产…

阅读更多 →
关于汉诺塔问题的分析 2026/10/4 2:31:56

关于汉诺塔问题的分析

Hanoi汉诺塔问题:古代有一个梵塔,塔内有3个柱子A、B、C,开始时,A柱上有64个金盘,金盘大小不等,大的在下,小的在上。有一个老和尚想把这64个金盘从A柱移动到C柱,但规定每次只允许移动…

阅读更多 →
用例建模之详解用例和用例规约 2026/10/4 2:31:04

用例建模之详解用例和用例规约

阅读更多 →
AI 给的 Zotero 插件清单,为什么还要核对版本? 2026/10/4 2:28:29

AI 给的 Zotero 插件清单,为什么还要核对版本?

作者:1world1cpc 利益关系披露:我在 AI4Paper 团队工作;文中涉及我们的产品时会明确说明。 问 AI:“Zotero 有什么好用的插件?”你可能很快就会得到一张清单。 清单有帮助,但在真正安装之前,…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉