8 Buildroot 根文件系统构建

一、根文件系统简介

  根文件系统一般也叫做 rootfs,这个是属于 Linux 内核的一部分。

  根文件系统首先是一种文件系统,该文件系统不仅具有普通文件系统的存储数据文件的功能,但是相对于普通的文件系统,它的特殊之处在于,它是内核启动时所挂载(mount)的第一个文件系统,内核代码的映像文件保存在根文件系统中,系统引导启动程序会在根文件系统挂载之后从中把一些初始化脚本(如rcS,inittab)和服务加载到内存中去运行。我们要明白文件系统和内核是完全独立的两个部分。在嵌入式中移植的内核下载到开发板上,是没有办法真正的启动Linux操作系统的,会出现无法加载文件系统的错误。

二、buildroot

  Buildroot 是 Linux 平台上一个开源的嵌入式 Linux 系统自动构建框架,用交叉编译生成 Linux 系统。整个Buildroot 是由 Makefile 脚本和 Kconfig 配置文件构成的。

1. buildroot 源码下载

  官方网站:Buildroot - 让嵌入式 Linux 变得简单

  由于我的 Ubuntu 版本较低,所以用正点推荐的 2020.02.6 版本。

2. buildroot 构建根文件系统

① 配置 buildboot

  先把 buildroot-2020.02.6.tar.bz2 拷贝到 Ubuntu 的 linux/tool 路径下。解压命令如下:

tar -vxjf buildroot-2020.02.6.tar.bz2

  buildroot 也支持图形化配置:

make menuconfig

1、配置 Target options

  需要配置的项目和其对应的内容如下(“=”号后面是配置项要选择的内容! ): 

-> Target Architecture = ARM (little endian)
-> Target Binary Format = ELF
-> Target Architecture Variant = cortex-A7
-> Target ABI = EABIhf
-> Floating point strategy = NEON/VFPv4
-> ARM instruction set = ARM

# 目标架构:ARM
# 目标二进制格式:ELF
# 目标架构变体:cortex-A7
# 目标ABI:EABIhf
# 浮点策略:NEON/VFPv4
# ARM指令集:ARM

 2、配置 Toolchain

  此配置项用于配置交叉编译工具链,也就是交叉编译器,这里设置为我们自己所使用的交叉编译器即可。 需要配置的项目和其对应的内容如下: 

Toolchain
    -> Toolchain type = External toolchain
    -> Toolchain = Custom toolchain // 用户自己的交叉编译器
    -> Toolchain origin = Pre-installed toolchain // 预装的编译器
    -> Toolchain path = /usr/local/arm/gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf
    -> Toolchain prefix = $(ARCH) -none-linux-gnueabihf 
    -> External toolchain gcc version = 9.x
    -> External toolchain kernel headers series = 4.20.x // 交叉编译器的 linux 版本号
    -> External toolchain C library = glibc/eglibc
    -> [*] Toolchain has SSP support? (NEW)
    -> [*] Toolchain has RPC support? (NEW) 
    > [*] Toolchain has C++ support? 
    -> [*] Enable MMU support (NEW)
    
# 工具链类型:外部工具链
# 工具链:自定义工具链
# 工具链来源:预安装的工具链
# 工具链路径:/usr/local/arm/gcc-arm-9.2-2019.12-x86_64-arm-none-linuxgnueabihf
# 工具链前缀:$(ARCH)-none-linux-gnueabihf
# 外部工具链gcc版本:9.x
# 外部工具链内核头文件系列:4.20.x
# 外部工具链C库:glibc/eglibc
# 工具链是否支持SSP(堆栈保护):选中
# 工具链是否支持RPC:选中
# 工具链是否支持C++:选中
# 是否启用MMU支持:选中

3、配置 System configuration 

  此选项用于设置一些系统配置,比如开发板名字、欢迎语、用户名、密码等。需要配置的项目和其对应的内容如下: 

System configuration
    -> System hostname = ATK-stm32mp1 // 平台名字
    -> System banner = Welcome Lxs // 欢迎语
    -> Init system = BusyBox // 使用 busybox
    -> /dev management = Dynamic using devtmpfs + mdev // 使用 mdev
    -> [*] Enable root login with password (NEW) // 使能登录密码
        -> Root password = 147258 // 登录密码

# 可以设置密码,但是每次重启都要输入密码很麻烦,所以我这里是失能的。

 4、配置 Filesystem images

  此选项配置我们最终制作的根文件系统为什么格式的,配置如下: 

-> Filesystem images
    -> [*] ext2/3/4 root filesystem // 如果是 EMMC 或 SD 卡的话就用 ext3/ext4
        -> ext2/3/4 variant = ext4 // 选择 ext4 格式
        -> exact size =1G // ext4 格式根文件系统 1GB(根据实际情况修改)
    -> [*] ubi image containing an ubifs root filesystem // 如果使用 NAND 的话就用 ubifs

  buildroot 可以直接制作出 ext4 格式的根文件系统,但是一般我们会自行往根文件系统里面添加很多其他的文件,所以产品开发完成以后需要自行打包根文件系统,然后烧写到开发板里面。不管是针对 EMMC 的 ext4 格式的根文件系统还是针对 NAND 的 ubi 格式的根文件系统,都要设置相应的大小,比如这里我们设置的 ex4 格式根文件系统大小为 1GB。 

5、禁止编译 Linux 内核和 uboot

  buildroot 不仅仅能构建根文件系统,也可以编译 linux 内核和 uboot。我们一般都不会使用 buildroot 下载的 linux 内核和 uboot,因为 buildroot 下载的 linux 和 uboot官方源码,里面会缺少很多驱动文件,而且最新的 linux 内核和 uboot 会对编译器版本号有要求,可能导致编译失败。因此我们需要配置 buildroot,关闭 linux 内核和 uboot 的编译,只使用buildroot 来构建根文件系统,首先是禁止 Linux 内核的编译,配置如下:

-> Kernel
    -> [ ] Linux Kernel // 不要选择编译 Linux Kernel 选项!
    
    
-> Bootloaders
    -> [ ] U-Boot // 不要选择编译 U-Boot 选项!

6、编译 Target packages 

  此选项用于配置要选择的第三方库或软件、比如 alsa-utils、 ffmpeg、 iperf 等工具,这里我们先只选择内核的模块加载相关软件,配置如下: 

-> Target packages
    -> System tools
        -> [*] kmod     // 使能内核模块相关命令

  先编译最基础的根文件系统,一步一步来。

7、保存配置项

  和 uboot、 kernel 一样,通过图形化界面配置好 buildroot 以后最好保存一下配置项,防止清除工程以后将配置项给删除掉。 buildroot 的默认配置项都保存在 configs 目录下,配置完成以后选择<Save>,然后输入要设置的配置项名字:

  如果以后重新配置 builroot 可以直接输入:

make stm32mp1_atk_defconfig

  保存完成后就可以看到  stm32mp1_atk_defconfig 这个文件。

② 编译 buildboot

  输入以下命令:

make -j8 //多线程编译

# "-j"参数可以指定同时执行的并发任务数。"-j8"表示同时进行8个并发编译任务。

  编译的时间是真的久,我直接翻墙然后再编译快一点。

  将 rootfs.tar 拷贝到在 nfs 目录下的 rootfs文件夹中并解压,命令如下: 

cp rootfs.tar /home/alientek/linux/nfs/rootfs/ -f
cd ~
cd linux/nfs/rootfs/
tar -vxf rootfs.tar
rm rootfs.tar

  这就是使用 buildroot 编译出来的根文件系统,我们可以通过 nfs 挂载到开发板上,然后对其进行测试。

③ buildboot 测试根文件系统 

  测试方法是通过 nfs 挂载的方式,启动 uboot,修改 bootargs 环境变量,设置 nfsroot 目录为 Ubuntu 中的rootfs 目录,命令如下: 

setenv bootargs console=ttySTM0,115200 root=/dev/nfs nfsroot=192.168.1.105:/home/alientek/linux/nfs/rootfs,proto=tcp rw ip=192.168.1.106:192.168.1.105:192.168.1.1:255.255.255.0::eth0:off''
saveenv

  这里有密码登录,需要取消,输入以下命令:

cd ~
vim linux/nfs/rootfs/etc/inittab

  修改成功后开发板 RESET 重复以下操作:

setenv bootargs console=ttySTM0,115200 root=/dev/nfs nfsroot=192.168.1.105:/home/alientek/linux/nfs/rootfs,proto=tcp rw ip=192.168.1.106:192.168.1.105:192.168.1.1:255.255.255.0::eth0:off''
boot

3. buildroot 下的 busybox 配置

① busybox 配置 

  buildroot 会自动下载 busybox 压缩包, buildroot 下载的源码压缩包都存放在/dl 目录下,在 dl 目录下就有一个叫做“busybox”的文件夹,此目录下保存着 busybox 压缩包,如下图所示:

  但是 buildroot 会将所有解压后的软件保存在 /output/build 目录中。

  进入 busybox 图形化配置界面:

cd ..            # 返回buildroot源码根目录下
make busybox-menuconfig

-> Settings
    -> Build static binary (no shared libs)

# 不要选择这个

  继续配置:

-> Settings
    -> vi-style line editing commands
# 选择这个

  继续配置:

-> Linux Module Utilities
    -> Simplified modutils
# 不要选择这个

  继续配置:

-> Linux System Utilities
    -> mdev (17 kb)     # 确保下面的全部选中,默认都是选中的

  使能 busybox 的 unicode 编码以支持中文:

-> Settings
    -> Support Unicode      # 选中
        -> Check $LC_ALL, $LC_CTYPE and $LANG environment variables     # 选中

  配置完成后还需要让busybox 支持中文:

cd /linux/tools/buildroot-2020.02.6/output/build/busybox-1.31.1
vim libbb/printable_string.c

  修改 31~32 行和 45行:

  修改  busybox-1.32.0/libbb/unicode.c  内容,修改 1022 行和 1031 行:

② 编译 busybox 

cd /linux/tools/buildroot-2020.02.6    # 进入 buildroot 源码目录下
make show-targets    # 当前 buildroot 所有 packages

  如果我们想单独编译并安装 busybox 的话执行下面命令即可:

make busybox    # 编译 busybox

  编译完成以后重新编译 buildroot,主要是对其进行打包,输入如下命令: 

make -j8

  编译完成后查看 output/images 目录下的 rootfs.tar 创建时间是否是刚刚编译的,如果不是就删掉 rootfs.tar,然后重新执行“sudo make”重新编译一下即可。 

4. buildroot 第三方软件和库的配置 

① 使能 VSFTPD 服务

   在开发板上搭建 FTP 服务器,这样可以使用 FileZilla 软件直接向开发板拷文件或把开发板文件拷贝到电脑中。

cd /linux/tools/buildroot-2020.02.6
make menuconfig
-> Target packages
    -> Networking applications
        -> [*] vsftpd

② 使能 SSH

  有时候需要远程登录开发板,这个时候就可以通过网络登录,要用到 SSH 服务。

  保存在 configs/stm32mp1_atk_defconfig。

  之后重新编译 buildroot ,用 make -j8 。将 ouput/images/rootfs.tar 拷贝到 nfs目录下的 rootfs 目录中,然后重新解压。 命令如下:

tar -vxf rootfs.tar

  解压完成以后就可以使用 FTP 和 SSH 等相关的软件了,由于 FTP 和 SSH 都是通过网络进行数据传输的,因此需要先配置网络,如果是通过 nfs 挂载的根文件系统,那么网络已经初始化完成了,因此可以直接使用。如果是烧写到 EMMC 里面的,那么就需要先配置网络相关功能。 

4. buildroot 根文件系统测试

① 软件运行测试

  编译的应用软件一般都使用动态库,使用动态库的话应用软件体积就很小,但是得提供库文件,库文件我们已经添加到了根文件系统中。我们编写一个小小的测试软件来测试一下库文件是否工作正常,在根文件系统下创建一个名为“drivers”的文件夹,以后我们学习 Linux 驱动的时候就把所有的实验文件放到这个文件夹里面。 

#include <stdio.h>
#include <unistd.h>

int main(void)
{
    while(1)
    {
        printf("hello world!\r\n");
        sleep(2);
    }
    return 0;
}

  sleep 相当于 Linux 的延时函数,单位为秒,所以 sleep(2)就是延时 2 秒。因为我们要在 ARM 芯片上运行,需要用交叉编译器编译:

arm-none-linux-gnueabihf-gcc hello.c -o hello

  可以使用 file 命令查看文件类型和编码格式:

file hello

  hello 是个 32 位的 LSB 可执行文件, ARM 架构的,并且是动态链接的。将拷贝到 rootfs/dervers 目录下。

  终止 hello 运行按下 CTRL+C,“./hello &”就是让 hello 在后台运行。在后台运行的软件可以使用“kill -9 pid(进程 ID)”命令来关闭掉,首先使用“ps”命令查看要关闭的软件 PID 是多少, ps 命令用于查看所有当前正在运行的进程,并且会给出进程的 PID。

  首先先让 hello 在后台运行,然后输入 ps 查看 PID 是多少,然后再用 kill -9 命令关闭。

./hello &
ps
kill -9 205

  因为 hello 在不断的输出“hello world”所以我们的输入看起来会被打断,其实是没有的,因为我们是输入,而 hello 是输出。在数据流上是没有打断的,只是显示在 SecureCRT 上就好像被打断了。

② 中文字符测试

  在 ubuntu 中向在 rootfs 目录新建一个名为“中文测试”的文件夹,然后在 MobaXterm 下查看中文名能不能显示正确。输入“ls”命令:

setenv bootargs console=ttySTM0,115200 root=/dev/nfs nfsroot=192.168.1.105:/home/alientek/linux/nfs/rootfs,proto=tcp rw ip=192.168.1.106:192.168.1.105:192.168.1.1:255.255.255.0::eth0:off''

③  开机自启动测试

  进入根文件系统的时候会运行/etc/init.d/rcS 这个 shell 脚本,因此我们可以在这个脚本里面添加自启动相关内容。添加完成以后的/etc/init.d/rcS 文件内容如下: 

#!/bin/sh

PATH=/sbin:/bin:/usr/sbin:/usr/bin
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib:/usr/lib
runlevel=S
umask 022
export PATH LD_LIBRARY_PATH runlevel

mount -a
mkdir /dev/pts
mount -t devpts devpts /dev/pts

echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s

# 开机自启动
cd /drivers        # 进入 drivers 目录,因为要启动的软件存放在 drivers 目录下
./hello &          # 以后台方式执行 hello 这个软件
cd /               # 退出 drivers 目录,进入到根目录下

④ 外网连接测试

  测试一下看开发板能不能上网,在 rootfs 中新建文件/etc/resolv.conf,然后在里面输入如下内容: 

nameserver 114.114.114.114
nameserver 192.168.1.1

  nameserver 表示这是个域名服务器,设置了两个域名服务器地址:114.114.114.114 和 192.168.1.1。之后重启开发板。

⑤ depmod 测试

  Linux 驱动的时候需要使用此命令分析模块的依赖性,此命令需要在 busybox 中使能,路径如下: 

-> Linux Module Utilities
    -> [*] depmod

  然后再重新编译,一般将驱动模块放到 lib/modules/5.4.31 目录下,既然当前根文件系统不存在这个目录,那么就手动创建此目录,命令如下: 

mkdir /lib/modules/5.4.31 -p

  系统会自动使用这三个文件。

⑥ vsftpd 测试

  首先需要对vsftpd 进行配置,打开/etc/vsftpd.conf 文件,将下面两行前面的“#”去掉: 

  接下来把文件的所属用户改为 root,输入以下命令:

chown root:root /etc/vsftpd.conf

  我们新建一个用户完成 FTP 登录。

  打开  FileZilla,设置新站点。

  连接就可以完成与开发版的 vsftpd 连接。

⑦ sshd 测试

  SSHD 不需要进行配置,只需要创建一个登陆用户即可。我们需要修改/var/empty目录所属用户以及用户组,输入如下命令: 

chown root:root /var/empty/

  同样的,也可以在 ubuntu 下通过 ssh 命令登录开发板,输入如下命令: 

ssh [email protected]

# 其中 luoxuesong 是登录账号名字,192.168.1.106 是我们自己给开发板设的 IP 地址。用户名和 IP 地址用 @ 连接。
# 输入 exit 退出 SSH 会话

⑧ 创建自启动文件

  默认情况下 buildroot 构建的根文件系统中 rcS 文件内容如下:

  rcS 默认会在/etc/init.d 目录下查找所有以‘S’开头的脚本,然后依次执行这些脚本。所以我们可以自己创建一个以‘S’开头的自启动脚本文件,比如我创建一个名为 Sautorun 的自启动文件,命令如下: 

cd /etc/init.d/ 
touch Sautorun 
chmod 777 Sautorun 

  设置好以后重启开发板,此时 Sautorun 脚本就会被 rcS 调用,进而运行 test 软件。 

⑨ 显示路径

  使用 buildroot 构建的根文件系统启动以后会发现,输入命令的时候命令行前面一直都是“#”,如果我们进入到某个目录的话前面并不会显示当前目录路径。

这个是跟 PS1 环境变量有关,它是用于设置命令提示符格式,格式如下: 

PS1 = ‘命令列表’

命令列表中可选的参数如下:
\!:显示该命令的历史记录编号。
\#:显示当前命令的命令编号。
\$:显示$符作为提示符,如果用户是 root 的话,则显示#号。
\\:显示反斜杠。
\d:显示当前日期。
\h:显示主机名。
\n:打印新行。
\nnn:显示 nnn 的八进制值。
\s:显示当前运行的 shell 的名字。
\t:显示当前时间。
\u:显示当前用户的用户名。
\W:显示当前工作目录的名字。
\w:显示当前工作目录的路径

  我们打开 /etc/profile 文件,文件内容如下所示: 

export PATH="/bin:/sbin:/usr/bin:/usr/sbin"

if [ "$PS1" ]; then
	if [ "`id -u`" -eq 0 ]; then
		export PS1='# '
	else
		export PS1='$ '
	fi
fi

export EDITOR='/bin/vi'

# Source configuration files from /etc/profile.d
for i in /etc/profile.d/*.sh ; do
	if [ -r "$i" ]; then
		. $i
	fi
done
unset i

# 3~9 行是设置 P1 环境变量,但是不建议修改,因为当我们重新编译了 buildroot 并解压后这个文件内容就会被替换。
# 14~17 行是 etc/profile 文件会遍历 etc/profile.d 目录下的 .sh 脚本文件,然后执行。所以我们可以自定义 .sh 脚本文件。

  在/etc/profile.d 目录下新建一个名为“myprofile.sh”的 shell 脚本文件,并且给予此文件可执行权限,命令如下: 

cd /etc/profile.d/ 
touch myprofile.sh 
chmod 777 myprofile.sh 

  最后在 myprofile.sh 里面添加如下代码:

#!/bin/sh

PS1='[\u@\h]:\w$ '
export PS1

  之后重启开发板,之后我们就可以看见当前路径和用户。

⑩ 使能 sysfs debug 目录

  后续调试驱动的时候我们可能要用到/sys/kernel/debug 目录,默认我们没有挂载 debugfs 文件系统,所以/sys/kernel/debug 目录下没有任何文件,挂载方法很简单。 输入以下代码:

mount -t debugfs none /sys/kernel/debug

# 修改完重启

5. 烧写根文件系统到 EMMC 中 

① 根文件系统打包

1、新建 ext4 格式磁盘

  输入如下命令创建 ext4 磁盘: 

cd ~
mkdir /home/alientek/linux/rootfs
cd /home/alientek/linux/rootfs   
dd if=/dev/zero of=rootfs.ext4 bs=1M count=1024 # dd 命令创建一个名为 rootfs.ext4 的磁盘,由于根文件系统比较大,因此 count设置为 1024,也就是根文件系统总空间为 1GB
mkfs.ext4 -L rootfs rootfs.ext4 

# "mkfs.ext4":这是用于创建Ext4文件系统的命令。
# "-L rootfs":这个选项用于设置文件系统的标签,将文件系统的标签设置为"rootfs"。
# "rootfs.ext4":指定要格式化的文件系统所在的设备或文件。在这个例子中,我们使用"rootfs.ext4"作为文件系统。

2、将系统镜像拷贝到 ext4 磁盘

  首先创建一个目录用来挂载前面制作制作出来的 rootfs.ext4:

sudo mkdir /mnt/rootfs

  然后使用 mount 命令将 rootfs.ext4 挂载到 /mnt/rootfs 目录下:

cd /home/alientek/linux/rootfs
mount rootfs.ext4 /mnt/rootfs/

  挂载成功以后就将/home/alientek/linux/nfs/rootfs 目录下的所有根文件系统文件拷贝到/mnt/bootfs 目录下,命令如下: 

cd /home/alientek/linux/nfs/rootfs/
sudo cp * /mnt/rootfs/ -drf

  umount 卸载 /mnt/rootfs:

sudo umount /mnt/rootfs

② 烧写到 EMMC

  根文件系统 rootfs.ext4 烧写到开发板的 EMMC里面,使用 STM32CubeProgrammer 软件完成此操作,并修改 Flashlayout。

③ EMMC 启动测试

  烧写完成后,用 uboot 命令行,设置 bootcmd 和 bootargs 两个环境变量:

setenv bootcmd 'ext4load mmc 1:2 c2000000 uImage;ext4load mmc 1:2 c4000000 stm32mp157datk.dtb;bootm c2000000 - c4000000'
setenv bootargs 'console=ttySTM0,115200 root=/dev/mmcblk1p3 rootwait rw'
saveenv
boot

  完成后系统之启动了lo网卡,eh0并没有启动,输入以下命令:

ifconfig eth0 up     # 打开 eth0 网卡

  但是此时开发板网络还不能使用,因为我们还没有配置 eth0 网卡地址信息输入以下命令,如果开发板连接交换机或电脑需要输入以下命令:w

ifconfig eth0 up                                      # 打开 eth0
ifconfig eth0 192.168.1.250 netmask 255.255.255.0     # 设置 IP 地址

  如果开发版直连路由器,直接输入 " udhcpc "命令直接从路由器获得动态IP地址即可。

猜你喜欢

转载自blog.csdn.net/qq_45475497/article/details/134940646
今日推荐