3.Yaffs 文件系统移植
当使用 linuette 现成提供的 zImage.yaffs 和 usr.yaffs 是不能正常启动桌面系统的,因为它们提供
的包含 yaffs 的测试内核,支持的 LCD 是 320*480,以及触摸板的驱动也没有修改,所以必须在原来的内 核源代码中移植 yaffs 文件系统,才能在支持 yaffs 系统的同时,任意修改内核代码部分,如 LCD 分辨率、 触摸板,以及将驱动编译进内核等。
移植调试思路:参照 mizi 提供的 yaffs(源码不公开)的使用,及输出信息为线索,一步步的使移植 的功能接近它。如:1> 启动时的分区信息(BON info、MTD partitions)2> /dev/mtd 和/dev/mtdblock 3>
/proc/filesystems 4> mount –t yaffs /dev/mtdblock/1 /usr
3.1 在 vivi 中进行分区
vivi>bon part 0 192k 1M 3M:M
注:最后面的 M 表示为 mtd 分区,下面的 flag 将为 00000001;当然也可以只分 3 个区。
viiv>bon part show
BON info. (4 partitions)
No: offset size flags
bad
---------------------------------------------
0: 0x00000000 0x00030000 00000000 0 192k
1: 0x00030000 0x000d0000 00000000 0 832k
2: 0x00100000 0x00200000 00000000 0 2M
3: 0x00300000 0x03cfc000 00000001 0 60M+1008k vivi>load flash vivi x
vivi>load flash kernel x vivi>load flash root x vivi>boot
……
NAND device: Manufacturer ID: 0xec, Chip ID: 0x76 (Samsung NAND 64MiB 3,3V)
bon0: 00000000-00030000 (00030000) 00000000 bon1: 00030000-00100000 (000d0000) 00000000 bon2: 00100000-00300000 (00200000) 00000000 bon3: 00300000-03ffc000 (03cfc000) 00000001
……
注意:也可以只分 3 个区:
vivi> bon part 0 192k 1M
3.2
修改 MTD 驱动的 NAND 分区
修改 kernel/drivers/mtd/nand/smc_s3c2410.c 文件中的 smc_partitions[],如下:
static struct mtd_partition smc_partitions[] = {
{
name: "bon",
}, {
size: 0x04000000, offset: 0x0,
mask_flags: MTD_WRITEABLE, /*force read-only */
name:
"mtd",
size: 0x03cfc000, offset: 0x00300000,
}
};
另外在该文件开始部分的消除分区宏定义:
#undef CONFIG_MTD_SMC_S3C2410_SMDK_PARTITION 修改成:
#define CONFIG_MTD_SMC_S3C2410_SMDK_PARTITION
内核配置时选中 Memory Technology Devices (MTD) ---> NAND Flash Device Drivers ---> SMC Device
Support 及下属所有项 重新编译内核,下载,启动。输出信息如下:
……
NAND device: Manufacture ID: 0xec, Chip ID: 0x76 (Samsung K9D1208V0M) Creating 2 MTD partitions on "Samsung K9D1208V0M":
0x00000000-0x04000000 : "bon"
0x00300000-0x03ffc000 : "mtd"
bon0: 00000000-00030000 (00030000) 00000000 bon1: 00030000-00100000 (000d0000) 00000000 bon2: 00100000-00300000 (00200000) 00000000 bon3: 00300000-03ffc000 (03cfc000) 00000001
……
#cat /proc/mtd
dev: size
erasesize name
mtd0: 04000000 00004000 "bon" mtd1: 03cfc000 00004000 "mtd"
#ls /dev/mtd
0 0ro 1 1ro
#ls /dev/mtdblock
0 1
3.3 移植 yaffs 源代码
从官网(http://www.aleph1.co.uk/cgi-bin/viewcvs.cgi/yaffs/)下载源码(yaffs.tar.gz)解压, 在kernel/fs/目录下新建yaffs目录,将源码(yaffs_fs.c、yaffs_guts.c、yaffs_mtdif.c、yaffs_ecc.c、devextras.h、yaffs_guts.h、yaffs_mtdif.h、yaffs_ecc.h、yaffsinterface.h、yportenv.h)复制到该 目录下,创建yaffs_config.h文件,加入源码中使用到的宏定义,如下:
#ifndef YAFFS_CONFIG_H
#define YAFFS_CONFIG_H
#define CONFIG_YAFFS_MTD_ENABLED
#define CONFIG_YAFFS_USE_OLD_MTD
#endif
在该目录下创建 Makefile 文件,内容如下: O_TARGET := yaffs.o
obj-y := yaffs_fs.o yaffs_guts.o yaffs_mtdif.o yaffs_ecc.o obj-m := $(O_TAGRET)
include $(TOPDIR)/Rules.make
在 fs 目录的 Makefile 文件中加入 yaffs 子目录,如下:
subdir-$(CONFIG_YAFFS_FS) += yaffs
在 fs 目录的 Config.in 文件中加入 YAFFS 选项,如下:
if [ “$CONFIG_MTD_SMC” = “y” ]; then
tristate ‘Yaffs filesystem on NAND’ CONFIG_YAFFS_FS
fi
注:if 的[ ]与字符间要用空隔隔开,否则 if 条件会始终不成立
内核配置时选中 File system ---> Yaffs filesystem on SMC,再重新编译,下载,启动。输出信息 如下:
#cat /proc/filesystems nodev rootfs
nodev bdev nodev proc nodev sockfs nodev tmpfs nodev shm nodev pipefs cramfs
nodev ramfs vfat
nodev devfs nodev nfs jffs2
nodev autofs nodev devpts yaffs
#mount -t yaffs /dev/mtdblock/1 /usr yaffs: dev is 7937 name is "1f:01"
#mkdir /usr/ccn
#ls /usr
ccn lost+found
#df -h
Filesystem Size Used Available UseMounted on
/dev/bon/2 2.7M 2.7M 0 100/
tmpfs 30.6M 0 30.6M 0/dev/shm
/dev/mtdblock/1 61.0M 100.0k 60.9M 0/usr
3.4 出现的问题
3.4.1 在 smc_partitions[]中添加 MTD 分区不起作用,如下:
……
NAND device: Manufacture ID: 0xec, Chip ID: 0x76 (Samsung K9D1208V0M)
bon0: 00000000-00030000 (00030000) 00000000 bon1: 00030000-00100000 (000d0000) 00000000 bon2: 00100000-00300000 (00200000) 00000000 bon3: 00300000-03ffc000 (03cfc000) 00000001
……
#ls /dev/mtd
0 0ro
#ls /dev/mtdblock
0
#cat /proc/mtd
dev: size erasesize name
mtd0: 04000000 00004000 "Samsung K9D1208V0M"
原因是定义分区的 smc_partitions[]在 CONFIG_MTD_SMC_S3C2410_SMDK_PARTITION 宏定义内,而在该 文件的开始又消除该宏定义,因此必须将消除修改成定义,如:
#undef CONFIG_MTD_SMC_S3C2410_SMDK_PARTITION 修改成:
#define CONFIG_MTD_SMC_S3C2410_SMDK_PARTITION
3.4.2 在 fs 目录的 Config.in 文件中加入 YAFFS 选项,但在内核配置中始终没有出现 File system
---> Yaffs filesystem on SMC 项。
原因:Config.in 中 if 语句的[ ]与字符间要用空隔隔开,否则 if 条件会始终不成立,如下:
if [ “$CONFIG_MTD_SMC” = “y” ]; then
tristate ‘Yaffs filesystem on NAND’ CONFIG_YAFFS_FS
fi
3.4.3 将加入 yaffs 的内核下载目标板启动后,仍没有 yaffs 项,如下:
# cat /proc/filesystems nodev rootfs
nodev bdev nodev proc nodev sockfs nodev tmpfs nodev shm nodev pipefs cramfs
nodev ramfs vfat
nodev devfs nodev nfs
nodev autofs nodev devpts
#
在 yaffs_fs.c 文件的 init_yaffs_fs()函数的开始和注册文件系统语句前增加打印信息,如下:
static int init init_yaffs_fs(void){
int error = 0;
yaffs_dev = yaffsram_dev = NULL;
printk(“init_yaffs_fs…….\n”);
printk(KERN_DEBUG "yaffs " DATE " " TIME " Initialisation\n");
......
#ifdef CONFIG_YAFFS_MTD_ENABLED
printk(“register yaffs filesystem………”); error = register_filesystem(&yaffs_fs_type); if (error){
#ifdef CONFIG_YAFFS_RAM_ENABLED
unregister_filesystem(&yaffs_ram_fs_type);
#endif //CONFIG_YAFFS_RAM_ENABLED
}
#endif // CONFIG_YAFFS_MTD_ENABLED
return error;
} 重新编译,下载,启动信息如下:
……
devfs: v1.10 (20020120) Richard Gooch (rgooch@atnf.csiro.au)
devfs: boot_options: 0x1 init_yaffs_fs...............
ttyS00 at I/O 0x50000000 (irq = 52) is a S3C2410 ttyS01 at I/O 0x50004000 (irq = 55) is a S3C2410
……
由上述信息中只有“init_yaffs_fs…….”而没有“register yaffs filesystem……”,说明系统调 用了 yaffs 初始化函数,但没有执行文件系统注册函数,所以在/proc/filesystems 中也就没有 yaffs 项。 必须增加CONFIG_YAFFS_MTD_ENABLED 的宏定义,才能使该部分的注册函数有效,故在文件开始前增加:
#defined CONFIG_YAFFS_MTD_ENABLED
或者在源码目录下创建 yaffs_config.h 文件,定义源码中所有的宏定义,再被其它源文件包含。 再次编译,下载,启动信息如下:
……
devfs: v1.10 (20020120) Richard Gooch (rgooch@atnf.csiro.au)
devfs: boot_options: 0x1 init_yaffs_fs............... register_filesystem...................
ttyS00 at I/O 0x50000000 (irq = 52) is a S3C2410 ttyS01 at I/O 0x50004000 (irq = 55) is a S3C2410
……
#cat /proc/filesystems
nodev rootfs nodev bdev nodev proc nodev sockfs nodev tmpfs nodev shm nodev pipefs cramfs
nodev ramfs vfat
nodev devfs nodev nfs nodev autofs nodev devpts yaffs
#
3.4.4 包含 CONFIG_YAFFS_MTD_ENABLED 宏定义后,编译出现错误:
yaffs_mtdif.c:33 variable ‘yaffs_oobinfo’ has initializer but incomplete type yaffs_mtdif.c:34 unknow field ‘useecc’ specified in initializer
……
将 yaffs_mtdif.c 中的用 nand_oobinfo 定义的两个结构体屏蔽掉
3.4.5 #mount –t yaffs /dev/mtdblock/1 /usr 出错
当执行该命令时会调用 yaffs_fs.c 文件中的 yaffs_internal_read_super()函数,主要还是该函数及 子函数出现错误,可以用 printk 函数打印信息的方法跟踪解决。本错误是由于当时没有将 yaffs_mtdif.c 文件中的 nand_oobinfo 结构完成屏蔽,而只是屏蔽掉了编译时出现错误的 useecc,所以在调试时出现一 系列对未初始化指针操作等错误。所以如果仔细按照上述的移植步骤操作,应不会出现类似的错误。
3.4.6 #./mkyaffs –e /dev/mtd/1 usr.yaffs 出现下述错误:
argc 4 sh 0 optcnt 2
MEMSETOOBSEL:Inappropriate ioctl for device
打开 yaffs 源码包 utils 目录下的 mkyaffs.c 文件(mkyaffs 工具的源文件),可以看出是下例语句出
现了错误:
Oobsel = usemtdecc ? yaffs_oobinfo : yaffs_noeccinfo;
if (ioctl(fd, MEMSETOOBSEL, &oobsel) != 0){
perror (“MEMSETOOBSEL”);
close (fd);
exit (1);
}
该功能给/dev/mtd/1 设备传递写入 nand flash 的 ecc 信息(mtdchar.c 文件的 ioctl()函数),和上 面屏蔽掉的 yaffs_mtdif.c 文件中的 yaffs_oobinfo 等是同一功能。由于我们使用的 MTD 驱动比较旧,查 看/drivers/mtd/mtdchar.c 文件的ioctl()函数可知还不支持该功能。因此也必须将 mkyaffs.c 文件中的 该功能去掉再重新编译生成 mkyaffs。或者使用原来的 mkyaffs 工具,但不加-e 参数,如:
#./mkyaffs /dev/mtd/1 usr.yaffs
或直接修改该源文件去掉-e 功能。
3.4.7 mkyaffs 编译出错
在 Makefile 文件中的 MAKETOOLS = 处添加交叉编译工具路径,如: MAKETOOLS = /opt/host/armv4l/bin/armv4l-unknown-linux-
将#include <mtd/mtd-user.h>替换成#include <linux/mtd/mtd.h>;将 nand_oobinfo 两个结构屏蔽 掉;将 main 函数中的 struct nand_oobinfo oobsel;和问题 6 提到的与 MEMSETOOBSEL 相关的语句屏蔽掉。
最后编译生成目标文件 mkyaffs_noecc(为了与原来的 mkyaffs 区别加上_noecc 后缀)。
3.4.8 系统启动后/proc 目录为空等问题,如下:
#df –h
Filesystem size Used Available Use% Mounted on df: /proc/mounts: No such file or directory
#ls /proc
而且,在宿主机上也不能用 ztelnet 登录,提示: [root@localhost root_dir]#ztelnet 192.168.1.7
Trying 192.168.1.7…
telnet: Unable to connect to remote host: Connection refused
原因是在 vivi 中的 kernel command line 参数有错误,如下述系统启动时的信息中缺少 linuxrc 脚本: Kernel command line: console=ttyS0 root=/dev/bon/2
在 vivi 下应设置成:
vivi> param set linux_cmd_line “noinitrd root=/dev/bon/2 init=linuxrc console=ttyS0” 启动后信息如下:
Kernel command line: noinitrd root=/dev/bon/2 init=linuxrc console=ttyS0
另外,yaffs 文件系统在多次使用,没有可用空间时,也可能出现该现象,需在 vivi 中重新分区,再 下载内核、文件系统等解决。
3.4.9 挂载 yaffs 文件系统时出现错误,如下:
#mount –t yaffs /dev/mtdblock/1 /usr
yaffs: Attempting MTD mount on 31.1, “if:01”
mout: Mounting /dev/mtdblock/1 on /usr failed: Not a directory
原因是在执行 mkyaffsimage 工具打包 yaffs 格式文件系统影像时,加入了 convert 参数,如 在 PC 机上:
[root@localhost root_dir]#./mkyaffsimage ./root_english ./root_english.yaffs convert
‘convert’ produce a big-endian image from a little-endian machine
在目标板上:
#./mkyaffs /dev/mtd/1 ./root_english.yaffs
…… OK
#mount –t yaffs /dev/mtdblock/1 /usr
yaffs: Attempting MTD mount on 31.1, “if:01”
mout: Mounting /dev/mtdblock/1 on /usr failed: Not a directory
只需将刚才的 MTD 设备重新用 yaffs 系统格式化就可以,如下:
#./mkyaffs /dev/mtd/1
……
Erasing block at 0x83cf8000
OK
#mount –t yaffs /dev/mtdblock/1 /usr
yaffs: Attempting MTD mount on 31.1, “if:01”
#
制作 yaffs 文件系统的镜像不应加 convert 参数,但又要满足参数大于 3 个,所以第四个参数只要不 为 convert 就可以,
PC 机如下:
[root@localhost root_dir]#./mkyaffsimage ./root_english ./root_english.yaffs c
下载到目标板后执行:
#./mkyaffs /dev/mtd/1 ./root_english.yaffs
…… OK
#mount –t yaffs /dev/mtdblock/1 /usr
yaffs: Attempting MTD mount on 31.1, “if:01”
#
3.5 yaffs 初始化及执行过程的简单总结
Step 1: 先调用 yaffs_fs.c 文件中的 init_yaffs_fs()初始化函数,它负责 yaffs 文件系统的注册,
将 yaffs 添加到/proc/filesystems 中;启动信息:
……
devfs: v1.10 (20020120) Richard Gooch (rgooch@atnf.csiro.au)
devfs: boot_options: 0x1
init_yaffs_fs............... (需要在函数中加该打印信息)
register_filesystem...................
……
Step 2: 调用 drivers/mtd/nand/smc_s3c2410.c 文件的 smc_s3c2410_init()函数扫描及初始化 NAND Flash 设备及底层接口函数,和 mtd 分区;启动信息:
……
NAND device: Manufacture ID: 0xec, Chip ID: 0x76 (Samsung K9D1208V0M)
add_mtd_partitions...
(需要在函数中加该打印信息)
Creating 2 MTD partitions on "Samsung K9D1208V0M":
0x00000000-0x04000000 : "bon"
0x00300000-0x03ffc000 : "mtd"
……
Step 3 : 执行 mount –t yaffs /dev/mtdblock/1 /usr 命令时,调用 yaffs_fs.c 文件中的
yaffs_internal_read_super()函数。执行信息:
# mount -t yaffs /dev/mtdblock/1 /usr yaffs_internal_read_super................. (需要在函数中加该打印信息) yaffs: Attempting MTD mount on 31.1, "1f:01"
Step 4: 另外还有对 yaffs 文件系统下的读或写等等,都会调用 yaffs_fs.c 文件下的相应函数,再 调用 mtd 设备对应的 NAND Flash 接口函数等。