根据 实验一 和实验二, 我们已经知道如何构建 kernel 和 u-boot, 知道在实际应用中如何使用 u-boot 来引导 kernel, 现在我们将重心移到根文件系统的构建上。对于一个驱动完整的 linux 来说, 剩下的工作就都放在根文件系统上了。
为构建方便, 我们创建一个环境变量 LFS, 将我们所有的文件都放在那里
- src 是放源文件的位置, rootfs 是构建的根文件系统目录, dst 是最终生成的文件目录
mkdir ~/lfs -p
export LFS=~/lfs
mkdir $LFS/src $LFS/rootfs $LFS/dst -p
构建 kernel
cd $LFS/src
wget https://mirrors.tuna.tsinghua.edu.cn/kernel/v5.x/linux-5.15.18.tar.xz
tar -xvf linux-5.15.18.tar.xz
cd linux-5.15.18
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabi-
make vexpress_defconfig
make zImage dtbs -j8
cp arch/arm/boot/zImage arch/arm/boot/dts/vexpress-v2p-ca9.dtb $LFS/dst
构建 busybox
cd $LFS/src
wget https://busybox.net/downloads/busybox-1.35.0.tar.bz2
tar -xvf busybox-1.35.0.tar.bz2
cd busybox-1.35.0
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabi-
make menuconfig
# 设置静态编译, 目前只能手动
make -j8
make install
cp _install/* $LFS/rootfs -r
busybox 初始配置
当 kernel 加载完成后将执行第一个用户空间程序 init, init 负责初始化系统和启动服务, 常见的 init 程序有 systemd, busybox 提供了一个简洁版本的 init, 它通过软链接放在 /sbin/init. 虽然可以移植使用 systemd, 但先看看如何配置与使用busybox 的 init:
- busybox 的 init 初始化系统过程会先访 /etc/inittab 文件来执行用户想要的初始化操作, 若没有该文件, 则执行默认操作
# 首先需要做得就像创建必备目录 sys proc dev 这些是作为 kernel 内部虚拟文件系统的挂载点使用的
# 其次是创建 /ect 和 /root , 分别是配置目录和 root 用户的工作目录
mkdir $LFS/rootfs/sys $LFS/rootfs/proc $LFS/rootfs/dev -p
mkdir $LFS/rootfs/etc/init.d $LFS/rootfs/root -p
mkdir $LFS/rootfs/lib -p
# 创建 root 用户, 默认无密码登录, 可在登录后设置
echo "root::0:0:root:/root:/bin/sh" > $LFS/rootfs/etc/passwd
# 让系统执行 rcS 下的脚本进行初始化工作
echo "::sysinit:/etc/init.d/rcS" > $LFS/rootfs/etc/inittab
# 设置可登录系统的终端
echo "ttyAMA0::respawn:/sbin/getty -L 0 ttyAMA0 vt100" >> $LFS/rootfs/etc/inittab
# 让 rcS 脚本挂载 kernel 虚拟文件系统,
echo "mount -t sysfs sys /sys" > $LFS/rootfs/etc/init.d/rcS
echo "mount -t proc proc /proc" >> $LFS/rootfs/etc/init.d/rcS
echo "mount -t devtmpfs udev /dev" >> $LFS/rootfs/etc/init.d/rcS
# [可选] ssh 登录时需要挂载 /dev/pts 文件系统
mkdir $LFS/rootfs/dev/pts
echo "mount -t devpts devpts /dev/pts" >> $LFS/rootfs/etc/init.d/rcS
chmod 755 $LFS/rootfs/etc/init.d/rcS
创建文件系统磁盘镜像(需要 root)
dd if=/dev/zero of=$LFS/dst/rootfs.img bs=1G count=2
mkfs.ext4 $LFS/dst/rootfs.img
sudo mount -o loop $LFS/dst/rootfs.img /mnt
sudo cp $LFS/rootfs/* /mnt -r
sudo umount /mnt
加载系统
qemu-system-arm \
-M vexpress-a9 \
-m 512M \
-kernel $LFS/dst/zImage \
-nographic \
-dtb $LFS/dst/vexpress-v2p-ca9.dtb \
-sd $LFS/dst/rootfs.img \
-append "root=/dev/mmcblk0 rw console=ttyAMA0"
复制动态库
虽然 busybox 是静态编译, 但为了后续各种库的移植和使用, 还是需要支持动态加载的, 因此手动将这些动态库复制到根文件系统
# 首先需要拷贝的是加载器 ld-xxx, 主要作用是加载程序到内存中执行并完成变量初始化和加载动态库等操作
cp /usr/arm-linux-gnueabi/lib/ld-linux.so.3 $LFS/rootfs/lib
或者直接一次性解决
cp /usr/arm-linux-gnueabi/lib/* $LFS/rootfs/lib -r
总结
到目前为止, 系统基本上是可用状态了, 剩下的基本就是各种库的移植和更加细致化的配置了, 将在后续篇幅中一一实践, 后续篇幅也将基于此系统进行更改,因此后续不再描述系统构建过程,且默认存放位置都是 $LFS
网友评论