嵌入式Linux根文件系统制作

2019-07-12 14:41发布

嵌入式Linux根文件系统制作

一、根文件系统简介     根文件系统首先是一种文件系统,该文件系统不仅具有普通文件系统的存储数据文件的功能,但是相对于普通的文件系统而言它还是内核启动时所挂载(mount)的第一个文件系统,系统引导启动程序会在根文件系统挂之后从中把一些初始化脚本(如inittab、rcS)和服务加载到内存中去运行。我们要明白文件系统和内核是完全独立的两个部分。在嵌入式中移植的内核下载到开发板上,是没有办法真正的启动Linux操作系统的,会出现无法加载文件系统的错误。     根文件系统之所以在前面加一个”根“,说明它是加载其它文件系统的”根“,既然是根的话,那么如果没有这个根,其它的文件系统也就没有办法进行加载的。它包括了Linux启动时所必须的目录和关键性的文件,例如Linux启动时都需要有init目录下的相关文件,在 Linux挂载分区时Linux一定会找/etc/fstab这个挂载配置文件等,根文件系统中还包括了应用程序(如ls、mkdir、rm、ifconfig等命令)和 GNU C 库(glibc、eglibc或uclibc)等。任何包括这些Linux 系统启动所必须的文件都可以成为根文件系统。Linux启动时,第一个必须挂载的是根文件系统;若系统不能从指定设备上挂载根文件系统,则系统会出错而退出启动。成功之后可以自动或手动挂载其他的文件系统。因此,一个系统中可以同时存在不同的文件系统。     在 Linux 中将一个文件系统与一个存储设备关联起来的过程称为挂载(mount)。使用 mount 命令将一个文件系统附着到当前文件系统层次结构中(根)。在执行挂载时,要提供文件系统类型、文件系统和一个挂载点。根文件系统被挂载到根目录下“/”上后,在根目录下就有根文件系统的各个目录,文件:/bin /sbin /mnt等,再将其他分区挂接到/mnt目录上,/mnt目录下就有这个分区的各个目录,文件。Linux操作系统可以支持多种多样不同的文件系统,如windows下的FAT32、NTFS,Linux服务器使用的ext2、ext3、ext4、btrfs、xfs、reiser4、ufs、hfs(苹果系统),Linux操作系统自身使用的伪文件系统如swap、proc、sysfs、tmpfs等,也有一些设备的文件系统如iso9660(光盘)、nfs(网络文件系统)等,当然还包括我们嵌入式设备上用的不同的文件系统如:initramfs(在内存中运行的文件系统)、jffs2(一种基于Norflash的文件系统,也支持小页的nandflash)、ubifs(目前Android手机上的Nandflash普遍使用的文件系统)、yaffs2(早期专门用来支持大页Nandflash的文件系统,具备可移植性可在单片机裸机情况下使用)、cramfs(一种基于内存的只读的文件系统)、squashfs(在openwrt路由器上广泛使用的俄文件系统)、romfs(一种只读、支持片上执行XIP的文件系统,在uClinux中广泛使用)等。下面是几种常用的嵌入式根文件系统的对比:           initramfs 该文件系统直接将根文件系统直接打包进Linux内核里(只有这种文件系统具有该功能),这样内核和根文件系统绑定在一块成为一个单独的文件,他在Linux系统启动后加载到内存中运行,所以速度快,但浪费内存,系统升级的时候内核和根文件系统一起升级比较方便。但因为他是基于内存的文件系统,所以系统掉电后针对根文件系统下所有文件的修改掉电都会丢失,如果要升级根文件系统只有重新编译、烧录Linux内核;           jffs2 专门针对Norflash设计的文件系统,小页的Nandflash也可以使用,只是效率不高;因为根文件系统存放在Flash上,所以根文件系统路径下的文件修改后掉电仍然存在;           yaffs2 早期专门针对大页Nandflash设计的文件系统,他的源码独立于Linux内核维护着,所以可以在单片机等裸机环境下使用(只有该文件系统可以),linux内核想用它必须要打上补丁;在分区较大时,nandflash的挂载时间较长,现在逐渐被ubifs广泛替代;           ubifs 专门针对Nandflash设计的一种文件系统,他在内核的MTD一层上面又建立了UBI一层,挂载速度、磨损均衡、读写速度非常快,目前nandflash上应用得最广的一种根文件系统;      Linux操作系统之所以能够支持这么多种不同的文件系统,主要是通过叫做VFS的中间层对这些文件系统提供了完美的支持。对于用户来说,这些文件系统几乎是透明的,在大部分情况下,用户通过libc和kernel的VFS交互,不需要关心底层文件系统的具体实现,但是有时应用程序也需要考虑底层文件系统限制(比如fat vfat不支持链接,比如各个文件系统支持最大文件限制不同)。VFS主要有以下特性:         1. 向上,对应用层提供一个标准的文件操作接口,如open()、read()、write()、ioct()、close()等;         2. 对下,对所有文件系统提供一个统一的标准接口,以便其他操作系统的文件系统可以方便的移植到Linux上;         3. VFS内部则通过一系列高效的管理机制,比如inode cache, dentry cache 以及文件系统的预读等技术,使得底层文件系统不需沉溺到复杂的内核操作,即可获得高性能;         4. 此外VFS把一些复杂的操作尽量抽象到VFS内部,使得底层文件系统实现更简单。 下图是Linux内核里文件系统的分层结构图: 二、mtd-utils工具源码编译     Linux内核MTD对同一Flash分区提供了两种设备文件给用户层使用,一种是/dev/mtdblockX块设备,该设备用来建立文件系统并挂载起来使用;另外一种相对应的/dev/mtdX字符设备,其里面添加了 一些ioctl,支持很多命令,如MEMGETINFO,MEMERASE等。而mtd-util就是以这些ioctl为基础而实现的工具,实现一些关于Flash的操作,如flash_erase、flash_eraseall、flashcp、nandwrite等命令,此外在PC上制作根文件系统所需要的一些工具也在里面,如制作JFFS2根文件系统用的mkfs.jffs2、制作UBIFS根文件系统工具mkfs.ubifs以及开发板上操作UBI文件系统的命令。     这里我们只介绍PC端的源码编译来获取mkfs.jffs2和mkfs.ubifs工具,如果相应的工具需要放在ARM开发板上运行则需要使用交叉编译器编译。mtd_utils需要lzo、zlib和e2fsprogs这三个库,所以在编译mtd_utils之前先需要编译这三个库。Linux下使用源码安装工具时,如果有Makefile则直接用make命令编译,如果没有Makefile文件,则一般有个configure的脚本,该源码结构的编译三步曲: ./configure、make、make install
2.1 创建mtd-utils的工作路径 [wudongxu@centos6_master ~]$ cd gitee/fl2440/ [wudongxu @centos6_master fl2440]$ mkdir -p x86_tools/mtd_utils     mtd-utils编译依赖lzo、zlib和libuuu这几个库,所以我们在编译它之前先要编译这些库。另外,为了在运行mkfs.jffs2和mkfs.ubifs这些命令时不依赖这些动态库,我们采用静态编译、然后静态链接生成这两个命令。
2.2 编译lzo库 [wudongxu @centos6_master ~]$ cd ~/gitee/fl2440/x86_tools/mtd_utils/ [wudongxu @centos6_master mtd_utils]$ wget http://www.oberhumer.com/opensource/lzo/download/lzo-2.10.tar.gz 下载lzo库 [wudongxu @centos6_master mtd_utils]$ tar -xzf lzo-2.10.tar.gz [wudongxu @centos6_master mtd_utils]$ cd lzo-2.10 [wudongxu @centos6_master lzo-2.10]$ ./configure --help 查看configure帮助信息,可以看出他支持哪些参数 [wudongxu @centos6_master lzo-2.10]$ ./configure --prefix=`pwd`/../install --enable- static --disable-shared --prefix指定安装路径 --enable-static指定生产静态库 --disable- shared 指定不要生成动态库 [wudongxu @centos6_master lzo-2.10]$ make && make install
2.3 编译zlib库 [wudongxu @centos6_master ~]$ cd ~/gitee/fl2440/x86_tools/mtd_utils/ [wudongxu @centos6_master mtd_utils]$ wget https://github.com/madler/zlib/archive/v1.2.10.tar.gz -O zlib-1.2.10.tar.gz [wudongxu @centos6_master mtd_utils]$ tar -xzf zlib-1.2.10.tar.gz [wudongxu @centos6_master mtd_utils]$ cd zlib-1.2.10 [wudongxu @centos6_master zlib-1.2.10]$ ./configure --prefix=`pwd`/../install --static [wudongxu @centos6_master zlib-1.2.10]$ make && make install
2.4 编译e2fsprogs库(libuuid) [wudongxu @centos6_master ~]$ cd ~/gitee/fl2440/x86_tools/mtd_utils/ [wudongxu @centos6_master mtd_utils]$ wget https://github.com/tytso/e2fsprogs/archive/v1.43.7.tar.gz -O e2fsprogs-1.43.7.tar.gz [wudongxu @centos6_master mtd_utils]$ tar -xzf e2fsprogs-1.43.7.tar.gz [wudongxu @centos6_master mtd_utils]$ cd e2fsprogs-1.43.7/ [wudongxu @centos6_master e2fsprogs-1.43.7]$ ./configure --prefix=`pwd`/../install -- enable-elf-shlibs --enable-libuuid [wudongxu @centos6_master e2fsprogs-1.43.7]$ make ; make install-libs
2.5 编译mtd-utils并安装mkfs.jffs2和mkfs.ubifs [wudongxu @centos6_master ~]$ cd ~/gitee/fl2440/x86_tools/mtd_utils/ [wudongxu @centos6_master mtd_utils]$ wget ftp://ftp.infradead.org/pub/mtd- utils/mtd-utils-1.5.2.tar.bz2 [wudongxu @centos6_master mtd_utils]$ tar -xjf mtd-utils-1.5.2.tar.bz2 [wudongxu @centos6_master mtd_utils]$ [wudongxu @centos6_master mtd-utils-1.5.2]$ export CFLAGS+=" -I../install/include/ " [wudongxu @centos6_master mtd-utils-1.5.2]$ export CFLAGS+=" -I../install/include/ " [wudongxu @centos6_master mtd-utils-1.5.2]$ export LDFLAGS+=" -L../install/lib/ - static " [wudongxu @centos6_master mtd-utils-1.5.2]$ make WITHOUT_XATTR=1
安装接下来制作根文件系统所需的两个工具到系统中: [wudongxu @centos6_master mtd-utils-1.5.2]$ sudo cp mkfs.jffs2 /bin/ [wudongxu @centos6_master mtd-utils-1.5.2]$ sudo cp mkfs.ubifs/mkfs.ubifs /bin/ [wudongxu @centos6_master mtd-utils-1.5.2]$ sudo cp ubi-utils/ubinize /bin/
三、内核调整Nandflash分区表 FL2440上使用K9F2G08这个256MB的Nandflash,就像PC上的硬盘一样,我们也需要对整个Nandflash进行分区。只不过这个分区的过程是通过在Linux的源码修改来调整,接下来我们按照下面这个分区表来调整Linux系统的分区表。 [wudongxu @centos6_master ~]$ cd gitee/fl2440/linux/linux-3.0 [wudongxu @centos6_master linux-3.0]$ vim arch/arm/plat-s3c24xx/common-smdk.c /* NAND pa rititon from 2.4.18-swl5 */ static struct mtd_partition smdk_default_nand_part[] = { [0] = { .name = "mtdblock0 u-boot 1MB", .offset = 0, .size = SZ_1M*1, /* 0x0000000 ~ 0x0100000 */ },[1] = { .name = "mtdblock1 kernel 15MB", .offset = MTDPART_OFS_NXTBLK, .size = SZ_1M*15, /* 0x0100000 ~ 0X1000000 */ },[2] = { .name = "mtdblock2 rootfs 40MB", .offset = MTDPART_OFS_NXTBLK, .size = SZ_1M*40, },[3] = { .name = "mtdblock3 apps 80MB", .offset = MTDPART_OFS_NXTBLK, .size = SZ_1M*80, },[4] = { .name = "mtdblock4 data 80MB", .offset = MTDPART_OFS_NXTBLK, .size = SZ_1M*80, },[5] = { .name = "mtdblock5 backup 40MB", .offset = MTDPART_OFS_NXTBLK, .size = SZ_1M*40, } }; static struct s3c2410_nand_set smdk_nand_sets[] = { 重新编译Linux内核并启动,这时我们就会发现内核启动时打印出新的分区信息 S3C24XX NAND Driver, (c) 2004 Simtec Electronics s3c24xx-nand s3c2440-nand: Tacls=3, 29ns Twrph0=7 69ns, Twrph1=3 29ns s3c24xx-nand s3c2440-nand: NAND soft ECC NAND device: Manufacturer ID: 0xec, Chip ID: 0xda (Samsung NAND 256MiB 3,3V 8-bit) Scanning device for bad blocks Bad eraseblock 94 at 0x000000bc0000 Bad eraseblock 418 at 0x000003440000 Bad eraseblock 713 at 0x000005920000 Bad eraseblock 1144 at 0x000008f00000 Bad eraseblock 1940 at 0x00000f280000 Bad eraseblock 2010 at 0x00000fb40000 Creating 6 MTD partitions on "NAND": 0x000000000000-0x000000100000 : "mtdblock0 u-boot 1MB" 0x000000100000-0x000001000000 : "mtdblock1 kernel 15MB" 0x000001000000-0x000003800000 : "mtdblock2 rootfs 40MB" 0x000003800000-0x000008800000 : "mtdblock3 apps 80MB" 0x000008800000-0x00000d800000 : "mtdblock4 data 80MB" 0x00000d800000-0x000010000000 : "mtdblock5 backup 40MB" dm9000 Ethernet Driver, V1.31 eth0: dm9000a at c4862300,c4864304 IRQ 51 MAC: 08:00:3e:26:0a:5b (chip) 登录开发板Linux后,我们也可以使用 cat /proc/mtd 命令查看分区信息 ~ >: cat /proc/mtd dev: size erasesize name mtd0: 00100000 00020000 "mtdblock0 u-boot 1MB" mtd1: 00f00000 00020000 "mtdblock1 kernel 15MB" mtd2: 02800000 00020000 "mtdblock2 rootfs 40MB" mtd3: 05000000 00020000 "mtdblock3 apps 80MB" mtd4: 05000000 00020000 "mtdblock4 data 80MB" mtd5: 02800000 00020000 "mtdblock5 backup 40MB" 开发板Linux系统的路径下会产生相应的分区文件,其中mtdX(X为0,1,2,3....)为可读写字符设备, mtdXro为只读的字符设备, mtdblockX为mount命令挂载使用的块设备。 ~ >: ls -l /dev/mtd* crw-rw---- 1 root root 90, 0 Jan 1 00:00 /dev/mtd0 crw-rw---- 1 root root 90, 1 Jan 1 00:00 /dev/mtd0ro crw-rw---- 1 root root 90, 2 Jan 1 00:00 /dev/mtd1 crw-rw---- 1 root root 90, 3 Jan 1 00:00 /dev/mtd1ro crw-rw---- 1 root root 90, 4 Jan 1 00:00 /dev/mtd2 crw-rw---- 1 root root 90, 5 Jan 1 00:00 /dev/mtd2ro crw-rw---- 1 root root 90, 6 Jan 1 00:00 /dev/mtd3 crw-rw---- 1 root root 90, 7 Jan 1 00:00 /dev/mtd3ro crw-rw---- 1 root root 90, 8 Jan 1 00:00 /dev/mtd4 crw-rw---- 1 root root 90, 9 Jan 1 00:00 /dev/mtd4ro crw-rw---- 1 root root 90, 10 Jan 1 00:00 /dev/mtd5 crw-rw---- 1 root root 90, 11 Jan 1 00:00 /dev/mtd5ro brw-rw---- 1 root root 31, 0 Jan 1 00:00 /dev/mtdblock0 brw-rw---- 1 root root 31, 1 Jan 1 00:00 /dev/mtdblock1 brw-rw---- 1 root root 31, 2 Jan 1 00:00 /dev/mtdblock2 brw-rw---- 1 root root 31, 3 Jan 1 00:00 /dev/mtdblock3 brw-rw---- 1 root root 31, 4 Jan 1 00:00 /dev/mtdblock4 brw-rw---- 1 root root 31, 5 Jan 1 00:00 /dev/mtdblock5 四、jffs2根文件系统制作 4.1 jffs2文件系统简介 JFFS2全名是 Journalling Flash File System Version2,是Redhat公司开发的Flash的文件系统,其 前身是JFFS, 最早只支援Norflash, 自2.6版以后开始支援NAND Flash,其功能就是管理在MTD设备 上实现的日志型文件系统,极适合使用于嵌入式系统。与其他的存储设备存储方案相比,JFFS2并不准 备提供让传统文件系统也可以使用此类设备的转换层。它只会直接在MTD设备上实现日志结构的文件系 统。JFFS2会在安装的时候,扫描MTD设备的日志内容,并在RAM中重新建立文件系统结构本身。除了 提供具有断电可靠性的日志结构文件系统,JFFS2还会在它管理的MTD设备上实现“损耗平衡”和“数 据压缩”等特性。下面是JFFS2的不足之处: JFFS2 的挂载(mount)过程需要对Flash从头到尾的扫描,这个过程是很慢的,我们在测试中发 现,挂载一个 16M 的闪存有时需要半分钟以上的时间 JFFS2 在分区的空间使用率比较大后,数据的读写非常缓慢 JFFS2 对磨损平衡是用概率的方法来解决的,这很难保证磨损平衡的确定性。在某些情况下,可 能造成对擦写块不必要的擦写操作;在某些情况下,又会引起对磨损平衡调整的不及时。 JFFS2没有write-back机制,不能将资料暂存于缓存(cache), 以致于flash I/O的动作频繁。 JFFS2是针对早起的Norflash和小页(页大小<4K)的Nandflash设计的,并不适合大页的Nandflash。 所以我们一般在Norflash上使用JFFS2文件系统,而现在普遍使用的大页Nandflash并不适用它。 4.2 根文件系统镜像文件制作 我们可以使用mtd-utils源码编译出来的mkfs.jffs2工具,将根文件系统树目录制作成jffs2根文件系统 镜像。在开始制作镜像之前,我们先看看mkfs.jffs2的使用说明: [wudongxu @centos6_master linux]$ mkfs.jffs2 -h mkfs.jffs2: error!: Usage: mkfs.jffs2 [OPTIONS] Make a JFFS2 file system image from an existing directory tree Options: -p, --pad[=SIZE] Pad output to SIZE bytes with 0xFF. If SIZE is 指 定jffs2文件系统镜像的填充大小 not specified, the output is padded to the end of the final erase block -r, -d, --root=DIR Build file system from directory DIR (default: cwd) 指 定根文件系统目录树的路径 -s, --pagesize=SIZE Use page size (max data node size) SIZE. 指 定Nandflash的页大小 Set according to target system's memory management page size (default: 4KiB) -e, --eraseblock=SIZE Use erase block size SIZE (default: 64KiB) 指 定Nandflash的块大小 -c, --cleanmarker=SIZE Size of cleanmarker (default 12) -m, --compr-mode=MODE Select compression mode (default: priority) -x, --disable-compressor=COMPRESSOR_NAME Disable a compressor -X, --enable-compressor=COMPRESSOR_NAME Enable a compressor -y, --compressor-priority=PRIORITY:COMPRESSOR_NAME Set the priority of a compressor -L, --list-compressors Show the list of the available compressors -t, --test-compression Call decompress and compare with the original (for test) -n, --no-cleanmarkers Don't add a cleanmarker to every eraseblock 指 定不添加清除标记 -o, --output=FILE Output to FILE (default: stdout) 指定制作出来的根文件系统镜像文件名 -l, --little-endian Create a little-endian filesystem -b, --big-endian Create a big-endian filesystem -D, --devtable=FILE Use the named FILE as a device table file -f, --faketime Change all file times to '0' for regression testing -q, --squash Squash permissions and owners making all files be owned by root -U, --squash-uids Squash owners making all files be owned by root -P, --squash-perms Squash permissions on all files --with-xattr stuff all xattr entries into image --with-selinux stuff only SELinux Labels into jffs2 image --with-posix-acl stuff only POSIX ACL entries into jffs2 image -h, --help Display this help text -v, --verbose Verbose operation -V, --version Display version information -i, --incremental=FILE Parse FILE and generate appendage output for it 下载我们开始使用根文件系统树制作JFFS2根文件系统镜像: [wudongxu @centos6_master ~]$ cd gitee/fl2440/linux/ [wudongxu @centos6_master linux]$ du -sh rootfs 12M rootfs [wudongxu @centos6_master linux]$ mkfs.jffs2 -n -s 2048 -e 128KiB -d ./rootfs -o rootfs-jffs2.bin 制作根文件系统时不进行填充 [wudongxu @centos6_master linux]$ du -sh rootfs-jffs2.bin 6.3M rootfs-jffs2.bin 不进行填充的文件系统大小为6.3M [wudongxu @centos6_master linux]$ mkfs.jffs2 -n -s 2048 -e 128KiB -d ./rootfs -o rootfs-jffs2.bin --pad=0xa00000 -n 指明不添加清除标记(nand flash 有自己的校检块,存放相关的信息),如果挂载后会出现 下面类似警告信息,则加上-n 就会消失: CLEANMARKER node found at 0x0042c000 has totlen 0xc != normal 0x0 -s 指定Nandflash的页大小为2KB -e 指定Nandflash的擦除块大小为128KB -d 指定根文件系统目录树的路径 为./rootfs -o 指定制作生成的根文件系统镜像文件名为 rootfs-jffs.bin,该文件需要u-boot烧录到 Nandflash的相应分区 --pad=0xa00000 将制作的根文件系统镜像(rootfs-jffs2.bin)文件大小用0xFF填充为--pad指 定的值。如果在制作根文件系统的不填充的话,Linux挂载启动根文件系统时将会出现下面警告 信息。 jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x006430dc: 0x5555 instead jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x006430e0: 0x5555 instead 我们在之前的Linux内核Nandflash分区修改里将rootfs分区大小设置为40M,所以这里的--pad值 应该为0x280000。但如果使用0x2800000,则根文件系统镜像的大小就为40M,这样u-boot下载烧 录的时间较长,另外如果在Nandflash上烧录该镜像文件的分区存在坏块的话,则在u-boot里用nand write烧录时会跳过坏块溢出到下一个分区空间中去,从而占用了下一个空间的使用,系统就会出错。这 里我们将填充大小值设置为10M是也可以解决上面jffs2_scan_eraseblock抛出的警告信息,之所以将 填充大小设置为10M是因为不进行填充时制作的根文件系统镜像大小为6.3M,这个值的大小根据分区 大小和根文件系统目录树的实际大小进行调整。 4.3 内核配置和编译 [wudongxu @centos6_master linux-3.0]$ export TERM=vt100 [wudongxu @centos6_master linux-3.0]$ make menuconfig General setup ---> [ ] Automatically append version information to the version string 取消这个 选项减少内核大小 [ ] Support for paging of anonymous memory (swap) Nandflash不需要 swap分区,如果是PC上的硬盘则需要swap分区 <*> Kernel .config support [ ] Initial RAM filesystem and RAM disk (initramfs/initrd) support 一定要 取消initramfs的支持,否则内核找到initramfs则直接使用initramfs启动 [*] Configure standard kernel features (expert users) ---> 添加这个选项 [*] Embedded system 添加这个选项 File systems ---> < > Second extended fs support 取消PC端用的ext2文件系统支持,减少内 核大小 < > Ext3 journalling file system support 取消PC端用的ext3文件系统支持,减少内 核大小 < > The Extended 4 (ext4) filesystem 取消PC端用的ext4文件系统支持,减少内 核大小 < > Kernel automounter version 4 support (also supports v3) 取消这个选项减少内 核大小 < > FUSE (Filesystem in Userspace) support 取消这个选项减少内 核大小 CD-ROM/DVD Filesystems ---> < > ISO 9660 CDROM file system support 取消这个光驱光盘选项,减少内 核大小 < > UDF file system support 取消这个光驱光盘选项,减少内 核大小 DOS/FAT/NT Filesystems ---> <*> MSDOS fs support <*> VFAT (Windows-95) fs support 添加Windows的FAT文件系统支 持,U盘或SD卡中会使用 (437) Default codepage for FAT (iso8859-1) Default iocharset for FAT <*> NTFS file system support 添加Windows的NTFS文件系统支 持,U盘或SD卡中会使用 [ ] NTFS debugging support [*] NTFS write support Pseudo filesystems ---> <*> Userspace-driven configuration filesystem 添加sysfs伪文件系统 支持 [*] Miscellaneous filesystems ---> <*> Journalling Flash File System v2 (JFFS2) support 添 加JFFS2文件系统支持 (0) JFFS2 debugging verbosity (0 = quiet, 2 = noisy) [*] JFFS2 write-buffering support [ ] Verify JFFS2 write-buffer reads [*] JFFS2 summary support (EXPERIMENTAL) [ ] JFFS2 XATTR support (EXPERIMENTAL) [ ] Advanced compression options for JFFS2 其他文件系统如果不需要的话都不要选 < > Compressed ROM file system support (cramfs) 如果不用的 话,取消cramfs文件系统的支持 < > SquashFS 4.0 - Squashed file system support 如果不用的 话,取消SquashFS文件系统的支持 < > ROM file system support 如果不用的 话,取消ROM文件系统的支持 [*] Network File Systems ---> <*> NFS client support [*] NFS client support for NFS version 3 [*] NFS client support for the NFSv3 ACL protocol extension [ ] NFS client support for NFS version 4 [*] Root file system on NFS 将其他不需要的网络文件系统都不要选 < > NFS server support < > Ceph distributed file system (EXPERIMENTAL) < > CIFS support (advanced network filesystem, SMBFS successor) < > NCP file system support (to mount NetWare volumes) < > Coda file system support (advanced network fs) < > Andrew File System support (AFS) (EXPERIMENTAL) Partition Types ---> [ ] PC BIOS (MSDOS partition tables) support 取消这个选项减少内 核大小 -*- Native language support ---> U盘的挂载可能需要下面这些语言编码的支 持,譬如简体中文的CP936和GB2312等 (iso8859-1) Default NLS Option <*> Codepage 437 (United States, Canada) <*> Simplified Chinese charset (CP936, GB2312) <*> Traditional Chinese charset (Big5) <*> ASCII (United States) <*> NLS ISO 8859-1 (Latin 1; Western European Languages) <*> NLS UTF-8 其他语言如果不需要全部不要选 因为禁用了initramfs重新编译Linux内核,新编译的内核不包含根文件系统所以文件较小。 [wudongxu @centos6_master linux-3.0]$ du -sh linuxrom-s3c2440.bin 2.4M linuxrom-s3c2440.bin 4.4 u-boot系统烧录和环境变量配置 因为使用jffs2根文件系统启动的Linux内核不包含根文件系统,所以u-boot烧录Linux系统时需要同时 烧录linux内核镜像(linuxrom-s3c2440.bin)和根文件系统镜像(rootfs-jffs2.bin),此外还要通过 bootargs环境变量告诉Linux内核根文件系统所在的位置。这里Linux内核、根文件系统的烧录地址、 bootargs传参应该与Linux内核里的Nandflash分区表相一致: u-boot的烧录地址应该是 0,大小不超过1M。该分区对应Linux内核分区 表的/dev/mtdblock0; Linux内核的烧录地址应该是0x100000(1M的偏移量处),大小不超过15M。该分区对应Linux 内核分区表的/dev/mtdblock1; 根文件系统镜像的烧录地址应该是0x1000000(16M的偏移量处),大小不超过40M。该分区对 应Linux内核分区表的/dev/mtdblock2; 烧录Linux内核命令 [wudongxu ]# tftp 30008000 linuxrom-s3c2440.bin 先将Linux内核下载到内存地址 30008000上去 [wudongxu ]# nand erase 100000 F00000 将Nandflash上Linux内核分区 (即1M开始总共15M的空间)全部擦除 [fl2440@lingyun]# nand write 30008000 100000 400000 将Linux内核写入到Nandflash上 的Linux内核分区上去 烧录根文件系统命令 [fl2440@lingyun]# tftp 30008000 rootfs-jffs2.bin 先将根文件系统下载到内存地址 30008000上去 [fl2440@lingyun]# nand erase 1000000 2800000 将Nandflash上根文件系统分区 (即16M开始总共40M的空间)全部擦除 [fl2440@lingyun]# nand write 30008000 1000000 $filesize 将根文件系统写入到Nandflash 上的根文件系统分区上去 u-boot设置烧录快捷方式 调试阶段我们可能经常需要烧录linux内核和根文件系统镜像,所以我们可以设置两个u-boot脚本变 量: [fl2440@lingyun]# set blx 'tftp 30008000 linuxrom-s3c2440.bin;nand erase 100000 F00000;nand write 30008000 100000 400000' [fl2440@lingyun]# set bjffs2 'tftp 30008000 rootfs-jffs2.bin;nand erase 1000000 2800000;nand write 30008000 1000000 $filesize' 以后我们在u-boot里想烧录根文件系统和Linux内核时,可以直接使用run blx 或 run bjffs2 命令完 成。 设置bootcmd和bootargs参数: 开发板上电或重启运行u-boot时,如果不按任意键u-boot将进入正常加载模式,这时他将读取环境 变量bootcmd来启动引导Linux内核。Linux内核是被烧录到Nandflash的0x100000位置上,所以uboot启动系统需要从该位置读取内核文件到内存相应位置中去,并且读取字节数应该不小于烧录的 Linux镜像文件大小,否则系统将启动失败。根文件系统则通过bootargs参数告诉Linux内核,Linux内 核在启动后根据该参数挂载相应的根文件系统,如果bootargs参数出错也将导致系统启动失败。 [fl2440@lingyun]# set bootcmd 'nand read 30008000 100000 400000; bootm 30008000' [fl2440@lingyun]# set bootargs 'console=tty0 console=ttyS0,115200 root=/dev/mtdblock2 rootfstype=jffs2 init=/linuxrc mem=64M rw noinitrd loglevel=7' [fl2440@lingyun]# save bootargs的参数解析如下: console=tty0 指定内核控制终端为LCD,内核启动信息输出到LCD上; console=ttyS0,115200 指定内核控制终端也为第一个串口,使用波特率115200,这样内核启动信 息也打印到第一个串口上; root=/dev/mtdblock2 指定根文件系统存放在mtdblock2上,该值应该与u-boot烧录位置、Linux 内核分区保持一致;如果错误则Linux内核会因找不到根文件系统而启动失败; rootfstype=jffs2 指定根文件系统类型为jffs2,如果该参数错误则内核启动失败; init=/linuxrc 指定init进程执行/linuxrc这个程序,他会解析并执行/etc/inittab下的命令; mem=64M u-boot告诉Linux内核有64M的内存; rw 根文件系统以读写的形式挂载; noinitrd 没有使用initrd; loglevel=7 定义内核printk的打印级别为7,即所有信息都通过console打印出来; 烧录过程 [fl2440@lingyun]# run blx 烧录Linux内核镜像 dm9000 i/o: 0x20000300, id: 0x90000a46 DM9000: running in 16 bit mode MAC: 08:00:3e:26:0a:5b could not establish link Using dm9000 device TFTP from server 192.168.2.2; our IP address is 192.168.2.222 Filename 'linuxrom-s3c2440.bin'. Load address: 0x30008000 Loading: ################################################################# ################################################################# #################################### done Bytes transferred = 2432984 (251fd8 hex) NAND erase: device 0 offset 0x100000, size 0xf00000 Skipping bad block at 0x00bc0000 Erasing at 0xfe0000 -- 100% complete. OK NAND write: device 0 offset 0x100000, size 0x400000 4194304 bytes written: OK [fl2440@lingyun]# run bjffs2 烧录jffs2根文件系统镜像 dm9000 i/o: 0x20000300, id: 0x90000a46 DM9000: running in 16 bit mode MAC: 08:00:3e:26:0a:5b could not establish link Using dm9000 device TFTP from server 192.168.2.2; our IP address is 192.168.2.222 Filename 'rootfs-jffs2.bin'. Load address: 0x30008000 Loading: T ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# done Bytes transferred = 10485760 (a00000 hex) NAND erase: device 0 offset 0x1000000, size 0x2800000 Skipping bad block at 0x03440000 Erasing at 0x37e0000 -- 100% complete. OK NAND write: device 0 offset 0x1000000, size 0xa00000 10485760 bytes written: OK 4.5 启动和登录测试: [fl2440@lingyun]# boot 直接使用boot命令启动,或重启开发板将自动启动 NAND read: device 0 offset 0x100000, size 0x400000 4194304 bytes read: OK ## Booting kernel from Legacy Image at 30008000 ... Image Name: Linux Kernel Created: 2017-11-07 19:26:55 UTC Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 2432920 Bytes = 2.3 MiB Load Address: 30008000 Entry Point: 30008040 Verifying Checksum ... OK XIP Kernel Image ... OK OK Starting kernel ... Uncompressing Linux... done, booting the kernel. Linux version 3.0.0 (guowenxue@centos6.localdomain) (gcc version 4.4.6 (crosstool-NG 1.16.0) ) #10 Wed Nov 8 03:26:11 CST 2017 CPU: ARM920T [41129200] revision 0 (ARMv4T), cr=c0007177 ... ... ... S3C244X: core 405.000 MHz, memory 101.250 MHz, peripheral 50.625 MHz CLOCK: Slow mode (1.500 MHz), fast, MPLL on, UPLL on Built 1 zonelists in Zone order, mobility grouping on. Total pages: 16256 下面是u-boot的bootargs传的参数: Kernel command line: console=tty0 console=ttyS0,115200 root=/dev/mtdblock2 rootfstype=jffs2 init=/linuxrc mem=64M rw noinitrd loglevel=7 PID hash table entries: 256 (order: -2, 1024 bytes) ... ... ... S3C24XX NAND Driver, (c) 2004 Simtec Electronics s3c24xx-nand s3c2440-nand: Tacls=3, 29ns Twrph0=7 69ns, Twrph1=3 29ns s3c24xx-nand s3c2440-nand: NAND soft ECC NAND device: Manufacturer ID: 0xec, Chip ID: 0xda (Samsung NAND 256MiB 3,3V 8- bit) Scanning device for bad blocks Bad eraseblock 94 at 0x000000bc0000 Bad eraseblock 418 at 0x000003440000 Bad eraseblock 713 at 0x000005920000 Bad eraseblock 1144 at 0x000008f00000 Bad eraseblock 1940 at 0x00000f280000 Bad eraseblock 2010 at 0x00000fb40000 Creating 6 MTD partitions on "NAND": 内核分区表 0x000000000000-0x000000100000 : "mtdblock0 u-boot 1MB" 0x000000100000-0x000001000000 : "mtdblock1 kernel 15MB" 0x000001000000-0x000003800000 : "mtdblock2 rootfs 40MB" 0x000003800000-0x000008800000 : "mtdblock3 apps 80MB" 0x000008800000-0x00000d800000 : "mtdblock4 data 80MB" 0x00000d800000-0x000010000000 : "mtdblock5 backup 40MB" dm9000 Ethernet Driver, V1.31 eth0: dm9000a at c4856300,c4858304 IRQ 51 MAC: 08:00:3e:26:0a:5b (chip) usbmon: debugfs is not available ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver ... ... ... drivers/rtc/hctosys.c: unable to open rtc device (rtc0) usb 1-1: new full speed USB device number 2 using s3c2410-ohci usb 1-1: device descriptor read/64, error -62 usb 1-1: device descriptor read/64, error -62 usb 1-1: new full speed USB device number 3 using s3c2410-ohci usb 1-1: device descriptor read/64, error -62 VFS: Mounted root (jffs2 filesystem) on device 31:2. Linux内核找到并以JFFS2格式挂 载根文件系统,如果bootargs传参有误则Linux内核将死在这里。 Freeing init memory: 108K usb 1-1: device descriptor read/64, error -62 usb 1-1: new full speed USB device number 4 using s3c2410-ohci usb 1-1: device not accepting address 4, error -62 usb 1-1: new full speed USB device number 5 using s3c2410-ohci usb 1-1: device not accepting address 5, error -62 hub 1-0:1.0: unable to enumerate USB device on port 1 dm9000 dm9000.0: eth0: link down Copyright (C) 2012 LingYun I.o.T Studio< iot-yun.com > Default Logon Username: root Password: 123456 LingYunFL2440 login: 登录测试: ~ >: mount rootfs on / type rootfs (rw) /dev/root on / type jffs2 (rw,relatime) 根路径(/)所挂载的文件系统即为根文件系统 proc on /proc type proc (rw,relatime) usbfs on /proc/bus/usb type usbfs (rw,relatime) tmpfs on /dev type tmpfs (rw,relatime) ramfs on /tmp type ramfs (rw,relatime) sysfs on /sys type sysfs (rw,relatime) devpts on /dev/pts type devpts (rw,relatime,mode=600) 因为JFFS2是建立在Nandflash上的根文件系统,在该文件系统路径下所有的文件修改掉电后都不会丢 失。所以我们在根路径下创建haha文件后,把开发板重启发现该文件还存在。 ~ >: pwd /~ >: touch haha ~ >: reboot 4.6 普通分区jffs2挂载 jffs2除了可以制作成根文件系统使用以外,我们也可以在系统成功启动后,将其他分区以jffs2文件系统 类型挂载使用。 ~ >: dmesg | grep mtdblock 通过dmesg命令查看内核的分区情况 Kernel command line: console=tty0 console=ttyS0,115200 root=/dev/mtdblock2 rootfstype=jffs2 init=/linuxrc mem=64M rw noinitrd loglevel=7 0x000000000000-0x000000100000 : "mtdblock0 u-boot 1MB" 0x000000100000-0x000001000000 : "mtdblock1 kernel 15MB" 0x000001000000-0x000003800000 : "mtdblock2 rootfs 40MB" 0x000003800000-0x000008800000 : "mtdblock3 apps 80MB" 0x000008800000-0x00000d800000 : "mtdblock4 data 80MB" 0x00000d800000-0x000010000000 : "mtdblock5 backup 40MB" ~ >: cat /proc/partitions 查看Linux内核分区表 major minor #blocks name 31 0 1024 mtdblock0 31 1 15360 mtdblock1 31 2 40960 mtdblock2 31 3 81920 mtdblock3 31 4 81920 mtdblock4 31 5 40960 mtdblock5 ~ >: ls -l /dev/mtdblock* 查看分区对应的块设备 brw-rw---- 1 root root 31, 0 Jan 1 00:00 /dev/mtdblock0 brw-rw---- 1 root root 31, 1 Jan 1 00:00 /dev/mtdblock1 brw-rw---- 1 root root 31, 2 Jan 1 00:00 /dev/mtdblock2 brw-rw---- 1 root root 31, 3 Jan 1 00:00 /dev/mtdblock3 brw-rw---- 1 root root 31, 4 Jan 1 00:00 /dev/mtdblock4 brw-rw---- 1 root root 31, 5 Jan 1 00:00 /dev/mtdblock 这里我们以 mtdblock5 为例将其以jffs2文件系统格式挂载到 /info 挂载点上: ~ >: flash_eraseall /dev/mtd5 将mtdblock5分区全部擦除 Erasing 128 Kibyte @ 1a60000 - 65% complete. Skipping bad block at 0x01a80000 Erasing 128 Kibyte @ 2320000 - 87% complete. Skipping bad block at 0x02340000 Erasing 128 Kibyte @ 2800000 - 100% complete. ~ >: mount -t jffs2 /dev/mtdblock5 /info/ ~ >: mount mount命令查看所有的文件系统挂载情况 rootfs on / type rootfs (rw) /dev/root on / type jffs2 (rw,relatime) proc on /proc type proc (rw,relatime) usbfs on /proc/bus/usb type usbfs (rw,relatime) tmpfs on /dev type tmpfs (rw,relatime) ramfs on /tmp type ramfs (rw,relatime) sysfs on /sys type sysfs (rw,relatime) devpts on /dev/pts type devpts (rw,relatime,mode=600) /dev/mtdblock5 on /info type jffs2 (rw,relatime) ~ >: touch /info/haha 在/info下创建文件haha ~ >: ls /info/ haha ~ >: reboot 系统重启后,并不会自动挂载/dev/mtdblock5到/info路径下,这时我们还是需要用命令手动挂载才能 看到/info路径下的haha文件存在。 4.7 制作JFFS2根文件系统镜像的Shell脚本 [guowenxue@centos6_master linux]$ vim build_jffs2.sh #!/bin/sh #+------------------------------------------------------------------------------- ------------- #|Description: This shell script is used to generate a JFFS2 rootfs for K9F2G08 nandflash #| Author: GuoWenxue <guowenxue@gmail.com> QQ: 281143292 #| ChangeLog: #| 1, Initialize 1.0.0 on 2012.04.18 #| Reference: #| http://www.linux-mtd.infradead.org/faq/ubifs.html #+------------------------------------------------------------------------------- ------------- # u-boot setup bootargs env : # set bjffs2 'tftp 30800000 rootfs-jffs2.bin;nand erase 1000000 2800000;nand write 30800000 1000000 $filesize' # set bootargs 'console=ttyS0,115200 root=/dev/mtdblock2 rootfstype=jffs2 init=/linuxrc mem=64M rw noinitrd loglevel=7' VERSION=1.0.0 ROOTFS_DIR=./rootfs IMAGE_NAME=rootfs-jffs2.bin INSTALL_PATH=/tftp #=========================================== # Shell script body start here + #=========================================== # k9f2g08 nand flash page size is 2KiB page_size=2048 # k9f2g08 has 64pages per block, so erase block size is 64*2KiB=128KiB erase_size=128KiB # jffs2 root filesystem image padding by 0xFF size, if not padded system will throw some noisy warnnings as: # jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x006430dc: 0x5555 instead # jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x006430dc: 0x5555 instead # The generate root file system images (rootfs-jffs2.bin) without padding is about 6.3M, and root filesystem partition is about 40M, # we just padding 10M is enuf. pad_size=0xa00000 if [ ! -d $ROOTFS_DIR ] ; then echo "decompress rootfs tree..." sudo tar -xjf $ROOTFS_DIR.tar.bz2 fi echo "" echo "generating $IMAGE_NAME file by mkfs.jffs2..." echo "mkfs.jffs2 -n -s $page_size -e $erase_size -d $ROOTFS_DIR -o $IMAGE_NAME -- pad=$pad_size" echo "" mkfs.jffs2 -n -s $page_size -e $erase_size -d $ROOTFS_DIR -o $IMAGE_NAME -- pad=$pad_size sudo chmod a+x $IMAGE_NAME if [ -d $INSTALL_PATH ] ; then cp $IMAGE_NAME $INSTALL_PATH fi 4.8 思考 如何设置让系统启动时自动将/dev/mtdblock5以jffs2文件 系统格式挂载到/info路径下? 五、ubifs根文件系统制作 5.1 ubifs文件系统简介 UBIFS(Unsorted Block Image File System,无排序区块图像文件系统)是用于固态存储设备上,并 与LogFS相互竞争,作为JFFS2的后继文件系统之一。由于Nand Flash容量的暴涨,JFFS2、Yaffs2等 皆无法操控大的Nand Flash空间,IBM、Nokia工程师Thomas Gleixner、Artem Bityutskiy等人2006 年发起,致力于开发性能卓越、扩展性高的FLASH专用文件系统,以解决嵌入式环境下以FLASH作为 MTD设备使用时的技术瓶颈。真正开始开发于2007年,并于2008年10月第一次加入稳定版本于Linux 核心2.6.27版,在设计与性能上均较优于YAFFS2、JFFS2,更实用于MLC NAND FLASH。因为UBIFS 是直接工作在Raw Flash设备上(如Nandflash),所以他不能工作在SD卡、U盘这些常用的存储设备上, 目前的安卓手机上绝大部分都是使用的UBIFS文件系统。关于UBIFS的更多信息请参 考: http://www.linux-mtd.infradead.org/doc/ubifs.html 传统的flash文件系统如Jffs2、yaffs2等是工作在MTD设备层之上,而UBIFS则建立在UBI卷层之上, UBI卷层工作在MTD设备层之上。也可以说,UBIFS涉及三个子系统: 1. MTD 子系统,提供对flash芯片Raw的访问接口。 MTD子系统提供了MTD device的概念,比 如/dev/mtdx(字符设备)和/dev/mtdblockX(块设备); 2. UBI Subsystem,它工作在MTD设备之上,提供了UBI逻辑卷(类似于Linux服务器上的LVM概 念),对上层屏蔽了一些直接使用MTD设备需要处理的问题,如wear-leveling(磨损平衡算法)和 volume management(坏块管理)功能等; 3. UBIFS文件系统,工作于UBI之上。它提供文件的open、read、write等操作; 作为新一代文件系统新贵,他具有如下特性: 可扩展性: UBIFS对Flash 尺寸有着很好的扩展性; 也就是说文件系统挂载时间,内存消耗以 及I/O速度都不依赖于Flash的大小; UBIFS可以很好的运行在GB级的 flashe设备; 当然UBI本身 还是有扩展性的问题,无论如何 UBI/UBIFS都比JFFS2的可扩展性好,如果UBI成为瓶颈,可以 改进UBI而不需改变UBIFS本身; 快速挂载:不像JFFS2,UBIFS在挂载阶段不需要扫描整个文件系统,UBIFS mount的时间只 是毫秒级,时间不依赖于Flash的大小;然而UBI的初始化时间依赖Flash的大小,因此必须把这 个时间考虑在内。 write-back 支持:文件的改变并不是立刻提交到flash media上,而是cache这些修改,直到达 到写入的条件,这减少了I/O的数目因此改善I/O性能和系统性能。回写本身也是文件系统的标准 技术,由于数据没有立刻写入flash, 回写带来了突然掉电就会存在数据丢失的风险。相反, JFFS2 不支持write-back, JFFS2文件系统的所有变化都是立刻同步到flash介质上。同JFFS2的writethrough(立即写入内存)相比可以显著的提高文件系统的吞吐量。 容忍不清洁的重启:UBIFS是日志文件系统,所以容忍突然关闭和不清洁的重启。UBIFS会回 放日志并从不切底的重启中恢复过来。这时挂载时间会有点慢。但由于只是需要重做日志,而不 需要扫描储存介质,所以性能影响不大。 快速I/O:即使回写功能被禁能(例如在挂载时加入“-o sync”的参数),UBIFS也表现良 好,接近jffs2。在同步I/O方面UBIFS是极难与jffs2相抗争的。因为jffs2在flash维护数据索引结 构,不需要额外的开销,而UBIFS需要。然而UBIFS依然是很快,因为它依靠日志。它不需要把 数据物理地从一个地方移动到另一个地方,仅把有关信息加入文件系统的索引以及为新日志挑选 一个擦除块。 快速压缩:与jffs2相似,UBIFS支持数据压缩储存。对于单个文件的储存,UBIFS可以使能/禁 能压缩功能。 自恢复功能:有数据索引有损坏的情况下,UBIFS可以恢复过来。在UBIFS每一块信息有描述 整个信息的数据头。在扫描介质的情况下这数据头信息可以重建。而在FAT文件系统,发生这样 的事件是致命的。 数据的完整性:UBIFS在每次写入数据时都会对数据进行核实,以确保数据的完整性。UBIFS 不会容忍任何不可用的数据或元数据。然而为了加快数据的读写速度,用户可以关闭CRC检查。 5.2 根文件系统镜像文件制作 我们可以使用mtd-utils源码编译出来的mkfs.jffs2工具,将根文件系统树目录制作成jffs2根文件系统镜 像。在开始制作镜像之前,我们先看看mkfs.jffs2的使用说明: [guowenxue@centos6_master ~]$ cd ~/gitee/fl2440/linux/ [guowenxue@centos6_master linux]$ mkfs.ubifs -h Usage: mkfs.ubifs [OPTIONS] target Make a UBIFS file system image from an existing directory tree Examples: Build file system from directory /opt/img, writting the result in the ubifs.img file mkfs.ubifs -m 512 -e 128KiB -c 100 -r /opt/img ubifs.img The same, but writting directly to an UBI volume mkfs.ubifs -r /opt/img /dev/ubi0_0 Creating an empty UBIFS filesystem on an UBI volume mkfs.ubifs /dev/ubi0_0 Options: -r, -d, --root=DIR build file system from directory DIR, 指定根文件系统目录 树的路径 -m, --min-io-size=SIZE minimum I/O unit size Nand Flash的最小读 写单元,一般为page size。 -e, --leb-size=SIZE logical erase block size 逻辑擦除块的大小 -c, --max-leb-cnt=COUNT maximum logical erase block count 逻辑擦除块的个数, 与分区大小有关 -o, --output=FILE output to FILE 输出的根文件系统镜 像文件 -j, --jrn-size=SIZE journal size -R, --reserved=SIZE how much space should be reserved for the super-user -x, --compr=TYPE compression type - "lzo", "favor_lzo", "zlib" or "none" (default: "lzo") -X, --favor-percent may only be used with favor LZO compression and defines how many percent better zlib should compress to make mkfs.ubifs use zlib instead of LZO (default 20%) -f, --fanout=NUM fanout NUM (default: 8) -F, --space-fixup file-system free space has to be fixed up on first mount (requires kernel version 3.0 or greater) -k, --keyhash=TYPE key hash type - "r5" or "test" (default: "r5") -p, --orph-lebs=COUNT count of erase blocks for orphans (default: 1) -D, --devtable=FILE use device table FILE -U, --squash-uids squash owners making all files owned by root -l, --log-lebs=COUNT count of erase blocks for the log (used only for debugging) -y, --yes assume the answer is "yes" for all questions -v, --verbose verbose operation -V, --version display version information -g, --debug=LEVEL display debug information (0 - none, 1 - statistics, 2 - files, 3 - more details) -h, --help display this help text Note, SIZE is specified in bytes, but it may also be specified in Kilobytes, Megabytes, and Gigabytes if a KiB, MiB, or GiB suffix is used. If you specify "lzo" or "zlib" compressors, mkfs.ubifs will use this compressor for all data. The "none" disables any data compression. The "favor_lzo" is not really a separate compressor. It is just a method of combining "lzo" and "zlib" compressors. Namely, mkfs.ubifs tries to compress data with both "lzo" and "zlib" compressors, then it compares which compressor is better. If "zlib" compresses 20 or more percent better than "lzo", mkfs.ubifs chooses "lzo", otherwise it chooses "zlib". The "--favor-percent" may specify arbitrary threshold instead of the default 20%. The -F parameter is used to set the "fix up free space" flag in the superblock, which forces UBIFS to "fixup" all the free space which it is going to use. This option is useful to work-around the problem of double free space programming: if the flasher program which flashes the UBI image is unable to skip NAND pages containing only 0xFF bytes, the effect is that some NAND pages are written to twice - first time when flashing the image and the second time when UBIFS is mounted and writes useful data there. A proper UBI-aware flasher should skip such NAND pages, though. Note, this flag may make the first mount very slow, because the "free space fixup" procedure takes time. This feature is supported by the Linux kernel starting from version 3.0. [guowenxue@centos6_master linux]$ mkfs.ubifs -x lzo -m 2048 -e 129024 -c 300 -r ./rootfs -o rootfs-ubifs.img -x lzo 指定使用lzo压缩方法,默认是lzo,还支持zlib,zlib压缩率高些,但 是lzo压缩解压速度快 。 -m 2048 Nand Flash的最小读写单元,一般为page size,K9F2G08的页大小 为2048字节。 -r ./rootfs 指定根文件系统目录树的路径 -o rootfs-ubifs.img 指定制作出的根文件系统镜像文件名 -e 129024 指定LEB(Logical Erase Block,逻辑擦除块)大小。大家知道 Nandflash读写单位为页,擦除单位为块,一个设备有多个块,一个块有多个页,K9F2G08 Nandflash一个块是64个页,而一个页大小为2048字节。这样一个PEB(Physical Eraseblock Size,物理擦除块)大小就是2048*64=131072,-e的算法是物理擦除块大小-1*页大小,这里 就是131072-1*2048=129024 -c 300 指定该分区最大逻辑擦除块数量,该值随着根文件系统分区的大小和 该分区的坏块数调整。该值很重要,不能大也不能小,太小也要大于image大小,太大mount有 问题。计算起点是分区的物理块数量,比如40MiB的mtd分区,物理擦除块数量是 40*1024*1024/2048/64 = 320个,需要减去2个volume table的块,1个wear-leveling块,1 个atomic LEB change块,以及一些坏块处理的保留块。因为一个分区上有多少个坏块是随机 的,一般做法是做一个坏块容忍数,比如16个,不要担心这个会浪费空间,ubinize的 autoresize选项就是解决这个问题的。在这里我们最终的逻辑擦除块个数计算公式为: 320- 2(volume table)-1(Wear-leveling)-1(atomic LEB change)-16(坏块容量数)=300 UBIFS官方关于逻辑擦除块大小的说明 参考: http://www.linux-mtd.infradead.org/doc/ubi.html#L_overhead UBIFS是建立在UBI之上的文件系统,因此使用mkfs.ubifs制作的根文件系统镜像不能直接使用u-boot 的nand write命令烧录,而需要在u-boot下使用ubi命令在根文件系统所在分区建立ubi卷之后才能烧 录。但这种烧录方式比较麻烦,这时我们可以使用另外ubinize命令对rootfs-ubifs.img文件进行处理后 就可以在u-boot上直接用nand write命令写入到根文件系统分区了。该命令的使用方法如下: [guowenxue@centos6_master linux]$ ubinize -h ubinize version 1.4.9 - a tool to generate UBI images. An UBI image may contain one or more UBI volumes which have to be defined in the input configuration ini-file. The ini file defines all the UBI volumes - their characteristics and the and the contents, but it does not define the characteristics of the flash the UBI image is generated for. Instead, the flash characteristics are defined via the command-line options. Note, if not sure about some of the command-line parameters, do not specify them and let the utility to use default values. INI-file format. The input configuration ini-file describes all the volumes which have to be included to the output UBI image. Each volume is described in its own section which may be named arbitrarily. The section consists on "key=value" pairs, for example: [jffs2-volume] mode=ubi image=../jffs2.img vol_id=1 vol_size=30MiB vol_type=dynamic vol_name=jffs2_volume vol_flags=autoresize vol_alignment=1 This example configuration file tells the utility to create an UBI image with one volume with ID 1, volume size 30MiB, the volume is dynamic, has name "jffs2_volume", "autoresize" volume flag, and alignment 1. The "image=../jffs2.img" line tells the utility to take the contents of the volume from the "../jffs2.img" file. The size of the image file has to be less or equivalent to the volume size (30MiB). The "mode=ubi" line is mandatory and just tells that the section describes an UBI volume - other section modes may be added in the future. Notes: * size in vol_size might be specified kilobytes (KiB), megabytes (MiB), gigabytes (GiB) or bytes (no modifier); * if "vol_size" key is absent, the volume size is assumed to be equivalent to the size of the image file (defined by "image" key); * if the "image" is absent, the volume is assumed to be empty; * volume alignment must not be greater than the logical eraseblock size; * one ini file may contain arbitrary number of sections, the utility will put all the volumes which are described by these section to the output UBI image file. Usage: ubinize [-o filename] [-p ] [-m ] [-s ] [-O ] [-e ] [-x ] [-Q ] [-v] [-h] [-V] [--output=] [-- peb-size=] [--min-io-size=] [--sub-page-size=] [--vid-hdroffset=] [--erase-counter=] [--ubi-ver=] [--image-seq=] [-- verbose] [--help] [--version] ini-file Example: ubinize -o ubi.img -p 16KiB -m 512 -s 256 cfg.ini - create UBI image 'ubi.img' as described by configuration file 'cfg.ini' -o, --output= output file name 处理后输出的镜像文件名 -p, --peb-size= size of the physical eraseblock of the flash 物理擦 除块大小 this UBI image is created for in bytes, kilobytes (KiB), or megabytes (MiB) (mandatory parameter) -m, --min-io-size= minimum input/output unit size of the flash nandflash页大小 in bytes -s, --sub-page-size= minimum input/output unit used for UBI headers, e.g. sub-page size in case of NAND flash (equivalent to the minimum input/output unit size by default) -O, --vid-hdr-offset= offset if the VID header from start of the physical eraseblock (default is the next minimum I/O unit or sub-page after the EC header) -e, --erase-counter= the erase counter value to put to EC headers (default is 0) -x, --ubi-ver= UBI version number to put to EC headers (default is 1) -Q, --image-seq= 32-bit UBI image sequence number to use (by default a random number is picked) -v, --verbose be verbose -h, --help print help message -V, --version print program version 首先我们需要创建ubinize的配置文件,然后再使用ubinize命令对image进行处理: [guowenxue@centos6_master linux]$ vim ubinize.ini [ubifs-volume] mode=ubi image=rootfs-ubifs.img vol_id=0 vol_size=38707200 vol_type=dynamic vol_name=rootfs vol_flags=autoresize vol_alignment=1 配置文件说明: mode=ubi image=rootfs-ubifs.img 指定mkfs.ubifs制作生成的根文件系统镜像文件路径; vol_id=0 指定根文件系统树的卷标为0,u-boot的bootargs参数需要根据它来设置; vol_size=38707200 指定该UBI逻辑卷的大小,该值计算公式一般为 逻辑擦除块大小*逻辑擦除块个数 =129024*300=38707200。该值一般不用写,默认值是image大小。写了这个作用是帮助检查image是否超过了 分区限制,制作时候就提示,否则mount会出错。逻辑擦除块个数的值是经过计算的最大值了,不过autoresize 参数会自适应大小,不会浪费空间的,后面Linux系统内核启动过程中可以看到这个现象。 vol_type=dynamic vol_name=rootfs 指定UBI卷的名称,u-boot的bootargs参数需要根据它来设置; vol_flags=autoresize UBI Subsystem在系统启动时自动调整逻辑擦除块的个数 vol_alignment=1 [guowenxue@centos6_master linux]$ ubinize -o rootfs-ubifs.bin -m 2048 -p 131072 -s 512 -O 512 ubinize.ini -o rootfs-ubifs.bin 指定ubinize处理后输出的image文件名,该文件可以由u-boot的nand write命令 直接烧录 -m 2048 指定minimum input/output unit大小,为nandflash的页大小。 -p 131072 指定物理擦除块大小: 64 Page*2048 Byte/Page = 131072 -s 512 指定sub-page-size大小,页大小为2048字节的nandflash对应值为512;对于其他的 Nandflash可以在Linux内核跑起来后挂载ubifs后查看该值 -O 512 指定vid-hdr-offset值,默认为sub-page-size的值,可以省略不用。 [guowenxue@centos6_master linux]$ du -h rootfs-ubifs.bin 8.3M rootfs-ubifs.bin 经过 ubinize 命令处理过后的根文件系统镜像文件rootfs-ubifs.bin 就可以直接在u-boot下使用nand write 命令烧录到相应的根文件系统分区上去了。 关于Minim Flash input/output、sub-pages、UBI Header的说 明 参考: http://www.linux-mtd.infradead.org/doc/ubi.html#L_min_io_unit 5.3 内核配置和编译 Linux内核需要重新make menuconfig配置做如下修改,编译并生成的Linux内核镜像文件才能支持 UBIFS文件系统。 [guowenxue@centos6_master ~]$ cd ~/gitee/fl2440/linux/linux-3.0 [guowenxue@centos6_master linux-3.0]$ export TERM=vt100 [guowenxue@centos6_master linux-3.0]$ make menuconfig General setup ---> [ ] Initial RAM filesystem and RAM disk (initramfs/initrd) support 一定 要取消initamfs,否则内核找到initramfs根文件系统的话就直接使用他启动了。 Device Drivers ---> <*> Memory Technology Device (MTD) support ---> < > RedBoot partition table parsing < > FTL (Flash Translation Layer) support < > NFTL (NAND Flash Translation Layer) support <*> Enable UBI - Unsorted block images ---> 因为UBIFS文 件系统建立在UBI一层上,所以只有这里选择了UBI之后,下面的文件系统里才会有UBIFS的选项 (4096) UBI wear-leveling threshold (NEW) (1) Percentage of reserved eraseblocks for bad eraseblocks handling (NEW) < > MTD devices emulation driver (gluebi) (NEW) [ ] UBI debugging (NEW) File systems ---> [*] Miscellaneous filesystems ---> <*> UBIFS file system support 选择支持UBIFS文件系 统 [*] Extended attributes support [*] Advanced compression options [*] LZO compression support (NEW) [*] ZLIB compression support (NEW) [ ] Enable debugging support (NEW) 重新编译生成Linux内核uImage镜像文件: [wudongxu @centos6_master linux-3.0]$ make [wudongxu @centos6_master linux-3.0]$ mkimage -A arm -O linux -T kernel -C none -a 30008000 -e 30008040 -n "Linux Kernel" -d arch/arm/boot/zImage linuxrom- s3c2440.bin [wudongxu @centos6_master linux-3.0]$ du -sh linuxrom-s3c2440.bin 2.5M linuxrom-s3c2440.bin 5.4 u-boot系统烧录和环境变量配置 因为使用UBIFS根文件系统启动的Linux内核不包含根文件系统,所以u-boot烧录Linux系统时需要 同时烧录linux内核镜像(linuxrom-s3c2440.bin)和根文件系统镜像(rootfs-ubifs.bin),此外还要通过 bootargs环境变量告诉Linux内核根文件系统所在的位置。这里Linux内核、根文件系统的烧录地址、 bootargs传参应该与Linux内核里的Nandflash分区表相一致: u-boot的烧录地址应该是 0,大小不超过1M。该分区对应Linux内核分区表 的/dev/mtdblock0; Linux内核的烧录地址应该是0x100000(1M的偏移量处),大小不超过15M。该分区对应Linux 内核分区表的/dev/mtdblock1; 根文件系统镜像的烧录地址应该是0x1000000(16M的偏移量处),大小不超过40M。该分区对 应Linux内核分区表的/dev/mtdblock2; 开发板上电或重启运行u-boot时,如果不按任意键u-boot将进入正常加载模式,这时他将读取环境 变量bootcmd来启动引导Linux内核。Linux内核是被烧录到Nandflash的0x100000位置上,所以uboot启动系统需要从该位置读取内核文件到内存相应位置中去,并且读取字节数应该不小于烧录的 Linux镜像文件大小,否则系统将启动失败。根文件系统则通过bootargs参数告诉Linux内核,Linux内 核在启动后根据该参数挂载相应的根文件系统,如果bootargs参数出错也将导致系统启动失败。 [fl2440@lingyun]# set bootcmd 'nand read 30008000 100000 400000; bootm 30008000' [fl2440@lingyun]# set blx 'tftp 30008000 linuxrom-s3c2440.bin;nand erase 100000 F00000;nand write 30008000 100000 400000' [fl2440@lingyun]# set bubifs 'tftp 30008000 rootfs-ubifs.bin;nand erase 1000000 2800000;nand write 30008000 1000000 $filesize' [fl2440@lingyun]# set bootargs 'console=tty0 console=ttyS0,115200 ubi.mtd=2 root=ubi0:rootfs rootfstype=ubifs mem=64M noinitrd rw loglevel=7' [fl2440@lingyun]# save bootargs的参数解析如下: console=tty0 指定内核控制终端为LCD,内核启动信息输出到LCD上; console=ttyS0,115200 指定内核控制终端也为第一个串口,使用波特率115200,这样内核启动信 息也打印到第一个串口上; ubi.mtd=2 指定UBI卷建立在mtd2上,该值应该与u-boot烧录位置、Linux内核分区保 持一致;如果错误则Linux内核会因找不到根文件系统而启动失败; root=ubi0:rootfs 指定根文件系统所在位置:在制作UBIFS的过程中,我们通过ubinize命令对 文件系统镜像进行处理时,其配置文件中的vol_id指定为0,vol_name指定为rootfs; rootfstype=jffs2 指定根文件系统类型为jffs2,如果该参数错误则内核启动失败; init=/linuxrc 指定init进程执行/linuxrc这个程序,他会解析并执行/etc/inittab下的命令; mem=64M u-boot告诉Linux内核有64M的内存; rw 根文件系统以读写的形式挂载; noinitrd 没有使用initrd; loglevel=7 定义内核printk的打印级别为7,即所有信息都通过console打印出来; [fl2440@lingyun]# run blx 烧录Linux内核镜像 dm9000 i/o: 0x20000300, id: 0x90000a46 DM9000: running in 16 bit mode MAC: 08:00:3e:26:0a:5b could not establish link Using dm9000 device TFTP from server 192.168.2.2; our IP address is 192.168.2.222 Filename 'linuxrom-s3c2440.bin'. Load address: 0x30008000 Loading: T ################################################################# ################################################################# ############################################## done Bytes transferred = 2574896 (274a30 hex) NAND erase: device 0 offset 0x100000, size 0xf00000 Skipping bad block at 0x00bc0000 Erasing at 0xfe0000 -- 100% complete. OK NAND write: device 0 offset 0x100000, size 0x400000 4194304 bytes written: OK [fl2440@lingyun]# run bubifs 烧录根文件系统镜像 dm9000 i/o: 0x20000300, id: 0x90000a46 DM9000: running in 16 bit mode MAC: 08:00:3e:26:0a:5b could not establish link Using dm9000 device TFTP from server 192.168.2.2; our IP address is 192.168.2.222 Filename 'rootfs-ubifs.bin'. Load address: 0x30008000 Loading: T ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ##### done Bytes transferred = 8650752 (840000 hex) NAND erase: device 0 offset 0x1000000, size 0x2800000 Skipping bad block at 0x03440000 Erasing at 0x37e0000 -- 100% complete. OK NAND write: device 0 offset 0x1000000, size 0x840000 8650752 bytes written: OK 5.5 启动和登录测试 [fl2440@lingyun]# boot 直接使用boot命令启动,或重启开发板将自动启动 NAND read: device 0 offset 0x100000, size 0x400000 4194304 bytes read: OK ## Booting kernel from Legacy Image at 30008000 ... Image Name: Linux Kernel Created: 2017-11-08 10:26:16 UTC Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 2574832 Bytes = 2.5 MiB Load Address: 30008000 Entry Point: 30008040 Verifying Checksum ... OK XIP Kernel Image ... OK OK Starting kernel ... Uncompressing Linux... done, booting the kernel. Linux version 3.0.0 (guowenxue@centos6.localdomain) (gcc version 4.4.6 (crosstool-NG 1.16.0) ) #13 Wed Nov 8 18:24:00 CST 2017 CPU: ARM920T [41129200] revision 0 (ARMv4T), cr=c0007177 CPU: VIVT data cache, VIVT instruction cache Machine: SMDK2440 Memory policy: ECC disabled, Data cache writeback CPU S3C2440A (id 0x32440001) S3C24XX Clocks, Copyright 2004 Simtec Electronics S3C244X: core 405.000 MHz, memory 101.250 MHz, peripheral 50.625 MHz CLOCK: Slow mode (1.500 MHz), fast, MPLL on, UPLL on Built 1 zonelists in Zone order, mobility grouping on. Total pages: 16256 下面是u-boot传给Linux内核的bootargs参数 Kernel command line: console=tty0 console=ttyS0,115200 ubi.mtd=2 root=ubi0:rootfs rootfstype=ubifs mem=64M noinitrd rw loglevel=7 PID hash table entries: 256 (order: -2, 1024 bytes) Dentry cache hash table entries: 8192 (order: 3, 32768 bytes) ... ... ... S3C24XX NAND Driver, (c) 2004 Simtec Electronics s3c24xx-nand s3c2440-nand: Tacls=3, 29ns Twrph0=7 69ns, Twrph1=3 29ns s3c24xx-nand s3c2440-nand: NAND soft ECC NAND device: Manufacturer ID: 0xec, Chip ID: 0xda (Samsung NAND 256MiB 3,3V 8- bit) Scanning device for bad blocks Bad eraseblock 94 at 0x000000bc0000 Bad erasebl