Linux 正在嵌入式开发范畴稳步开展。由于 Linux 运用 GPL(请参阅本文后边的参考资料), 所以任何对将 Linux 定制于 PDA、掌上机或许可佩戴设备感喜好的人都能够从因特网免费下载其内核和应用程序,并开端移植或开发。许多 Linux 改良品种投合了嵌入式/实时商场。它们包含 RTLinux(实时 Linux)、uclinux(用于非 MMU 设备的 Linux)、Montavista Linux(用于 ARM、MIPS、PPC 的 Linux 分发版)、ARM-Linux(ARM 上的 Linux)和其它 Linux 体系(请参阅参考资料以链接到本文中说到的这些和其它术语及产品。)
嵌 入式 Linux 开发大致触及三个层次:引导装载程序、Linux 内核和图形用户界面(或称 GUI)。在本文中,咱们将会集评论触及这三层的一些根本概念;深化了解引导装载程序、内核和文件体系是怎么交互的;并将研讨可用于文件体系、GUI 和引导装载程序的许多选项中的一部分。
引导装载程序
引导装载程序一般是在任 何硬件上履行的榜首段代码。在象台式机这样的惯例体系中,一般将引导装载程序装入主引导记载(Master Boot Record,(MBR))中,或许装入 Linux 驻留的磁盘的榜首个扇区中。一般,在台式机或其它体系上,BIOS 将操控移交给引导装载程序。这就提出了一个风趣的问题:谁将引导装载程序装入(在大多数状况中)没有 BIOS 的嵌入式设备上呢?
处理这个问题有两种惯例技能:专用软件和细小的引导代码(tiny bootcode)。
专用软件能够直接与长途体系上的闪存设备进行交互并将引导装载程序装置在闪存的给定方位中。闪存设备是与存储设备功用相似的特别芯片,而且它们能耐久存储信息 — 即,在从头引导时不会擦除其内容。
这个软件运用方针(在嵌入式开发中,嵌入式设备一般被称为方针)上的 JTAG 端口,它是用于履行外部输入(一般来自主机机器)的指令的接口。JFlash-linux 是一种用于直接写闪存的盛行东西。它支撑为数许多的闪存芯片;它在主机机器(一般是 i386 机器 — 本文中咱们把一台 i386 机器称为主机)上履行并经过 JTAG 接口运用并行端口拜访方针的闪存芯片。当然,这意味着方针需求有一个并行接口使它能与主机通讯。Jflash-linux 在 Linux 和 Windows 版别中都可运用,能够在指令行顶用以下指令发动它:
某些品种的嵌入式设备具有细小的引导代码 — 依据几个字节的指令 — 它将初始化一些 DRAM 设置并启用方针上的一个串行(或许 USB,或许以太网)端口与主机程序通讯。然后,主机程序或装入程序能够运用这个衔接将引导装载程序传送到方针上,并将它写入闪存。
在装置它并给予其操控后,这个引导装载程序履行下列各类功用:
初始化 CPU 速度初始化内存,包含启用内存库、初始化内存装备寄存器等初始化串行端口(假如在方针上有的话)启用指令/数据高速缓存设置仓库指针设置参数区域并结构参数结构和符号(这是重要的一步,由于内核在标识根设备、页面巨细、内存巨细以及更多内容时要运用引导参数)履行 POST(加电自检)来标识存在的设备并陈述任何问题为电源办理供给挂起/康复支撑跳转到内核的开端 带有引导装载程序、参数结构、内核和文件体系的体系典型内存布局或许如下所示:
清单 1. 典型内存布局
/* Top Of Memory */
Bootloader
Parameter Area
Kernel
Filesystem
/* End Of Memory */
/* End Of Memory */
嵌入式设备上一些盛行的并可免费运用的 Linux 引导装载程序有 Blob、Redboot 和 Bootldr(请参阅参考资料取得链接)。一切这些引导装载程序都用于依据 ARM 设备上的 Linux,并需求 Jflash-linux 东西用于装置。
一旦将引导装载程序装置到方针的闪存中,它就会履行咱们上面说到的一切初始化作业。然后,它预备接纳来自主机的内核和文件体系。一旦装入了内核,引导装载程序就将操控转给内核。
设置东西链
设置东西链在主机机器上创立一个用于编译将在方针上运转的内核和应用程序的构建环境 — 这是由于方针硬件或许没有与主机兼容的二进制履行等级。
东西链由一套用于编译、汇编和链接内核及应用程序的组件组成。 这些组件包含:
Binutils — 用于操作二进制文件的实用程序调集。它们包含比如 ar、as、objdump、objcopy 这样的实用程序。Gcc — GNU C 编译器。Glibc — 一切用户应用程序都将链接到的 C 库。防止运用任何 C 库函数的内核和其它应用程序能够在没有该库的状况下进行编译。 构建东西链树立了一个穿插编译器环境。本地编译器编译与本机同类的处理器的指令。穿插编译器运 行在某一种处理器上,却能够编译另一种处理器的指令。重头设置穿插编译器东西链可不是一项简略的使命:它包含下载源代码、修补补丁、装备、编译、设置头文 件、装置以及许多许多的操作。别的,这样一个完全的构建进程对内存和硬盘的需求是巨大的。假如没有满意的内存和硬盘空间,那么在构建阶段由于相关性、装备 或头文件设置等问题会忽然冒出许多问题。
因而能够从因特网上取得已预编译的二进制文件是一件功德(但不太好的一点是,现在它们大多数只限于依据 ARM 的体系,但迟早会改动的)。一些比较盛行的已预编译的东西链包含那些来自 Compaq(Familiar Linux )、LART(LART Linux)和 Embedian(依据 Debian 但与它无关)的东西链 — 一切这些东西链都用于依据 ARM 的渠道。
内核设置
Linux 社区正积极地为新硬件增加功用部件和支撑、在内核中批改过错而且及时地进行惯例改善。这导致大约每 6 个月(或 6 个月不到)就有一个安稳的 Linux 树的新发行版。不同的维护者维护针对特定体系结构的不同内核树和补丁。当为一个项目挑选了一个内核时,您需求评价最新发行版的安稳性怎么、它是否契合项目 要求和硬件渠道、从编程视点来看它的舒适程度以及其它难以确认的方面。还有一点也十分重要:找到需求应用于根本内核的一切补丁,以便为特定的体系结构调整 内核。
内核布局
内核布局分为特定于体系结构的部 分和与体系结构无关的部分。内核中特定于体系结构的部分首要履行,设置硬件寄存器、装备内存映射、履行特定于体系结构的初始化,然后将操控转给内核中与体 系结构无关的部分。体系的其余部分在这第二个阶段期间进行初始化。内核树下的目录 arch/ 由不同的子目录组成,每个子目录用于一个不同的体系结构(MIPS、ARM、i386、SPARC、PPC 等)。每一个这样的子目录都包含 kernel/ 和 mm/ 子目录,它们包含特定于体系结构的代码来完结象初始化内存、设置 IRQ、启用高速缓存、设置内核页面表等操作。一旦装入内核并给予其操控,就首要调用这些函数,然后初始化体系的其余部分。
依据可用的体系资源和引导装载程序的功用,内核能够编译成 vmlinux、Image 或 zImage。vmlinux 和 zImage 之间的首要差异在于 vmlinux 是实践的(未紧缩的)可履行文件,而 zImage 是或多或少包含相同信息的自解压紧缩文件 — 仅仅紧缩它以处理(一般是 Intel 强制的)640 KB 引导时刻的约束。有关一切这些的权威性解说,请参阅 Linux Magazine 的文章Kernel Configuration: dealing with the unexpected(请参阅参考资料)。
内核链接和装入
一旦为方针体系编译了内核后,经过运用引导装载程序(它现已被装入到方针的闪存中),内核就被装入到方针体系的内存(在 DRAM 中或许在闪存中)。经过运用串行、USB 或以太网端口,引导装载程序与主机通讯以将内核传送到方针的闪存或 DRAM 中。在将内核完
全装入方针后,引导装载程序将操控传递给装入内核的地址。
内核可履行文件由许多链接在一起的方针文件组成。方针文件有许多节,如文本、数据、init 数据、bass 等等。这些方针文件都是由一个称为链接器脚本的文件链接并装入的。这个链接器脚本的功用是将输入方针文件的各节映射到输出文件中;换句话说,它将一切输入方针文件都链接到单一的可履行文件中,将该可履行文件的各节装入到指定地址处。vmlinux.lds 是存在于 arch/target>/ 目录中的内核链接器脚本,它担任链接内核的各个节并将它们装入内存中特定偏移量处。典型的 vmlinux.lds 看起来象这样:
清单 2. 典型的 vmlinux.lds 文件
OUTPUT_ARCH(arch>) /* arch> includes architecture type */
ENTRY(stext) /* stext is the kernel entry point */
SECTIONS /* SECTIONS command describes the layout
of the output file */
{
. = TEXTADDR; /* TEXTADDR is LMA for the kernel */
.init : { /* Init code and data*/
_stext = .; /* First section is stext followed
by __init data section */
__init_begin = .;
*(.text.init)
__init_end = .;
}
.text : { /* Real text segment follows __init_data section */
_text = .;
*(.text)
_etext = .; /* End of text section*/
}
.data :{
_data=.; /* Data section comes after text section */
*(.data)
_edata=.;
} /* Data section ends here */
.bss : { /* BSS section follows symbol table section */
__bss_start = .;
*(.bss)
_end = . ; /* BSS section ends here */
}
}
LMA 是装入模块地址;它表明即将装入内核的方针虚拟内存中的地址。TEXTADDR 是内核的虚拟开端地址,而且在 arch/target>/ 下的 Makefile 中指定它的值。这个地址有必要与引导装载程序运用的地址相匹配。一旦引导装载程序将内核仿制到闪存或 DRAM 中,内核就被从头定位到 TEXTADDR — 它一般在 DRAM 中。然后,引导装载程序将操控转给这个地址,以便内核能开端履行。
参数传递和内核引导
stext 是内核进口点,这意味着在内核引导时将首要履行这一节下的代码。它一般用汇编语言编写,而且一般它在 arch/target>/ 内核目录下。这个代码设置内核页面目录、创立身份内核映射、标识体系结构和处理器以及履行分支 start_kernel(初始化体系的主例程)。
start_kernel 调用 setup_arch 作为履行的榜首步,在其间完结特定于体系结构的设置。这包含初始化硬件寄存器、标识根设备和体系中可用的 DRAM 和闪存的数量、指定体系中可用页面的数目、文件体系巨细等等。一切这些信息都以参数方法从引导装载程序传递到内核。
将参数从引导装载程序传递到内核有两种办法:parameter_structure 和符号列表。在这两种办法中,不赞成运用参数结构,由于它强加了约束:指定在内存中,每个参数有必要坐落 param_struct 中的特定偏移量处。最新的内核期望参数作为符号列表的格局来传递,并将参数转化为已符号格局。param_struct 界说在 include/asm/setup.h 中。它的一些重要字段是:
清单 3. 样本参数结构
struct param_struct {
unsigned long page_size; /* 0: Size of the page */
unsigned long nr_pages; /* 4: Number of pages in the system */
unsigned long ramdisk /* 8: ramdisk size */
unsigned long rootdev; /* 16: Number representing the root device */
unsigned long initrd_start; /* 64: starting address of initial ramdisk */
/* This can be either in flash/dram */
unsigned long initrd_size; /* 68: size of initial ramdisk */
}
请注意:这些数表明界说字段的参数结构中的偏移量。这意味着假如引导装载程序将参数结构放置在地址 0xc0000100,那么 rootdev 参数将放置在 0xc0000100 + 16,initrd_start 将放置在 0xc0000100 + 64 等等 — 不然,内核将在解说正确的参数时遇到困难。
正如上面说到的,由于从引导装载程序到内 核的参数传递会有一些约束条件,所以大多数 2.4.x 系列内核期望参数以已符号的列表格局传递。在已符号的列表中,每个符号由标识被传递参数的 tag_header 以及这今后的参数值组成。符号列表中符号的惯例格局能够如下所示:
清单 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*/
};
struct tag_mem32 {
u32 size; /* size of memory */
u32 start; /* physical start address of memory*/
};
/* 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*/
};
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 文件体系。
图形用户界面(GUI)选项
从 用户的观念来看,图形用户界面(GUI)是体系的一个最至关重要的方面:用户经过 GUI 与体系进行交互。所以 GUI 应该易于运用而且十分牢靠。但它还需求是有内存认识的,以便在内存受限的、微型嵌入式设备上能够无缝履行。所以,它应该是轻量级的,而且能够快速装入。
另一个要考虑的重要方面触及许可证问题。一些 GUI 分发版具有答应免费运用的许可证,乃至在一些商业产品中也是如此。另一些许可证要求假如想将 GUI 兼并入项目中则要付出版税。
最终,大多数开发人员或许会挑选 XFree86,由于 XFree86 为他们供给了一个能运用他们喜爱的东西的了解环境。可是商场上较新的 GUI,象 Century Software 的 Microwindows(Nano-X)和 Trolltech 的 QT/Embedded,与 X 在嵌入式 Linux 的竞技舞台中展开了剧烈竞赛,这首要是由于它们占用很少的资源、履行的速度很快而且具有定制窗口构件的支撑。
让咱们看一看这些选项中的每一个。
Xfree86 4.X(带帧缓冲区支撑的 X11R6.4)
XFree86 Project, Inc. 是一家出产 XFree86 的公司,该产品是一个能够免费重复分发、敞开源码的 X Window 体系。X Window 体系(X11)为应用程序以图形方法进行显现供给了资源,而且它是 UNIX 和类 UNIX 的机器上最常用的窗口体系。它很小但很有用,它运转在为数许多的硬件上,它对网络通明而且有杰出的文档阐明。X11 为窗口办理、事情处理、同步和客户机间通讯供给强壮的功用 — 而且大多数开发人员现已了解了它的 API。它具有对内核帧缓冲区的内置支撑,并占用十分少的资源 — 这十分有助于内存相对较少的设备。X 服务器支撑 VGA 和非 VGA 图形卡,它对色彩深度 1、2、4、8、16 和 32 供给支撑,并对烘托供给内置支撑。最新的发行版是 XFree86 4.1.0。
它的长处包含:
帧缓冲区体系结构的运用提高了功用。占用的资源相对很小 — 巨细在 600 K 到 700 K 字节的规模内,这使它很简略在小型设备上运转。十分好的支撑:在线有许多文档可用,还有许多专用于 XFree86 开发的邮寄列表。X API 十分合适扩展。 它的缺陷包含:
比最近呈现的嵌入式 GUI 东西功用差。此外,当与 GUI 中最新的开发 — 象专门为嵌入式环境规划的 Nano-X 或 QT/Embedded — 比较时,XFree86 好像需求更多的内存。
Microwindows
Microwindows 是 Century Software 的敞开源代码项目,规划用于带小型显现单元的微型设备。它有许多针对现代图形视窗环境的功用部件。象 X 相同,有多种渠道支撑 Microwindows。
Microwindows 体系结构是依据客户机/服务器的而且具有分层规划。最底层是屏幕和输入设备驱动程序(关于键盘或鼠标)来与实践硬件交互。在中间层,可移植的图形引擎供给对线的制作、区域的填充、多边形、裁剪以及色彩模型的支撑。
在最上层,Microwindows 支撑两种 API:Win32/WinCE API 完结,称为 Microwindows;另一种 API 与 GDK 十分相似,它称为 Nano-X。Nano-X 用在 Linux 上。它是象 X 的 API,用于占用资源少的应用程序。
Microwindows 支撑 1、2、4 和 8 bpp(每像素的位数)的 palletized 显现,以及 8、16、24 和 32 bpp 的真彩色显现。
Microwindows 还支撑使它速度更快的帧缓冲区。Nano-X 服务器占用的资源大约在 100 K 到 150 K 字节。
原始 Nano-X 应用程序的均匀巨细在 30 K 到 60 K。由于 Nano-X 是为有内存约束的低端设备规划的,所以它不象 X 那样支撑许多函数,因而它实践上不能作为微型 X(Xfree86 4.1)的替代品。
能够在 Microwindows 上运转 FLNX,它是针对 Nano-X 而不是 X 进行修正的 FLTK(快速轻盈东西箱(Fast Light Toolkit))应用程序开发环境的一个版别。本文中描绘 FLTK。
Nano-X 的长处包含:
与 Xlib 完结不同,Nano-X 仍在每个客户机上同步运转,这意味着一旦发送了客户机恳求包,服务器在为另一个客户机供给服务之前一向等候,直到整个包都抵达停止。这使服务器代码十分简略,而运转的速度仍十分快。占用很小的资源 Nano-X 的缺陷包含:
联网功用部件至今没有经过恰当地调整(特别是网络通明性)。还没有太多现成的应用程序可用。与 X 比较,Nano-X 尽管近来正在加快开发,但仍没有那么多文档阐明而且没有很好的支撑,但这种景象会有所改动。 Microwindows 上的 FLTK API 是一个简略但灵敏的 GUI 东西箱,它在 Linux 国际中赢得越来越多的重视,它特别适用于占用资源很少的环境。它供给了您期望从 GUI 东西箱中取得的大多数窗口构件,如按钮、对话框、文本框以及超卓的赋值器挑选(用于输入数值的窗口构件)。还包含滑动器、滚动条、刻度盘和其它一些构件。
针 对 Microwindows GUI 引擎的 FLTK 的 Linux 版别被称为 FLNX。FLNX 由两个组件构成:Fl_Widget 和 FLUID。Fl_Widget 由一切根本窗口构件 API 组成。FLUID(快速轻盈的用户界面规划器(Fast Light User Interface Designer, FLUID))是用来发生 FLTK 源代码的图形编辑器。总的来说,FLNX 是能用来为嵌入式环境创立应用程序的一个超卓的 UI 构建器。
Fl_Widget 占用的资源大约是 40 K 到 48 K,而 FLUID(包含了每个窗口构件)大约占用 380 K。这些十分小的资源占用率使 Fl_Widget 和 FLUID 在嵌入式开发国际中十分受欢迎。
长处包含:
习惯于在象 Windows 这样已树立得较好的环境中开发依据 GUI 的应用程序的任何人都会十分简略地习惯 FLTK 环境。它的文档包含一本十分完好且编写杰出的手册。它运用 LGPL 进行分发,所以开发人员能够灵敏地发放他们应用程序的许可证。FLTK 是一个 C++ 库(Perl 和 Python 绑定也可用)。面向方针模型的挑选是一个好的挑选,由于大多数现代 GUI 环境都是面向方针的;这也使将编写的应用程序移植到相似的 API 中变得更简略。Century Software 的环境供给了几个有用的东西,比如 ScreenToP 和 ViewML 浏览器。
它的缺陷是:
一般的 FLTK 能够与 X 和 Windows API 一起作业,而 FLNX 不能。它与 X 的不兼容性阻止了它在许多项目中的运用。
Qt/Embedded
Qt/Embedded 是 Trolltech 新开发的用于嵌入式 Linux 的图形用户界面体系。Trolltech 开始创立 Qt 作为跨渠道的开发东西用于 Linux 台式机。它支撑各种有 UNIX 特色的体系以及 Microsoft Windows。KDE — 最盛行的 Linux 桌面环境之一,便是用 Qt 编写的。
Qt/Embedded 以原始 Qt 为根底,并做了许多超卓的调整以适用于嵌入式环境。Qt Embedded 经过 Qt API 与 Linux I/O 设备直接交互。那些了解并已习惯了面向方针编程的人员将发现它是一个抱负环境。而且,面向方针的体系结构使代码结构化、可重用而且运转快速。与其它 GUI 比较,Qt GUI 十分快,而且它没有分层,这使得 Qt/Embedded 成为用于运转依据 Qt 的程序的最紧凑环境。
Trolltech 还推出了 Qt 掌上机环境(Qt Palmtop Environment,俗称 Qpe)。Qpe 供给了一个根本桌面窗口,而且该环境为开发供给了一个易于运用的界面。Qpe 包含全套的个人信息办理(Personal Information Management (PIM))应用程序、因特网客户机、实用程序等等。可是,为了将 Qt/Embedded 或 Qpe 集成到一个产品中,需求从 Trolltech 取得商业许可证。(原始 Qt 自版别 2.2 今后就能够依据 GPL 取得 。)
它的长处包含:
面向方针的体系结构有助于更快地履行占用很少的资源,大约 800 K 抗锯齿文本和混合视频的象素映射。
它的缺陷是:
Qt/Embedded 和 Qpe 只能在取得商业许可证的状况下才干运用。
结束语
嵌入式 Linux 开发正迅速地开展着。您有必要学习并从引导装载程序和分发版到文件体系和 GUI 中的每一个事物的各种选项中作出挑选。可是要感谢有这种挑选自由度以及十分活泼的 Linux 社区,Linux 上的嵌入式开发现已达到了新的境地,而且调整模块以合适您的标准从未比现在更简略。这现已导致呈现了许多时新的手持和微型设备作为敞开盒,这是件功德 — 由于事实是您不必成为一个专家从这些模块中进行挑选来调整您的设备以满意您自己的要求和需求。
咱们期望这篇对嵌入式 Linux 范畴的介绍性概述能激起您进行实验的愿望,而且期望您将领会耍弄微型设备的趣味以满意您的喜好。为进一步有助于您的项目,请参阅下面的参考资料,链接到有关咱们这儿现已概述的技能的更深化的信息。