访问手机版页面
你的位置:老古开发网 > 其他 > 正文  
嵌入式设备上的 Linux 系统开发(二)
内容导读:
清单 4. 样本标记格式。内核通过 <ATAG_TAGNAME> 头来标识每个标记。 #define <aTAG_TAGNAME> <Some Magic number> 

struct <tag_tagname> { 
u32 <tag_param>; 
u32 <tag_param>; 
}; 

/* Example tag for passing memory information */ 

#define ATAG_MEM 0x54410002 /* Magic number */ 

struct tag_mem32 { 
u32 size; /* size of memory */ 
u32 start; /* physical start address of memory*/ 
}; 



setup_arch 还需要对闪存存储库、系统寄存器和其它特定设备执行内存映射。一旦完成了特定于体系结构的设置,控制就返回到初始化系统其余部分的 start_kernel 函数。这些附加的初始化任务包含: 

·设置陷阱 
·初始化中断 
·初始化计时器 
·初始化控制台 
·调用 mem_init,它计算各种区域、高内存区等内的页面数量 
·初始化 slab 分配器并为 VFS、缓冲区高速缓存等创建 slab 高速缓存 
·建立各种文件系统,如 proc、ext2 和 JFFS2 
·创建 kernel_thread,它执行文件系统中的 init 命令并显示 lign 提示符。 如果在 /bin、/sbin 或 /etc 中没有 init 程序,那么内核将执行文件系统的 /bin 中的 shell。 



设备驱动程序 
嵌入式系统通常有许多设备用于与用户交互,象触摸屏、小键盘、滚动轮、传感器、RA232 接口、LCD 等等。除了这些设备外,还有许多其它专用设备,包括闪存、USB、GSM 等。内核通过所有这些设备各自的设备驱动程序来控制它们,包括 GUI 用户应用程序也通过访问这些驱动程序来访问设备。本节着重讨论通常几乎在每个嵌入式环境中都会使用的一些重要设备的设备驱动程序。 

帧缓冲区驱动程序 
这是最重要的驱动程序之一,因为通过这个驱动程序才能使系统屏幕显示内容。帧缓冲区驱动程序通常有三层。最底层是基本控制台驱动程序 drivers/char/console.c,它提供了文本控制台常规接口的一部分。通过使用控制台驱动程序函数,我们能将文本打印到屏幕上 — 但图形或动画还不能(这样做需要使用视频模式功能,通常出现在中间层,也就是 drivers/video/fbcon.c 中)。这个第二层驱动程序提供了视频模式中绘图的常规接口。 

帧缓冲区是显卡上的内存,需要将它内存映射到用户空间以便可以将图形和文本能写到这个内存段上:然后这个信息将反映到屏幕上。帧缓冲区支持提高了绘图的速度和整体性能。这也是顶层驱动程序引人注意之处:顶层是非常特定于硬件的驱动程序,它需要支持显卡不同的硬件方面 — 象启用/禁用显卡控制器、深度和模式的支持以及调色板等。所有这三层都相互依赖以实现正确的视频功能。与帧缓冲区有关的设备是 /dev/fb0(主设备号 29,次设备号 0)。 

输入设备驱动程序 
可触摸板是用于嵌入式设备的最基本的用户交互设备之一 — 小键盘、传感器和滚动轮也包含在许多不同设备中以用于不同的用途。 

触摸板设备的主要功能是随时报告用户的触摸,并标识触摸的坐标。这通常在每次发生触摸时,通过生成一个中断来实现。 

然后,这个设备驱动程序的角色是每当出现中断时就查询触摸屏控制器,并请求控制器发送触摸的坐标。一旦驱动程序接收到坐标,它就将有关触摸和任何可用数据的信号发送给用户应用程序,并将数据发送给应用程序(如果可能的话)。然后用户应用程序根据它的需要处理数据。 

几乎所有输入设备 — 包括小键盘 — 都以类似原理工作。 

闪存 MTD 驱动程序 
MTD 设备是象闪存芯片、小型闪存卡、记忆棒等之类的设备,它们在嵌入式设备中的使用正在不断增长。 

MTD 驱动程序是在 Linux 下专门为嵌入式环境开发的新的一类驱动程序。相对于常规块设备驱动程序,使用 MTD 驱动程序的主要优点在于 MTD 驱动程序是专门为基于闪存的设备所设计的,所以它们通常有更好的支持、更好的管理和基于扇区的擦除和读写操作的更好的接口。Linux 下的 MTD 驱动程序接口被划分为两类模块:用户模块和硬件模块。 

用户模块 
这些模块提供从用户空间直接使用的接口:原始字符访问、原始块访问、FTL(闪存转换层,Flash Transition Layer — 用在闪存上的一种文件系统)和 JFS(即日志文件系统,Journaled File System — 在闪存上直接提供文件系统而不是模拟块设备)。用于闪存的 JFS 的当前版本是 JFFS2(稍后将在本文中描述)。 

硬件模块 
这些模块提供对内存设备的物理访问,但并不直接使用它们。通过上述的用户模块来访问它们。这些模块提供了在闪存上读、擦除和写操作的实际例程。 

MTD 驱动程序设置 
为了访问特定的闪存设备并将文件系统置于其上,需要将 MTD 子系统编译到内核中。这包括选择适当的 MTD 硬件和用户模块。当前,MTD 子系统支持为数众多的闪存设备 — 并且有越来越多的驱动程序正被添加进来以用于不同的闪存芯片。 

有两个流行的用户模块可启用对闪存的访问:MTD_CHAR 和 MTD_BLOCK。 

MTD_CHAR 提供对闪存的原始字符访问,而 MTD_BLOCK 将闪存设计为可以在上面创建文件系统的常规块设备(象 IDE 磁盘)。与 MTD_CHAR 关联的设备是 /dev/mtd0、mtd1、mtd2(等等),而与 MTD_BLOCK 关联的设备是 /dev/mtdblock0、mtdblock1(等等)。由于 MTD_BLOCK 设备提供象块设备那样的模拟,通常更可取的是在这个模拟基础上创建象 FTL 和 JFFS2 那样的文件系统。 

为了进行这个操作,可能需要创建分区表将闪存设备分拆到引导装载程序节、内核节和文件系统节中。样本分区表可能包含以下信息: 

清单 5. MTD 的简单闪存设备分区 struct mtd_partition sample_partition = { 

/* First partition */ 
name : bootloader, /* Bootloader section */ 
size : 0x00010000, /* Size */ 
offset : 0, /* Offset from start of flash- location 0x0*/ 
mask_flags : MTD_WRITEABLE /* This partition is not writable */ 
}, 
{ /* Second partition */ 
name : Kernel, /* Kernel section */ 
size : 0x00100000, /* Size */ 
offset : MTDPART_OFS_APPEND, /* Append after bootloader section */ 
mask_flags : MTD_WRITEABLE /* This partition is not writable */ 
}, 
{ /* Third partition */ 
name : JFFS2, /* JFFS2 filesystem */ 
size : MTDPART_SIZ_FULL, /* Occupy rest of flash */ 
offset : MTDPART_OFS_APPEND /* Append after kernel section */ 





上面的分区表使用了 MTD_BLOCK 接口对闪存设备进行分区。这些分区的设备节点是: 

简单闪存分区的设备节点 
User device node Major number Minor number 

Bootloader /dev/mtdblock0 31 0 
Kernel /dev/mtdblock1 31 1 
Filesystem /dev/mtdblock2 31 2 



在本例中,引导装载程序必须将有关 root 设备节点(/dev/mtdblock2)和可以在闪存中找到文件系统的地址(本例中是 FLASH_BASE_ADDRESS + 0x04000000)的正确参数传递到内核。一旦完成分区,闪存设备就准备装入或挂装文件系统。 

Linux 中 MTD 子系统的主要目标是在系统的硬件驱动程序和上层,或用户模块之间提供通用接口。硬件驱动程序不需要知道象 JFFS2 和 FTL 那样的用户模块使用的方法。所有它们真正需要提供的就是一组对底层闪存系统进行 read、 write 和 erase 操作的简单例程。 

嵌入式设备的文件系统 
系统需要一种以结构化格式存储和检索信息的方法;这就需要文件系统的参与。Ramdisk(请参阅参考资料)是通过将计算机的 RAM 用作设备来创建和挂装文件系统的一种机制,它通常用于无盘系统(当然包括微型嵌入式设备,它只包含作为永久存储媒质的闪存芯片)。 

用户可以根据可靠性、健壮性和/或增强的功能的需求来选择文件系统的类型。下一节将讨论几个可用选项及其优缺点。 

第二版扩展文件系统(Ext2fs) 
Ext2fs 是 Linux 事实上的标准文件系统,它已经取代了它的前任 — 扩展文件系统(或 Extfs)。Extfs 支持的文件大小最大为 2 GB,支持的最大文件名称大小为 255 个字符 — 而且它不支持索引节点(包括数据修改时间标记)。Ext2fs 做得更好;它的优点是: 

·Ext2fs 支持达 4 TB 的内存。 
Ext2fs 文件名称最长可以到 1012 个字符。 
当创建文件系统时,管理员可以选择逻辑块的大小(通常大小可选择 1024、2048 和 4096 字节)。 
·Ext2fs 了实现快速符号链接:不需要为此目的而分配数据块,并且将目标名称直接存储在索引节点(inode)表中。这使性能有所提高,特别是在速度上。 



因为 Ext2 文件系统的稳定性、可靠性和健壮性,所以几乎在所有基于 Linux 的系统(包括台式机、服务器和工作站 — 并且甚至一些嵌入式设备)上都使用 Ext2 文件系统。然而,当在嵌入式设备中使用 Ext2fs 时,它有一些缺点: 

Ext2fs 是为象 IDE 设备那样的块设备设计的,这些设备的逻辑块大小是 512 字节,1 K 字节等这样的倍数。这不太适合于扇区大小因设备不同而不同的闪存设备。 
Ext2 文件系统没有提供对基于扇区的擦除/写操作的良好管理。在 Ext2fs 中,为了在一个扇区中擦除单个字节,必须将整个扇区复制到 RAM,然后擦除,然后重写入。考虑到闪存设备具有有限的擦除寿命(大约能进行 100,000 次擦除),在此之后就不能使用它们,所以这不是一个特别好的方法。 
在出现电源故障时,Ext2fs 不是防崩溃的。 
Ext2 文件系统不支持损耗平衡,因此缩短了扇区/闪存的寿命。(损耗平衡确保将地址范围的不同区域轮流用于写和/或擦除操作以延长闪存设备的寿命。) 
Ext2fs 没有特别完美的扇区管理,这使设计块驱动程序十分困难。 



由于这些原因,通常相对于 Ext2fs,在嵌入式环境中使用 MTD/JFFS2 组合是更好的选择。 

用 Ramdisk 挂装 Ext2fs 
通过使用 Ramdisk 的概念,可以在嵌入式设备中创建并挂装 Ext2 文件系统(以及用于这一目的的任何文件系统)。 

清单 6. 创建一个简单的基于 Ext2fs 的 Ramdisk mke2fs -vm0 /dev/ram 4096 
mount -t ext2 /dev/ram /mnt 
cd /mnt 
cp /bin, /sbin, /etc, /dev ... files in mnt 
cd ../ 
umount /mnt 
dd if=/dev/ram bs=1k count=4096 of=ext2ramdisk 

mke2fs 是用于在任何设备上创建 ext2 文件系统的实用程序 — 它创建超级块、索引节点以及索引节点表等等。 

在上面的用法中,/dev/ram 是上面构建有 4096 个块的 ext2 文件系统的设备。然后,将这个设备(/dev/ram)挂装在名为 /mnt 的临时目录上并且复制所有必需的文件。一旦复制完这些文件,就卸装这个文件系统并且设备(/dev/ram)的内容被转储到一个文件(ext2ramdisk)中,它就是所需的 Ramdisk(Ext2 文件系统)。 

上面的顺序创建了一个 4 MB 的 Ramdisk,并用必需的文件实用程序来填充它。 

一些要包含在 Ramdisk 中的重要目录是: 

·/bin — 保存大多数象 init、busybox、shell、文件管理实用程序等二进制文件。 
·/dev — 包含用在设备中的所有设备节点 
·/etc — 包含系统的所有配置文件 
·/lib — 包含所有必需的库,如 libc、libdl 等 



日志闪存文件系统,版本 2(JFFS2) 
瑞典的 Axis Communications 开发了最初的 JFFS,Red Hat 的 David Woodhouse 对它进行了改进。 第二个版本,JFFS2,作为用于微型嵌入式设备的原始闪存芯片的实际文件系统而出现。JFFS2 文件系统是日志结构化的,这意味着它基本上是一长列节点。每个节点包含有关文件的部分信息 — 可能是文件的名称、也许是一些数据。相对于 Ext2fs,JFFS2 因为有以下这些优点而在无盘嵌入式设备中越来越受欢迎: 

·JFFS2 在扇区级别上执行闪存擦除/写/读操作要比 Ext2 文件系统好。 
·JFFS2 提供了比 Ext2fs 更好的崩溃/掉电安全保护。当需要更改少量数据时,Ext2 文件系统将整个扇区复制到内存(DRAM)中,在内存中合并新数据,并写回整个扇区。这意味着为了更改单个字,必须对整个扇区(64 KB)执行读/擦除/写例程 — 这样做的效率非常低。要是运气差,当正在 DRAM 中合并数据时,发生了电源故障或其它事故,那么将丢失整个数据集合,因为在将数据读入 DRAM 后就擦除了闪存扇区。JFFS2 附加文件而不是重写整个扇区,并且具有崩溃/掉电安全保护这一功能。 
·这可能是最重要的一点:JFFS2 是专门为象闪存芯片那样的嵌入式设备创建的,所以它的整个设计提供了更好的闪存管理。 



因为本文主要是写关于闪存设备的使用,所以在嵌入式环境中使用 JFFS2 的缺点很少: 

当文件系统已满或接近满时,JFFS2 会大大放慢运行速度。这是因为垃圾收集的问题(更多信息,请参阅参考资料)。 



创建 JFFS2 文件系统 
在 Linux 下,用 mkfs.jffs2 命令创建 JFFS2 文件系统(基本上是使用 JFFS2 的 Ramdisk)。 

清单 7. 创建 JFFS2 文件系统 mkdir jffsfile 
cd jffsfile 

/* copy all the /bin, /etc, /usr/bin, /sbin/ binaries and /dev entries 
that are needed for the filesystem here */ 

/* Type the following command under jffsfile directory to create the JFFS2 Image */ 

./mkfs.jffs2 -e 0x40000 -p -o ../jffs.image 




上面显示了 mkfs.jffs2 的典型用法。-e 选项确定闪存的擦除扇区大小(通常是 64 千字节)。-p 选项用来在映像的剩余空间用零填充。-o 选项用于输出文件,通常是 JFFS2 文件系统映像 — 在本例中是 jffs.image。一旦创建了 JFFS2 文件系统,它就被装入闪存中适当的位置(引导装载程序告知内核查找文件系统的地址)以便内核能挂装它。 

tmpfs 
当 Linux 运行于嵌入式设备上时,该设备就成为功能齐全的单元,许多守护进程会在后台运行并生成许多日志消息。另外,所有内核日志记录机制,象 syslogd、dmesg 和 klogd,会在 /var 和 /tmp 目录下生成许多消息。由于这些进程产生了大量数据,所以允许将所有这些写操作都发生在闪存是不可取的。由于在重新引导时这些消息不需要持久存储,所以这个问题的解决方案是使用 tmpfs。 

tmpfs 是基于内存的文件系统,它主要用于减少对系统的不必要的闪存写操作这一唯一目的。因为 tmpfs 驻留在 RAM 中,所以写/读/擦除的操作发生在 RAM 中而不是在闪存中。因此,日志消息写入 RAM 而不是闪存中,在重新引导时不会保留它们。tmpfs 还使用磁盘交换空间来存储,并且当为存储文件而请求页面时,使用虚拟内存(VM)子系统。 

tmpfs 的优点包括: 

动态文件系统大小 — 文件系统大小可以根据被复制、创建或删除的文件或目录的数量来缩放。使得能够最理想地使用内存。 
速度 — 因为 tmpfs 驻留在 RAM,所以读和写几乎都是瞬时的。即使以交换的形式存储文件,I/O 操作的速度仍非常快。 



tmpfs 的一个缺点是当系统重新引导时会丢失所有数据。因此,重要的数据不能存储在 tmpfs 上。 

挂装 tmpfs 
诸如 Ext2fs 和 JFFS2 等大多数其它文件系统都驻留在底层块设备之上,而 tmpfs 与它们不同,它直接位于 VM 上。因而,挂装 tmpfs 文件系统是很简单的事: 

清单 8. 挂装 tmpfs /* Entries in /etc/rc.d/rc.sysinit for creating/using tmpfs */ 

# mount -t tmpfs tmpfs /var -o size=512k 
# mkdir -p /var/tmp 
# mkdir -p /var/log 
# ln -s /var/tmp /tmp 




上面的命令将在 /var 上创建 tmpfs 并将 tmpfs 的最大大小限制为 512 K。同时,tmp/ 和 log/ 目录成为 tmpfs 的一部分以便在 RAM 中存储日志消息。 

如果您想将 tmpfs 的一个项添加到 /etc/fstab,那么它可能看起来象这样: 

tmpfs /var tmpfs size=32m 0 0 

这将在 /var 上挂装一个新的 tmpfs 文件系统。 

标签:
来源:电子产品世界 作者: 时间:2006/3/24 16:28:00
相关阅读
推荐阅读
阅读排行
最近更新
商品推荐