Linux根文件系统构建
直接参考【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.81
本文仅作为个人笔记使用,方便进一步记录自己的实践总结。
Linux“三巨头”已经完成了 2 个了,就剩最后一个 rootfs(根文件系统)了,本章我们就来学习一下根文件系统的组成以及如何构建根文件系统。这是 Linux 移植的最后一步,根文件系统构建好以后就意味着我们已经拥有了一个完整的、可以运行的最小系统。以后我们就在这个最小系统上编写、测试 Linux 驱动,移植一些第三方组件,逐步的完善这个最小系统。最终得到一个功能完善、驱动齐全、相对完善的操作系统。
根文件系统简介
根文件系统一般也叫做 rootfs,那么什么叫根文件系统?看到“文件系统”这四个字,很多人,包括我第一反应就是 FATFS、FAT、EXT4、YAFFS 和 NTFS 等这样的文件系统。在这里,根文件系统并不是 FATFS 这样的文件系统代码,EXT4 这样的文件系统代码属于 Linux 内核的一部分。Linux 中的根文件系统更像是一个文件夹或者叫做目录(在我看来就是一个文件夹,只不过是特殊的文件夹),在这个目录里面会有很多的子目录。根目录下和子目录中会有很多的文件,这些文件是 Linux 运行所必须的,比如库、常用的软件和命令、设备文件、配置文件等等。
以后我们说到文件系统,如果不特别指明,统一表示根文件系统。对于根文件系统专业的解释,百度百科上是这么说的(原谅我把百度百科引用为专业解释,因为我实在找不到根文件系统的最初定义,也不要建议我到哪些 404 网站去查找,毕竟我胖,我怕翻到一般梯子不稳把我摔丑了):
根文件系统首先是内核启动时所 mount(挂载)的第一个文件系统,内核代码映像文件保存在根文件系统中,而系统引导启动程序会在根文件系统挂载之后从中把一些基本的初始化脚本和服务等加载到内存中去运行。
百度百科上说内核代码镜像文件保存在根文件系统中,但是我们嵌入式 Linux 并没有将内核代码镜像保存在根文件系统中,而是保存到了其他地方。比如 NAND Flash 的指定存储地址、EMMC 专用分区中。根文件系统是 Linux 内核启动以后挂载(mount)的第一个文件系统,然后从根文件系统中读取初始化脚本,比如 rcS,inittab 等。根文件系统和 Linux 内核是分开的,单独的 Linux 内核是没法正常工作的,必须要搭配根文件系统。如果不提供根文件系统,Linux 内核在启动的时候就会提示内核崩溃(Kernel panic)的提示,这个在 37.2.4 小节已经说过了。
根文件系统的这个“根”字就说明了这个文件系统的重要性,它是其他文件系统的根,没有这个“根”,其他的文件系统或者软件就别想工作。比如我们常用的 ls、mv、ifconfig 等命令其实就是一个个小软件,只是这些软件没有图形界面,而且需要输入命令来运行。这些小软件就保存在根文件系统中,这些小软件是怎么来的呢?这个就是我们本章教程的目的,教大家来构建自己的根文件系统,这个根文件系统是满足 Linux 运行的最小根文件系统,后续我们可以根据自己的实际工作需求不断的去填充这个最小根文件系统,最终使其成为一个相对完善的根文件系统。
在构建根文件系统之前,我们先来看一下根文件系统里面大概都有些什么内容,以 Ubuntu为例,根文件系统的目录名字为‘/’,没看错就是一个斜杠,所以输入如下命令就可以进入根目录中:
cd / //进入根目录
进入根目录以后输入“ls”命令查看根目录下的内容都有哪些,结果如图 38.1.1 所示:
图 38.1.1 中根目录下子目录和文件不少,但是这些都是 Ubuntu 所需要的,其中有很多子目录和文件我们嵌入式 Linux 是用不到的,所以这里就讲解一些常用的子目录:
1、/bin 目录
看到“bin”大家应该能想到 bin 文件,bin 文件就是可执行文件。所以此目录下存放着系统需要的可执行文件,一般都是一些命令,比如 ls、mv 等命令。此目录下的命令所有的客户都可以使用。
2、/dev 目录
dev 是 device 的缩写,所以此目录下的文件都是和设备有关的,此目录下的文件都是设备文件。在 Linux 下一切皆文件,即使是硬件设备,也是以文件的形式存在的,比如/dev/ttymxc0(I.MX6ULL 根目录会有此文件)就表示 I.MX6ULL 的串口 0,我们要想通过串口 0发送或者接收数据就要操作文件/dev/ttymxc0,通过对文件/dev/ttymxc0 的读写操作来实现串口0 的数据收发。
3、/etc 目录
此目录下存放着各种配置文件,大家可以进入 Ubuntu 的 etc 目录看一下,里面的配置文件非常多!但是在嵌入式 Linux 下此目录会很简洁。
4、/lib 目录
lib 是 library 的简称,也就是库的意思,因此此目录下存放着 Linux 所必须的库文件。这些库文件是共享库,命令和用户编写的应用程序要使用这些库文件。
5、/mnt 目录
临时挂载目录,一般是空目录,可以在此目录下创建空的子目录,比如/mnt/sd、/mnt/usb,这样就可以将 SD 卡或者 U 盘挂载到/mnt/sd 或者/mnt/usb 目录中。
6、/proc 目录
此目录一般是空的,当 Linux 系统启动以后会将此目录作为 proc 文件系统的挂载点,proc是个虚拟文件系统,没有实际的存储设备。proc 里面的文件都是临时存在的,一般用来存储系统运行信息文件。
7、/usr 目录
要注意,usr 不是 user 的缩写,而是 Unix Software Resource 的缩写,也就是 Unix 操作系统软件资源目录。这里有个小知识点,那就是 Linux 一般被称为类 Unix 操作系统,苹果的 MacOS也是类 Unix 操作系统。关于 Linux 和 Unix 操作系统的渊源大家可以直接在网上找 Linux 的发展历史来看。既然是软件资源目录,因此/usr 目录下也存放着很多软件,一般系统安装完成以后此目录占用的空间最多。
8、/var 目录
此目录存放一些可以改变的数据。
9、/sbin 目录
此目录页用户存放一些可执行文件,但是此目录下的文件或者说命令只有管理员才能使用,主要用户系统管理。
10、/sys 目录
系统启动以后此目录作为 sysfs 文件系统的挂载点,sysfs 是一个类似于 proc 文件系统的特殊文件系统,sysfs 也是基于 ram 的文件系统,也就是说它也没有实际的存储设备。此目录是系统设备管理的重要目录,此目录通过一定的组织结构向用户提供详细的内核数据结构信息。
11、/opt
可选的文件、软件存放区,由用户选择将哪些文件或软件放到此目录中。
关于 Linux 的根目录就介绍到这里,接下来的构建根文件系统就是研究如何创建上面这些子目录以及子目录中的文件。
BusyBox 构建根文件系统
BusyBox 简介
上一小节说了,根文件系统里面就是一堆的可执行文件和其他文件组成的?难道我们得一个一个的从网上去下载这些文件?显然这是不现实的!那么有没有人或者组织专门干这个事呢?他们负责“收集”这些文件,然后将其打包,像我们这样的开发者可以直接拿来用。答案是有的,它就叫做 BusyBox!其名字分为“Busy”和“Box”,也就是忙碌的盒子。盒子是用来放东西的,忙碌的是因为它要提供根文件系统所需的文件,所以忙碌。BusyBox 是一个集成了大量的 Linux 命令和工具的软件,像 ls、mv、ifconfig 等命令 BusyBox 都会提供。BusyBox 就是一个大的工具箱,这个工具箱里面集成了 Linux 的许多工具和命令。一般下载 BusyBox 的源码,然后配置 BusyBox,选择自己想要的功能,最后编译即可。BusyBox 可以在其官网下载到,官网地址为:
官网比较简陋,如图38.2.1.1 所示:
在官网左侧的“Get BusyBox”栏有一行“Download Source”,点击“Download Source”即可打开 BusyBox 的下载页,如图 38.2.1.2 所示:
从图 38.2.1.2 可以看出,目前最新的 BusyBox 版本是 1.31.0,不过我建议大家使用我们开发板光盘里面提供的 1.29.0 版本的 BusyBox。因为笔者测试 1.29.0 版本目前还没有出现任何问题,路径为:1、例程源码->6、BusyBox 源码->busybox-1.29.0.tar.bz2,BusyBox 准备好以后就可以构建根文件系统了。
编译 BusyBox 构建根文件系统
一般我们在 Linux 驱动开发的时候都是通过 nfs 挂载根文件系统的,当产品最终上市开卖的时候才会将根文件系统烧写到 EMMC 或者 NAND 中。所以要在 4.2.1 小节中设置的 nfs 服务器目录中创建一个名为 rootfs 的子目录(名字大家可以随意起,为了方便就用了 rootfs),比如我的电脑中“/home/zuozhongkai/linux/nfs”就是我设置的 NFS 服务器目录,使用如下命令创建名为 rootfs 的子目录:
mkdir rootfs
创建好的 rootfs 子目录就用来存放我们的根文件系统了。
将 busybox-1.29.0.tar.bz2 发送到 Ubuntu 中,存放位置大家随便选择。然后使用如下命令将其解压:
tar -vxjf busybox-1.29.0.tar.bz2
解压完成以后进入到 busybox-1.29.0 目录中,此目录中的文件和文件夹如图 38.2.2.1 所示:
更多参考正点原子手册。
具体参看正点原子开发手册。
配置 busybox
根我们编译 Uboot、Linux kernel 一样,我们要先对 busybox 进行默认的配置,有以下几种 配置选项:
- defconfig,缺省配置,也就是默认配置选项。
- allyesconfig,全选配置,也就是选中 busybox 的所有功能。
- allnoconfig,最小配置。
我们一般使用默认配置即可,因此使用如下命令先使用默认配置来配置一下 busybox:
make defconfig
编译 busybox
配置好 busybox 以后就可以编译了,我们可以指定编译结果的存放目录,我们肯定要将编 译结果存放到前面创建的 rootfs 目录中,输入如下命令:
make
make install CONFIG_PREFIX=/home/zuozhongkai/linux/nfs/rootfs
COFIG_PREFIX指 定 编 译 结 果 的 存 放 目 录 , 比 如 我 存 放 到
“/home/zuozhongkai/linux/nfs/rootfs”目录中,等待编译完成
编译完成以后会在 busybox 的所有工具和文件就会被安装到 rootfs 目录中,rootfs 目录内容如图 38.2.2.9 所示:
从图 38.2.2.9 可以看出,rootfs 目录下有 bin、sbin 和 usr 这三个目录,以及 linuxrc 这个文件。前面说过 Linux 内核 init 进程最后会查找用户空间的 init 程序,找到以后就会运行这个用户空间的 init 程序,从而切换到用户态。如果 bootargs 设置 init=/linuxrc,那么 linuxrc 就是可以作为用户空间的 init 程序,所以用户态空间的 init 程序是 busybox 来生成的。
busybox 的工作就完成了,但是此时的根文件系统还不能使用,还需要一些其他的文件,我
们继续来完善 rootfs。
更多参看正点原子开发手册。
rcS 是个 shell 脚本,Linux 内核启动以后需要启动一些服务,而 rcS 就是规定启动哪些文件的脚本文件。
开机自启动测试
在 38.5.1 小节测试 hello 软件的时候都是等 Linux 启动进入根文件系统以后手动输入命令“./hello”来完成的。我们一般做好产品以后都是需要开机自动启动相应的软件,本节我们就hello 这个软件为例,讲解一下如何实现开机自启动。前面我们说过了,进入根文件系统的时候会运行/etc/init.d/rcS 这个 shell 脚本,因此我们可以在这个脚本里面添加自启动相关内容。添加完成以后的/etc/init.d/rcS 文件内容如下:
示例代码 38.5.3.1 rcS 文件代码 1 #!/bin/sh 2 PATH=/sbin:/bin:/usr/sbin:/usr/bin 3 LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib:/usr/lib 4 runlevel=S 5 umask 022 6 export PATH LD_LIBRARY_PATH runlevel 7 8 mount -a 9 mkdir /dev/pts 10 mount -t devpts devpts /dev/pts 11 12 echo /sbin/mdev > /proc/sys/kernel/hotplug 13 mdev -s 14 15 #开机自启动 16 cd /drivers 17 ./hello & 18 cd /
第 16 行,进入 drivers 目录,因为要启动的软件存放在 drivers 目录下。
第 17 行,以后台方式执行 hello 这个软件。
第 18 行,退出 drivers 目录,进入到根目录下。
自启动代码添加完成以后就可以重启开发板
补充
动态库和静态库
参考
详解Linux下静态库/动态库的生成和使用(含代码示例和操作流程)&&动态库和静态库的区别_生成静态库的过程及作用-CSDN博客
更多待补充。
Initramfs
是内核启动但还未访问真正的根文件系统之前用到的一个临时的根文件系统
Initramfs 原理和实践 - wipan - 博客园 (cnblogs.com)
initrd和initramfs实操 - 小满的博客 - 博客园 (cnblogs.com)
initrd
linux 发行版必须适应各种不同的硬件架构,将所有的驱动编译进内核是不现实的,根文件系统可能保存到各种存储设备上包括scsi、sata,u-disk等等,但是又必须先加载他们的驱动才能加载根文件系统。
为了解决这一矛盾,于是出现了基于ramdisk的initrd( bootloader initialized RAM disk )。Initrd是一个被压缩过的小型根目录,这个目录中包含了启动阶段中必须的驱动模块,可执行文件和启动脚本。当系统启动的时候,bootloader会把initrd文件读到内存中,然后把initrd文件在内存中的起始地址和大小传递给内核。内核在启动初始化过程中会解压缩initrd文件,然后将解压后的initrd挂载为根目录,然后执行根目录中的/linuxrc脚本。
initrd 的英文含义是 boot loader iniTIalized RAM disk,就是由 boot loader 初始化的内存盘。在 linux内核启动前, boot loader 会将存储介质中的 initrd 文件加载到内存,内核启动时会在访问真正的文件系统前先访问该内存中的 initrd 文件系统。
initramfs
在linux2.5中出现了initramfs,它的作用和initrd类似,只是和内核编译成一个文件(该initramfs是经过gzip压缩后的cpio格式的数据文件),该cpio格式的文件被链接进了内核中特殊的数据段.init.ramfs上,其中全局变量__initramfs_start 和 __initramfs_end分别指向这个数据段的起始地址和结束地址。内核启动时会对.init.ramfs段中的数据进行解压,然后使用它作为临时的根文件系统。
源码自带资料
不管是UBOOT还是kernel或者根文件系统等等,一般都会自带一些说明,可以在源码里找一找,比如README.txt文档;然后就是documents;除了文档,还会有一些程序的examples、demo、quickstart等等;也可能会自带一些模块驱动drivers;总之,多看看源码。
原文地址:https://blog.csdn.net/qq_28576837/article/details/142411740
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!