当前位置:首页 > 公众号精选 > 嵌入式云IOT技术圈
[导读]关注、星标嵌入式云IOT技术圈,精彩及时送达来源|Github-EmbeddedSystem1.根文件系统原理1.1为什么需要根文件系统init进程的应用程序在根文件系统上根文件系统提供了根目录/内核启动后的应用层配置(etc目录)在根文件系统上。几乎可以认为:发行版=内核roo...

嵌入式云IOT技术圈" data-alias="" data-signature="分享单片机、嵌入式Linux/Android、物联网等相关产品项目开发经验,打造最硬核嵌入式技术公众号。" data-from="0">

关注、星标嵌入式云IOT技术圈,精彩及时送达

来源 | Github-EmbeddedSystem

1. 根文件系统原理

1.1 为什么需要根文件系统

  • init进程的应用程序在根文件系统上
  • 根文件系统提供了根目录 /
  • 内核启动后的应用层配置( etc 目录)在根文件系统上。几乎可以认为:发行版=内核 rootfs
  • shell命令程序在根文件系统上,比如 ls、cd 等命令
一套linux体系,只有内核本身是不能工作的,必须要 rootfs 上的 etc 目录下的配置文件、/bin /sbin 等目录下的 shell 命令,还有 /lib 目录下的库文件等···)相配合才能工作 。

1.2 根文件系统的实质

  • 根文件系统是特殊用途的文件系统。
  • 根文件系统也必须属于某种文件系统格式。rootfstype=
存储设备(块设备,像硬盘、flash等)是分块(扇区)的,物理上底层去访问存储设备时是按照块号(扇区号)来访问的。

文件系统是一些代码,是一套软件,这套软件的功能就是对存储设备的扇区进行管理,将这些扇区的访问变成了对目录和文件名的访问。我们在上层按照特定的目录和文件名去访问一个文件时,文件系统会将这个目录 文件名转换成对扇区号的访问。不同的文件系统的差异就在于对这些扇区的管理策略和方法不同,譬如坏块管理、碎片管理。

1.3 根文件系统的形式

  • 使用专用工具软件制作的可供烧录的镜像文件
  • 镜像中包含了根文件系统中的所有文件
  • 烧录此镜像类似于对相应分区格式化。
  • 镜像文件系统具有一定的格式,格式是内化的,跟文件名后缀是无关的。
以文件夹形式构成的文件系统:

  • 根文件系统其实就是一个包含特定内容的文件夹
  • 根文件系统可由任何一个空文件夹添加必要文件构成而成
  • 根文件系统的雏形就是在开发主机中构造的文件夹形式的
镜像文件形式的根文件系统主要目的是用来烧录到块设备上,设备上的内核启动后去挂载它。镜像文件形式的根文件系统是由文件夹形式的根文件系统使用专用的镜像制作工具制作而成的。

最初在开发主机中随便 mkdir 创建了一个空文件夹,然后向其中添加一些必要的文件(包括etc目录下的运行时配置文件、/bin 等目录下的可执行程序、/lib目录下的库文件等···)后就形成了一个文件夹形式的 rootfs。然后这个文件夹形式的 rootfs 可以被 kernel 通过 nfs 方式来远程挂载使用,但是不能用来烧录块设备。我们为了将这个 rootfs 烧录到块设备中于是用一些专用的软件工具将其制作成可供烧录的一定格式的根文件系统镜像。

文件夹形式的 rootfs 是没有格式的,制作成镜像后就有了一定的 rootfs 格式了,格式是由我们的镜像制作过程和制作工具来决定的。每一种格式的镜像制作工具的用法都不同。

1.4 自己制作简单的根文件系统

1.4.1 动手制作ext3格式的根文件系统

  • mke2fs介绍
mke2fs 是一个应用程序,在 ubuntu 中默认是安装了的。这个应用程序就是用来制作 ext2、ext3、ext4 等格式的根文件系统的。一般用来制作各种不同格式的 rootfs 的应用程序的名字都很相似,类似于 mkfs.xxx(譬如用来制作 ext2 格式的 rootfs 的工具叫 mkfs.ext2、用来制作 jffs2 格式的 rootfs 的工具就叫 mkfs.jffs2)。ubuntu14.04中的 mkfs.ext2 等都是 mke2fs 的符号链接而已。

  1. 创建rootfs.ext2文件并且将之挂载到一个目录下方便访问它 《参考资料:http://blog.csdn.net/zhengmeifu/article/details/24174513》
dd if=/dev/zero of=rootfs.ext2 bs=1024 count=2048
losetup  /dev/loop1 rootfs.ext2
mke2fs -m 0 /dev/loop1 2048
mount -t ext2 /dev/loop1 ./rootfs/
  1. 我们向镜像中写入一个普通文件linuxrc。这个文件就会成为我们制作的镜像中的/linuxrc。内核挂载了这个镜像后就会尝试去执行/linuxrc。然后执行时必然会失败。我们将来实验看到的现象就应该是:挂载成功,执行/linuxrc失败。

  2. 将来真正去做有用的rootfs时,就要在这一步添加真正可以执行的 linuxrc 程序,然后还要添加别的 /lib 目录下的库文件,/etc目录下的配置文件等。

  3. 卸载掉,然后镜像就做好了。

umount /dev/loop1
losetup -d /dev/loop1

1.4.2 nfs 方式启动 rootfs

  • 什么是 nfs?
nfs 是一种网络通讯协议,由服务器和客户端构成。利用 nfs 协议可以做出很多直接性应用,我们这里使用 nfs 主要是做 rootfs 挂载。开发板中运行 kernel 做 nfs 客户端,主机 ubuntu 中搭建 nfs 服务器。在主机 ubuntu 的 nfs 服务器中导出我们制作的文件夹形式的 rootfs 目录,则在客户端中就可以去挂载这个文件夹形式的 rootfs 进而去启动系统。

  • 搭建nfs服务器
配置内核以支持 nfs 作为 rootfs,设置 nfs 启动方式的 bootargs,在 menuconfig 中配置支持 nfs 启动方式。

  • 总结
nfs 方式启动相当于开发板上的内核远程挂载到主机上的 rootfs,nfs 方式启动不用制作 rootfs 镜像。nfs 方式不适合真正的产品,一般作为产品开发阶段调试使用。

  • uboot 中的启动参数设置
setenv bootargs root=/dev/nfs nfsroot=192.168.1.104:/home/SummerGift/work/samsung_kernel/rootfs/rootfs ip=192.168.1.88:192.168.1.104:192.168.1.1:255.255.255.0::eth0:off  init=/linuxrc console=ttySAC2,115200 
  • 测试 nfs 挂载
mount -t nfs -o nolock 192.168.1.104:/home/SummerGift/work/samsung_kernel/rootfs/rootfs  /opt

1.4.3 关于 linuxrc

  • /linuxrc 是一个可执行的应用程序 /linuxrc 是应用层的,和内核源码一点关系都没有,/linuxrc 在开发板当前内核系统下是可执行的。因此在 ARM SoC 的 linux 系统下,这个应用程序就是用 arm-linux-gcc 编译链接的;如果是在 PC 机 linux 系统下,那么这个程序就是用 gcc 编译连接的。
/linuxrc如果是静态编译连接的那么直接可以运行;如果是动态编译连接的那么我们还必须给他提供必要的库文件才能运行。但是因为我们 /linuxrc 这个程序是由内核直接调用执行的,因此用户没有机会去导出库文件的路径,因此实际上这个 /linuxrc 没法动态连接,一般都是静态连接的。

  • /linuxrc执行时引出用户界面 操作系统启动后在一系列的自己运行配置之后,最终会给用户一个操作界面(也许是 cmdline,也许是 GUI),这个用户操作界面就是由 /linuxrc 带出来的。
用户界面等很多事并不是在 /linuxrc 程序中负责的,用户界面有自己专门的应用程序,但是用户界面的应用程序是直接或者间接的被 /linuxrc 调用执行的。用户界面程序和其他的应用程序就是进程2、3、4·····,这就是我们说的进程1(init进程,也就是 /linuxrc)是其他所有应用程序进程的祖宗进程。

  • /linuxrc 负责系统启动后的配置 就好像一个房子建好之后不能直接住,还要装修一样;操作系统启动起来后也不能直接用,要配置下。操作系统启动后的应用层的配置(一般叫运行时配置,英文简写 etc)是为了让我们的操作系统用起来更方便,更适合我个人的爱好或者实用性。

  • /linuxrc在嵌入式linux中一般就是busybox busybox 是一个 C 语言写出来的项目,里面包含了很多 .c 文件和 .h 文件。这个项目可以被配置编译成各个平台下面可以运行的应用程序。我们如果用 arm-linux-gcc 来编译busybox就会得到一个可以在我们开发板 linux 内核上运行的应用程序。

busybox 这个程序开发出来就是为了在嵌入式环境下构建 rootfs 使用的,也就是说他就是专门开发的 init 进程应用程序。

busybox 为当前系统提供了一整套的 shell 命令程序集。譬如 vi、cd、mkdir、ls 等。在桌面版的linux 发行版(譬如ubuntu、redhat、centOS等)中 vi、cd、ls 等都是一个一个的单独的应用程序。但是在嵌入式 linux 中,为了省事我们把 vi、cd 等所有常用的 shell 命令集合到一起构成了一个shell 命令包,起名叫 busybox。

1.4.4 rootfs 中的其他目录

  • /linuxrc

  • dev目录下的设备文件


在linux中一切皆是文件,因此一个硬件设备也被虚拟化成一个设备文件来访问,在linux系统中/dev/xxx就表示一个硬件设备,我们要操作这个硬件时就是open打开这个设备文件,然后read/write/ioctl操作这个设备,最后close关闭这个设备。在最小 rootfs 中 /dev 目录也是不可少的,这里面有一两个设备文件是 rootfs 必须的。

  • sys和proc目录
在最小 rootfs 中也是不可省略的,但是这两个只要创建了空文件夹即可,里面是没东西的,也不用有东西。这两个目录也是和驱动有关的。属于linux中的虚拟文件系统。

  • usr是系统的用户所有的一些文件的存放地,这个东西将来 busybox 安装时会自动生成。

  • etc 目录中的所有文件全部都是运行时配置文件。/etc 目录下的所有配置文件会直接或者间接的被 /linuxrc 所调用执行,完成操作系统的运行时配置。etc 目录是制作 rootfs 的关键,所以后面下一个课程专门讲这个 etc 目录。

  • lib 目录也是 rootfs 中很关键的一个,不能省略的一个。lib目录下放的是当前操作系统中的动态和静态链接库文件。我们主要是为了其中的动态链接库。

2. 用 busybox 制作一个简单的 rootfs

2.1 移植 busybox 到开发板

  • busybox源码下载
busybox 是一个开源项目,所以源代码可以直接从网上下载。版本差异不大,版本新旧无所谓。下载busybox可以去 linuxidc 等镜像网站,也可以去 www.busybox.net官方网站下载。

  • 修改Makefile
ARCH = arm
CROSS_COMPILE = /usr/local/arm/arm-2009q3/bin//arm-none-linux-gnueabi-
  • make menuconfig 进行配置
Busybox Settings--->
 Build Options--->
  [*]Build BusyBox as a static binary(no shared libs)

Busybox Library Tuning--->
 [*]vi-style line editing commands
 [*]Fancy shell prompts

Linux Module Utilities--->
 [ ]Simplified modutils
 [*]insmod
 [*]rmmod
 [*]lsmod
 [*]modprobe
 [*]depmod

Linux System Utilities--->[*]mdev
 [*]Support /etc/mdev.conf
 [*]Support subdirs/symlinks
 [*]Support regular expressions substitutions when renaming dev
 [*]Support command execution at device addition/removal
 [*]Support loading of firmwares
  • make 然后 make install
make 编译,如果有错误解决之,make install 执行的时候其实是在执行 busybox 顶层目录下的一个目标 install。

make install 在所有的 linux 下的软件中作用都是安装软件。在传统的 linux 系统中安装软件时都是选择源代码方式安装的。我们下载要安装的软件源代码,然后配置、编译、安装。make install的目的就是将编译生成的可执行程序及其依赖的库文件、配置文件、头文件安装到当前系统中指定(一般都可以自己指定安装到哪个目录下,如果不指定一般都有个默认目录)的目录下。

  • 设置 bootargs 挂载添加了busybox移植的rootfs
之前建立了一个空的文件夹然后自己 touch linuxrc 随便创建了一个不能用的 /linuxrc 然后去 nfs 挂载 rootfs,实验结果是:挂载成功,执行 /linuxrc 失败。现在我们移植了 busybox 后 /linuxrc 就可以用了,然后再次去 nfs 挂载这个 rootfs。预计看到的效果是:挂载成功,执行/linuxrc也能成功。

uboot 的 bootargs 设置成:

setenv bootargs root=/dev/nfs nfsroot=192.168.1.141:/root/porting_x210/rootfs ip=192.168.1.10:192.168.1.141:192.168.1.1:255.255.255.0::eth0:off  init=/linuxrc console=ttySAC2,115200 
挂载成功,执行 /linuxrc(也就是busybox)成功,但是因为找不到 /etc/init.d/rcS 和 /dev/tty2 等文件所以一直在打印错误提示信息,但是其实有进入命令行。

2.2 inittab 详解

  • 添加一个典型的inittab
将一个典型的 inittab 文件复制到我们制作的 rootfs 的根目录下的 /etc/ 目录下,再次启动内核挂载这个 rootfs 看效果,实验现象是成功启动并且挂载 rootfs 进入了控制台命令行。当前制作的最小rootfs 成功了。

  • inittab格式解析
inittab 的工作原理就是被 /linuxrc(也就是busybox)执行时所调用起作用。

inittab 在 /etc 目录下,所以属于一个运行时配置文件,是文本格式的(内容是由一系列的遵照一个格式组织的字符组成的),实际工作的时候 busybox 会(按照一定的格式)解析这个 inittab 文本文件,然后根据解析的内容来决定要怎么工作。

busybox 究竟如何完成解析并且解析结果如何去工作(busybox 中实现 /etc/inittab 的原理)并不是我们的目标,我们的重点是 inittab 的格式究竟怎样的?我们看到一个 inittab 后怎么去分析这个inittab 对启动的影响。inittab 的格式在 busybox 中定义的。

  • 常见的配置项
第一个:#开始的行是注释 第二个:冒号在里面是分隔符,分隔开各个部分。第三个:inittab内容是以行为单位的,行与行之间没有关联,每行都是一个独立的配置项,每一个配置项表示一个具体的含义。第四个:每一行的配置项都是由3个冒号分隔开的4个配置值共同确定的。这四个配置值就是id:runlevels:action:process。值得注意是有些配置值可以空缺,空缺后冒号不能空缺,所以有时候会看到连续2个冒号。第五个:每一行的配置项中4个配置值中最重要的是 action 和 process,action 是一个条件/状态,process 是一个可被执行的程序的 pathname。合起来的意思就是:当满足 action 的条件时就会执行process 这个程序。

理解 inittab 的关键就是明白“当满足 action 的条件时就会执行 process 这个程序。” 分析 busybox的源代码就会发现,busybox 最终会进入一个死循环,在这个死循环中去反复检查是否满足各个action 的条件,如果某个 action 的条件满足就会去执行对应的 process。

3. busybox 源码分析

3.1 分析 busybox 启动状况

分析一个程序,不管多庞大还是小,最好的路线都是按照程序运行时的逻辑顺序来。所以找到一个程序的入口至关重要。主函数main函数就是整个程序的入口,这种情况适应于操作系统下工作的应用程序的情况。

在 uboot 和 linux kernel 这两个大的 C 语言的项目中,main函数都没有,都不是入口。在我们这种裸机程序中入口不是 main 函数,而是由连接脚本来指定的。

busybox 是 linux 启动起来后工作的一个应用程序,因此其中必然有 main 函数,而且 main 就是入口。

3.2 busybox 中 main 函数全解析

busybox 入口就是 main 函数,其中有很多个 main 但是只有一个起作用了,其他的是没起作用的。真正的busybox工作时的入口是 libbb/appletlib.c 中的 main 函数。

busybox中有很多 xxx_main 函数,这些 main 函数每一个都是 busybox 支持的一个命令的真正入口。例如 ls_main 函数就是 busybox 当作 ls 函数使用时的入口程序。ls 或者 cd 等命令其实都是 busybox 一个程序,但是实际执行时的效果却是各自的效果。

busybox 每次执行时都是先执行其 main,在 main 函数中识别(靠 main 函数的传参 argv[0] 来识别)我们真正要执行的函数(譬如ls)然后去调用相应的xxx_main(譬如ls_main)来具体实现这个命令。

3.3 inittab 解析与执行

inittab 的解析是在 busybox/init/init.c/init_main 函数中。执行逻辑是:先通过 parse_inittab 函数解析 /etc/inittab(解析的重点是将 inittab 中的各个 action 和 process 解析出来),然后后面先直接执行 sysinit 和 wait 和 once(注意这里只执行一遍),然后在 while(1) 死循环中去执行 respwan 和 askfirst。

3.4 busybox 的体积优势原理

busybox 实际上就是把 ls、cd、mkdir 等很多个 linux 中常用的 shell 命令集成在一起了。集成在一起后有一个体积优势:就是 busybox 程序的大小比 busybox 中实现的那些命令的大小加起来要小很多。

busybox 体积变小的原因主要有2个:

  • 第一个是 busybox 本身提供的 shell 命令是阉割版的(busybox 中的命令支持的参数选项比发行版中要少,譬如ls在发行版中可以有几十个 -x,但是在 busybox 中只保留了几个常用的选项,不常用的都删除掉了)

  • 第二个是 busybox 中因为所有的命令的实现代码都在一个程序中实现,而各个命令中有很多代码函数都是通用的(譬如 ls 和 cd、mkdir 等命令都会需要去操作目录,因此在 busybox 中实现目录操作的函数就可以被这些命令共用),共用会降低重复代码出现的次数,从而减少总的代码量和体积。

busybox 的体积优势是嵌入式系统本身的要求和特点造成的。

4. rcS 文件分析与实战

4.1 rcS 文件介绍

/etc/init.d/rcS 文件是linux的运行时配置文件中最重要的一个,其他的一些配置都是由这个文件引出来的。这个文件可以很复杂也可以很简单,里面可以有很多的配置项。

  • PATH=xxx
首先从shell脚本的语法角度分析,这一行定义了一个变量PATH,值等于后面的字符串,后面用export导出了这个PATH,那么PATH就变成了一个环境变量。

PATH 这个环境变量是 linux 系统内部定义的一个环境变量,含义是操作系统去执行程序时会默认到PATH 指定的各个目录下去寻找。如果找不到就认定这个程序不存在,如果找到了就去执行它。将一个可执行程序的目录导出到 PATH,可以让我们不带路径来执行这个程序。

  • rcS 中为什么要先导出 PATH?
因为我们希望一旦进入命令行下时,PATH 环境变量中就有默认的 /bin /sbin /usr/bin /usr/sbin 这几个常见的可执行程序的路径,这样我们进入命令行后就可以 ls、cd 等直接使用了。

为什么rcS 文件还没添加,系统启动就有了 PATH 中的值?原因在于 busybox 自己用代码硬编码为我们导出了一些环境变量,其中就有 PATH。

  • runlevel=
runlevel也是一个shell变量,并且被导出为环境变量,runlevel=S表示将系统设置为单用户模式。

  • umask=
umask 是 linux 的一个命令,作用是设置 linux 系统的 umask 值。umask值决定当前用户在创建文件时的默认权限。

  • mount -a
mount -a 是挂载所有的应该被挂载的文件系统,在 busybox中 mount -a 时 busybox 会去查找一个文件 /etc/fstab 文件,这个文件按照一定的格式列出来所有应该被挂载的文件系统(包括了虚拟文件系统)

  • mdev
mdev 是 udev 的嵌入式简化版本,udev/mdev 是用来配合 linux 驱动工作的一个应用层的软件,udev/mdev 的工作就是配合 linux 驱动生成相应的 /dev 目录下的设备文件。

在 rcS 文件中没有启动 mdev 的时候,/dev 目录下启动后是空的。在 rcS 文件中添加上 mdev 有关的 2 行配置项后,再次启动系统后发现 /dev 目录下生成了很多的设备驱动文件。(4)/dev目录下的设备驱动文件就是mdev生成的,这就是mdev的效果和意义。

  • hostname
hostname 是 linux 中的一个 shell 命令。命令(hostname xxx)执行后可以用来设置当前系统的主机名为 xxx,直接 hostname 不加参数可以显示当前系统的主机名。

/bin/hostname -F /etc/sysconfig/HOSTNAME -F 来指定了一个主机名配置文件(这个文件一般文件名叫 hostname 或者 HOSTNAME)

  • ifconfig
有时候我们希望开机后进入命令行时ip地址就是一个指定的 ip 地址(譬如192.168.1.30),这时候就可以在 rcS 文件中 ifconfig eth0 192.168.1.88

4.2 rcS 文件测试问题记录

  • PATH
本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

为了满足日益增长的数据处理需求,铁威马NAS推出了全新的性能巅峰2024年旗舰之作F4-424 Pro,并搭载了最新的操作系统--TOS 6。这款高效办公神器的问世,无疑将为企业和专业人士带来前所未有的便捷与效率。

关键字: 存储 Linux 服务器

2024年4月11日,中国——意法半导体的ST25R100近距离通信(NFC)读取器芯片独步业界,集先进的技术功能、稳定可靠的通信连接和低廉的成本价格于一身,在大规模制造的消费电子和工控设备内,可以提高非接触式互动功能的...

关键字: 嵌入式 数据读取器 芯片

单片机是一种嵌入式系统,它是一块集成电路芯片,内部包含了处理器、存储器和输入输出接口等功能。

关键字: 单片机 编写程序 嵌入式

深圳2024年4月23日 /美通社/ -- 全球AI解决方案与工业级存储领导品牌宜鼎国际 (Innodisk)持续深化边缘AI布局,今(23)日发表全球首创"MIPI over Type-C"独家技术,让旗下嵌入式相机模...

关键字: AI 嵌入式 相机

为增进大家对嵌入式主板的认识,本文将对嵌入式主板以及嵌入式主板常见问题及其解决方法予以介绍。

关键字: 嵌入式 指数 主板

为增进大家对嵌入式系统的认识,本文将对嵌入式系统、嵌入式系统的特点予以介绍。

关键字: 嵌入式 指数 嵌入式系统

为增进大家对嵌入式的认识,本文将对嵌入式、嵌入式工作相关的内容予以介绍。

关键字: 嵌入式 指数 嵌入式技术

机器人操作系统(ROS)驱动程序基于ADI产品而开发,因此可直接在ROS生态系统中使用这些产品。本文将概述如何在应用、产品和系统(例如,自主导航、安全气泡地图和数据收集机器人)中使用和集成这些驱动程序;以及这样将如何有助...

关键字: 电机控制器 机器人 嵌入式

支持高达48V@5A的PD受电模式,达到目前USB PD最高标准。

关键字: 嵌入式 开发板

【2024年4月8日,德国慕尼黑讯】低碳化和数字化是当今时代人们面临的两大核心挑战,人类社会需要依靠创新和先进的技术,才能破除挑战、推动转型进程。在德国纽伦堡举办的2024国际嵌入式展(Embedded World 20...

关键字: 半导体 微控制器 嵌入式
关闭
关闭