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 和引导装载程序的众多选项中的一部分。
这个软件使用目标(在嵌入式开发中,嵌入式设备通常被称为目标)上的 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 树的新发行版。不同的维护者维护针对特定体系结构的不同内核树和补丁。当为一个项目选择了一个内核时,您需要评估最新发行版的稳定性如何、它是否符合项目 要求和硬件平台、从编程角度来看它的舒适程度以及其它难以确定的方面。还有一点也非常重要:找到需要应用于基本内核的所有补丁,以便为特定的体系结构调整 内核。
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 中。然后,引导装载程序将控制转给这个地址,以便内核能开始执行。