基于ARM的嵌入式linux系统设计
摘要:本文简要介绍了ARM处理器的特点及其基本结构,详细论述了基于ARM的嵌入式linux系统的关键技术,包括引导加载程序、Linux内核、文件系统、用户应用程序。对linux系统的各部分开发设计做了较深入清晰地分析,总结了linux系统的特点,及其在嵌入式操作系统竞争中的优势。
关键字:ARM linux 引导加载程序 内核 文件系统
Design of the embedded linux system based ARM
Abstract: This paper simply introduces the character and basic architecture about processor of ARM, and emphasizes the key technologies of embedded linux based on ARM, including bootloader、linux kernel、file system、user application. For design each part of linux system, the paper gives a clearly analysis, summarizing the character embed linux system and the advantage of embed linux system among all embed system OS.
Key words: ARM linux bootloader kernel file system
1、引言
随着科技的发展,嵌入式系统已经是无处不在,嵌入式系统在包括工业自动化、国防、运输和航天领域、消费电子等领域得到了非常广泛的应用。例如神州飞船和长征火箭中肯定有很多嵌入式系统,导弹的制导系统也是嵌入式系统,高档汽车中也有多达几十个嵌入式系统。基于ARM的嵌入式系统更是发展迅猛,ARM在嵌入式处理器中处于领先地位,在各个行业都有着良好的应用。基于ARM的嵌入式linux系统近年也得到了巨大的发展,linux系统已经成为三大主流OS之一,是最有发展前景的嵌入式OS。 一个嵌入式 Linux 系统从软件的角度看通常可以分为四个层次:引导加载程序、 Linux 内核、 文件系统、 用户应用程序。
2、ARM 介绍
ARM(Advanced RISC Machines),既可以认为是一个公司的名字,也可以认为是对一类微处理器的通称,还可以认为是一种技术的名字。1991年ARM公司成立于英国剑桥,主要出售芯片设计技术的授权。目前,采用ARM技术知识产权(IP)核的微处理器,即我们通常所说的ARM微处理器,已遍及工业控制、消费类电子产品、通信系统、网络系统、无线系统等各类产品市场,基于ARM技术的微处理器应用约占据了32位RISC微处理器75%以上的市场份额,ARM技术正在逐步渗入到我们生活的各个方面。
采用RISC架构的ARM微处理器一般具有如下特点,体积小、低功耗、低成本、高性能;支持Thumb(16位)/ARM(32位)双指令集,能很好的兼容8位/16位器件;大量使用寄存器,指令执行速度更快;大多数数据操作都在寄存器中完成;寻址方式灵活简单,执行效率高;指令长度固定。
普通ARM处理器内核结构如图一所示:
图1、ARM普通处理器内核结构图
3、嵌入式linux系统
嵌入式Linux(Embedded Linux)是指对Linux经过裁剪小型化后,可固化在存储器或单片机中,应用于特定嵌入式场合的专用Linux操作系统。嵌入式Linux的开发和研究已经成为目前操作系统领域的一个热点。Linux 操作系统是一种性能优良、层次结构且内核完全开放、强大的网络支持功能、具备一整套工具链、具有广泛的硬件支持特性、源码公开且被广泛应用的免费操作系统,由于其体积小、可裁减、运行速度高、良好的网络性能等优点,可以作为嵌入式操作系统。随着2.6内核的发布,Linux向现有主流的RTOS提供商在嵌入式系统市场提出了巨大挑战,例如VxWorks和WinCE,具有许多新特性,将成为更优秀的嵌入式操作系统。嵌入式Linux 的Boot Loader、内核的启动参数、内核映像和根文件系统映像的固态存储设备的典型空间分配结构图如图2:
图2 固态存储设备的典型空间分配结构
3.1、bootloader技术
简单地说,Boot Loader 就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。 通常,Boot Loader 是严重地依赖于硬件而实现的,特别是在嵌入式世界。Boot Loader 的操作模式 (Operation Mode)
大多数 Boot Loader 都包含两种不同的操作模式:"启动加载"模式和"下载"模式,这种区别仅对于开发人员才有意义。但从最终用户的角度看,Boot Loader 的作用就是用来加载操作系统,而并不存在所谓的启动加载模式与下载工作模式的区别。
从操作系统的角度看,Boot Loader 的总目标就是正确地调用内核来执行。另外,由于 Boot Loader 的实现依赖于 CPU 的体系结构,因此大多数 Boot Loader 都分为 stage1 和 stage2 两大部分。依赖于 CPU 体系结构的代码,比如设备初始化代码等,通常都放在 stage1 中,而且通常都用汇编语言来实现,以达到短小精悍的目的。而 stage2 则通常用C语言来实现,这样可以实现给复杂的功能,而且代码会具有更好的可读性和可移植性。Boot Loader 的 stage1 通常包括以下步骤(以执行的先后顺序):硬件设备初始化,为加载 Boot Loader 的 stage2 准备 RAM 空间,拷贝 Boot Loader 的 stage2 到 RAM 空间中,设置好堆栈,跳转到 stage2 的 C 入口点。 Boot Loader 的 stage2 通常包括以下步骤(以执行的先后顺序):初始化本阶段要使用到的硬件设备, 检测系统内存映射(memory map),将 kernel 映像和根文件系统映像从 flash 上读到 RAM 空间中,为内核设置启动参数,调用内核。
基本的硬件初始化包括:屏蔽所有的中断。为中断提供服务通常是 OS 设备驱动程序的责任,因此在 Boot Loader 的执行全过程中可以不必响应任何中断。中断屏蔽可以通过写 CPU 的中断屏蔽寄存器或状态寄存器(比如 ARM 的 CPSR 寄存器)来完成。设置 CPU 的速度和时钟频率。RAM 初始化。包括正确地设置系统的内存控制器的功能寄存器以及各内存库控制寄存器等。初始化 LED。典型地,通过 GPIO 来驱动 LED,其目的是表明系统的状态是 OK 还是 Error。如果板子上没有 LED,那么也可以通过初始化 UART 向串口打印 Boot Loader 的 Logo 字符信息来完成这一点。 关闭 CPU 内部指令/数据 cache。
为加载 stage2 准备 RAM 空间主要是分配1M大小空间给OS,再调用内核,最后把控制权交给OS。
3.2、linux系统内核
linux系统内核的重要特点是可移植性,支持硬件平台广泛,在大多数的体系结构上都可以运行,可量测性,即可以运行在超级计算机上,也可以运行在很小的设备上,标准化和互用性,安全性,开发的源代码使得代码变得稳定,可靠性好,模块化,运行时可以根据系统的需要加载程序,编程容易,还可以从网上找到很多学习的资料,网上linux社区也非常活跃;linux内核全部源代码是遵守GPL软件许可的免费软件,这要求在发布linux软件的时候免费开放源码,linux有许多开放驱动程序可以使用,使得开发的时候不需要从头写起。
3.2.1 可抢占内核
在先前的内核版本中(包括2.4内核)不允许抢占以核心态运行的任务(包括通过系统调用进入内核模式的用户任务),只能等待它们自己主动释放CPU。这样必然导致一些重要任务延时以等待系统调用结束。一个内核任务可以被抢占,为的是让重要的用户应用程序可以继续运行。这样做最主要的优势是极大地增强系统的用户交互性。2.6内核并不是真正的RTOS(Real Time Operation System),其在内核代码中插入了抢占点,允许调度程序中止当前进程而调用更高优先级的进程,通过对抢占点的测试避免不合理的系统调用延时。2.6内核在一定程度上是可抢占的,比2.4内核具备更好的响应性。但也不是所有的内核代码段都可以被抢占,可以锁定内核代码的关键部分,确保CPU的数据结构和状态始终受到保护而不被抢占。
软件需要满足最终时间限制与虚拟内存请求页面调度之间是相互矛盾的。慢速的页错误处理将会破坏系统的实时响应性,而2.6内核可以编译无虚拟内存系统避免这个问题,这是解决问题的关键,但要求软件设计者有足够的内存来保证任务的执行。
3.2.2 有效的调度程序
2.6版本的 Linux内核使用了由 Ingo Molnar开发的新的调度器算法,称为O(1)算法,如图1所示。它在高负载情况下执行得极其出色,并且当有很多处理器并行时也可以很好地扩展[2]。过去的调度程序需要查找整个ready task队列,并且计算它们的重要性以决定下一步调用的task,需要的时间随task数量而改变。O(1)算法则不再每次扫描所有的任务,当task就绪时被放入一个活动队列中,调度程序每次从中调度适合的task,因而每次调度都是一个固定的时间。任务运行时分配一个时间片,当时间片结束,该任务将放弃处理器并根据其优先级转到过期队列中。活动队列中任务全部调度结束后,两个队列指针互换,过期队列成为当前队列,调度程序继续以简单的算法调度当前队列中的任务。这在多处理器的情况更能提高SMP的效率,平衡处理器的负载,避免进程在处理器间的跳跃。
3.2.3 同步原型与共享内存
多进程应用程序需要共享内存和外设资源,为避免竞争采用了互斥的方法保证资源在同一时刻只被一个任务访问。Linux内核用一个系统调用来决定一个线程阻塞或是继续执行来实现互斥,在线程继续执行时,这个费时的系统调用就没有必要了。Linux2.6所支持的Fast User-Space Mutexes 可以从用户空间检测是不是需要阻塞线程,只在需要时执行系统调用终止线程。它同样采用调度优先级来确定将要执行的进程[4]。 多处理器嵌入式系统各处理器之间需要共享内存,对称多处理技术对内存访问采用同等优先级,在很大程度上限制了系统的可量测性和处理效率。Linux2.6则提供了新的管理方法——NUMA(Non Uniform Memory Access)。NUMA根据处理器和内存的拓扑布局,在发生内存竞争时,给予不同处理器不同级别权限以解决内存抢占瓶颈,提高吞吐量。
3.2.4 POSIX线程及NPTL
新的线程模型基于一个1:1的线程模型(一个内核线程对应一个用户线程),包括内核对新的 NPTL(Native POSIX Threading Library)的支持,这是对以前内核线程方法的明显改进。2.6内核同时还提供POSIX signals和POSIX high-resolution timers。POSIX signals不会丢失,并且可以携带线程间或处理器间的通信信息。嵌入式系统要求系统按时间表执行任务,POSIX timer可以提供1kHz的触发器使这一切变得简单,从而可以有效地控制进度。
3.2..5 微控制器的支持
Linux2.6内核加入了多种微控制器的支持。无MMU的处理器以前只能利用一些改进的分支版本,如uClinux,而2.6内核已经将其整合进了新的内核中,开始支持多种流行的无MMU微控制器,如Dragonball、ColdFire、Hitachi H8/300。Linux在无MMU控制器上仍旧支持多任务处理,但没有内存保护功能。同时也加入了许多流行的控制器的支持,如S3C2410等。
3.3、linux文件系统
Linux采用文件系统组织系统中的文件和设备,为设备和用户程序提供统一接口,Linux 支持多种文件系统,如JFFS2、Ext2fs 、Cramfs等。
瑞典的 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结合Cramfs,Cramfs是只读的可以用来存放系统内核,JFFS2是可读写的,用来存放应用程序,这样就减少了开发过程中的烧写时间,读提高开发进度非常有用。
3.4、应用程序
根据嵌入式系统的实际应用开发的应用程序之间差异是很大的,但是实际开发的方式、手段还是有共性的。嵌入式系统的应用程序都是采用交叉编译的,因为目标板上的资源是非常有限的。开发的编译工具一般都是GCC,在实际工程中可能需要对数以百计的源文件进行编译,这显然不能采用命令行逐个编译,因此有效的利用make和makefile工具可以大大减少程序员的工作量,提高项目开发的效率。
make是一个解释Makefile文件的命令工具,它可以根据Makefile文件来描述的众多源文件之间的相互关系进行自动维护编译,它会告诉系统采取什么样的方式编译和链接程序。简单地说Makefile的特殊文件是用来来告诉make需要做什么、完成什么任务、该怎么做的文件。Linux程序员能写出高效的Makefile文件,就会使得开发变得简单许多,能缩短开发的周期,为产品占得市场先机有着非常重要的意义。开发的应用程序可以用GDB进行调试,在此不再展开。
四、总结
本文简要介绍了ARM处理器,详细论述了基于ARM的嵌入式linux系统的关键技术,包括引导加载程序、 Linux 内核、 文件系统、 用户应用程序。对linux系统的各部分开发设计做了较深入清晰地分析,总结了linux系统的特点,及其在嵌入式操作系统竞争中的优势。随着嵌入式系统不断发展,作为最有发展前景的ARM、linux将会逐渐扩大市场,学习好ARM及linux系统将有着广阔的天空和美好的前景。
参考文献
[1]张纪坤等.嵌入式linux系统开发技术详解.北京:人民邮电出版社
[2]沈建华译. ARM嵌入式系统开发软件设计与优化.北京:北京航天航空大学出版社
[3]王学龙.嵌入式Linux 系统设计与应用.北京:清华大学出版社
[4]杜春雷等.ARM 体系结构与编程.北京:清华大学出版社,2003
[5]马忠梅.ARM 嵌入式处理器与嵌入式系统.北京:北京航天航空大学出版社
[6]李善平,等. Linux 操作系统及试验教程. 北京:机械工业出版社, 1999.