The Linux MTD, JFFS HOWTO

[译者序]

在学习嵌入式Linux时看到本文,尚未发现中文译本,因此将其翻译出来,希望对大家有所帮助。
版权请参见原文。译文可自由用于非商业用途。转载请注明出处。
==================================================================

#
# ftp://ftp.uk.linux.org/pub/people/dwmw2/mtd/cvs/mtd/mtd-jffs-HOWTO.txt
#
                      ***  The 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

    <作者赘言>
    一个通用的,由不知名维护者维护的非商业嵌入式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

    <作者赘言结束>

[获取最新代码]

完整的MTD/DOC/JFFS (以及一些工具)的源代码可以通过匿名CVS下载。
按下列步骤进行:
1. 确认你是root;
2. cd /usr/src
3. cvs -d :pserver:anoncvs@cvs.infradead.org:/home/cvs login
   (密码: 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文件名


    确保打补丁的过程一切正常,没有出现任何错误。
    这将把MTD功能加入到你的内核,并将MTD代码更新到补丁发布的日期。

    现在你有两个选择。你可以make config然后在当前内核里配置MTD;或者你可能想打最新的CVS补丁。
    如果你想打最新的CVS补丁,按下面2.4.x的操作步骤进行。

    [使用2.4.x系列内核]

    如果你想打CVS上的最新代码(在/usr/src/mtd目录),执行:

    cd /usr/src/mtd/patches
    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”选项。

* 如果你使能了这一选项,你可以指定检测DiskOnChip设备时的物理地址。通常检测代码会从0xC8000到0xEE000间每隔0x2000字节检测一次。修改CONFIG_MTD_DOCPROBE_ADDRESS选项允许你指定一个被检测的地址。注意:你的DiskOnChip设备很有可能被映射到0xD0000地址而不是0xD000地址。请使用实际物理地址而不是段地址。
  如果你保留地址为空,(或者根本未使能”Advanced detection options for DiskOnChip”选项),代码将进行自动检测。它工作的很好(至少对我来说是这样)。请先尝试一下自动检测。

* 打开”Probe High Addresses”选项将在内存顶部开始检测,而不是从BIOS ROM的扩展范围(640k – 1M)检测起。这需要和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/mtd0,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/mtd*)读写它们。
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分区]

啊哈~~~这非常有趣(并且很复杂)。

先决条件:
a. 你的开发系统的内核必须支持ramdisk,而且它的大小至少要与你所mount的root文件系统的大小相等。这只是为了压缩root文件系统。如果你已经有了一个压缩的root文件系统,那么你可以跳过这一步。

步骤:
1. 在你的支持mtd的开发系统上制作一个root文件系统。(支持MTD意味着你的开发系统内核必须支持MTD,而且你能够从你的开发系统上烧写你的MTD flash设备)。
制作root文件系统的工作留给读者完成。在网络上有大量已经做好的root文件系统,你可以使用其中任何一个,或者制作你自己的(这不是必要的娱乐,如果你之前从未制作过的话)。

2. 在ramdisk中制作一个ext2文件系统,大小和未压缩过的root文件系统相同。通过以下命令:

#mke2fs /dev/ram0 size_of_root_fs


size_of_root_fs:你的root文件系统大小,以1k为单位

3. 把这个空的文件系统mount到/mnt目录下的一个空闲目录中:

#mount -t ext2 /dev/ram0 /mnt/ramdisk


4. 把你小心翼翼制作出来的root文件系统目录拷贝到这个ramdisk中:

#cp -af /tmp/my_final_root_fs_files/* /mnt/ramdisk


5. 如果你的操作正确,那么通过如下命令,你现在可以看到根目录了(etc, root, bin, lib, sbin等等):

# ls -ld /mnt/ramdisk


6. 现在umount并且压缩这个文件系统:

 #umount /mnt/ramdisk
 #dd if=/dev/ram0 bs=1k count=<your_root_fs_size_in_1k_blocks> | gzip
         -9 > /tmp/compressedRootFS.gz


7. 现在,我们要告诉即将使用此压缩文件的内核:这是一个压缩文件系统,并且要在MTD设备上找到它。
   确信MTD支持已经被编译进此内核。另外,你还需对此内核做下面这两个修改(对2.2.x和2.4.x内核都适用):

   A. 在drivers/block/rd.c文件中,你需要把检测ROOT_DEV是软驱的代码注释掉。这段代码通常看起来是这样的:

        if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR
#ifdef CONFIG_BLK_DEV_INITRD
                && MAJOR(real_root_dev) != FLOPPY_MAJOR
#endif
        )
                return;


      一定不要在此处返回,因为你的ROOT_DEV不是软驱,而是MTD块设备。

    B. 因为对rd_load()函数(此函数用于装载任何压缩文件系统到ramdisk)的调用发生在MTD驱动有机会注册MTD块设备之前,这将导致rd_load()不能找到你的root设备,也就无法从root设备上装载压缩文件系统。
    尽管这个问题在内核中已经得到修正,你仍需修改main.c文件,在mount_root()调用之前,显式的调用一次rd_load()函数。所以,在init/main.c文件中,在mount_root()前加入一个rd_load()调用。

    C. 现在编译内核,加入MTD和ext2支持(不要作为modules)。

8. 在你把内核烧写到目标板前,需要告诉它,你想要装载一个压缩的root文件系统,以及这个压缩的映像在哪儿。 有两种方法可以做到:简单的方法(使用命令行参数)和复杂的方法。 我们将通过复杂的方法来做。运用简单方法将留给读者做为练习。 不,我通常不会仅仅为了乐趣而选择复杂的方法来做事情的,这背后是有原因的。 我正要做的,是直接在flash上引导Linux内核,不需要安装boot loader。在这种情况下,没有任何办法向内核传递命令行参数。

   像下面这样告诉目标板的内核,你想加载一个压缩的文件系统,以及到哪里去找到这个文件系统:

   #rdev -r <your_target_kernel_image> <offset_number_in_dec>


   <offset_number_in_dec>按下面的方法计算:
   这个数字是一串包含多个bit的二进制数字的十进制表示方式。
   Bit 0-9指出到root设备起始地址的偏移,以1KB块为单位。
   Bit 14表示是否需要装载一个ramdisk(在我们的例子中是经过压缩的ramdisk) — 当然要选择yes。不然你为什么要看这段呢!
   其它Bit:设为0。

作为下面的例子,17408是你应该在上面的rdev -r命令中键入的第二个参数。
这个数字告诉内核,偏移是1024个1K块(也就是说,应该在距MTD设备起始为1M字节的偏移查找并装载这个压缩的映像,并把它mount成root设备)。

注意:如果这个bit定义发生了变化,或者你怀疑我的正确性,请打开arch/i386/kernel/setup.c文件,查看这个文件的宏定义。这个文件是这些bit掩码定义的地方。

9. 现在告诉你的目标板内核你的root设备是什么:

#rdev <your_target_kernel> /dev/mtdblock<0,1,2….n>


10. 当然,你需要把你的压缩文件系统拷贝到MTD设备的正确偏移上。首先确保你的目标设备已经被擦除了:

  #dd if=/tmp/compressedRootFS.gz bs=1k of=/dev/mtd<0,1,2….n> seek=seek_offset


    seek_offset:1K块的数目,以KB为单位。这个偏移是你在第8步中告诉内核的。

    所以,对1M字节的偏移,你应该取“seek=1024”。

注意:”dd”可能会打印”operation not permitted”或一些这样信息,忽略它们!dd会试图截短被操作的设备,但MTD当然不会允许”dd”这样的命令截短它。拷贝操作将会像你看到的那样继续进行(不会受这些错误信息的影响)。

11. 完整性检查 (多年来的教训告诉我每一步都要检查两次,甚至三次)
    让我们确定你的压缩映像是正确的!

12. 我们将查看映像前若干字节以确定它们是正确的。你也可以”dd”目标映像回一个文件并比较它和原文件(留给读者做实验)。

  #dd if=/dev/mtd<0,1,2…n> bs=1k skip=1024 (或者是你的偏移,以KB为单位)  | od -Ax -tx1 |less


    记下前面几行。(注意上面”skip”的用法,不是”seek”)

    现在让我们查看你硬盘上的压缩root文件系统:

  #dd if=/tmp/compressedRootFS.gz | od -Ax -tx1 | less


    和你前面记下的进行比较,它们应该是相同的(我需要说这个吗?)

13. 安装内核,不管你是打算如何引导它(如果你打算用LILO引导,运行lilo)或把它放在其它boot loader所能引导的位置(或者直接从flash引导)。

14. 重启(目标板)。现在,你应该看到ramdisk启动代码执行两次,并且在第两次会找到压缩映像并把它mount成root文件系统。

15. 跳过这步。申请加薪吧(并且也要寄一点给我)!

[在一个没有BIOS的MTD设备上引导Linux内核,并且mount此设备上的压缩root文件系统]

这是嵌入式Linux的圣杯!:) 我将试图讲解怎么做。但最好只把它当做一个指南,因为嵌入式系统间相互的差异是非常大的,不仅仅指内存映射,而且包括处理器的类型,flash的类型,RAM的数量等等。

* 假设:
如果你的需求符合下面所讲,这将(或者可能)帮到你:

你想要:
1. 使用你在ftp.kernel.org下载的标准Linux内核。

2. 知道如何初始化你的处理器和芯片组。这包括,内存映射(和片选解码寄存器等)。你应该可以使用一个你或你们硬件工程师写的“简单”的初始化程序来测试你的板子。(注意:如果你打算使用BIOS,那么这个限制就消失了)。

3. 如果你的目标平台支持IDE硬盘的话,你已经在这场游戏中领先了(注意:这仅仅是在开发阶段,我们不打算在最终发布时包含硬盘)。这并不是没理由的要求。至少你能够买到支持你的目标处理器的,并且具有BIOS,支持IDE硬盘和串口的试验板或开发板。

4. 你不会把100次甚至200次的编译内核看做是一件辛苦的事。 :)

* 概述

我们将做下列几步:

1. 使用一个硬盘来在目标平台上设置并启动linux。

2. 喝瓶啤酒休息一下,带上你的伴侣(男朋友/女朋友)出去吃顿晚餐,因为他/她们将有一段时间不会再见到你。

3. 配置MTD驱动,这样你就能读/写flash以及mount一个jffs文件系统在上面。在这一步我们将使用modules。

4. 一旦开心舒适的完成了上面的第3步,我们开始编译MTD/jffs到内核中,准备引导。这一步我们将把内核安装到硬盘,把压缩文件系统放在MTD块设备上,然后引导它。接下来我们将根据你的喜好,进行5a或者5b。

5a. 在MTD设备上的非压缩root文件系统

    一旦我们成功的完成了第4步,我们将安装一个jffs文件系统到mtdbolck,并且mount成root(这很简单)。如果你想通过(简单)的拷贝单个文件来更改你的root文件系统的话,你可能想这样做。这样做的缺点是文件系统没有经过压缩。而flash一般比DRAM要贵3倍,其实你可以简单的把root文件系统压缩到FLASH上然后把它解压到更便宜的DRAM中(见下面5b)。

5b. 在MTD设备上的压缩root文件系统

    或者我们可以跳过上面简单的步骤,直接安装一个压缩的root文件系统到MTD设备上,然后在引导时把它解压缩到ramdisk(在DRAM中)并把这个ramdisk mount成root。(在我心里)这更好一些,因为DRAM通常要比FLASH更快。
    如果你的处理器支持DRAM控制器,那么它可能有read ahead和write combining,这将把性能提高一大截。如果你想写flash的话你需要把在flash地址上把这两个功能关闭。
    如果你的处理器有cache,那么你能更快的访问DRAM,因为这个区域可以被缓存。如果你要写flash的话,确保你关闭了cache功能(否则写操作将会失败。在C语言操作符中,应该把FLASH内存区域定义为”volatile”)。

    一旦我们把压缩文件系统mount为root,我们可以很容易的mount一个MTD flash分区到一个root分区的一个目录,用于保存配置文件、日志,或更新root文件系统。

6. 噩梦到来了!通过flash引导kernel (注意:它可能是MTD flash的一个部分,不需要对MTD进行什么操作,但MTD要从kernel保留区域后面开始)。
   这是最难解决的问题,但现在已经解决了。看下面。

   让我们开始工作吧:
   这是现在x86系统上可能的bzImage kernel,点下面的链接查看详细内容:

   http://www.EmbeddedLinuxWorks.com/articles/rolo_guide.html

原创文章,请阅读页脚的许可方式,转载请注明:转载自易水博客 [ http://easwy.com/blog/ ]

本文链接地址: http://easwy.com/blog/archives/the-linux-mtd-jffs-howto/

文章的脚注信息由WordPress的wp-posturl插件自动生成