Linux内核及文件系统移植
Linux内核及文件系统移植
嵌入式系统包含硬件子系统与软件子系统,其中软件子系统大致可分为:bootloader、Linux内核、文件系统与应用开发,这四个组成部分中前三者构建成嵌入式应用功能的基础运行环境,是进行嵌入式产品项目开发前期就需要敲定的配置环境,非常重要与关键。本课程主要对第三部分嵌入式文件系统的构建与移植进行介绍,讲解如何选择、配置、移植与制作一个可用的文件系统及其镜像,以及怎样配合Linux内核的配置调整来应用生成的文件系统,进而掌握构建完整的嵌入式软件子系统应用开发环境。
开发移植环境:虚拟机Ubuntu 12.04 + FriendlyARM Smart210SDK + Windows 7 Ultimate
Lesson 1. Linux内核启动参数介绍与设置
引导:
软件子系统各组成部分之间的层次与关联,怎样相互识别、配置与加载?
一、系统启动流程
bootloader(uboot) ———— Linux Kernel(uImage) ———— Rootfs(Init) ———— Applications
二、启动环境配置
uboot环境变量: printenv setenv saveenv tftpboot nand read/write ...
baudrate 115200
bootdelay
bootcmd boot bootd运行bootcmd变量指定的命令进行启动
ipaddr, serverip, ethaddr,gatewayip
bootargs
内核启动参数:bootargs ' 三、启动参数设置 setenv bootcmd 'tftpboot 20008000 tiny_uImage;bootm 20008000' 总结: 一、Linux文件系统 二、根文件系统概念 三、根文件系统形式 结构 一般说来,只有/bin,/dev,/etc,/lib,/proc,/var,/usr这些需要的,而其他都是可选的。 总结: 引导: 一、从零开始构建最小根文件系统 二、通用嵌入式根文件系统项目:busybox busybox项目: http://www.busybox.net/ busybox源码 总结: 引导: 一、init进程:linuxrc --> ELF二进制程序 二、/etc/inittab文件: init程序的默认配置文件 三、/etc/init.d/rcS文件及/etc/init.d目录 四、编写并添加自定义的启动脚本 总结: 怎样从源码交叉编译得到符合需求的可用busybox二进制以及根文件系统框架? 一、busybox的构建流程 make menuconfig --> 裁剪定制构建选项: make defconfig make --> 根据选项编译出二进制文件 make install ---> 根据选项安装busybox 二、busybox的交叉编译 三、busybox的裁剪定制 可配置选项简介: busybox settings 工具应用程序定制: applets 裁剪主要目标:降低busybox的文件大小,节省存储空间 总结 使用busybox需要确保busybox的运行,以及掌握常用的工具命令。 一、补全目录与文件 动态库依赖:readelf -d busybox|grep NEEDED 设备文件: 配置文件: 二、机制与使用 直接使用busybox:(二进制程序) 将命令名称作为参数调用busybox:等同于直接使用命令 所有工具命令的通用选项:--help 三、嵌入式常用的工具命令 文本编辑处理: 网络信息配置: 系统信息管理: 总结: 一个开发中实用的根文件系统,还需要完善哪些内容,怎样来部署一个根文件系统? 一、完善根文件系统 check程序运行库:/lib/ check配置文件: /etc目录 check启动脚本:/etc目录 fi 二、 制作文件系统镜像 产品的生产部署阶段使用:批量烧录到产品 总结: 在类Unix系统中一切都是文件,那么Linux是如何将系统的运行信息、设备信息等抽象成文件进行管理的? Linux内核实现了一套特殊的内存虚拟文件系统用于使用与文件接口统一的操作来完成系统信息管理,它们包括: 一、procfs procfs的挂载:首先确定你的内核已经支持procfs,默认支持 使用/etc/fstab条目:none /proc proc defaults 0 0 procfs的内容: procfs信息查看 procfs参数调整 二、tmpfs tmpfs的挂载:首先确定你的内核已经支持tmpfs 使用/etc/fstab条目:tmpfs /tmp tmpfs defaults 0 0 tmpfs的使用:用来存放应用临时生成的信息,不需要持久保存 tmpfs的作用 三、devfs /dev ————— 根文件系统目录 特殊设备文件 devfs的缺点 ————> sysfs的设计 四、sysfs sysfs的原理 sysfs的挂载:首先确定你的内核已经支持sysfs,默认支持 使用/etc/fstab条目:none /sys sysfs defaults 0 0 sysfs的使用 sysfs的应用 总结: 嵌入式是宿主机 + 开发板的开发模式,两者之间的网络通讯与文件共享是进行高效率开发调试的前提条件。 一、NFS简介 2、NFS模式:C/S模式,RPC服务框架 二、NFS使用配置 配置文件: /etc/exports 格式:[共享目录] 主机名或IP NFS共享控制参数:man exports 配置命令 showmount 二、NFS开发板使用 1、宿主机防火墙:在挂载失败时返回来检查设置 2、NFS内核支持 3、NFS目录挂载 检查挂载:挂载失败会有错误原因打印 取消挂载 Linux内核加载根文件系统执行/sbin/init程序前,需要找到根设备位置,如果根设备需要驱动的支持, 一、rootfs,ramfs,ramdisk与tmpfs 二、initrd与initramfs initrd: initial Ramdisk initramfs: initial RAM file system 三、initramfs使用 init程序文件: hello world int main(int argc, char *argv[]) 打包initramfs镜像 解包initramfs镜像 内核initramfs的构建 总结: 在嵌入式系统中进行数据读写时,为了保证可靠性,我们可以选择哪些合适的文件系统? 一、Flash闪存类型 NOR Flash: 非易失内存 NAND Flash:类似硬盘的块设备 二、JFFS2 三、YAFFS2 1.特性: 总结: 如何来制作一个cramfs文件系统的镜像以及验证它? 一、工具安装 命令: 二、镜像制作 三、镜像使用 文件系统测试:losetup命令 总结:文件系统镜像制作:安装工具 --- 准备文件系统内容 --- 使用工具制作镜像 --- 测试镜像 如何来制作一个squashfs件系统的镜像? 一、工具安装 命令:dpkg -L squashfs-tools|grep bin 二、镜像制作 文件系统内容:mini_busybox/ 三、镜像使用 烧录挂载: 卸载解依附: 如何来制作一个jffs2文件系统的镜像? 一、工具安装 命令:mkfs.jffs2 二、镜像制作 mkfs.jffs2 [options] 文件系统内容:mini_busybox/ 三、镜像使用 应用: 烧录到Flash设备或者分区 总结:mtd-utils包带有很多的工具命令可以使用,辅助管理和使用Flash设备 如何来制作一个yaffs2文件系统的镜像? 一、获取yaffs2源码 制作工具: 二、镜像制作 三、镜像使用 应用: 烧录到Flash设备或者分区 如何将文件系统镜像烧录到嵌入式Flash设备中,怎么样进行Flash的布局? 一、Flash设备分区 嵌入式通用Flash布局 内核启动参数bootargs: mtparts 0x000000000000-0x000000100000 : "boot" 二、uboot环境下的Flash命令 nand info - show available NAND devices nand write.yaffs - addr off|partition size nand erase[.spread] [clean] off size - erase 'size' bytes from offset 'off' 二、文件系统镜像烧录 镜像制作: Flash型号的Page大小与Block大小,查看Datasheet手册 mkfs.jffs2 -d mini_busybox --pad=0x1000000 -s 2048 -e 0x20000 -l -o rootfs_128K.jffs2 下载镜像到系统内存中: 确定内存地址 确定烧录要使用的分区: 确定Flash地址 烧录内存中的镜像到Flash分区中 完整命令: 将Flash设备分区挂载到根文件系统才能进行读写操作,挂载动作是系统正常运行的基础工作。 一、根文件系统与应用文件系统 二、文件系统的挂载 挂载命令: 启动挂载控制:启动脚本设置 构建嵌入式软件开发的基础设施环境是嵌入式应用开发的前提 一、嵌入式软件开发 uboot ———— 提供开发控制环境 kernel(linux) ———— 系统管理与任务调度 FileSystem(rootfs + appfs) ———— 提供用户应用环境 分区管理控制 二、文件系统移植应用 应用范畴 应用文件系统:存放用户应用程序与数据 临时文件系统:运行时存在的文件系统 内存文件系统:临时数据的存放管理 总结:内核与文件系统是嵌入式软件开发的基础设施,最重要的原则就是必须保证稳定可靠。
bootargs=root=/dev/nfs nfsroot=192.168.10.7:/home/hong/nfsroot ip=192.168.10.11 init=/linuxrc console=ttySAC0,115200root, rootfstype, nfsroot
root=/dev/nfs nfsroot=nfsserver:path
root=/dev/mtdblock2
rootfstype=jffs2/yaffs2/squashfs/ubifs/...
mtdparts: mtdparts=mtd-id:<size1>@<offset1>(<name1>),<size2>@<offset2>(<name2>)
mtdparts=s5pv210-nand:1M(boot),5M(kernel),80M(rootfs),426M(usrfs)
要想这个参数起作用,内核中的mtd驱动必须要支持,即内核配置时需要选上
Device Drivers ---> Memory Technology Device (MTD) support ---> Command line partition table parsing
ip: nfs必须进行设置
ip=ip addr
ip=ip addr:server ip addr:gateway:netmask::which netcard:off
init, console
mem 限制linux内核的使用内存 mem=128M
setenv bootargs 'root=/dev/nfs nfsroot=192.168.10.7:/home/hong/nfsroot ip=192.168.10.11 init=/linuxrc console=ttySAC0,115200'
Lession 2.Linux的根文件系统与基本框架
---------------------------------------
引导:
Q1.什么是根文件系统,为什么需要根文件系统?
Q2.根文件系统需要满足哪些要求?
目录结构
树形结构:倒立 —— 根目录 /
内核第一个挂载的文件系统,包含Linux系统完整启动所需的目录结构和重要文件
其它所有文件系统进行挂载使用的载体
Linux完整启动的需要,进入用户态操作环境:VFS设计
提供了良好强大的文件系统扩展性
根文件系统能被内核找到并加载:存储介质驱动、存在地址问题
格式能被内核识别:initrd/cramfs/...
包含基本的目录结构与启动程序
/bin 存放二进制可执行命令的目录
/dev 存放设备文件的目录
/etc 存放系统管理和配置文件的目录
/home 用户主目录,比如用户user的主目录就是/home/user,可以用~user表示
/lib 存放动态链接共享库的目录
/sbin 存放系统管理员使用的管理程序的目录
/tmp 公用的临时文件存储点
/root 系统管理员的主目录
/mnt 系统提供这个目录是让用户临时挂载其他的文件系统。
/proc 虚拟文件系统,可直接访问这个目录来获取系统信息。
/var 某些大文件的溢出区
/usr 最庞大的目录,要用到的应用程序和文件几乎都在这个目录。
1.概念:根文件系统必不可少,有基本的格式与结构要求
2.框架:/bin,/dev,/etc,/lib,/proc,/var,/usrLession 3.嵌入式根文件系统框架:busybox简介
每次从零开始构建根文件系统框架,还是可以从一个现成的通用框架开始构建满足需求的根文件系统?
/bin,/dev,/etc,/lib,/proc,/var,/usr
23 March 2015 -- BusyBox 1.23.2 (stable)
嵌入式Linux的瑞士军刀
BusyBox 将许多具有共性的小版本的UNIX工具结合到一个单一的可执行文件。这样的集合可以替代大部分常用工具比如的GNU fileutils, shellutils等工具,BusyBox提供了一个比较完善的环境,可以适用于任何小的嵌入式Linux系统。
下载稳定的版本
编译构建二进制:make defconfig;make
make menuconfig
安装得到目录结构:make CONFIG_PREFIX=../mini_rootfs/ install
以busybox为起点,进行项目根文件系统的裁剪定制,构建自己的根文件系统。[Lession 4]. 嵌入式根文件系统框架:启动脚本
前提:基于busybox的根文件系统移植与应用
init程序的限制性与局限性如何实现灵活动态调整的嵌入式应用启动控制?
/bin/busybox, 进程号1
sysinit —— 为init提供初始化命令行的路径及脚本程序
respawn —— 每当相应的进程终止执行便会重新启动
askfirst —— 类似respawn,不过它的主要用途是减少系统上执行的终端应用程序的数量。它将会促使init在控制台上显示“Please press Enter to active this console”的信息,并在重新启动之前等待用户按下enter键
wait —— 告诉init必须等到相应的进程完成之后才能继续执行
once —— 仅执行相应的进程一次,而且不会等待它完成
restart —— 当init重新启动时,执行相应的进程,通常此处所执行的进程就是init本身
ctrlaltdel —— 当按下Ctrl+Alt+Delete组合键时,执行相应的进程
shutdown —— 当系统关机时,执行相应的进程
初始化脚本:rcS --> 系统环境准备与配置
应用及服务脚本:S[0-9]* --> 应用环境准备与配置
S71myapp_demo S01hello
1.init —— inittab —— /etc/init.d/rcS —— /etc/init.d/S[0-9][0-9]* —— Applications
2.用C编写一个应用程序,修改或者创建启动脚本使程序上电自动运行Lession 5. 嵌入式根文件系统框架:busybox编译
ncurses库的支持:
sudo apt-get install libncurses*
aptitude search libncurses
which arm-linux-gcc
Build Options --->
()Cross Compiler prefix
()Path to sysroot
通用配置
[ ] Don't use /usr
构建选项:静态库、交叉编译
[ ] Build BusyBox as a static binary (no shared libs)
安装目录:./_install
(./_install) BusyBox installation prefix
注意:记得保存裁剪配置,可以查看.config文件进行简单的确认
对应busybox的源码目录
裁剪原则:确信你在做什么,否则就不要做
掌握busybox的编译构建步骤和busybox的配置选项
对busybox的配置选项进行各种尝试,观察构建出的busybox体积大小在去掉哪些选项时会有显著的降低Lession 6. 嵌入式根文件系统框架:busybox应用
补全需要的目录:/proc /lib /etc /dev /usr /var
ld-linux.so.3 libc.so.6 libm.so.6
ld-linux.so ----> 实现动态库的链接
C库的选择:glibc,还是uclibc ----> 取决于你的交叉编译器
glibc ---> 更全面完善的功能
uclibc ---> 更小的体积
库文件的查找:交叉编译器的安装目录 find命令
/dev/console
/dev/tty1 /dev/tty2 /dev/tty3
拷贝 examples/bootfloppy/etc
busybox是一个二进制程序,集合大量简单常用的工具程序到单个执行文件代码共用,让busybox更小
单一执行文件,让busybox更简单
得到可用的工具命令(applets)列表
/bin/busybox ls ---> ls
手动创建链接文件:ln -s /bin/busybox /bin/ls
安装过程自动创建所有的链接文件 ---> make install
提供命令的简洁使用说明
设备驱动管理:fdisk fsck hwclock mkdosfs
insmod rmmod lsmod mknod modprobe
lsusb mdev mount umount
mkdir mkfifo ln mv cp touch rm unlink
awk cat cut find vi sed wc tar
grep head tail less more xargs od stat
udhcpc udhcpd route netstat ping ifconfig
chmod clear date dd df echo free
ipcrm ipcs ls ps pwd top uptime
kill killall reboot sleep sysctl usleep
编译完成后的安装步骤是进行busybox根文件系统应用高效开始的第一步
熟悉并掌握常用的工具命令是进行busybox根文件系统应用开发的第二步
确保busybox的正确运行需要额外的库支持,这是进行busybox应用的前提条件Lession 7 文件系统移植实践一:基于busybox制作可用根文件系统
从交叉编译工具目录拷贝
libpthread.so libthread_db.so
libresolv.so
librt.so
/etc/inittab
/etc/fstab: 文件内容与格式介绍, man fstab
设备名称(分区) 挂载点 文件系统类型 挂载选项 备份检查[0|1] fsck优先级[0|1|2]
defaults 使用默认设置,等于rw,suid,dev,exec,auto,nouser,async
内核文件系统挂载:proc
/etc/profile:环境变量的设置与导出
#!/bin/sh
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH
export PATH LD_LIBRARY_PATH
/etc/resolv.conf
DNS配置: nameserver 192.168.10.1
/etc/init.d/rcS
for script in /etc/init.d/S[0-9][0-9]*
do
if [ -x $script ];then/bin/sh -c $script
done
/etc/init.d/S80network:网络配置
ifconfig eth0 hw ether 00:aa:11:cc:01:10
静态配置:
ifconfig eth0 192.168.10.111 broadcast 255.255.255.0
route add default gw 192.168.10.1
动态配置:
udhcpc -i eth0 -t 20 -naq
二进制镜像是根文件系统的目录结构以某种数据组织格式打包成的二进制文件组织格式:文件系统格式
cramfs jffs2 yaffs2 ...
镜像可以方便地进行存储、分发与部署
实践取决于应用需求,原理是相通的,但是不同的需求决定需要包含哪些内容。
Lession 9 Linux内核文件系统:proc、tmpfs、devfs、sysfs
procfs、devfs、sysfs。
procfs是Linux内核信息的抽象文件接口,大量内核中的信息以及可调参数都被作为常规文件映射到
一个目录树中/proc.这样我们就可以简单直接的通过echo或cat这样的文件操作命令对系统信息进行查取
和调整了。大量的系统工具也通过procfs获取内核参数,例如ps、lspci等。mount -t proc none /proc
进程信息
系统信息
cat命令: cat /proc/cmdline
echo命令
tmpfs是一种虚拟内存文件系统,使用内存作为存储分区进行文件的临时性存取,掉电会丢失,创建时不需要使用mkfs等进行格式化。mount -t tmpfs -o size=10M tmpfs /tmp
df -h
正常使用挂载目录:创建文件,存储信息,删除文件等
记住:目录下的所有信息将在系统掉电后全部丢失
提高存储效率,内存的访问速度比Flash快很多
避免对Flash存储设备的频繁读写,提高使用寿命
Linux2.6内核以前设备文件的抽象机制:提供了一种类似于文件的方法来管理位于/dev目录下的所有设备。
设备文件创建
制作根文件系统时创建基本的,比如console,tty1等
设备驱动加载时创建相应的设备文件
/dev/console
/dev/null /dev/zero
不确定的设备映射,有时一个设备映射的设备文件可能不同,例如我的U盘可能对应sda有可能对应sdb
没有足够的主/辅设备号,当设备过多的时候,显然这会成为一个问题
Linux2.6内核以后引入sysfs:挂载于/sys目录下,把实际连接到系统上的设备和总线组织成一个分级的文件,用户空间的程序同样可以利用这些信息以实现和内核的交互,该文件系统是当前系统上实际设备树的一个直观反应。
kobject子系统:建立目录树
当一个kobject被创建的时候,/sys/目录下对应的文件和目录也就被创建
每个设备在sysfs中都有唯一对应的目录,可以被用户空间读写mount -t none sysfs /sys
cat命令: 查看/sys目录下的设备信息
用户空间的工具udev:利用了sysfs提供的信息来实现所有devfs的功能
udev运行在用户空间中,而devfs却运行在内核空间
一切皆文件的抽象思想,使得Linux系统的管理变得简单统一,好的哲学产生好的设计。Lession 10 嵌入式NFS文件系统的介绍与应用
NFS文件系统是嵌入式开发调试的快速高效手段,掌握与熟练使用是必备技能。
1、NFS:Network FileSystem
通过NFS挂载远程主机的目录,访问该目录就像访问本地目录一样
使用NFS服务能够方便地使各unix-like系统之间实现共享
Samba:在unix-like系统和windows系统之间共享
NFS Server <----------> NFS Client
NFS运行在SUN的RPC(Remote Procedure Call,远程过程调用)基础上,RPC定义了一种与系统无关的方法来实现进程间通信
portmap服务
nfs-kernel-server服务
安装:# sudo apt-get install nfs-kernel-server
启动:# sudo /etc/init.d/nfs-kernel-server start
停止:# sudo /etc/init.d/nfs-kernel-server stop
状态:# sudo /etc/init.d/nfs-kernel-server status
重启:# sudo /etc/init.d/nfs-kernel-server restart
对NFS服务的访问是由exports来批准,它枚举了若干有权访问NFS服务器上文件系统的主机名。
文件控制对目录的共享(NFS挂载目录及权限由该文件定义),书写规则是每个共享为一行)。
第一个参数是要让客户机访问的目录,第二个是你允许的主机IP,最后的()内是访问控制方式。
ro 只读访问
rw 读写访问
sync 所有数据在请求时写入共享(默认)
async NFS在写入数据前可以相应请求
secure NFS通过1024以下的安全TCP/IP端口发送
insecure NFS通过1024以上的端口发送
wdelay 如果多个用户要写入NFS目录,则归组写入(默认)
no_wdelay 如果多个用户要写入NFS目录,则立即写入,当使用async时,无需此设置
hide 在NFS共享目录中不共享其子目录
no_hide 共享NFS目录的子目录
subtree_check 要求检查请求访问的目录或者文件是否在共享目录下
no_subtree_check 只检查请求访问的目录或文件是否在共享的文件系统中
all_squash 共享文件的UID和GID映射匿名用户anonymous,适合公用目录
no_all_squash 保留共享文件的UID和GID(默认)
root_squash root用户的所有请求映射成如anonymous用户一样的权限(默认)
no_root_squash root用户具有根目录的完全管理访问权限
anonuid=xxx 指定NFS服务器/etc/passwd文件中匿名用户的UID
anongid=xxx 指定NFS服务器/etc/passwd文件中匿名用户的GID
exportfs
重新加载/etc/exports的共享目录,卸载NFS Server共享的目录或者重新共享
若更改了/etc/exports,运行以下命令进行更新:$ sudo exportfs -r
用來查看NFS共享的目录资源, 查看NFS Server的export list:$ sudo showmount -e
一般需要关闭防火墙服务,确保没有屏蔽NFS使用的端口和允许通信的主机
Network FileSystem --> [] NFS Client
首先查看目标板kernel自身是否支持NFScat /proc/filesystems命令: 是否有NFS一行
挂载格式: mount [Server IP]:/[share dir] [local mount point]# mount -t nfs -o nolock 192.168.10.11:/opt/FriendlyARM/mini2440/root_nfs /mnt/root_nfs
# df -h
# umount /mnt/root_nfs
Lession 11 Ramfs文件系统:initramfs概念与使用
内核有可能无能为力,通过提供一个过渡的临时根文件系统可以使得内核的设计更灵活简单。
内核启动的初始始根文件系统,大部分linux系统正常运行后都会安装另外的文件系统,然后忽略rootfs
基于内存的文件系统。ramfs文件系统没有容量大小的限制,它可以根据需要动态增加容量。
直接利用了内核的磁盘高速缓存
基于ram的块设备,占据一块固定的内存,事先要使用特定的工具比如mke2fs格式化,还需要一个文件系统驱动来读写其上的文件
空间固定导致容量有限,要想装入更多的文件需要重新格式化
Linux的块设备缓冲特性, ram disk上的数据被拷贝到page cache(对于文件数据)和dentry cache(对于目录项),导致内存浪费
ramfs的一个缺点是它可能不停的动态增长直到耗尽系统的全部内存,所以只有root或授权用户允许使用ramfs。
增加了容量大小的限制 + 允许把数据写入交换分区
由于增加了这两个特性,tmpfs允许普通用户使用。
过渡根文件系统机制:将加载真正的根文件系统需要的设备驱动、工具以及初始化程序先加载到内存运行。
/linuxrc文件
基于ramdisk技术
文件系统(ext2等)镜像文件 ————> cpio格式镜像文件
在内核启动完成后把它复制到/dev/ram块设备中, 作为内核加载真正根文件系统的过渡根文件系统
init文件
cpio格式镜像文件
在内核启动完成后把它复制到rootfs中,作为内核初始的根文件系统,完成挂载系统真正的根文件系统
#include
{
printf("Hello world Initramfs!\n");
sleep(999999999);
}
交叉编译:arm-linux-gcc -static hello.c -o hello
修改命名:mv hello init
find .|cpio -o -H newc|gzip > ~/myinitramfs.cpio.gz
在内核中选择使用: 注意选择initramfs的压缩格式
cpio -i -F myinitramfs.cpio --no-absolute-filenames
zcat myinitramfs.cpio.gz | cpio -i -d -H newc --no-absolute-filenames
General setup --->
[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support
(/rootfs_dir) Initramfs source file(s)
Built-in initramfs compression mode (None) ---> [] None [] GZIP
Linux内核 ————> initrd/initramfs(包含根文件系统的设备驱动等) ————> Real Root Filesystem
详细官方的描述文档:内核源码树下 Documentation/filesystems/ramfs-rootfs-initramfs.txtLession 13 Flash文件系统:jffs/jffs2和yaffs/yaffs2
非易失存储器,可以对称为块的存储器单元块进行擦写和再编程
任何flash器件的写入操作只能在空或已擦除的单元内进行,在进行写入操作之前必须先执行擦除
应用:代码存储介质
特点:
芯片内执行(XIP, eXecute In Place)
低容量高成本: 1 - 16MB(常见)
读写速度:读取速度快,写入速度慢
块最大擦写次数:10W
应用:数据存储介质
特点:
极高的单元密度
读写速度:写入和擦除的速度很快
高容量低成本:16 - 1024MB(常见)
块最大擦写次数:100W
JFFS:1999
Journalling Flash File System, Version 2:2001-9-23,Linux 2.4.10
主要用于NOR Flash,可用于NAND Flash
掉电保护与损耗平衡
垃圾回收机制
CRC循环冗余校验机制
挂载时间与内存消耗跟文件系统的大小成正比:文件系统越大,越慢,消耗越多 ————> 很差的扩展性
挂载需要进行全盘扫描,挂载一个 16M 的闪存有时需要半分钟以上的时间
在实际应用中,JFFS2 最大能用在 128M 的闪存上
YAFFS:2002
Yet Another Flash File System, Version 2:2003
只能用于NAND Flash, YAFFS1支持512Bytes/Page的NAND Flash;YAFFS2支持2kBytes/Page的NAND Flash.储存资料的基本单位是Chunk:Page
支持YAFFS/Direct使用:可以不需要VFS,甚至操作系统支持
ECC冗余校验机制
纠正单比特错误和检测双比特错误,而且计算速度很快,但对1比特以上的错误无法纠正,对2比特以上的错误不保证能检测。
更快的挂载速度,更少的内存使用
512B/page ————> 4KB RAM/1MB NAND
2KB/Page ————> 1KB RAM/1MB NAND
JFFS与YAFFS都是日志结构文件系统(LFS),保障了数据的可靠性与安全性,可以恢复数据。
一般来说,对于小于64MB的NAND Flash,可以选用JFFS2;如果超过64MB,用YAFFS2比较合适Lesson 16 Cramfs文件系统的制作与使用
sudo apt-get install cramfsprogsmkcramfs
cramfsck
文件系统内容:mini_busybox/
mkcramfs [dir] [fs-name]
文件系统验证:cramfsck [fs-name]
losetup [loop device] [fs-file]
losetup -a
losetup -d [loop device]
Lesson 17 squashfs文件系统的制作与使用
sudo apt-get install squashfs-toolsmksquashfs
unsquashfs
mksquashfs source1 source2 ... dest [options] [-e list of exclude dirs/files]
主要选项:-comp <comp> 指定压缩算法:gzip (default)/lzo/xz
-b <block_size> 设置块大小,单位 Bytes,默认 131072 bytes (1MB)
-no-exports 不支持NFS文件系统导出
-no-sparse 不检测稀疏文件
-no-xattrs 不存储扩展文件属性(XATTR)
-xattrs 存储扩展文件属性(default)
-noI 不压缩Inode节点表
-noD 不压缩数据块
-noF 不压缩片段块
-noX 不压缩扩展文件属性
-no-fragments 不使用片段管理
-always-use-fragments 对比块大小大的文件也是用片段块
-no-duplicates 不对文件重复进行检查
-all-root 修改所有的文件拥有者为root
-force-uid uid 设置所有文件的uid为指定的uid
-force-gid gid 设置所有文件的gid为指定的gid
-nopad 不对文件系统进行4K字节对齐
-keep-as-directory 如果指定的源中有目录,在文件系统中创建根目录包含该目录,而不是包含目录内容
mksquashfs mini_busybox rootfs.squashfs -no-exports -no-xattrs -all-root
内容提取:unsquashfs [options] filesystem [directories or files to extract]
主要选项:
-d[est] <pathname> 解压到指定目录,默认为"squashfs-root"
-n[o-progress] 不显示进度条
-no[-xattrs] 不提取xattr属性,默认提取
-l[s] 列出文件系统内容,不进行解压缩提取
unsquashfs rootfs.squashfs
sudo losetup /dev/loop0 rootfs.squashfs
sudo mount /dev/loop0 /mnt
sudo losetup -a
sudo umount /dev/loop0
sudo losetup -d /dev/loop0
Lession 18 jffs2文件系统的制作与使用
sudo apt-get install mtd-utils
信息收集:Flash的页大小、擦除块大小
主要选项: -p, --pad[=SIZE] 使用0xff填充文件系统到指定大小,不指定则只填充完最后一个擦除块
-r, -d, --root=DIR 使用指定的目录内容构建文件系统(default: cwd)
-s, --pagesize=SIZE 使用指定的页大小(最大数据节点大小) (default: 4KiB)
-e, --eraseblock=SIZE 指定擦除块的大小 (default: 64KiB)
-c, --cleanmarker=SIZE 擦除标记的大小 (default 12)
-m, --compr-mode=MODE 选择压缩模式(default: priortiry)
-x, --disable-compressor=COMPRESSOR_NAME 禁用指定的压缩算法
-X, --enable-compressor=COMPRESSOR_NAME 启用指定的压缩算法
-y, --compressor-priority=PRIORITY:COMPRESSOR_NAME 设置压缩算法的优先级
-L, --list-compressors 列出可用的压缩算法
-t, --test-compression 测试压缩算法
-n, --no-cleanmarkers 不添加擦除标记到擦除块
-o, --output=FILE 指定文件系统镜像名称(default: stdout)
-l, --little-endian 创建一个小端的文件系统
-b, --big-endian 创建一个大端的文件系统
-q, --squash 压缩权限和设置所有文件的拥有者为root
-U, --squash-uids 设置所有文件的拥有者为root
-P, --squash-perms 压缩所有文件的权限
mkfs.jffs2 -d mini_busybox --pad=0x1000000 -s 4096 -l -o rootfs.jffs2
MTD设备文件系统: 无法使用/dev/loop0块设备来模拟只能在Flash设备上使用
Lession 19 yaffs2文件系统的制作与使用
git clone git://www.aleph1.co.uk/yaffs2
从源码中编译制作工具:cd yaffs2/utils
make
error: unknown type name ‘u8’
error: unknown type name ‘u32’
修改yportenv.h文件,增加:#define CONFIG_YAFFS_DEFINES_TYPES
mkyaffs2image: YAFFS2(2KB/page)
mkyaffsimage: YAFFS(512B/page)
文件系统内容:mini_busybox/
mkyaffs2image dir image_file [convert]
MTD设备文件系统: 无法使用/dev/loop0块设备来模拟只能在NAND Flash设备上使用
Lession 20 文件系统移植实践三:Flash分区与文件系统镜像烧录
bootloader + kernel + rootfs + appfs
mtdparts: mtdparts=mtd-id:
mtdparts=s5pv210-nand:1M(boot),5M(kernel),80M(rootfs),426M(usrfs)
mtdparts=s5pv210-nand:1M(boot),5M(kernel),80M(rootfs),16M(jffs2),394M(yaffs2)
要想这个参数起作用,内核中的mtd驱动必须要支持,即内核配置时需要选上
Device Drivers ---> Memory Technology Device (MTD) support ---> Command line partition table parsing
0x000000100000-0x000000600000 : "kernel"
0x000000600000-0x000005600000 : "rootfs"
0x000005600000-0x000006600000 : "jffs2"
0x000006600000-0x000020000000 : "yaffs2"
nand - NAND sub-system
nand device [dev] - show or set current device
nand read - addr off|partition size
nand write - addr off|partition sizeread/write 'size' bytes starting at offset 'off'
to/from memory address 'addr', skipping bad blocks.
write 'size' bytes starting at offset 'off' with yaffs format
from memory address 'addr', skipping bad blocks.
With '.spread', erase enough for given file size, otherwise,
'size' includes skipped bad blocks.
K9F4G08X0B Array Organization:
1 Page = (2K + 64)Bytes
1 Block = 64 Pages = (128K + 4K) Bytes
tftp 0x20008000
Flash地址偏移
0x000005600000-0x000006600000 : "jffs2"
0x000006600000-0x000020000000 : "yaffs2"
nand erase[.spread]
nand write
nand write.yaffs
tftp 0x20008000 rootfs.jffs2;nand erase 0x5600000 0x1000000;nand write 0x20008000 0x6600000 0x1000000
tftp 0x20008000 rootfs.yaffs2;nand erase 0x6600000 0x19a00000;nand write.yaffs 0x20008000 0x6600000 0x4194c0Lession 21 文件系统的挂载配置与选项
根文件系统挂载: 内核完成
应用文件系统(设备分区)挂载:mount命令Linux伪文件系统
tmpfs文件系统
Flash设备分区
准备工作:设备分区:/dev/mtdblock3 /dev/mtdbock4
创建挂载点:/mnt /tmp /apps
mount 系统当前的文件系统挂载信息
mount -a 挂载/etc/fstab文件中指定的文件系统与设备
mount -t <fstype> [options] <device name> <mount-point> 挂载指定类型的设备到指定挂载点
mount -t jffs2 /dev/mtdblock3 /appfs/jffs2 ----> 时间比yaffs2的挂载长很多
mount -t yaffs2 /dev/mtdblock4 /appfs/yaffs2
/etc/fstab 添加设备与文件系统的挂载配置
注意:确保MTD设备分区已识别(udev/mdev的运行需要比/etc/fstab的挂载早)
/etc/init.d/rc.S 添加具体的设备挂载命令
添加挂载脚本:
mount -t jffs2 /dev/mtdblock3 /appfs/jffs2
mount -t yaffs2 /dev/mtdblock4 /appfs/yaffs2
Lession 22 嵌入式开发文件系统的选择与配置原则
基础硬件驱动移植
串口控制终端
Flash设备
网卡识别
完整硬件驱动移植
文件系统支持移植
移植构建根文件系统
组织应用文件系统
应用开发
uboot + kernel + fs
镜像制作与烧录
根文件系统:建立用户空间使用环境
busybox -----> 提供系统管理等全面的用户工具集合
启动脚本 -----> 配置用户空间的环境变量与提供应用开机启动机制
防止修改: cramfs squashfs
Flash设备: jffs2 yaffs2
SD卡等外部设备:FAT32
系统信息管理:Linux伪文件系统proc
sys
tmpfs