Firefly RK3399 - 从零构建Ubuntu 20.04.4根文件系统实战指南
1. 准备工作与环境搭建
第一次接触Firefly RK3399开发板时,我就被它强大的性能吸引住了。这块六核ARM开发板搭载了双Cortex-A72和四Cortex-A53处理器,性能足以运行完整的Ubuntu桌面系统。不过要从零开始构建根文件系统,确实需要做好充分准备。
首先需要准备一台运行Ubuntu的宿主机,我使用的是Ubuntu 20.04 LTS版本。建议选择这个版本,因为它与我们要构建的目标系统版本一致,可以避免很多兼容性问题。宿主机需要至少100GB的可用磁盘空间,因为编译过程中会产生大量中间文件。
在宿主机上安装必要的工具链:
sudo apt update sudo apt install -y git build-essential bc kmod cpio flex libncurses5-dev libelf-dev libssl-dev dwarves bison特别提醒一下,如果你和我一样使用的是虚拟机作为宿主机,记得给虚拟机分配足够的内存和CPU资源。我刚开始只给了4GB内存,编译内核时频繁卡死,后来增加到8GB才顺畅。另外,建议使用SSD硬盘,机械硬盘的编译速度会让你怀疑人生。
2. 获取Ubuntu基础文件系统
Ubuntu-base是一个最小化的根文件系统,它只包含最基本的运行环境,非常适合嵌入式系统定制。我们可以从Ubuntu官方或国内镜像站下载。
我推荐使用清华大学的镜像源,速度更快:
wget https://mirrors.tuna.tsinghua.edu.cn/ubuntu-cdimage/ubuntu-base/releases/20.04/release/ubuntu-base-20.04.4-base-arm64.tar.gz下载完成后,我们需要解压这个文件系统包。这里有个小技巧:必须使用root权限并保留文件权限:
mkdir -p rootfs/ubuntu sudo tar -xpvf ubuntu-base-20.04.4-base-arm64.tar.gz -C rootfs/ubuntu/解压后,你会得到一个约100MB的基础系统。这个系统小得惊人,连最基本的文本编辑器都没有。但正是这种精简,让我们可以按需定制,避免不必要的软件占用宝贵的内存和存储空间。
3. 配置交叉编译环境
由于RK3399是ARM架构,我们需要配置交叉编译环境。这里我推荐使用Linaro的工具链:
wget https://releases.linaro.org/components/toolchain/binaries/7.5-2019.12/aarch64-linux-gnu/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz sudo tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz -C /opt/设置环境变量,方便后续使用:
export PATH=/opt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin:$PATH export CROSS_COMPILE=aarch64-linux-gnu- export ARCH=arm64验证工具链是否安装成功:
aarch64-linux-gnu-gcc --version如果看到版本信息输出,说明工具链已经准备就绪。这一步很关键,后续的内核编译和驱动编译都依赖这个工具链。
4. 安装QEMU模拟器
由于我们的宿主机是x86架构,而目标系统是ARM架构,我们需要QEMU来进行模拟运行:
sudo apt install -y qemu-user-static安装完成后,将QEMU的ARM64模拟器复制到目标文件系统中:
sudo cp /usr/bin/qemu-aarch64-static rootfs/ubuntu/usr/bin/这个小技巧非常实用,它允许我们在x86主机上直接chroot到ARM文件系统进行配置和安装软件。我第一次尝试时跳过了这一步,结果chroot后所有命令都无法执行,浪费了不少时间排查问题。
5. 配置软件源和网络
为了让目标系统能够安装软件,我们需要配置合适的软件源。国内用户建议使用华为或清华的镜像源:
sudo vim rootfs/ubuntu/etc/apt/sources.list替换为以下内容:
deb http://mirrors.huaweicloud.com/ubuntu-ports/ focal main multiverse restricted universe deb http://mirrors.huaweicloud.com/ubuntu-ports/ focal-security main multiverse restricted universe deb http://mirrors.huaweicloud.com/ubuntu-ports/ focal-updates main multiverse restricted universe配置DNS,确保网络连接正常:
sudo cp /etc/resolv.conf rootfs/ubuntu/etc/resolv.conf在实际操作中,我发现有时候resolv.conf会被覆盖,所以更稳妥的做法是在文件系统中固定DNS配置:
sudo vim rootfs/ubuntu/etc/systemd/resolved.conf添加:
[Resolve] DNS=8.8.8.8 114.114.114.1146. 挂载和进入目标系统
现在我们可以挂载目标文件系统并进行配置了。创建一个挂载脚本mnt_ubuntu.sh:
#!/bin/bash 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 -o bind /dev/pts ${2}dev/pts sudo chroot ${2} } 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给脚本执行权限并挂载:
sudo chmod +x mnt_ubuntu.sh ./mnt_ubuntu.sh -m rootfs/ubuntu/成功执行后,你会发现命令行提示符变了,这时你已经进入了目标系统的环境。这个步骤看似简单,但却是整个过程中最关键的一环,后续的所有配置都在这个环境中进行。
7. 安装基础软件和桌面环境
在目标系统环境中,首先更新软件包列表:
apt update安装一些基础工具:
apt install -y net-tools ethtool ifupdown psmisc nfs-common htop vim rsyslog iputils-ping language-pack-en-base sudo network-manager systemd openssh-sftp-server接下来安装桌面环境。RK3399性能不错,可以运行完整的Ubuntu桌面:
apt install -y ubuntu-desktop这个安装过程会比较长,大约需要下载1GB的数据。我在第一次安装时因为网络不稳定失败了,后来发现可以用apt的缓存机制:
apt -o Acquire::http::Timeout=30 -o Acquire::https::Timeout=30 -o Acquire::ftp::Timeout=30 install -y ubuntu-desktop安装完成后,建议安装一些常用的多媒体支持:
add-apt-repository multiverse apt install -y ubuntu-restricted-extras8. 系统配置和优化
设置root密码:
passwd root配置SSH允许root登录:
vim /etc/ssh/sshd_config找到PermitRootLogin并修改为:
PermitRootLogin yes设置主机名和网络:
echo "rk3399" > /etc/hostname echo "127.0.0.1 localhost" >> /etc/hosts echo "127.0.0.1 rk3399" >> /etc/hosts配置有线网络使用DHCP:
echo auto eth0 > /etc/network/interfaces.d/eth0 echo iface eth0 inet dhcp >> /etc/network/interfaces.d/eth0优化系统启动速度:
vim /lib/systemd/system/networking.service将TimeoutStartSec=5min改为:
TimeoutStartSec=1sec配置开机自动登录图形界面:
vim /etc/gdm3/custom.conf添加:
[daemon] AutomaticLoginEnable=true AutomaticLogin=root9. 安装内核头文件和驱动模块
退出chroot环境,回到宿主机:
exit编译内核头文件:
cd linux-5.2.8 make -j$(nproc) bindeb-pkg将生成的头文件包复制到目标系统:
sudo cp linux-headers-5.2.8_5.2.8-1_arm64.deb rootfs/ubuntu/opt/重新进入chroot环境安装头文件:
./mnt_ubuntu.sh -m rootfs/ubuntu/ cd /opt dpkg -i linux-headers-*.deb编译内核模块:
export KMODULES_OUTDIR=`pwd`/out/output_rk3399_kmodules make modules -j$(nproc) make INSTALL_MOD_PATH=${KMODULES_OUTDIR} modules_install将编译好的驱动模块复制到目标系统:
cp -af ${KMODULES_OUTDIR}/lib/modules/* rootfs/ubuntu/lib/modules/10. 制作根文件系统镜像
退出chroot环境,开始制作镜像:
exit mkdir ubuntu_rootfs dd if=/dev/zero of=ubuntu_ext4_rootfs.img bs=1M count=6144 mkfs.ext4 ubuntu_ext4_rootfs.img挂载镜像并复制文件:
mount ubuntu_ext4_rootfs.img ubuntu_rootfs/ cp rootfs/ubuntu/* ubuntu_rootfs/ -af umount ubuntu_rootfs优化镜像大小:
e2fsck -p -f ubuntu_ext4_rootfs.img resize2fs -M ubuntu_ext4_rootfs.img最终得到的镜像文件就可以烧录到开发板了。整个过程虽然步骤繁多,但只要按部就班操作,就能成功构建一个完整的Ubuntu根文件系统。
