[译者序]
在学习嵌入式Linux时看到本文,尚未发现中文译本,因此将其翻译出来,希望对大家有所帮助。
版权请参见原文。译文可自由用于非商业用途。
本文将随原文更新而更新,或者因修正翻译失误而更新,因此,请尽量不要转载,避免其它人因为看到不同的版本而产生迷惑。
如确需转载,请保留译者序部分。
译文原文链接:
http://blog.csdn.net/easwy/archive/2006/08/01/1006624.aspx
英文水平有限,如发现存在翻译错误,请反馈给我,我将及时修改。
联系方式: easwy.yang - at - gmail.com
Easwy
2006/7/31
==================================================================
#
# ftp://ftp.uk.linux.org/pub/people/dwmw2/mtd/cvs/mtd/mtd-jffs-HOWTO.txt
#
*** Linux MTD, JFFS HOWTO ***
(正在编写中,请贡献你所知道的)
$Id: mtd-jffs-HOWTO.txt,v 1.16 2001/08/13 23:17:55 dwmw2 Exp $
最后更新: <见CVS Id>
编辑: Vipin Malik (vipin@embeddedLinuxWorks.com)
其它作者的贡献见文档中的注释。
[关于]
本文致力于描述在Linux 2.2.x和2.4.x中设置MTD(Memory Technology Devices), DOC, CFI和JFFS (Journaling Flash File System)的方法。
本文整理工作正在进行中,(希望)在MTD和JFFS邮件列表中其它人的帮助下,本文能够成为一个相当全面的文档。
请将任何注释、更正、贡献发送到:vipin@embeddedLinuxWorks.com
请不要直接向此邮箱发送你的疑问,疑问应发送到邮件列表(见后)。
**************************** NO WARRANTY *****************************
# This HOWTO is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# If you break something you get to keep both parts! Follow these
# directions at YOUR OWN RISK.
# See the GNU General Public License for more details.
**********************************************************************
[开始]
如果你想使用MTD/JFFS认真设计一个项目,请定阅相应的邮件列表。这两个邮件列表都是由majordomo管理的。
MTD:
要定阅此列表,请到http://lists.infradead.org/mailman/listinfo/linux-mtd-cvs
或发送邮件到linux-mtd-request@lists.infradead.org,邮件内容包含"subscribe"。
不要向邮件列表本身发送定阅请求!邮件列表的地址为:linux-mtd@lists.infradead.org。
JFFS:
要定阅此列表,发送邮件到majordomo@axis.com,邮件内容包含"subscribe jffs-dev"。
不要向邮件列表本身发送定阅请求!邮件列表的地址为:jffs-dev@axis.com。
这两个项目的主页:
MTD/DOC/
http://www.linux-mtd.infradead.org/
JFFS
http://developer.axis.com/software/jffs/
MTD邮件列表归档位置:
http://www.linux-mtd.infradead.org/list-archive/
JFFS邮件列表归档位置:
http://mhonarc.axis.se/jffs-dev/threads.html
<blatant plug by author>
一个通用的,由不知名维护者维护的非商业嵌入式Linux网站在:
http://www.EmbeddedLinuxWorks.com
在这里,你可以找到在嵌入式系统中使用IDE flash磁盘的文章,JFFS/JFF2掉电可靠性测试的报告,在你的设计中使用JFFS系统的技巧,由FLASH引导x86 Linux内核而不需使用BIOS的详情,以及在留言板上嵌入式Linux开发社团成员们讨论的论点。
[MTD Flash设备数据库]
在上述网站上,你也会看到一个MTD Flash设备的数据库。这个数据库中列出了能够和MTD驱动程序一起工作的Flash设备列表。如果你使一个Flash设备或DOC (Disk On Chip)支持MTD驱动,请花几分钟时间将相关信息加入此数据库,使其它用户受益。任何人都可以添加或查看此数据库。
使用此链接直接访问MTD Flash数据库:
http://www.embeddedLinuxWorks.com/db.html
[掉电可靠嵌入数据库]
有一个独立的项目(有自己的邮件列表)致力于在JFFS2上开发写入零时延、掉电可靠的小嵌入数据库。想知道为什么需要这样一个东西,看这里:
http://www.embeddedLinuxWorks.com/articles/db_project.html
</blatant plug by author>
[获取最新代码]
完整的MTD/DOC/JFFS (以及一些工具)的源代码可以通过匿名CVS下载。
按下列步骤进行:
1. 确认你是root;
2. cd /usr/src
3. cvs -d :pserver:anoncvs@cvs.infradead.org:/home/cvs login
(password: anoncvs)
4. cvs -d :pserver:anoncvs@cvs.infradead.org:/home/cvs co mtd
这将在/usr/src下创建一个名为mtd的目录。
现在你有两种选择,取决于你想使用何种内核版本。
2.2系列内核需要增加额外的一步,因为2.2系列内核内未包含任何MTD的代码。
注意:
查看/dev/目录,如果你没有mtd0, mtd1, mtd2, mtdblock0, mtdblock1, mtdblock2这样的设备,请运行mtd/util下的MAKEDEV工具:
#sh /usr/src/mtd/util/MAKEDEV
这将在/dev目录下创建出正确的设备。
[使用2.2.x系列内核]
(注意:我所能告诉你的是,MTD和JFFS在2.2.x系列内核中不能以modules的方式工作。如果你想使用modules,我推荐你升级到2.4.x系列内核。)
从你所喜爱的源(ftp.kernel.org)下载2.2.17或2.2.18内核源代码,然后安装内核到/usr/src/linux-2.2.x,并将/usr/src/linux这个符号链接指向你的内核目录。
按你喜爱的方法配置内核(使用make config或make menuconfig或make xconfig),确保内核可以编译通过。
从下面的网站下载MTD补丁:
ftp://ftp.infradead.org/pub/mtd/patches
将补丁移到/usr/src/linux并执行:
patch -p1 < <patch file name here>
确保打补丁的过程一切正常,没有出现任何错误。
这将把MTD若能加入到你的内核,并将MTD代码更新到补丁发布的日期。
在这里你有两个选择。你可以make config然后在当前内核里配置MTD;或者你可能想打最新的CVS补丁。
如果你想打最新的CVS补丁,按下面2.4.x的操作步骤进行。
[使用2.4.x系列内核]
如果你想打CVS上的最新代码(在/usr/src/mtd目录),执行:
1. cd /usr/src/mtd/patches
2. sh patchin.sh /usr/src/linux
这将会创建从"/usr/src/linux/drivers/mtd/<files here>"到"/usr/src/mtd/kernel/<latest files here>"对应文件的符号链接。
同样的,也会在"/usr/src/linux/fs/jffs"和"/usr/src/linux/include/linux/mtd"间建立对应的符号链接。
现在你内核中的代码已经是CVS上的最新代码了。你可以make config (或menuconfig或xconfig),并且按照下面的方法配置MTD/JFFS等功能。
[配置内核中的MTD以及DOC]
不要在2.2.x系列内核中使用任何MTD modules。就像我所说的,它根本不能工作即使是编译通过。
modules可以和2.4.x系列内核一起使用。
在这里你有几种选择,这取决于你的目标。如下:
*** 1. Disk On Chip Devices (DOC):
为支持DOC,在编译内核时需打开(或编译为modules)下列选项:
* MTD core support
* Debugging (设置需要的debug级别)
* 根据你的DOC选择正确的DOC驱动。(1000, 2000或Millennium)。注意:CONFIG_MTD_DOC2000选项是同时支持DiskOnChip 2000和DiskOnChip Millenium设备的驱动。如果选择此选项存在问题,可以尝试另外一个DiskOnChip Millennium驱动,CONFIG_MTD_DOC2001。为使DiskOnChip probe代码能够使用Millennium相关驱动,你需要编辑docprobe.c,在文件开头处取消DOC_SINGLE_DRIVER的定义。
* 除非你正在做什么超出寻常的事,否则的话,不需要使能"Advanced detection options for DiskOnChip"选项。
* 如果你这样做了(指使能了"Advanced detection options for DiskOnChip"选项 --- 译者注),你可以指定检测DiskOnChip设备时的物理地址。通常检测代码会从0xC8000到0xEE000间每隔0x2000字节检测一次。修改CONFIG_MTD_DOCPROBE_ADDRESS选项允许你指定单个被检测的地址。注意:你的DiskOnChip设备很有可能被映射到0xD0000地址而不是0xD000地址。请使用实际物理地址而不是段地址。
如果你保留地址为空,(或者根本未使能"Advanced detection options for DiskOnChip"选项),代码将进行自动检测。它工作的很好(至少对我来说是这样)。请先尝试一下自动检测。
* 打开"Probe High Addresses"选项将在内存顶部开始检测,而不是从BIOS ROM的扩展范围(640k - 1M)检测起。This has to do with LinuxBIOS。关于此,请查看邮件列表存档中的相关邮件。如果你不知道我在讲什么,保留此选项为关闭状态。
* "Probe for 0x55 0xaa BIOS signature"。除非你的DiskOnChip Millennium上有LinuxBIOS,而且需要检测它,然后,还要用你的芯片设置代码替换掉IPL,然后才能在此处选择"Yes"。
保持其它选项为off,一直到"User Modules and Translation layers:"
* Direct char device access - yes
* NFTL layer support - yes
* Write support for NFTL(beta) - yes
注意,你不需要支持MTDBLOCK。那是完全不同的东西: 一种缓存的块设备,它直接在无wear levelling的FLASH芯片上工作。
保存所有配置,然后make dep, make bzImage, make modules, make modules_install
注意: 如果你使用的是2.4.x系列内核,但你现有的系统基于2.2.x系列内核,你就需要从ftp.kernel.org/utils/kernel下载最新版本modutils,不然的话make modules_install或depmod -a命令将会执行失败。
把所有东西放到正确的位置,安装kernel,运行lilo,然后重启。
如果你把MTD功能编译进了内核(如果你把MTD功能编译为modules,请参阅后面的章节。编译为modules意味不需要反复重启你的机器),留意一下启动信息,特别是留意MTD DOC的启动提示,看上去类似下面的信息:
"DiskOnChip found at address 0xD0000 (你的地址可能与此不同)"
"nftla1"
上面的信息显示,DOC已经被检测到并且找到了一个分区,分配为/dev/nftla1。如果更多的分区被检测到,它们将会被分配为/dev/nftla2等。
注意,MTD设备为/dev/mtd0,可以用下面的命令查看它的详细信息:
#cat /proc/mtd
dev: size erasesize name
mtd0: 02000000 00004000 "DiskOnChip 2000"
/dev/nftla1,2,3是正常的块设备分区,你可以使用mke2fs命令在上面创建一个ext2文件系统,然后它们就可以使用正常的方式被mount上系统上。
如果DiskOnChip已经检测到,但你看到的不是nftla1,2,3...,而是类似下面的信息:
"Could not find valid boot record"
"Could not mount NFTL device"
首先确保你使用了最新的CVS上的DiskOnChip和NFTL代码。
如果这还不行,特别是驱动表现出奇怪或有bug的行为,并且内嵌到设备中的DOS驱动也不再工作了,那么你可能使用的是"hosed"设备("hosed"是个技术术语)。你首先要"un-hose"它。在/usr/src/mtd/util下有一个称做nftl_format的工作可以帮助你脱离这个困境。
警告: 如果没有搜索过邮件列表中相关信息,千万不要使用nftl_format工具!它将擦除设备上的所有块,有可能导致出厂时写入的坏块信息丢失。(真应该有人在某天解决这个问题 - ed)
从根本上说,如果你的设备被检测到但报了"Could not mount NFTL device"的错时,运行一下:
#./nftl_format /dev/mtd0 (假设你的设备安装为mtd0,请查看cat /proc/mtd/的输出)
在使用nftl_format工具前,你应该卸载nftl驱动。在运行之后,再重新加载此驱动。重格式化驱动下层的NFTL并不是愉快方法。如果驱动不能识别出NFTL格式,没有关系:重启机器或在运行nftl_format后重新加载modules,它就会被再次识别。
如果你的设备的"擦除大小"是8K (0x2000),nftl_format工具仍然会继续并格式化它。然后重启,这次驱动将提示"unknown partition table"的错误,别担心,执行:
# fdisk /dev/nftla
然后在它上面创建分区。太好了!现在你可以在这些分区上用e2fsck或其它工具了。注意,如果你不想有超过一个分区,你完全不需为分区烦恼: 只需要在整个/dev/nftla设备上创建文件系统;而不需要先分区,然后再使用/dev/nftla1。
***如果你编译MTD功能为modules(这是我所推荐的):
确保你在使用新内核重启后执行了"depmod -a"命令。然后执行:
#modprobe -a doc2000 nftl mtdchar mtdblock
现在你加载了核心功能。而实际的检测动作发生在你加载docprobe模块的时候:
#modprobe -a docprobe
现在你就会看到上一节描述的信息了。请按上一节的步骤做(在上一节,你把mtd/DOC功能编译进了内核)。
*** 2. Raw Flash(主要为NOR)芯片
你的板上或许焊了几只(或仅有一个)FLASH芯片,或许你正打算这样设计。不像DOC设备,这些芯片以线性内存的方式映射到地址空间中(虽然不是必需,它们也经常被分页)。
MTD可以处理8位、16位或32位宽度的内存接口,使用8位、16位(甚至是32位芯片(是否有这种芯片?) -- 需要确认)。
现在,CFI芯片看上去工作的很好,而且我的板上使用的正是这种芯片。因此我先讲CFI芯片。也许其它使用JEDEC芯片的人可以讲一下JEDEC芯片。
你必须在raw flash MTD设备上使用(针对所有的操作,包括写)JFFS文件系统。这是因为JFFS提供了丰富的写入以及封装机制。想了解更多这方面的知识,请参阅FAQ。
如果你希望在你开发过程中文件系统可写,但在交付时只读,这可以通过MTDBLOCK设备来实现。MTDBLOCK设备以下面的方式实现写操作:首先读出整个擦除块,然后擦除它,以你将写入的内容更改刚才读回的内容,然后再将这段内容写回到FLASH中。显然,你不希望以这种方式进行生产,但对开发来讲这就足够了。
*** 配置内核支持MTD/CFI/JFFS
除了下面提到的选项,关闭其它所有的MTD选项。
* MTD support (核心功能)
* Debugging -yes (初始设为level 3)
* Support for ROM chips in bus mapping -yes
* CFI (common flash interface) support -yes
* Specific CFI flash geometry selection -yes
* <选择在你板上的FLASH芯片的geometry>
* 如果你使用8位FLASH芯片提供32位宽度的FLASH接口,那么你就有4 way interleaving。打开那些看起来不会损伤任何东西的选项。
* CFI支持Intel.Sharp或AMD/Fujitsu芯片,也许符合你的情况。
* Physical mapping of flash chips - 在这里设你的配置,或者这里已经列出了你所用的板,选择它。
然后,在"File systems"中,选择:
* jffs,以及
* /proc file-system support,正好在jffs下面
* 选择一个jffs debug级别,由高开始,然后逐渐调低。
保存,make dep, make bzImage, make modules, make modules_install, 把内核移到正确的位置,增加lilo项目,运行lilo(或者你自己的引导程序),重启。
如果你把它编译成modules,那么执行(以root身份):
# depmod -a
# modprobe -a mtdchar mtdblock cfi_cmdset_0002 map_rom cfi_probe
上面的命令装载了CFI FLASH的核心模块,现在使用下面的命令检测实际的FLASH:
#modprobe -a physmap
查看控制台的输出(注意如果你是telnet到机器上,那么信息可能会输出到tty0上,tty0是与显卡相连的终端)。能够查看控制台的输出是非常重要的。你也可以在/var/log/messages中看到内核输出的信息(这取决于你使用的linux发行版本,在Red Hat上是这样的)。
不要被下面的信息迷惑了:
"physmap flash device:xxxxx at yyyyyyy"
这只是在报告你编译进内核的参数(看上面的 "Physical mapping of flash chips"部分)。
如果你的FLASH真的被检测到了,将会打印出类似这样的信息:
"Physically mapped flash: Found bla-bla-bla at location 0".
如果没有设备被检测到,那么physmap模块将不会被装载。这并不是把它编译成模块的问题,也不是physmap或modprobe本身的问题。不幸的很这是最麻烦的。你不得不深入研究physmap.c中所调用的"do_cfi_probe()"函数。
注意:physmap.c使用ioremap()函数把物理内存映射到逻辑内核空间。如果你的处理器内部有cache,那么你要改用ioremap_nocache(),否则的话你会扯光你的头发,因为你的FLASH永远也不会被检测到。
这个函数名为cfi_probe() (上面的名字是do_cfi_probe(),需确认哪个是正确的 --- 译者注),在mtd/kernel/目录下的"cfi_probe.c"文件中。
在这个文件中插入printk,以发现为什么你的FLASH不能被检测到。如果你的芯片被检测到了,那么在使用"modprobe physmap"命令装载physmap时,你将看到类似这样的信息:
"Physically mapped flash: Found bla-bla-bla at location"
现在,芯片已经被注册,你可以通过下面的命令看到相关信息:
#cat /proc/mtd
*** 把JFFS文件系统装到FLASH设备上
到现在为止,你已经想办法成功的检测到你的FLASH设备,接下来你需要做的是在上面创建一个JFFS文件系统。不像mke2fs,并没有一个工具可以直接在/dev/mdt0,1,2设备上创建一个JFFS文件系统。
你必须使用一个称为mkfs.jffs的工具,这个工具在mtd/util目录下。
先把你将要放在jffs文件系统上的内容放在一个目录中,我们假设这个目录的名字叫做/home/jffsstuff。
然后执行:
#/usr/src/mtd/util/mkfs.jffs -d /home/jffsstuff -o /tmp/jffs.image
这将创建一个JFFS映像文件,如果你的FLASH芯片已经擦除,接下来执行(如果没有擦除,请看后面):
#cp /tmp/jffs.image /dev/mtd0,1,2... (这里选择你的设备,很可能是/dev/mtd0)。
你也可以直接mount一个已擦除的mtdblock设备,不必在上面安装一个文件系统。这允许你通过shell交互式的往你的设备上填加内容(直接拷贝文件到安装点目录)。
如果你的FLASH芯片未经擦除,或者你已经记不清楚了,你不能简直的拷贝一个新映像文件去覆盖旧的。这样的话会出现糟糕的事情。使用mtd/util/erase去擦除你的设备。
#/usr/src/mtd/util/erase /dev/mtd0,1,2,3 <offset> <erase-size>
在上面:
offset: 如果你不清楚的话,使用0 (将从mtd设备的开始处擦除),否则的话填入十进制表示的字节数,但是必须是擦写扇区边界值的整数倍。
erase-size: 你想擦除的"擦写扇区“的数目。你的FLASH的最大erase size为:
FLASH大小 / 你的MTD设备的擦写大小(使用`cat /proc/mtd`命令查看)
在你的控制台上查看输出信息(假设你在配置内核时选择了verbose输出),你应该不会看到任何错误。
在命令行提示符显示出来后,执行:
#cp /tmp/jffs.image /dev/mtd0,1,2... (这里选择你的设备,很可能是/dev/mtd0)。
接下来把JFFS module装载进来:
#modprobe jffs
然后mount文件系统:
#mount -t jffs /dev/mtdblock0 /mnt/jffs (假设/mnt/jffs目录存在,不存在的话创建它)
注意:上面命令使用了/dev/mtdblock0而不是/dev/mtd0。"mount"命令需要块设备接口,/dev/mtdblock0,1,2,3...就是为这个目的提供的。/dev/mtd0,1,2,3是字符设备,提供它们是为了处理像拷贝二进制映像文件到原始FLASH设备上这类操作的。
*** 在CFI FLASH上创建分区,以及使用多片FLASH芯片
不像一般的块设备,你不能在/dev/mtdblock0,1,2,3...上使用fdisk并创建分区。
(就我所知)CFI flash的分区必须在physmap.c文件中创建并编译进驱动。
对多片FLASH也说也是一样的。(正确与否?确认并更正)
可以在文件mtd/kernel/sbc_mediagx.c中找到创建分区的一个例子。
可以在文件mtd/kernel/octagon_5066.c中找到把多片FLASH芯片映射成单独的/dev/mtdn设备的例子(特别需要注意的,是在"init_oct5066()"函数中注册mtd设备时所采用多重循环)。你也可以为每个bank增加分区,参见mtd/kernel/sbc_mediagx.c的代码。
*** Mount JFFS文件系统做为root分区
这非常简单。
注意:这里假设你能够用某种方法引导你的内核。这一节并不涉及从一个MTD分区(或设备)上引导你的内核。
你可以通过IDE flash盘/CF盘等来引导内核,使用lilo。
不管你通过什么方式来引导内核(甚至你想直接从FLASH来引导),下面的步骤是相同的。这次你只是把内核烧进原始FLASH设备中(在下面的"rdev"步骤完成之后)。
1. 保证你能够检测到你的flash设备,并且可以通过MTD设备文件(/dev/mtdn)读写它们。
2. 保证你能够mount所需要的JFFS(1或2)文件系统到你的flash设备上,向它拷贝文件,unmount,重启,再mount,你的文件仍然在那儿(也要在一组文件上运行 "diff",保证数据没有被损坏)。
3. 把所有必需的MTD/JFFS(1/2)功能编译到内核中(使用模块来mount root文件系统留给读者做练习)。
4. 告诉内核将用什么做为你的root分区,使用下面的命令:
# rdev <你的flash映像> /dev/mtdblock<n>
mtdblock<n>是你要在上面构建你的root文件系统的设备,它在重启后将被mount为root分区。
5. 运行boot loader的初始化程序(对LILO引导程序来说,是lilo)。
6. 重启。你的jffs mtdblock<n>分区将被mount为root分区。
*** Mount MTD分区(或设备)上经过压缩的ext2文件系统做为root分区
(未完待续)