3.4制作根文件系统

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 的 binsbin 目录添加到系统的 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挂载到临时目录,修改其中的内容。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值