网站建设项目验收表,源码论坛网站,wordpress 免插件,有限责任公司注册要求最近在学习系统移植的相关知识#xff0c;在学习和调试过程中#xff0c;发现了很多问题#xff0c;也解决了很多问题#xff0c;但总是对于我们的开发结果有一种莫名其妙的感觉#xff0c;纠其原因#xff0c;主要对于我们的开发环境没有一个深刻的认识#xff0c;有时…最近在学习系统移植的相关知识在学习和调试过程中发现了很多问题也解决了很多问题但总是对于我们的开发结果有一种莫名其妙的感觉纠其原因主要对于我们的开发环境没有一个深刻的认识有时候几个简单的命令就可以完成非常复杂的功能可是我们有没有想过为什么会有这样的效果如果没有去追问只是机械地完成并且看到实验效果这样做其实并没有真正的掌握系统移植的本质。在做每一个步骤的时候首先问问自己为什么要这样做然后再问问自己正在做什么搞明白这几个问题我觉得就差不多了以后不管更换什么平台什么芯片什么开发环境你都不会迷糊很快就会上手。对于嵌入式的学习方法我个人方法就是从宏观上把握(解决为什么的问题)微观上研究(解决正在做什么的问题)下面以自己学习的arm-cortex_a8开发板为目标介绍下自己的学习方法和经验。嵌入式Linux系统移植主要由四大部分组成一、搭建交叉开发环境二、bootloader的选择和移植三、kernel的配置、编译、和移植四、根文件系统的制作第一部分搭建交叉开发环境 先介绍第一分部的内容搭建交叉开发环境首先必须得思考两个问题什么是交叉环境? 为什么需要搭建交叉环境 先回答第一个问题在嵌入式开发中交叉开发是很重要的一个概念开发的第一个环节就是搭建环境第一步不能完成后面的步骤从无谈起这里所说的交叉开发环境主要指的是在开发主机上(通常是我的pc机)开发出能够在目标机(通常是我们的开发板)上运行的程序。嵌入式比较特殊的是不能在目标机上开发程序(狭义上来说)因为对于一个原始的开发板在没有任何程序的情况下它根本都跑不起来为了让它能够跑起来我们还必须要借助pc机进行烧录程序等相关工作开发板才能跑起来这里的pc机就是我们说的开发主机想想如果没有开发主机我们的目标机基本上就是无法开发这也就是电子行业的一句名言搞电子说白了就是玩电脑然后回答第二个问题为什么需要交叉开发环境主要原因有以下几点原因1嵌入式系统的硬件资源有很多限制比如cpu主频相对较低内存容量较小等想想让几百MHZ主频的MCU去编译一个Linux kernel会让我们等的不耐烦相对来说pc机的速度更快硬件资源更加丰富因此利用pc机进行开发会提高开发效率。原因2嵌入式系统MCU体系结构和指令集不同因此需要安装交叉编译工具进行编译这样编译的目标程序才能够在相应的平台上比如ARM、MIPS、 POWEPC上正常运行。交叉开发环境的硬件组成主要由以下几大部分1.开发主机2.目标机开发板3.二者的链接介质常用的主要有3中方式(1)串口线 (2)USB线 (3)网线对应的硬件介质还必须要有相应的软件“介质”支持1.对于串口通常用的有串口调试助手putty工具等工具很多功能都差不多会用一两款就可以2.对于USB线当然必须要有USB的驱动才可以一般芯片公司会提供比如对于三星的芯片USB下载主要由DNW软件来完成3.对于网线则必须要有网络协议支持才可以常用的服务主要两个第一tftp服务 主要用于实现文件的下载比如开发调试的过程中主要用tftp把要测试的bootloader、kernel和文件系统直接下载到内存中运行而不需要预先烧录到Flash芯片中一方面在测试的过程中往往需要频繁的下载如果每次把这些要测试的文件都烧录到Flash中然后再运行也可以但是缺点是过程比较麻烦而且Flash的擦写次数是由限的另外一方面测试的目的就是把这些目标文件加载到内存中直接运行就可以了而tftp就刚好能够实现这样的功能因此更没有必要把这些文件都烧录到Flash中去第二nfs服务 主要用于实现网络文件的挂载实际上是实现网络文件的共享在开发的过程中通常在系统移植的最后一步会制作文件系统那么这是可以把制作好的文件系统放置在我们开发主机PC的相应位置开发板通过nfs服务进行挂载从而测试我们制作的文件系统是否正确在整个过程中并不需要把文件系统烧录到Flash中去而且挂载是自动进行挂载的bootload启动后kernel运行起来后会根据我们设置的启动参数进行自动挂载因此对于开发测试来讲这种方式非常的方便能够提高开发效率。 另外还有一个名字叫samba的服务也比较重要主要用于文件的共享这里说的共享和nfs的文件共享不是同一个概念nfs的共享是实现网络文件的共享而samba实现的是开发主机上Windows主机和Linux虚拟机之间的文件共享是一种跨平台的文件共享方便的实现文件的传输。以上这几种开发的工具在嵌入式开发中是必备的工具对于嵌入式开发的效率提高做出了伟大的贡献因此要对这几个工具熟练使用这样你的开发效率会提高很多。等测试完成以后就会把相应的目标文件烧录到Flash中去也就是等发布产品的时候才做的事情因此对于开发人员来说所有的工作永远是测试。 通过前面的工作我们已经准备好了交叉开发环境的硬件部分和一部分软件最后还缺少交叉编译器读者可能会有疑问为什么要用交叉编译器前面已经讲过交叉开发环境必然会用到交叉编译工具通俗地讲就是在一种平台上编译出能运行在体系结构不同的另一种平台上的程序开发主机PC平台X86 CPU上编译出能运行在以ARM为内核的CPU平台上的程序编译得到的程序在X86 CPU平台上是不能运行的必须放到ARM CPU平台上才能运行虽然两个平台用的都是Linux系统。相对于交叉编译平常做的编译叫本地编译也就是在当前平台编译编译得到的程序也是在本地执行。用来编译这种跨平台程序的编译器就叫交叉编译器相对来说用来做本地编译的工具就叫本地编译器。所以要生成在目标机上运行的程序必须要用交叉编译工具链来完成。 这里又有一个问题不就是一个交叉编译工具吗为什么又叫交叉工具链呢原因很简单程序不能光编译一下就可以运行还得进行汇编和链接等过程同时还需要进行调试对于一个很大工程还需要进行工程管理等等所以这里 说的交叉编译工具是一个由编译器、连接器和解释器组成的综合开发环境交叉编译工具链主要由binutils(主要包括汇编程序as和链接程序ld)、gcc(为GNU系统提供C编译器)和glibc(一些基本的C函数和其他函数的定义) 3个部分组成。有时为了减小libc库的大小也可以用别的 c 库来代替 glibc例如 uClibc、dietlibc 和 newlib。 那么如何得到一个交叉工具链呢是从网上下载一个“程序”然后安装就可以使用了吗回答这个问题之前先思考这样一个问题我们的交叉工具链顾名思义就是在PC机上编译出能够在我们目标开发平台比如ARM上运行的程序这里就又有一个问题了我们的ARM处理器型号非常多难道有专门针对我们某一款的交叉工具链吗若果有的话可以想一想这么多处理器平台每个平台专门定制一个交叉工具链放在网络上然后供大家去下载想想可能需要找很久才能找到适合你的编译器显然这种做法不太合理且浪费资源因此要得到一个交叉工具链就像我们移植一个Linux内核一样我们只关心我们需要的东西编译我们需要的东西在我们的平台上运行不需要的东西我们不选择不编译所以交叉工具链的制作方法和系统移植有着很多相似的地方也就是说交叉开发工具是一个支持很多平台的工具集的集合(类似于Linux源码)然后我们只需从这些工具集中找出跟我们平台相关的工具就行了那么如何才能找到跟我们的平台相关的工具这就是涉及到一个如何制作交叉工具链的问题了。通常构建交叉工具链有如下三种方法方法一 分步编译和安装交叉编译工具链所需要的库和源代码最终生成交叉编译工具链。该方法相对比较困难适合想深入学习构建交叉工具链的读者。如果只是想使用交叉工具链建议使用下列的方法二构建交叉工具链。方法二 通过Crosstool-ng脚本工具来实现一次编译生成交叉编译工具链该方法相对于方法一要简单许多并且出错的机会也非常少建议大多数情况下使用该方法构建交叉编译工具链。方法三 直接通过网上下载已经制作好的交叉编译工具链。该方法的优点不用多说当然是简单省事但与此同时该方法有一定的弊端就是局限性太大因为毕竟是别人构建好的也就是固定的没有灵活性所以构建所用的库以及编译器的版本也许并不适合你要编译的程序同时也许会在使用时出现许多莫名其妙的错误建议读者慎用此方法。 crosstool-ng是一个脚本工具可以制作出适合不同平台的交叉编译工具链在进行制作之前要安装一下软件 $ sudo apt-get install g libncurses5-dev bison flex texinfo automake libtool patch gcj cvs cvsd gawk crosstool脚本工具可以在http://ymorin.is-a-geek.org/projects/crosstool下载到本地然后解压接下来就是进行安装配置了这个配置优点类似内核的配置。主要的过程有以下几点 1. 设定源码包路径和交叉编译器的安装路径 2. 修改交叉编译器针对的构架 3. 增加编译时的并行进程数以增加运行效率加快编译因为这个编译会比较慢。 4. 关闭JAVA编译器 减少编译时间 5. 编译 6. 添加环境变量 7. 刷新环境变量。 8. 测试交叉工具链 到此嵌入式Linux系统移植四大部分的第一部分工作全部完成接下来可以进行后续的开发了。第二部分bootloader的选择和移植一、Boot Loader 概念 就是在操作系统内核运行之前运行的一段小程序。通过这段小程序我们可以初始化硬件设备、建立内存空间的映射图从而将系统的软硬件环境带到一个合适的状态以便为最终调用操作系统内核准备好正确的环境他就是所谓的引导加载程序Boot Loader。【图1】Flash存储中存放文件的分布图 二、为什么系统移植之前要先移植BootLoader BootLoader的任务是引导操作系统所谓引导操作系统就是启动内核让内核运行就是把内核加载到内存RAM中去运行那先问两个问题第一个问题是谁把内核搬到内存中去运行第二个问题我们说的内存是SDRAM大家都知道这种内存和SRAM不同最大的不同就是SRAM只要系统上电就可以运行而SDRAM需要软件进行初始化才能运行那么在把内核搬运到内存运行之前必须要先初始化内存吧那么内存是由谁来初始化的呢其实这两件事情都是由bootloader来干的目的是为内核的运行准备好软硬件环境没有bootloadr我们的系统当然不能跑起来。三、bootloader的分类。 首先更正一个错误的说法很多人说bootloader就是U-boot这种说法是错误的确切来说是u-boot是bootloader的一种。也就是说bootloader具有很多种类大概的分类如下图所示 【图2】bootloader分类图 由上图可以看出不同的bootloader具有不同的使用范围其中最令人瞩目的就是有一个叫U-Boot的bootloader是一个通用的引导程序而且同时支持X86、ARM和PowerPC等多种处理器架构。U-Boot全称 Universal Boot Loader是遵循GPL条款的开放源码项目是由德国DENX小组开发的用于多种嵌入式CPU的bootloader程序对于Linux的开发德国的u-boot做出了巨大的贡献而且是开源的。 u-boot具有以下特点 ① 开放源码 ② 支持多种嵌入式操作系统内核如Linux、NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS ③ 支持多个处理器系列如PowerPC、ARM、x86、MIPS、XScale ④ 较高的可靠性和稳定性 ⑤ 高度灵活的功能设置适合U-Boot调试、操作系统不同引导要求、产品发布等 ⑥ 丰富的设备驱动源码如串口、以太网、SDRAM、FLASH、LCD、NVRAM、EEPROM、RTC、键盘等 ⑦ 较为丰富的开发调试文档与强大的网络技术支持 其实把u-boot可以理解为是一个小型的操作系统。四、u-boot的目录结构 * board 目标板相关文件主要包含SDRAM、FLASH驱动 * common 独立于处理器体系结构的通用代码如内存大小探测与故障检测 * cpu 与处理器相关的文件。如mpc8xx子目录下含串口、网口、LCD驱动及中断初始化等文件 * driver 通用设备驱动如CFI FLASH驱动(目前对INTEL FLASH支持较好) * doc U-Boot的说明文档 * examples可在U-Boot下运行的示例程序如hello_world.c,timer.c * include U-Boot头文件尤其configs子目录下与目标板相关的配置头文件是移植过程中经常要修改的文件 * lib_xxx 处理器体系相关的文件如lib_ppc, lib_arm目录分别包含与PowerPC、ARM体系结构相关的文件 * net 与网络功能相关的文件目录如bootp,nfs,tftp * post 上电自检文件目录。尚有待于进一步完善 * rtc RTC驱动程序 * tools 用于创建U-Boot S-RECORD和BIN镜像文件的工具五、u-boot的工作模式 U-Boot的工作模式有启动加载模式和下载模式。启动加载模式是Bootloader的正常工作模式嵌入式产品发布时Bootloader必须工作在这种模式下Bootloader将嵌入式操作系统从FLASH中加载到SDRAM中运行整个过程是自动的。下载模式就是Bootloader通过某些通信手段将内核映像或根文件系统映像等从PC机中下载到目标板的SDRAM中运行用户可以利用Bootloader提供的一些令接口来完成自己想要的操作这种模式主要用于测试和开发。六、u-boot的启动过程 大多数BootLoader都分为stage1和stage2两大部分U-boot也不例外。依赖于cpu体系结构的代码如设备初始化代码等通常都放在stage1且可以用汇编语言来实现而stage2则通常用C语言来实现这样可以实现复杂的功能而且有更好的可读性和移植性。1、 stage1(start.s代码结构) U-boot的stage1代码通常放在start.s文件中它用汇编语言写成其主要代码部分如下1 定义入口。由于一个可执行的image必须有一个入口点并且只能有一个全局入口通常这个入口放在rom(Flash)的0x0地址因此必须通知编译器以使其知道这个入口该工作可通过修改连接器脚本来完成。2设置异常向量(exception vector)。3设置CPU的速度、时钟频率及中断控制寄存器。4初始化内存控制器 。5将rom中的程序复制到ram中。6初始化堆栈 。7转到ram中执行该工作可使用指令ldrpc来完成。2、 stage2C语言代码部分lib_arm/board.c中的start armboot是C语言开始的函数也是整个启动代码中C语言的主函数同时还是整个u-bootarmboot的主函数该函数主要完成如下操作1调用一系列的初始化函数。2初始化flash设备。3初始化系统内存分配函数。4如果目标系统拥有nand设备则初始化nand设备。5如果目标系统有显示设备则初始化该类设备。6初始化相关网络设备填写ip,c地址等。7进入命令循环即整个boot的工作循环接受用户从串口输入的命令然后进行相应的工作。七、基于cortex-a8的s5pc100bootloader启动过程分析s5pc100支持两种启动方式分别为USB启动方式和NandFlash启动方式1. S5PC100 USB启动过程[1] A8 reset, 执行iROM中的程序[2] iROM中的程序根据S5PC100的配置管脚(SW1开关4拨到4对面)判断从哪里启动(USB)[3] iROM中的程序会初始化USB然后等待PC机下载程序[4] 利用DNW程序从PC机下载SDRAM的初始化程序到iRAM中运行初始化SDRAM[5] SDRAM初始化完毕iROM中的程序继续接管A8, 然后等待PC下载程序(BootLoader)[6] PC利用DNW下载BootLoader到SDRAM[7] 在SDRAM中运行BootLoader2. S5PC100 Nandflash启动过程[1] A8 reset, 执行IROM中的程序[2] iROM中的程序根据S5PC100的配置管脚(SW1开关4拨到靠4那边)判断从哪里启动(Nandflash)[3] iROM中的程序驱动Nandflash[4] iROM中的程序会拷贝Nandflash前16k到iRAM[5] 前16k的程序(BootLoader前半部分)初始化SDRAM然后拷贝完整的BootLoader到SDRAM并运行[6] BootLoader拷贝内核到SDRAM并运行它[7] 内核运行起来后挂载rootfs并且运行系统初始化脚本八、u-boot移植(基于cortex_a8的s5pc100为例)1.建立自己的平台(1).下载源码包2010.03版本比较稳定(2).解压后添加我们自己的平台信息以smdkc100为参考版移植自己s5pc100的开发板(3).修改相应目录的文件名和相应目录的Makefile指定交叉工具链。(4).编译(5).针对我们的平台进行相应的移植主要包括修改SDRAM的运行地址从0x20000000(6).“开关”相应的宏定义(7).添加Nand和网卡的驱动代码(8).优化go命令(9).重新编译 make distclean(彻底删除中间文件和配置文件) make s5pc100_config(配置我们的开发板) make(编译出我们的u-boot.bin镜像文件)(10).设置环境变量即启动参数把编译好的u-boot下载到内存中运行过程如下1. 配置开发板网络 ip地址配置: $setenv ipaddr 192.168.0.6 配置ip地址到内存的环境变量 $saveenv 保存环境变量的值到nandflash的参数区 网络测试: 在开发开发板上ping虚拟机 $ ping 192.168.0.157(虚拟机的ip地址) 如果网络测试失败,从下面几个方面检查网络 1. 网线连接好 2. 开发板和虚拟机的ip地址是否配置在同一个网段 3. 虚拟机网络一定要采用桥接(VM--Setting--option) 4. 连接开发板时虚拟机需要设置成静态ip地址 2. 在开发板上配置tftp服务器(虚拟机)的ip地址 $setenv serverip 192.168.0.157(虚拟机的ip地址) $saveenv 3. 拷贝u-boot.bin到/tftpboot(虚拟机上的目录) 4. 通过tftp下载u-boot.bin到开发板内存 $ tftp 20008000(内存地址即可) u-boot.bin(要下载的文件名) 如果上面的命令无法正常下载: 1. serverip配置是否正确 2. tftp服务启动失败重启tftp服务 #sudo service tftpd-hpa restart 5. 烧写u-boot.bin到nandflash的0地址 $nand erase 0(起始地址) 40000(大小) 擦出nandflash 0 - 256k的区域 $nand write 20008000((缓存u-boot.bin的内存地址) 0(nandflash上u-boot的位置) 40000(烧写大小) 6. 切换开发板的启动方式到nandflash 1. 关闭开发板 2. 把SW1的开关4拨到4的那边 3. 启动开发板它就从nandflash启动第三部分kernel的配置、编译、和移植一、将下载好的linux-2.6.35.tar.bz2拷贝到主目录下解压二、修改顶层目录下的Makefile主要修改平台的体系架构和交叉编译器代码如下 ARCH ? $(SUBARCH) CROSS_COMPILE ? CROSS_COMPILE ? $(CONFIG_CROSS_COMPILE:%%) 修改以上代码为 ARCH ? arm ----体系架构是arm架构 CROSS_COMPILE ? arm-cortex_a8-linux-gnueabi- ----交叉编译器是arm-cortex_a8平台的 注意这两个变量值会直接影响顶层Makefile的编译行为即选择编译哪些代码用什么编译器进行编译。三、拷贝标准版配置文件目的是得到跟我们开发板相关的配置信息。 $ cp arch/arm/configs/s5pc100_defconfig .config 这里拷贝arch/arm/configs/s5pc100_defconfig到 .config文件是选取跟我们开发板相关的代码。因为Linux支持的平台非常非常多不仅仅是ARM处理器当然我们编译的时候只需要编译跟我们平台相关的代码就可以了平台相关的不需要编译那么就有个问题Linux系统中的源代码文件有一万多以个面对这么庞大的文件数量我们如何去选择呢 其实我们担心的问题也是写操作系统的那哥们早就担心过的问题了只不过人家已经把这个问题帮我们解决了我们只需进行很简单的操作就可以选择出我们要编译的代码具体的方法就是把相应平台的_deconfig直接拷贝到顶层目录的.config文件中这样.config文件中就记录了我们要移植平台的平台信息因为在配置内核时系统会把所有的配置信息都保存在顶层目录的.config文件中。注意在第一次进行make menuconfig时系统会根据我们选取的平台信息自动选取相关的代码和模块因此我们只需要进入然后再退出选择保存配置信息就行了系统会把这些跟我们移植平台相关的所有配置信息全部保存在顶层目录的.config文件中。四、配置内核 $make menuconfig 注意第一次进去不做任何操作直接推出在推出时提示是否保存配置信息一定要保存配置信息点击“YES”。这样我们的.config中就已经保存了我们开发平台的信息。 在这个环节我们需要关心一个问题make menuconfig时系统到低都做了哪些事情为什么会出现图形化的界面图形化的界面中的相关内容是从哪里来的 图形化的界面当然是由一个特殊的图形库来实现的还记得第一次make menuconfig时系统并没有出现图形化的界面而是报错了并且提示我们缺少 ncurses-devel ,此时只需要按照要求安装一个libncurses5-dev就行了sudo apt-get install libncurses5-dev有了这个图形化库的支持我们才能够正常显示图形化界面。 好了图形化界面的问题解决了那还有另外一个问题就是图形化界面里面的内容是从哪里来的要回答这个问题我们就要提一下Linux内核的设计思想了Linux 内核是以模块的方式来组织这个操作系统的那么为什么要用模块的方式来组织呢模块的概念又是什么呢在此来一一回答这个问题。 Linux2.6内核的源码树目录下一般都会有两个文件Kconfig和Makefile。分布在各目录下的Kconfig构成了一个分布式的内核配置数据库每个Kconfig分别描述了所属目录源文件相关的内核配置菜单。每个目录都会存放功能相对独立的信息在每个目录中会存放各个不同的模块信息比如在/dev/char/目录下就存放了所有字符设备的驱动程序而这些程序代码在内核中是以模块的形式存在的也就是说当系统需要这个驱动的时候会把这个驱动以模块的方式编译到系统的内核中编译分为静态编译和动态编译静态编译内核体积比动态编译的体积要大前面已经说了每个目录下面都会有一个Kconfig的文件我们还会问这个文件中都存放了什么信息前面说了每个目录的Kconfig文件描述了所属目录源文件相关的内核配置菜单有其特殊的语法格式图形化界面的文字正是从这个文件中读取出来的如果把这个文件中的相应目录文件的信息全部删除那么在图形化界面中将看不到该模块的信息因此也不能进行模块的配置。 在内核配置make menuconfig(或xconfig等)时系统会自动从Kconfig中读出配置菜单用户配置完后保存到.config(在顶层目录下生成)中。在内核编译时主Makefile调用这个.config(.config的重要性就体现在它保存了我们的所有的配置信息是我们选取源代码并且进行编译源代码的最终依据)就知道了用户对内核的配置情况。上面的内容说明Kconfig就是对应着内核的配置菜单。假如要想添加新的驱动到内核的源码中可以通过修改Kconfig来增加对我们驱动的配置菜单这样就有途径选择我们的驱动假如想使这个驱动被编译还要修改该驱动所在目录下的Makefile。因此一般添加新的驱动时需要修改的文件有两种即Kconfig 和相应目录的Makefile注意不只是两个系统移植的重要内容就是给内核添加和删除相应的模块因此主要修改的内核文件就是Kconfig 和相应目录的Makefile这两个文件。五、编译内核 $make zImage 通过上述操作我们能够在 arch/arm/boot 目录下生成一个 zImage 文件这就是经过压缩的内核镜像。 内核的编译过程是非常复杂的注意这里的编译是静态编译此时会执行顶层目录下的Makefile中的zImage命令在执行的过程中会根据当前目录的.config文件去选择编译源代码。编译内核的具体步骤比较复杂有时间会另写文章详细描述。六、通过tftp网络服务下载测试内核 setenv bootcmd tftp 20008000(内存地址) zImage\;go 20008000 setenv bootargs nfs nfsroot192.168.1.199(虚拟机的ip):/source/rootfs ip192.168.1.200(开发板的ip) init/linuxrc(第一个要启动的用户进程) ttySAC0,115200(设置中断为串口1波特率为115200) 保存环境变量复位开发板测试是否能够正常启动(注意在此之前应设置好需要nfs挂载的文件系统最后才能看到效果).内核测试和启动过程也是比较复杂的在后续的文章中会详细介绍。第四部分根文件系统的介绍 由本文的第一张图Flash存储中存放文件的分布图可知文件系统的制作和移植是系统移植的最后一道工序了在这里首先要提几个问题 1.什么是文件系统 2.如何实现文件系统 3.常用的文件系统有哪些为什么需要这些文件系统 下面来一一回答这些问题 文件系统我们在日常生活中则很少听说但是它确实存在只是名字不叫文件系统罢了一般叫资料库。资料库里面的文件众多我们如何快速准确的找到我们要的那份文件呢资料库采用了分类索引的方法来实现快速查找。类似于我们学校图书馆的管理方式一楼可能是哲学类二楼是社科类的三楼是电子类的四楼是计算机类的…………等等我们把这种进行了分类索引的资料库叫文件系统。 对于计算机而言文件其实就是资料数据只能存储在物理介质上面比如硬盘但是我们人不可能自己读取物理介质上的文件或者自己把文件写入物理介质物理介质上文件的读写只能采用程序来完成为了方便实现程序又被分成了物理介质驱动程序、内容存储程序和文件内容存储程序。物理介质驱动程序专门用于从物理介质上存取数据内容存储程序用于把文件内容和文件属性信息打包文件内容存储程序用于把用户输入形成文件内容或者取得文件内容显示出来。 我们可以把一个文件系统(倒树)分解成多个文件系统(倒树)分别存放到存储介质上比如一个存储到光盘里一个存储到硬盘中在使用时我们把光盘里的文件系统的根目录挂到硬盘文件系统的一个目录下面这样访问这个目录就相当于是访问光盘的根目录了找到了根目录我们也就可以访问整个光盘上的文件系统了。 “在Linux系统中一切皆是文件”这句话是我们学习Linux系统的时候常常听到的一句话。虽然有些夸张但是它揭示了文件系统对于Linux系统的重要性实际上文件系统对于所有的操作系统都很重要因为它们把大部分的硬件设备和软件数据以文件的形式进行管理。Linux系统对设备和数据的管理框架图如下 【图3】文件系统实现 [说明] A. VFS(virtual file system)是虚拟文件系统它管理特殊文件(虚拟文件)、磁盘文件和设备文件 B. fs_operations结构是由一系列文件操作接口函数组成由文件系统层来完成为VFS提供文件操作 C. 在文件系统层磁盘文件要实现各种文件系统(如ext2)设备文件要实现各种抽象的设备驱动 D. 在设备驱动层磁盘驱动要实现各种磁盘的驱动程序其他设备驱动要实现具体的设备驱动 E. 物理层就是设备自身 为什么会有不同的文件类型 由于存储介质有很多种所以没有办法用一种统一的格式存放文件系统到各种不同的存储介质上而是需要多种不同的存储格式来适应各种存储介质的特性以求达到存取效率和空间利用率的最优化这样就需要对每种存储格式制定一个规范这写规范就叫文件系统类型。常见的文件系统类型有1.Dos FAT162.windows FAT16、FAT32、NTFS3.Linux Minix、ext、ext2 、ext3 、ISO9660 、jffs2, yaffs, yaffs2、cramfs, romfs, ramdisk, rootfs、proc、sysfs、usbfs、devpts、 tmpfs ramfs、 NFS 由此可见Linux支持的文件系统最多。以不同的介质来分类如下所示? 磁盘 FAT16、 FAT16、FAT32、NTFS、ext、ext2 、ext3、Minix? 光盘 ISO9660、? Flash jffs2, yaffs, yaffs2、cramfs, romfs? 内存 Ramdisk、tmpfs ramfs? 虚拟 rootfs、proc、sysfs、usbfs、devpts、NFS 常用的存储介质理论上都可以用于存储Linux支持的文件系统因为我们这里只研究嵌入式系统而嵌入式系统由于体积和移动特性的限制不能采用磁盘和光盘所以只能采用flash类的存储设备、内存和虚拟存储设备作为文件系统的存储介质 flash芯片的驱动程序是由系统来提供所以它的存取特点完全是flash自身的特点这时最好有更加适合flash的文件系统——Jffs、Yaffs、Cramfs和Romfs。这些文件系统都是嵌入式Linux系统中常用的文件系统可以根据特点来选择使用它们特点如下共同点基于MTD驱动Jffs A.针对NOR Flash的实现 B.基于哈希表的日志型文件系统 C.采取损耗平衡技术每次写入时都会尽量使写入的位置均匀分布 D.可读写支持数据压缩 E.崩溃/掉电安全保护 F.当文件系统已满或接近满时因为垃圾收集的关系运行速度大大放慢Yaffs A.针对Nand Flash的实现 B.日志型文件系统 C.采取损耗平衡技术每次写入时都会尽量使写入的位置均匀分布 D.可读写不支持数据压缩 E.挂载时间短占用内存小 F.自带Nandflash驱动可以不使用VFS和MTDCramfs A.单页压缩支持随机访问压缩比高达21 B.速度快效率高 C.只读有利于保护文件系统免受破坏提高了系统的可靠性但是无法对其内容进行扩充Romfs A.简单的、紧凑的、只读的文件系统 B.顺序存放数据因而支持应用程序以XIP(execute In Place片内运行)方式运行在系统运行时节省RAM空间 特有的文件系统类型Ramdisk文件系统 在Linux系统中内存经常用于存储文件系统这种叫做RamdiskRamdisk有两种一种是完全把内存看成物理存储介质利用内存模拟磁盘运用磁盘的文件系统类型另一种只是在内存中存储了文件系统逻辑结构运用tmpfs ramfs文件系统类型 tmpfs ramfs 1. 概述 用物理内存模拟磁盘分区挂载这种分区后就可以跟读写磁盘文件一样读写这里面的文件但是操作速度要比磁盘文件快得多所以一般应用在下面几个方面 1)读写速度要求快的文件应该放在这种文件系统中 2)磁盘分区为flash的情况下把需要经常读写的文件放在这种文件系统中然后定期写回flash 3)系统中的临时文件如/tmp、/var目录下的文件应该放在这种文件系统中 4)/dev设备文件(因为设备文件随驱动和设备的加载和卸载而变化)应该放在这种文件系统中 2. 特点 1)由于数据都存放在物理内存中所以系统重启后这个文件系统中的数据会全部丢失 2)ramfs在没有指定最大的大小值情况下会自动增长直到用掉系统中所有的物理内存为止这时会导致系统的崩溃建议挂载时最好限定其最大的大小值 3)tmpfs如果指定了大小值自动增长至大小值后系统会限定它的大小这个文件系统占用的物理内存页可以背置换到swap分区但是ramfs不行 不同的文件系统具有不同的制作方法有的比较复杂有的比较简单在此由于篇幅限制先不做介绍在后续的文章中会单独介绍文件系统的制作。