3.4 制作根文件系统
基于ubuntu基础镜像
根文件系统(Root File System)是Linux操作系统的核心组成部分,包含启动和运行系统所需的全部目录结构和关键文件。它是内核挂载的第一个文件系统,提供了/bin、/etc、/lib等基础目录,是用户空间程序运行的基础环境。
Ubuntu-base是由Ubuntu官方提供的轻量化根文件系统基础镜像,其设计遵循最小化原则,核心组件仅包含Debian软件包管理器(APT)及必要的运行时依赖,整体体积通常控制在数十兆级别。该镜像深度集成Ubuntu软件仓库生态,能够便捷地通过apt-get install指令扩展功能,具备高度的可定制性与稳定性,因而广泛应用于嵌入式设备的根文件系统(rootfs)构建场景。
在嵌入式开发领域,常见的文件系统构建方案(如BusyBox、Yocto、Buildroot等)通常需要开发者手动管理依赖链与编译环境,其灵活性与维护成本存在显著权衡。相比之下,Ubuntu-base依托成熟的APT包管理体系,可直接调用逾数万款经过严格测试的预编译软件包,大幅降低系统扩展复杂度。同时,Ubuntu活跃的开发者社区及长期支持(LTS)策略,进一步保障了嵌入式系统的安全更新与生态兼容性。
Ubuntu-base支持多架构跨平台部署,涵盖x86_64、ARM(32/64位)等多种指令集。本文以ARM64架构为范例详细阐述构建流程。核心目标是,基于Ubuntu-base最小化镜像,通过模块化软件包安装与配置,逐步构建包含Xenomai用户层地完整Ubuntu ARM64根文件系统。此根文件系统既能用于演示Xenomai用户层编程与实践,同时也可适应于真正的嵌入式系统。
3.4.1 准备工作
假定当前工作目录为/root/xenomai/rootfs。
目标是生成一个 linuxroot.img块文件,作为根文件系统,传递给QEMU ARM64 qemu-system-aarch64。
1. 获取Ubuntu Core基础镜像
从Ubuntu官方仓库下载:ubuntu-base-22.04.5-base-arm64.tar.gz
http://cdimage.ubuntu.com/ubuntu-base/releases/22.04.5/release/
rm -fr ./temp; mkdir ./temp
tar -xpf ubuntu-base-22.04.5-base-arm64.tar.gz -C ./temp
ls temp/
bin boot dev etc home lib media mnt opt proc root run sbin srv sys tmp usr var
-
-p:保留文件权限,避免后续权限错误。
-
-C:指定解压目录,确保目录结构完整。
2. 安装QEMU实现跨架构仿真
sudo apt-get install qemu-user-static
注入QEMU仿真器
sudo cp /usr/bin/qemu-aarch64-static temp/usr/bin/ # 注入QEMU仿真器
同时需QEMU支持跨架构命令执行。
3. 配置网络
sudo cp -b /etc/resolv.conf temp/etc/resolv.conf # 同步DNS配置
在chroot环境中,需解析域名以下载软件包.
4. 替换软件源
sudo sed -i 's/ports.ubuntu.com/mirrors.ustc.edu.cn/g' temp/etc/apt/sources.list
设置国内ports源
设置Ubuntu arm源
根据ubuntu | 镜像站使用帮助 | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror
本镜像仅包含 32/64 位 x86 架构处理器的软件包,在 ARM(arm64, armhf)、PowerPC(ppc64el)、RISC-V(riscv64) 和 S390x 等架构的设备上(对应官方源为ports.ubuntu.com)请使用 ubuntu-ports 镜像。
实际使用中科大的源比较好用
方法:Ubuntu 源使用帮助 — USTC Mirror Help 文档
实际使用源:Ubuntu Ports 源使用帮助 — USTC Mirror Help 文档
http://mirrors.ustc.edu.cn/ubuntu-ports
3.4.2 chroot根文件系统
创建mount.sh脚本:
#!/bin/bash
function mnt() {
echo "MOUNTING"
sudo mount -t proc /proc ${2}proc
sudo mount -t sysfs /sys ${2}sys
sudo mount -o bind /dev ${2}dev
sudo mount -B /dev/pts ${2}dev/pts
sudo chroot ${2}
}
function umnt() {
echo "UNMOUNTING"
sudo umount ${2}proc
sudo umount ${2}sys
sudo umount ${2}dev/pts
sudo umount ${2}dev
}
if [ "$1" == "-m" ] && [ -n "$2" ] ;
then
mnt $1 $2
elif [ "$1" == "-u" ] && [ -n "$2" ];
then
umnt $1 $2
else
echo ""
echo "Either 1'st, 2'nd or both parameters were missing"
echo ""
echo "1'st parameter can be one of these: -m(mount) OR -u(umount)"
echo "2'nd parameter is the full path of rootfs directory(with trailing '/')"
echo ""
echo "For example: ch-mount -m /media/sdcard/"
echo ""
echo 1st parameter : ${1}
echo 2nd parameter : ${2}
fi
创建mount.sh脚本并执行:
sudo ./mount.sh -m temp/
挂载点解析:
/proc:提供进程和内核状态信息,ps、top等工具依赖此目录。
/sys:暴露硬件设备与驱动信息,用于动态设备管理。
/dev:设备文件入口,如/dev/sda对应磁盘设备。
chroot的作用:
将当前进程的根目录切换到指定路径,实现隔离的“虚拟系统”,便于安全地进行系统级修改。
此时已经进入到了ARM64根文件系统,通过lscpu命令可以确认当前的处理器架构aarch64。
lscpu
Architecture: aarch64
CPU op-mode(s): 32-bit, 64-bit
Address sizes: 43 bits physical, 48 bits virtual
Byte Order: Little Endian
CPU(s): 8
On-line CPU(s) list: 0-7
Vendor ID: GenuineIntel
Model name: 12th Gen Intel(R) Core(TM) i5-12500H
CPU family: 6
Model: 154
Thread(s) per core: 1
Core(s) per cluster: 8
Socket(s): 128
Cluster(s): 1
Stepping: 3
BogoMIPS: 6220.81
Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1g
b rdtscp lm constant_tsc arch_perfmon nopl xtopology tsc_reliable nonstop_tsc cpuid tsc_known_freq pni pclmulqdq vmx ssse
3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dn
owprefetch invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx
2 smep bmi2 invpcid rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xsaves arat pku ospke md_clear flush_l1d arch_
capabilities
Virtualization features:
Virtualization: VT-x
Caches (sum of all):
L1d: 384 KiB (8 instances)
L1i: 256 KiB (8 instances)
L2: 10 MiB (8 instances)
L3: 18 MiB (1 instance)
NUMA:
NUMA node(s): 1
NUMA node0 CPU(s): 0-7
Vulnerabilities:
Itlb multihit: KVM: Mitigation: VMX disabled
L1tf: Not affected
Mds: Not affected
Meltdown: Not affected
Mmio stale data: Not affected
Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl and seccomp
Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization
Spectre v2: Mitigation; Enhanced IBRS, IBPB conditional, RSB filling
Srbds: Not affected
Tsx async abort: Not affected
3.4.3 定制根文件系统
1. 更新系统与安装必备软件
apt update && apt upgrade -y
apt install systemd -y
apt install sudo -y
apt install vim -y
apt install net-tools -y
apt install ethtool -y
apt install ifupdown -y
apt install iputils-ping -y
apt install htop -y
apt install openssh-server -y
为何必须安装systemd?
Ubuntu 20.04采用systemd作为初始化系统(init),负责启动守护进程、挂载文件系统等核心任务。缺少systemd将导致系统无法正常启动。
2. 主机名与用户管理
echo xeno-demo > /etc/hostname
passwd root
useradd -s '/bin/bash' -m -G adm,sudo xeno
passwd xeno
- 启用root账户,并设置密码
- 创建用户xeno并加入sudo组,并设置密码
- -s:指定用户默认Shell。
- -m:自动创建家目录(/home/xeno)。
- -G:附加用户到管理员组(adm)和超级用户组(sudo)。
3. 配置网络
(1)配置IP地址
在 Ubuntu 系统中,/etc/network/interfaces 文件支持从 /etc/network/interfaces.d/ 目录加载额外的配置文件。这样可以将不同网络接口的配置分离到独立的文件中,便于管理和维护。
以下是为 eth0(以太网接口)创建配置文件的步骤:
在 /etc/network/interfaces.d/ 目录下创建eth0.cfg,并添加以下内容,使用 DHCP 动态获取 IP 地址。
auto eth0
iface eth0 inet dhcp
auto eth0:表示系统启动时自动启用eth0接口。iface eth0 inet dhcp:配置eth0使用 DHCP 协议动态获取 IP 地址。
使用vi编辑eth0.cfg,或直接用如下命令快速追加内容。
echo "auto eth0" > /etc/network/interfaces.d/eth0.cfg
echo "iface eth0 inet dhcp" >> /etc/network/interfaces.d/eth0.cfg
(2)SSH登录配置
在上面的步骤中,已经安装了openssh-server软件包,默认会启动sshd服务。
默认情况下,sshd不允许root账号登录。如果希望使用root账号ssh登录QEMU虚拟机,则需要修改配置。
echo "PermitRootLogin yes" > /etc/ssh/sshd_config.d/permitroot.conf
将 PermitRootLogin yes 写入到 /etc/ssh/sshd_config.d/permitroot.conf 文件中。这样做的目的是启用 SSH 服务对 root 用户的登录权限,而不需要直接修改主配置文件 /etc/ssh/sshd_config。SSHD支持从 /etc/ssh/sshd_config.d/ 目录加载额外的配置文件。这些文件的内容会被合并到主配置文件 /etc/ssh/sshd_config 中。
4. 设置console控制台
ARM64默认使用ttyAMA0,而Ubuntu默认仅启动tty1,因此默认情况下,使用此文件系统会遇到如下问题:
[ TIME ] Timed out waiting for device /dev/ttyAMA0.
[DEPEND] Dependency failed for Serial Getty on ttyAMA0
如果安装了Ubuntu的桌面,例如apt install lubuntu-desktop,实测是不会出现此问题的。其背后的原理在于systemd-getty-generator会自动生成并启动getty@ttyAMA0.service服务:
/run/systemd/generator/getty.target.wants/serial-getty@ttyAMA0.service
本文仅使用串口登录,并不安装Ubuntu桌面(一般占用2~3GB空间)。为了解决此问题,需要手动生成getty@ttyAMA0.service服务文件:
ln -s /lib/systemd/system/getty\@.service /etc/systemd/system/getty.target.wants/getty\@ttyAMA0.service
sed -i 's/TTYVTDisallocate=yes/TTYVTDisallocate=no/g' /lib/systemd/system/getty\@.service
ln命令创建一个符号链接,将getty@.service模板服务实例化为getty@ttyAMA0.service,以便在ttyAMA0终端上启用登录服务。sed命令,修改配置文件getty@.service,将TTYVTDisallocate的值从yes改为no,禁止在登录时清屏,以保留内核启动信息。
3.4.4 退出chroot根文件系统
exit
sudo ./mount.sh -u temp/
在完成上述定制后,在ARM64根文件系统下,执行exit命令退出并返回到主机根文件系统。
最后务必调用./mount.sh -u取消/proc等之前已经挂载的虚拟文件系统。
3.4.5 添加Xenomai用户层库和工具
在上一章节,已经完成了Xenomai用户层的编译,并临时安装到了/root/xenomai/xenomai-v3.2.4-install目录。将其中的/usr/xenomai目录完整的拷贝到temp/usr目录下。
cp -af /root/xenomai/xenomai-v3.2.4-install/usr/xenomai/ ./temp/usr/
在 Linux 系统中,/etc/profile.d/ 目录用于存放用户登录时自动加载的脚本文件。这些脚本会在用户启动 shell 时执行,主要用于设置全局环境变量或运行初始化命令。通过在此目录下创建 xenomai.sh 文件并添加相关配置,可以为 Xenomai 实时框架设置必要的环境变量。
export XENOMAI_ROOT_DIR=/usr/xenomai
export XENOMAI_PATH=/usr/xenomai
export PATH=$PATH:$XENOMAI_PATH/bin:$XENOMAI_PATH/sbin:$XENOMAI_PATH/demo
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$XENOMAI_PATH/lib/pkgconfig
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$XENOMAI_PATH/lib
export OROCOS_TARGET=xenomai
-
export PATH=$PATH:$XENOMAI_PATH/bin:$XENOMAI_PATH/sbin
将 Xenomai 的bin和sbin目录添加到系统的PATH环境变量中,使用户能够直接执行 Xenomai 的命令和工具。 -
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$XENOMAI_PATH/lib/pkgconfig
添加 Xenomai 的pkgconfig目录到PKG_CONFIG_PATH,以便编译时能够找到 Xenomai 库的配置文件。 -
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$XENOMAI_PATH/lib
将 Xenomai 的库路径添加到LD_LIBRARY_PATH,确保运行时可以正确加载 Xenomai 的共享库。 -
export OROCOS_TARGET=xenomai
设置 OROCOS 实时框架的目标平台为xenomai,以适配 Xenomai 实时内核。
3.4.6 生成块设备
查看temp目录的大小,大概在600MB左右。
du -hs temp
573M temp
通过如下命令,生成一个1GB大小的linuxroot.imgRAW块文件,格式化为ext4文件系统后,把temp目录的内容拷贝其中。
dd if=/dev/zero of=linuxroot.img bs=1M count=1024
mkfs.ext4 linuxroot.img
mkdir -p rootfs
sudo mount linuxroot.img rootfs/
sudo cp -rfp temp/* rootfs/
sudo umount rootfs/
e2fsck -p -f linuxroot.img
最终,linuxroot.img可以作为根文件系统,传递给QEMU ARM64 qemu-system-aarch64。
如果需要更新根文件系统的内容:
- 可以先更新
temp目录,然后重新生成linuxroot.img。 - 直接把
linuxroot.img挂载到临时目录,修改其中的内容。
2713

被折叠的 条评论
为什么被折叠?



