嵌入式Linux系列第5篇:Nand Flash根文件系统制作
1.引言
之前系列的文章介绍了如何编译Uboot、Kernel以及使用默认的ramdisk根文件系统来构建一个完整的嵌入式Linux系统,本篇文章介绍如何从头制作一个放在NAND Flash上的根文件系统。经过我这段时间的总结,rootfs相关的编译、配置等工作还是比较麻烦的。所以你可能会看到一般做核心板的第三方厂家会建议初学者直接使用现成提供的文件系统,比如一个做NUC972核心板的厂家,其文档里这么描述:
再比如另外一个做NXP I.MX6核心板的厂家,其文档里这么描述:
他们都建议初学者直接使用他们提供好的文件系统。但是我还是强烈建议大家自己一步一步的去操作制作一次,因为一是这有助于你理解根文件系统是怎么来的,最小的能用的根文件系统包含了哪些东西,二是将来你很有可能需要对文件系统做一些定制化的裁剪和修改工作,只有自己做了一遍你对会明白这个东西到底是怎么回事,比如我原来就搞不清楚Busybox、Buildroot、Yocto这些名词在Linux中的作用,现在随着实践增多,就大概知道他们的用处了。
2.环境介绍
2.1.硬件
因为本系列博客都会以NUC972为平台来介绍。
2.2.软件
本篇新用到的软件工具一个是busybox,它用来生成文件系统里的几个最基本的文件夹,二是打包工具mkyaffs2,它用来生成能直接烧录到板子里的镜像文件。
大家有没有注意,我为什么每次都把这个官方的链接放过来,让大家自己去下载,原因是我们要知道我们用的东西的源头在哪里,最官方的资料渠道在哪里,这很重要。
我们这次要实现的目标是:自己亲手制作的文件系统能够跑起来,同时能够运行我们第二篇文章介绍的Helloworld程序。
3.使用Busybox制作根文件系统
1)进入到nuc972文件夹,新建一个tool文件夹,用来存放busybox、mkyaffs2等工具,把上面下载的NUC970_Linux_Applications-master.zip文件解压到tool文件夹里,因为解压后含有NUC970_Linux_Applications-master,我们把里面的内容移出来,然后删除掉空的NUC970_Linux_Applications-master文件夹和NUC970_Linux_Applications-master.zip源文件。然后进入到busybox目录里。同样的,在编译前要设置交叉编译的环境变量。
cd ~/nuc972
mkdir tool
unzip NUC970_Linux_Applications-master.zip
cd NUC970_Linux_Applications-master
mv ./* ../
cd ..
rm NUC970_Linux_Applications-master -fr
rm NUC970_Linux_Applications-master.zip
cd busybox-1.22.1/
source ~/nuc972//toolchain/environment.sh
2)make menuconfig 进入配置界面
make menuconfig
我们这里就设置一个地方,其他的全部使用默认配置。
修改make install生成的文件夹路径,我们把默认的./_install改成nuc972目录下的rootfs。
Busybox Settings --->
Installation Options ("make install" behavior) --->
(../../rootfs) BusyBox installation prefix
3)make 编译
make
编译成功后显示如下:
编译完成之后我们可以查看一下busybox的文件属性,可以看到如下信息,说明我们交叉编译的没问题。
4)make install 安装
make install
这样就在前面我们设置的地方生成一个rootfs的文件夹,进到里面看一下
cd ~/nuc972/rootfs
ls
bin、sbin、usr :存放一些命令
linuxrc :挂载根文件系统时,第一个执行的文件
4)再创建几个文件夹
mkdir etc lib dev
5)在 rootfs 目录的dev目录下创建设备节点
cd dev
sudo mknod console c 5 1
sudo mknod null c 1 3
6)在根文件系统rootfs/etc目录下创建一个inittab 文件,在文件里面填写:.console::askfirst:-/bin/sh
cd ../etc
vim inittab
4.文件系统打包
1)进入到tool文件夹的yaffs2utils目录里
cd yaffs2utils
2)编译,生成mkyaffs2
make clean
make
注:编译这个工具,不需要修改Makefile,用file看下属性,它是在x86-64运行的,这是没问题的,因为它就是在Ubuntu下使用的,不是在嵌入式环境下去执行使用的。
将它复制到/usr/bin下以后用起来方便了,可以直接使用这个指令了,你可一在终端敲mkya,然后TAB建看不能出来。
sudo cp mkyaffs2 /usr/bin/
4) 生成文件系统
sudo mkyaffs2 --inband-tags -p 2048 rootfs rootfs_yaffs2.img
5.内核修改
内核也要做一定的修改,具体如下:
1)make menuconfig进入到内核配置界面
make menuconfig
2)默认用的RAM filesytem 需要去掉
General setup —>
[ ] Initial RAM filesystem and RAM disk (initramfs/initrd) support
3)默认的Boot option需要修改成如下:
Boot options --->
(noinitrd root=/dev/mtdblock2 rootfstype=yaffs2 rootflags=inband-tags console=ttyS0,115200n8 rdinit=/sbin/init mem=64M)
4)NAND Flash驱动相关配置
Device Drivers --->
Generic Driver Options --->
<*> Nuvoton NUC970 FMI function selection
Select FMI device to support (Support MTD NAND Flash) --->
5)选中MTD的支持
Device Drivers --->
<*> Memory Technology Device (MTD) support --->
<*> Caching block device access to MTD devices
-*- NAND Device Support --->
-*- Nuvoton NUC970 MTD NAND --->
NUC970 NAND Flash pin selection (Port C) --->
6)选中yaff2文件系统的支持
File systems --->
[*] Miscellaneous filesystems --->
<*> yaffs2 file system support
7)保存配置,编译
6.结果查看
6.1.验证文件系统是否可用
1)将上述生成的kernel 970uimage、文件系统rootfs_yaffs2.img、还有之前第三讲生成的uboot.bin,uboot-spl.bin,以及env.txt 下载到板子里,env.txt做了一些改动,主要是加入了boocmd那一行,这样下载进去就能直接启动了。
baudrate=115200
bootcmd=nboot 0x7fc0 0 0x200000; bootm 0x7fc0
bootdelay=1
ethact=emac
ethaddr=00:00:00:11:66:88
stderr=serial
stdin=serial
stdout=serial
烧写前,最好对芯片进行一次Erase。几个文件的烧写类型及地址大家注意下,别搞错了。
2)上电,看看效果,调试串口打印信息如下:
这一次很顺利啊,一次就成功了,这就说明我们上述做的根文件系统是可以正常使用的了。
6.2.验证helloworld能否在板子上运行
我们还要看看我们之前编译的helloworld程序能不能运行,我们把helloworld放到板子里去,怎么把这个文件放到板子上呢?有以下几种方式:
a) 把Helloworld在Ubuntu下放到rootfs文件夹里,然后按照上述的方法打包、下载进去。
b)通过scp或者NFS服务,直接通过网口放到板子里
c) 先放到U盘里,然后U盘插入到板子上,再复制过去
方法a)自然没问题,不过有些麻烦,方法b)现阶段我们的文件系统并不支持,暂时先不弄了,下一篇文章会介绍scp的移植,我们来试试方法c)吧
1)插入U盘到电脑上,把helloworld拷贝过去
2)把U盘插入到板子上,这时调试串口会自动输出如下信息,提示我们有USB Mass Storage设备接入了,看来内核已经把USB这部门驱动已经做进去了。这不是有点像我们给PC机重装Windows系统的过程,默认鼠标键盘也是可以直接使用的。
我们进入到/dev目录里,可以看到有sda1设备,LINUX所有的存储设备都是映射成"文件"来访问的,包括U盘、光驱、硬盘等。这个sda1就对应我们刚插入的U盘。
那么该如何访问U盘的东西呢?
我们需要挂载,使用mount指令,我们执行以下命令:
mkdir mnt
cd mnt
mkdir usb
cd usb
mount -t vfat /dev/sda1 /mnt/usb
cd /
mkdir opt
cp /mnt/usb/helloworld /opt
完成的事情是把sda1挂载到了/mnt/usb目录上,这样/mt/usb目录里就有了U盘里的内容,然后再复制到了系统的/opt目录。
我们在/opt目录里执行./helloworld,提示如下错误:
-/bin/sh: ./helloworld: not found
这是怎么回事呢?原因很简单,helloworld的执行是需要依赖一些库的,不可能系统里什么都没有就执行能执行成功了。所以需要我们把交叉编译链~/nuc972/toolchain/arm-2014.05/arm-none-linux-gnueabi/libc/lib里的库文件复制到板子的lib目录里。
可以先到arm-2014.05/arm-none-linux-gnueabi/libc/lib目录中,压缩下
tar -cvf lib.bin *
然后通过U盘放到板子的/lib目录中解压
tar -xvf lib.bin
这样操作之后,再次执行helloword,结果如下:
另外可以对板子断电-再上电,看看我们之前操作的内容都还在,因为它是存到NAND Flash里的,所以断电是不丢失的。
7.结束语
如果你亲自动手实现了这篇文章介绍的所有内容,相信你对根文件系统一定有了一个非常感官的认识。包括这篇在内,我用了5篇文章一直在介绍嵌入式Linux基础环境相关的内容,你应该也能感受到这和我们以前接触的单片机开发还是有着较大的差异。从下一篇文章开始,我们就正式进入到具体的应用了。我会陆续介绍GPIO、UART使用;网络通信;WIFI使用;摄像头采集数据;EC20 4G模块使用;QT编程;Opencv使用等。
Linux 的启动流程
本篇的重点是讲解设备和驱动的启动流程,设备和驱动的流程是整个内核启动的核心,也是工作中最常面对的问题。出于知识点的系统性考虑,在进入主题之前我们先看下整个 Linux 在 ARM 中的启动流程如何。
Uboot 的启动流程
ARM Linux 的启动流程大致为:Uboot → Kernel → Root filesystem。Uboot 在上电的时候就拿到 CPU 的控制权,实现了硬件的初始化。具体是怎么实现的呢?一起来看一下,CPU 的内部集成了小容量的 Sram,而 PC 指针一上电就指向 Sram 的起始地址 0x00000000,所以一上电 Uboot 代码就得到了运行。
Uboot 拿到 CPU 使用权就开始做初始化工作,比如关闭看门狗、设置 CPU 运行模式、设置堆栈、初始化内存、网卡、nand flash 等,最后把 Linux 内核加载到内存中。
初始化 RAM
因为内核要在 RAM 中运行,所以在调用内核之前必须初始化和设置 RAM,为调用内核做好准备。
初始化串口
内核在启动过程中可以将信息通过串口输出,这样就可以清楚的知道内核启动信息。虽然串口不是 Uboot 必须要完成的工作,但是通过串口可以方便调试 Uboot 和内核的各种信息。
检测处理器类型
Uboot 在调用内核前需要检测系统的处理器类型,并将其保存在某个变量中提供给内核,内核在启动过程中会根据该处理器的类型调用相应的初始化程序。
设置内核启动参数
内核在启动过程中会根据该启动参数进行相应的初始化工作。
调用内核镜像
值得注意的是存储 Uboot 的存储器不同,Uboot 的执行过程也并不相同,一般来讲 Flash 分为 nor Flash 和 nand Flash 两种:nor Flash 支持芯片内执行(XIP,eXecute In Place),这样代码可以在 Flash 上直接执行而不必复制到 RAM 中去执行。
但是 nand Flash 并不支持 XIP,所以要想执行 nand Flash 上的代码,必须先将其复制到 RAM 中去,然后跳到 RAM 中去执行。如果内核存放在 nor Flash 中,那么可直接跳转到内核中去执行。但通常由于在 nor Flash 中执行代码会有种种限制,而且速度也远不及 RAM 快,所以一般的嵌入式系统都是将内核复制到 RAM 中,然后跳转到 RAM 中去执行。不论哪种情况,在跳到内核执行之前 CPU 的寄存器必须满足以下条件:r0 = 0,r1 = 处理器类型,r2 = 标记列表在 RAM 中的地址。
Linux 内核的启动流程(设备和驱动的加载)
关于 Uboot 的启动本课程不做详细介绍,因为本课程的主要内容是内核。在讲述内核启动之前让我们先了解下内核的组成结构:
其中,
(1)vmlinusx 是 ELF 格式的 Object 文件,这种文件只是各个源代码经过连接以后得到的文件,并不能在 ARM 平台上运行。
(2)经过 objcopy 这个工具转换以后,得到了二进制格式文件 Image,Image 文件相比于 vmlinusx 文件,除了格式不同以外,还被去除了许多注释和调试的信息。
(3)Image 文件经过压缩以后得到了 piggy.gz,这个文件仅仅是 Image 的压缩版,并无其他不同。
(4)接着编译生成另外几个模块文件 misc.o、big_endian.o、head.o、head-xscale.o,这几个文件组成一个叫 Bootstrap Loader 的组件,又叫引导程序,编译生成 piggy.o 文件。
(5)最后 piggy.o 文件和 Bootstrap Loader 组成一个 Bootable Kernel Image 文件(可启动文件)。
经过上面的分析不难知道 piggy.o 就是内核镜像,而剩下的几个文件就组成了引导程序。知道了内核的组成结构,Uboot 就是按照内核的组成结构一层一层剥开然后引导内核的:
可以说 start_kernel之前的所有工作都是为了将环境准备好,满足start_kernel的要求,然后由start_kernel开始进行内核的加载:
关于 start_kernl函数的内容太多,可以通过红色回调函数看出,start_kernel函数基本是在回调很多对应的注册函数。为了本系列课程的结构性这里就不展开所有知识点讲解,本篇内容接着前一篇设备树的内容重点讲解下设备和驱动的匹配过程。
还记得上一篇讲到的设备树三大作用吗?
平台标识;
运行时配置;
设备信息集合。
接下来我们就看看内核在启动的时候是如何寻找设备,驱动又如何和设备绑定的。
首先在平台目录下可以看到有很多平台描述的文件,如图:
有那么多的平台,我们到底要执行哪个平台是首先要考虑的事情。这也是设备三大功能的第一个功能——平台标识。
设备树里有对设备根节点的 Compatible 描述,平台文件里有对 __initconst的描述,如果两个字段一致则找到了对应的板级文件,这样就通过设备树把要用的设备平台与其他平台区分开来了,如图:
找到平台后就可以根据回调函数的指针调用该平台的注册函数。这里以飞思卡尔 imx.6dl 平台为例,回调的时候会调用 imx6q_init_machine函数,如下:
这里补充一个知识点,细心的读者也许发现了在 Compatible 字段里用逗号分隔了两个字符串。板级匹配的时候用的是哪个字符串,另外一个字符串又是做什么用?首先后面的字段 "fsl,imx6dl" 是抽象共用平台描述符,前面的字段 "fsl,imx6dl-sabresd" 是通用平台下的具体平台描述符,可以理解为母板和子板的区别。在具体的子板文件中我们可以通过前面的字段进行设备信息的获取,如图:
接着是运行时配置,让内核在启动的时候根据参数设置进行不同的处理。有经验的读者清楚在 Uboot 里也有对 Bootargs 的配置,这里为什么多此一举呢,是为了在 Uboot 中更灵活的对内核启动进行配置。
最后的作用就是设备信息集合,这是设备和驱动匹配的核心,也是工作中面对最多的情况。出于这一作用的内容是工作中经常遇到的重点也是难点,我们专门用一篇内容来详细讲解各级设备是如何展开的,并且手把手教你如何定制一套自己的开发板全新案例。
相关问答
linux 系统怎么安装 flash 插件?下载系统对应的Flash插件,我的电脑在此下载的是install_flash_player_11_linux.i386.tar.gz解压缩*.tar.gz文件:tar-zxvf文件名.tar....
嵌入式 linux 系统中怎么把应用程序和文件系统放在两个 flash 分区上?第一,应用程序app不论放在哪个目录下面都可以单独升级,不用升级整个文件系统;第二,你可以发flash分成2个分区,root文件系统放系统文件,usr文件系统放程序文...
MTD是什么意思?说到NANDflash类文件系统,不得不提到之前的Yaffs2以及UBIFS。这两种文件系统都是基于linux的MTD层而实现的。MTD层就是linux对于NANDflashdriver封装的一...
linux flashtool怎么用[最佳回答]天拿到MTK新发布的flash_tool,支持linux下直接烧手机,遂试用之,总结如下:安装流程如下:1、解压SP_Flash_Tool_Linux_v5.1336.00.100_Custome...
LINUX 可以看的视频网站有哪些 - nancykh 的回答 - 懂得都可以看啊,只要装了flash插件就OK了卓1000一看就深受linux的毒害!1,根据网页提示下载flashplayer包!(tar.gz格式)2,tarzxvfflashplayer.tar.g...
嵌入式 Linux 为什么要从NorFlash启动?首先Linux内核是无法无直接启动的,一定要使用BootLoader进行引导,BootLoader从Nor启动是为了方便,CPU上电后从0地址运行,NorFlash可以像Ram一样进行数据读取...
内核kernel以及根文件系统rootfs是如何映射到对应的 nandflash 的?需要修改Linux内核源码中的一个控制logbuffersize的宏:CONFIG_LOG_BUF_SHIFT,buffersize是2^shift,加大这个就可以。一、配置$...
位童鞋!求帮忙!!荆州经验丰富的曲臂式高空作业平台租赁,...[回答]成为一名嵌入式Linux开发工程师需要学习哪些知识?随着嵌入式行业的迅猛发展,嵌入式Linux凭借其系统发展的成熟度、市场应用的高份额也受到更多工程...
目前常用的 linux 版本有哪些?都有什么优缺点? - 满天飞 的回...CentOS:可靠的服务器2113发行版。是一个重新编译可安装5261的RedHatEnterpriseLinux(RHEL)代码,并提供及时的安全更新4102的所有套装软1653件升级为...
嵌入式单片机有前途吗?非常有前途。嵌入式单片机,即嵌入式微控制器,指以微控制器为核心控制单元的嵌入到对象体系中的专用计算机系统,是应用十分广泛的一种嵌入式系统结构。无论是...