首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

嵌入式linux论文

嵌入式linux论文

目 录
第一章 绪论
第二章 嵌入时操作系统
§1什么是嵌入式操作系统
§2嵌入式系统的特征
2.1嵌入式系统具有的产品特征
2.2嵌入式系统软件的特征
§3 Linux在嵌入式系统中的优势
§4规划一个好的硬件平台
4.1 选择一个好的嵌入式微处理器
4.2 规划通讯技术
4.3 适合嵌入式Linux的开发工具
§5构造嵌入式Linux前先要了解的几个关键问题
5.1 如何引导?
5.2 需要虚拟内存么?
5.3 选用什么样的文件系统
5.4 如何消除嵌入式Linux对磁盘的依赖
5.5 嵌入式Linux达到怎样的实时性?
第三章 实时操作系统
§1什么是实时系统
§2几种实时Linux的比较
 2.1 RT-Linux
2.2 RTAI
2.3 KURT
§3实时Linux的最后选择
§4构造嵌入式Linux需要了解的几个概念
4.1 Frame Buffer的配置方法--XWindow显卡配置通用解决方法
4.2 Linux下创建和使用RamDisk的技巧
4.3 LINUX下的设备驱动程序
4.4 Linux可卸载内核模块
4.5什么是Busybox
4.6什么是QT
第四章 构造嵌入式实时Linux
§1构造嵌入式实时Linux的开发环境
§2 Linux启动过程简介
§3 配置和编译内核
§5定制文件系统
§4制作启动盘
§6生成文件系统的ramdisk压缩镜像文件
§7运行及测试
第五章 如何从eprom引导Linux
51 c8051f(f020,f040) msp430 arm(2410,2510) fpga(xc3s4000) dsp(5116 dm642) keilc vc++ matlab linux protel Ten_layerPCB mpegx h.26x Rscode Turbocode ofdm VideoBroadcasting ldpc_code(now!)
摘要:
本文介绍了嵌入式实时Linux的构造方法,介绍了嵌入式,实时操作系统的概念,同时分析了它们在Linux中的应用情况,以及其中涉及的一些概念如frambuffer,ramdisk,驱动程序,模块和一些源代码开放的软件如Qt,busybox,RTAI。在这些概念和应用的基础上,构造了自己的嵌入式实时Linux,定制了启动盘和压缩的文件系统。在此基础上,进一步的又对引导过程加以延伸,提供了从Eprom引导的方法。
关键词:Linux,embedded,real time,

abstract:
This paper introduced builting method of embedded real time Linux,the concept of embedded real time OS,also analyzed the using condition in Linux ,as well as related concept such as frambuffer,ramdisk,Linux drivers,modules and some GPL code such as Qt,busybox,RTAI.On the base of these concepts and applications,we builted our embedded real time Linux,customized booting disk and file system.farther,we extended the booting process,offered the method of booting from eprom.


第一章 绪论
Internet与网络的迅速普及应用,并向家庭领域不断扩展,使消费电子、计算机、通信(3C)一体化趋势日趋明显,嵌入式系统再度成为研究与应用的热点。实时操作系统在多媒体通信、在线事务处理、生产过程控制、交通控制等各个领域得到广泛的应用,因而越来越引起人们的重视。嵌入式实时Linux操作系统以价格低廉、功能强大又易于移植而正在被广泛采用,成为新兴的力量,所以,众多商家纷纷转向了嵌入式实时linux的研究。本文就以嵌入式实时Linux为题进行讨论。

第二章 嵌入时操作系统
§1什么是嵌入式操作系统
所谓嵌入式操作系统(Embedded System)是指以应用为中心、以计算机技术为基础,软件硬件可裁剪、适应应用系统对功能、可靠性、成本、体积、功耗严格要求的专用计算机系统。
嵌入式计算机在应用数量上远远超过了各种通用计算机,一台通用计算机的外部设备中就包含了5-10个嵌入式微处理器,键盘、鼠标、软驱、硬盘、显示卡、显示器、Modem、网卡、声卡、打印机、扫描仪、数字相机、USB集线器等均是由嵌入式处理器控制的。在制造工业、过程控制、通讯、仪器、仪表、汽车、船舶、航空、航天、军事装备、消费类产品等方面均是嵌入式计算机的应用领域。
嵌入式系统是将先进的计算机技术、半导体技术和电子技术和各个行业的具体应用相结合后的产物,这一点就决定了它必然是一个技术密集、资金密集、高度分散、不断创新的知识集成系统。
一个小型的嵌入式Linux系统只需要下面三个基本元素:
  * 引导工具
  * Linux微内核,由内存管理、进程管理和事务处理构成
  * 初始化进程
  如果要让它能干点什么且继续保持小型化,还得加上:
  * 硬件驱动程序
  * 提供所需功能的一个或更多应用程序。
  再增加功能,或许需要这些:
  * 一个文件系统(也许在ROM或RAM)中
  * TCP/IP网络堆栈
§2嵌入式系统的特征
2.1嵌入式系统具有的产品特征
嵌入式系统是面向用户、面向产品、面向应用的,如果独立于应用自行发展,则会失去市场。嵌入式处理器的功耗、体积、成本、可靠性、速度、处理能力、电磁兼容性等方面均受到应用要求的制约,这些也是各个半导体厂商之间竞争的热点。
和通用计算机不同,嵌入式系统的硬件和软件都必须高效率地设计,量体裁衣、去除冗余,力争在同样的硅片面积上实现更高的性能,这样才能在具体应用对处理器的选择面前更具有竞争力。嵌入式处理器要针对用户的具体需求,对芯片配置进行裁剪和添加才能达到理想的性能;但同时还受用户订货量的制约。因此不同的处理器面向的用户是不一样的,可能是一般用户,行业用户或单一用户。
嵌入式系统和具体应用有机地结合在一起,它的升级换代也是和具体产品同步进行,因此嵌入式系统产品一旦进入市场,具有较长的生命周期。嵌入式系统中的软件,一般都固化在只读存储器中,而不是以磁盘为载体,可以随意更换,所以嵌入式系统的应用软件生命周期也和嵌入式产品一样长。另外,各个行业所以嵌入式系统的应用软件生命周期也和嵌入式产品一样长。另外,各个行业的应用系统和产品,和通用计算机软件不同,很少发生突然性的跳跃,嵌入式系统中的软件也因此更强调可继承性和技术衔接性,发展比较稳定。
嵌入式处理器的发展也体现出稳定性,一个体系一般要存在8-10年的时间。一个体系结构及其相关的片上外设、开发工具、库函数、嵌入式应用产品是一套复杂的知识系统,用户和半导体厂商都不会轻易地放弃一种处理器。
2.2嵌入式系统软件的特征
嵌入式处理器的应用软件是实现嵌入式系统功能的关键,对嵌入式处理器系统软件和应用软件的要求也和通用计算机有所不同。
(1) 软件要求固态化存储
为了提高执行速度和系统可靠性,嵌入式系统中的软件一般都固化在存储器芯片或单片机本身中,而不是存贮于磁盘等载体中。
(2) 软件代码高质量、高可靠性
尽管半导体技术的发展使处理器速度不断提高、片上存储器容量不断增加,但在大多数应用中,存储空间仍然是宝贵的,还存在实时性的要求。为此要求程序编写和编译工具的质量要高,以减少程序二进制代码长度、提高执行速度。序编写和编译工具的质量要高,以减少程序二进制代码长度、提高执行速度。
(3) 系统软件(OS)的高实时性是基本要求在多任务嵌入式系统中,对重要性各不相同的任务进行统筹兼顾的合理调度是保证每个任务及时执行的关键,单纯通过提高处理器速度是无法完成和没有效率的,这种任务调度只能由优化编写的系统软件来完成,因此系统软件的高实时性是基本要求。
(4) 多任务操作系统是知识集成的平台和走向工业标准化道路的基础
51 c8051f(f020,f040) msp430 arm(2410,2510) fpga(xc3s4000) dsp(5116 dm642) keilc vc++ matlab linux protel Ten_layerPCB mpegx h.26x Rscode Turbocode ofdm VideoBroadcasting ldpc_code(now!)
§3 Linux在嵌入式系统中的优势
1 免许可费用
大多数的商业操作系统,例如Windows 、Windows CE对每套操作系统收取一定的许可证费用。相对的,Linux是一个免费软件,并且公开源代码。只要你不违反GPL协议,你就可以自由应用和发布Linux。
2 有很高的稳定性
在PC硬件上运行时,Linux是非常可靠和稳定的,特别是和想在流行的一些操作系统相比。嵌入式内核本身有多稳定呢?对大多数微处理器来说,Linux非常好。一直到新微处理器家族的Linux内核运行起来与本来的微处理器一样稳定。他经常被一直到一个或多个特定的主板上。这些本包括特定的外围设备和CPU。
幸运的是,许多不同的处理器的指令代码是相通的,所以移植集中在差异上。其中大多数是在内存管理和中断控制领域。一旦成功移植,它们就非常稳定。
根据大部分国内外使用者的经验,Linux至少和许多著名的商业性操作系统一样稳定。总之,这些操作系统和Linux的问题在于对工作过程微妙之处的误解,而不在于代码的难度或基本的设计错误。任何操作系统都有很多争论不休的故事,这里不需要重复。Linux的优势在于源代码是公开¬、注释清晰和文挡齐全的。这样,你就可以控制和处理所出现的任何问题。
不过仍然有两个因素会影响稳定性,一是使用了混乱的驱动程序。驱动程序的选择很有限,有些稳定有些不稳定。一旦你离开了通用的PC平台,你需要自己编写。幸运的是,周围有许多驱动程序,你可能可以找到一个与你的需求相近的修改一下。这种驱动程序界面已定义好。许多类的驱动程序都非常相近,所以把磁盘、网络和一系列的端口驱动程序从一个设备移植到另一个设备上通常并不难。现在许多驱动程序都写得很好,很容易理解,但你还是要准备一本关于内核结构的书在手头。二是使用了硬盘。文件系统的可靠性就成了问题。用磁盘进行Linux系统设计。这些系统几乎不能正常关闭,电源随时都可能被中断。标准Linux初始化脚本运行fsck程序,它在检查和清除不稳定的inodes方面非常有效。将默认的每隔30秒运行更新程序改为每隔5或10秒运行是比较明智的。这样缩短了数据在进入磁盘之前,待在高速缓冲存储器内的时间,降低了丢失数据的可能性。
3 强大的网络功能
Linux天生就是一个网络操作系统,几乎所有的网络协议和网络接口都已经被定制在Linux中。Linux内核在处理网络协议方面比标准的Unix更具执行效率,在每一个端口上有更高的吞吐量。
4 丰富的开发工具
Linux提供C、C++、JAVA以及其他很多的开发工具。更重要的是,爱好者可以免费获得。并且这些开发工具设计时已经考虑到支持各种不同的微处理器结构和调试环境。Linux基于GNU的工具包,此工具包提供了完整与无缝交叉平台开发工具,从编辑器到底层调试。其C编译器产生更有效率的执行代码。
5 大量的文档
对新手来说,有很多用户界面友好的参考文档,这些资料很容易从网上获得。对处于黄金时期的Linux来说,许多书店都愿意在书架上放上这方面的书籍。
§4规划一个好的硬件平台
4.1 选择一个好的嵌入式微处理器
嵌入式微处理器的基础是通用计算机中的CPU。在应用中,将处理器装配在专门设计的电路板上,只保留和嵌入式应用有关的母板功能,这样可以大幅度减小系统体积和功耗。为了满足嵌入式应用的特殊要求,嵌入式微处理器虽然在功能上和标准处理器基本是一样的,但在工作温度、成本、功耗、可靠性、健壮性等方面和工业控制计算机相比,嵌入式微处理器具有体积小、重量轻、成本低、可靠性高的优点,但是在电路板上必须包括ROM、RAM、总线接口、各种外设等器件,从而降低了系统的可靠性,技术保密性也较差。嵌入式微处理器及其存储器、总线、外设、等安装在一块电路板上,称为单板计算机。如STD-BUS、PC104等。嵌入式处理器目前主要有国半X86、Dragon Ball、ARM、Strong ARM、Power PC、68000、MIPS系列等。
4.2 规划通讯技术
PCI方案:在高速通信中一个重要的因素是嵌入装置如何快速地传输数据而不涉及CPU。在很多低功率手持产品中,基本的I/O设备是与主处理器集成在一起的,不需要主CPU总线扩展。但大多数新的设计不仅需要基本的I/O设备,而且很多都采用广泛应用PC机标准以便主CPU总线扩展,即PCI(外设部件互连)总线。PCI总线工作频率为33MHz(rev2.1支持66MHz),对于连接到它上面的器件是具有即插即用能力。Compact PCI(PCI总线的一种)正在进入工业和通信市场。PC104+基本上分别为PC ISA和PCI总线的改进型。PC104总线与ISA总线完全兼容的。这些总线的出现有助于PCI技术进入嵌入领域。
IrDA/FastIrDA:红外数据联盟(IrDA)是一个由150多个公司组成的联合体。IrDA提供一种价廉的无线、点到点、双向红外通信技术。它旨在用于小于1米的极短距离通信。IrDA有两个速度:低速运行于9.6—115kits/s(简称IrDA);高速运行于1—4Mbits/s(即FastIrDA)。高达16Mbits/s的更高速度的正在开发。IrDA用于笔记本计算机、PDA、打印机、照相机等产品中。其他产品如复印机、投影机和游戏控制等也正在考虑采用。USB:通用串形总线(USB)是由IBM、Compaq、Nortel、NEC、Intel和Microsoft公司开发的一种外设总线标准。它为所有USB 外设提供一种通用的连接,其数据率12Mbits/s。USB缆线是为适用于短距离(最长5米)而设计的。连接遵从树拓扑结构,在任何时间可连接127个器件而外设可以是带电交换的。USB缆线也把功率(+5V)分配给低功率外设。它为不能处理瞬间传输、又需要保证带宽和有限执行时间的应用提供同步通信。同步工作量可以是USB总线带宽的一部分或全部。USB特别适合于需要高数据率和易于即插即用的应用,如调制解调器、游戏控制、打印机、扫描仪和数字相机。需要保证带宽和有限执行时间的应用包括PC电话和其他语言及视频通信应用。除了这些新的多媒体设备外,USB也用于传统的I/O设备,如键盘和鼠标,其处理速度为低速(1.5Mbits/s)。Windows CE为USB提供支持。USB的系统软件由两部分组成:USBD(通用串行总线驱动器)和HCD(主控制器驱动器)。USBD由Microsoft提供而用USB器件驱动器实现高级功能。HCD模件提供到实际硬件(OHCD开路主控制器驱动器或UHCD通用主控制器驱动器)的接口。
Ethernet/Fast Ethernet:Ethernet(以太网)和Fast Ethernet(IEEE802.3和802.3n)是最广泛应用的局域网络技术,旨在小区域(即一个办公室)范围连接计算机。Ethernet工作在10Mbits/s而Fast Ethernet工作在100Mbits/s。两个协议的差别限于物理层和通信媒体。媒提存取规则是CSMA/CD(载波检测多路存取/冲突检测)。Windows CE通过其NDIS 4.0实现支持IEEE802.3小口驱动器。Ethernet卡可以在平台上或通过一个PCMCIA槽进行热插拔。
IEEE1394:IEEE1394是高速串行总线,其数据为25—400Mbits/s。它起源于Apple Computer的FireWire总线,是作为通用外设串行总线而设计的,但它的应用重点转为所有类型的消费类设备如数字相机和扫描仪。缆线型1394总线可支持63个器件。其间之一变成总线管理者,与其他器件协调之后管理总线执行。缆线越长它所能够处理的数据率就越低。一般长度为几米。IEEE1394和USB都是串行协议,然而USB和IEEE1394比其竞争技术有更大的互补性,USB属于低到中带宽,而IEEE1394属于中到高带宽。
51 c8051f(f020,f040) msp430 arm(2410,2510) fpga(xc3s4000) dsp(5116 dm642) keilc vc++ matlab linux protel Ten_layerPCB mpegx h.26x Rscode Turbocode ofdm VideoBroadcasting ldpc_code(now!)
4.3 适合嵌入式Linux的开发工具
开发嵌入式系统的关键的是可用的工具包。像任何工作一样,好的工具使得工作更快更好。开发的不同阶段需要不同的工具。
传统上,首先用于开发嵌入式系统工具是内部电路仿真器(ICE),它是一个相对昂贵的部件,用于植入微处理器与总线之间的电路中,允许使用者监视和控制微处理器所有信号的进出。这有点难做,因为它是异体,可能会引起不稳定。但是它提供了总线工作的清晰状况,免了许多对硬件软件底层工作状况的猜测。
过去,一些工作依赖ICE为主要调试工具,用于整个开发过程。但是,一旦初始化软件对串口支持良好的话,多数的调试可以不用ICE而用其他方法进行。较新的嵌入式系统利用非常清晰的微处理器设计。有时,相应工作初始码已经有了能够快速获得串口工作。这意味着没有ICE人们也能够方便地工作。省去ICE降低了开发的成本。一旦串口开始工作,它可以支持各种专业开发工具。
Linux是基于GNU的C编译器,作为GNU工具链的一部分,与gdb源调试器一起工作。它提供了开发嵌入式Linux系统的所有软件工具。这有些典型的、用于在新硬件上开发嵌入式Linux系统的调试工具。
(1). 写入或植入引导码
(2). 向串口打印字符串的编码,如“Hello World”
(3). 将gdb目标码植入工作串口,这可与另一台运行gdb程序的Linux主机系统对话。只要简单地告诉gdb通过串口调试程序。它通过串口与测试机的gdb目标码对话,你可以进行C源代码调试,也可以用这个功能将更多的码载入RAM或Flash Memory中。
(4). 利用gdb让硬件和软件初始化码在Linux内核启动时工作。
(5). 一旦Linux内核启动,串口成为Linux控制口并可用于后续开发。利用kgdb,内核调试版的gdb,这步常常不作要求,如果你与网络联接,如10BaseT,下一步你可能要启动它。
(6). 如果在你的目标硬件上运行了完整的Linux内核,你可以调试你的应用进程。利用其他的gdb或覆盖gdb的图形如xgdb。
§5构造嵌入式Linux前先要了解的几个关键问题
5.1 如何引导?
当一个微处理器第一次启动的时候,它开始在预先设置的地址上执行指令。通常在那里有一些只读内存,包括初始化或引导代码。在PC上,这是BIOS。它执行了一些低水平的CPU初始化和其它硬件的配置。BIOS继续辨认哪个磁盘里有操作系统,把操作系统复制到RAM并且转向它。实际上,这非常复杂,但对我们的目标来说也非常重要。在PC上运行的Linux依靠PC的BIOS来提供这些配置和OS加载功能。
在一个嵌入式系统里经常没有这种BIOS。这样你就要提供同等的启动代码。幸运的是,嵌入式系统并不需要PC BIOS引导程序那样的灵活性,因为它通常只需要处理一个硬件的配置。这个代码更简单也更枯燥。它只是一指令清单,将固定的数字塞到硬件寄存器中去。然而,这是关键的代码,因为这些数值要与你的硬件相符而且要按照特定的顺序进行。所以在大多数情况下,一个最小的通电自检模块,可以检查内存的正常运行、让LED闪烁,并且驱动其它必须的硬件以使主Linux OS启动和运行。这些启动代码完全根据硬件决定,不可随意移动。
幸运的是,许多系统都有为核心微处理器和内存所定制的菜单式硬件设计。典型的是,芯片制造商有一个样本主板,可以用来作为设计的参考或多或少与新设计相同。通常这些菜单式设计的启动代码是可以获得的,它可以根据你的需要轻易的修改。在少数情况下,启动代码需要重新编写。 为了测试这些代码,你可以使用一个包含‘模拟内存’的电路内置模拟器,它可以代替目标内存。你把代码装到模拟器上并通过模拟器调试。如果这样不行,你可以跳过这一步,但这样就要一个更长的调试周期。
这个代码最终要在较为稳定的内存上运行,通常是Flash或EPROM芯片。你需要使用一些方法将代码放在芯片上。怎么做,要根据“目标”硬件和工具来定。
一种流行的方法是把Flash或EPROM芯片插入EPROM或Flash烧制器。这将把你的程序“烧”(存)入芯片。然后,把芯片插入你的目标板的插座,打开电源。这个方法需要板上配有插座,但有些设备是不能配插座的。 另一个方法是通过一个JTAG界面。一些芯片有JTAG界面可以用来对芯片进行编程。这是最方便的方法。芯片可以永远被焊在主板上,一个小电缆从板上的JTAG连接器,通常是一个PC卡,联到JTAG界面。下面是PC运行JTAG界面所需的一些惯用程序。这个设备还可以用来小量生产。
5.2 需要虚拟内存么?
标准Linux的另一个待征是虚拟内存的能力。正是这种神奇的特征使应用程序员可以狂热的编写代码而不计后果,不管程序有多大。程序溢出到了磁盘交换区。在没有磁盘的嵌入式系统里,通常不能这么做。
在嵌入式系统里不需要这种强大的功能。实际上,你可能不希望它在实时的关键系统里,因为它会带来无法控制的时间因素。这个软件必须设计得更加精悍,以适合市面上物理内存,就象其它嵌入式系统一样。
注意由于CPU的原因,通常在Linux中保存虚拟内存代码是明智的,因为将它清除很费事。而且还有另外一个原因是它支持共享文本,这样就可以使许多程序共享一个软件。没有这个,每一个程序都要有它自己的库,就象printf一样。
虚拟内存的调入功能可以被关掉,只要将交换空间的大小设置为零。然后,如果你写的程序比实际的内存大,系统就会当作你的运行用尽了交换空间来处理;这个程序将不会运行,或者malloc将会失灵。
在许多CPU上,虚拟内存提供的内存管理可以将不同程序分开,防止它们写到其它地址的空间上。这在嵌入式系统上通常不可能,因为它只支持一个简单、扁平的地址空间。Linux的这种功能有助于其发展。它减少了胡乱的编写程序造成系统崩溃的可能性。许多嵌入式系统基于效率方面的原因有意识使用程序间可以共享的“全局”数据。这也可以通过Linux共享内存功能来支持,共享的只是指定的内存部分。
51 c8051f(f020,f040) msp430 arm(2410,2510) fpga(xc3s4000) dsp(5116 dm642) keilc vc++ matlab linux protel Ten_layerPCB mpegx h.26x Rscode Turbocode ofdm VideoBroadcasting ldpc_code(now!)
5.3 选用什么样的文件系统
许多嵌入式系统没有磁盘或者文件系统。Linux不需要它们也能运行。如前所述,应用程序任务可以和内核一起编写,并且在引导时作为一个影像加载。对于简单的系统来说,这就够了。然而,它缺乏前面所说的灵活性。
实际上,许多商业性嵌入式系统,提供文件系统作为选项。许多或者是专用的文件系统或者是MS-DOS-Compatible文件系统。Linux提供MS-DOS-Compatible文件系统,同时还有其它多种选择。之所以提供其它选择是因为它们更加强大而且具有容错功能。Linux还具有检查和维护的功能,商业性供应商往往不提供这些。这对于Flash系统来说尤其重要,因为它是通过网络更新的。如果系统在升级过程中失去了能力,那它就没有用了。维护的功能通常可以解决这类问题。
文件系统可以被放在传统的磁盘驱动器、Flash Memory或其它这类的介质上。而且,用于暂时保存文件,一个小RAM盘就足够了。Flash Memories被分割成块。这些块中也许包括一个含有当CPU启动时运行的最初的软件的引导块。这可能包括Linux 引导代码。剩余的Flash可以用作文件系统。Linux的内核可以通过引导代码从Flash复制到RAM,或者还有一个选择,内核可以被存储在Flash的一个独立部分,并且直接从那里执行。
另外对于一些系统来说还有一个有趣的选择,那就是将一个便宜的CD-ROM包含在内。这比Flash Memory 便宜,而且通过交换CD-ROM支持简单的升级。有了这个,Linux 只要从 CD-ROM上引导,并且象从硬盘上一样从CD-ROM上获得所有的程序。
最后,对于联网的嵌入式系统来说,Linux 支持NFS(Network File System)。这为实现联网系统的许多增值功能打开了大门。第一,它允许通过网络上加载应用程序。这是控制软件修改的基础,因为每一个嵌入式系统的软件都可以在一个普通的服务器上加载。它在运行的时候也可以用来输入或输出大量的数据、配置和状态信息。这对用户监督和控制来说是一个非常强大的功能。举例来说,嵌入式系统可以建立一个小的RAM磁盘,包含的文件中有与当前状态信息同步的内容。其它系统可以简单的把这个RAM磁盘设置为基于网络的远程磁盘,并且空中存取状态文件。这就允许另一个机器上的Web服务器通过简单的CGI Script存取状态信息。在其它电脑上运行的其它应用程序包可以很容易的存取数据。对更复杂的监控,应用程序包如Matlab(http://www.mathworks.com/products/matlab/),可以用来在操作员的PC或工作站的提供系统运行的图形展示。
5.4 如何消除嵌入式Linux对磁盘的依赖
对于Linux一个共同的认识是它用于嵌入式系统简直是神奇极了。这可能不大对,典型的PC上的Linux对PC用户来说功能有多。
对初学者而言,可以将内核与任务分开,标准的Linux内核通常驻留在内存中,每一个应用程序都是从磁盘运到内存上执行。当程序结束后,它所占用的内存就被释放,程序就被下载了。
在一个嵌入式系统里,可能没有磁盘。有两种途径可以消除对磁盘的依赖,这要看系统的复杂性和硬件的设计。
在一个简单的系统里,当系统启动后,内核和所有的应用程序都在内存里。这就是大多数传统的嵌入式系统工作模式,它同样可以被Linux支持。
有了Linux,就有了第二种可能性。因为Linux已经有能力“加载”和“卸载”程序,一个嵌入式系统就可以利用它来节省内存。试想一个典型的包括一个大概8MB到16MB的Flash
Memory和8MB内存的系统。Flash Memory可以作为一个文件系统。Flash Memory驱动程序用来连接Flash
Memory和文件系统。作为替代,可使用Flash Disk。这Flash部件用软件仿真磁盘。其中一个例是M-Systems的DiskOnChip,可以达到160MB。(http://www.m-systems.com)。所有的程序都以文件形式存储在Flash文件中,需要时可以装入内存。这种动态的、“根据需要加载”的能力是支持其它一系列功能的重要特征:
它使初始化代码在系统引导后被释放。Linux同样有很多内核外运行的公用程序。这些通常程序在初始化时运行一次,以后就不再运行。而且,这些公用程序可以用它们相互共有的方式,一个接一个按顺序运行。这样,相同内存空间可以被反复使用以“召入”每一个程序,就象系统引导一样。这的确可以节省内存,特别是那些配置一次以后就不再更改的网络堆栈 如果Linux可加载模块的功能包括在内核里,驱动程序和应用程序就都可以被加载。它可以检查硬件环境并且为硬件装上相应的软件。这就消除了用一个程序占用许多Flash
Memory来处理多种硬件的复杂性。
软件的升级更模块化。你可以在系统运行的时候在Flash上升级应用程序和可加载驱动程序。
配置信息和运行时间参数可以作为数据文件储存在Flash上。
5.5 嵌入式Linux达到怎样的实时性?
嵌入式系统常常被错误地分为实时系统,尽管多数系统一般并不要求实时功能。实时是一个相对的词,纯化论者常常严格地定义实时为对一事件以预定的方式在极短的时间如微秒作出响应渐渐地,在如此短暂时间间隔内的严格实时功能在专用DSP芯片或ASIC上实现了。只有在设计低层硬件FIFO、分散/聚集DMA引擎和定制硬件时才会有这样的要求。
许多设计人员因为对真实的要求设有清晰的理解而对实时的要求焦虑不安。对于大多数的系统,在一至五微秒的近似实时响应已经足够。同样软需求也是可以接受的。如 Windows 98 已经崩溃的中断必须在4毫秒内(±98%)内、或20毫秒(±0)内进行处理。
这种软要求是比较容易满足的,包括环境转换时间、中断等待时间、任务优先级和排序。环境转换时间曾是操作系统的一个热门话题。总之,多数CPU这些要求处理得很好,而且CPU的速度现在已经快了很多,这个问题也就不重要了。
严格的实时要求通常由中断例程或其他内核环境驱动程序功能处理,以确保稳定的表现,等待时间,一旦请求出现要求服务的时间很大程度上取决于中断的优先及其他能暂时掩盖中断的软件。
中断必须进行处理和管理以确保时间要求能符合,如同许多其他的操作系统。在IntelX86处理器中,这工作很容易由Linux实时扩展处理。这是提供了一个以后台任务方式运行Linux的中断处理调度。关键的中断响应不必通知Linux。因此可以得到许多对于关键时钟的控制。在实时控制级和时间限制宽松的基本Linux级之间提供接口,这提供了与其他嵌入式操作系统相似的实时框架。因此,实时关键代码是隔开的、并“设计”成满足要求的。代码处理的结果是以更一般的方法也许只在应用任务级。
51 c8051f(f020,f040) msp430 arm(2410,2510) fpga(xc3s4000) dsp(5116 dm642) keilc vc++ matlab linux protel Ten_layerPCB mpegx h.26x Rscode Turbocode ofdm VideoBroadcasting ldpc_code(now!)
第三章 实时操作系统
§1什么是实时系统
实时的含义是指在规定的时限内能够传递正确的结果,迟到的结果就是错误。
实时系统可以被定义为“在它的控制下系统有能力确定进程的时间需求”。
实时系统必须是快的和可预测的。快的意思是它有一个短的等待时间,也就是,它在短时间内对外部的不同时间的事件做出响应。等待时间越短,系统越能更好的对需要及时处理的事件做出响应。可预测的是指它有能力确定任务的结束时间。
典型的一个实时系统表现为管理和配合被控制系统活动的,可以看作计算机相互作用环境的计算机控制系统。互相作用是双向的,通过各种各样的传感器(环境-)计算机)和激励器(计算机-)环境),被时间确定性限制所描述。
理想的情况是时间判断和非时间判断的活动共存于实时系统中。两者都称为任务,其中需要及时条件的任务称为实时任务。
典型的实时任务具有以下类型的需求和限制
*时间限制。主要是周期性的或非周期性的。一个非周期性的任务有一个截止时间,到时必须完成或开始,或者可能在开始和完成时间上都有一个限制。一个周期性任务在每周期必须重复一次。大多数传感的处理是周期性的,但非周期性的需要可以从动态事件中产生。
*资源需求。一个实时任务可能要访问特定的资源比如I/O设备,数据结构,文件和数据库。
*通信需求。一个实时任务应该可以同消息进行通信。
*并列性限制。任务应该可以访问共同的资源,如果符合资源的一致性。
实时系统又可分为“硬实时系统”和“软实时系统。两者的区别在于:前者如果在不满足响应时限、响应不及时或反映过早的情况下都会导致灾难性的后果;而后者则在不满足响应时限时,系统性能退化,但并不会导致灾难性的后果。
§2几种实时Linux的比较
2.1 RT-Linux
NMT 是新墨西哥科技大学(New Mexico Technology) 的缩写。这一套系统可以说是 所有 Real-time Linux 的鼻祖。它目前已经发展到 3.0 版。这个系统是由 Victor Yodaiken 和它的学生 Michael Barabanov 所完成。这个系统的概念是”架空” Linux kernel,使得它的 real-time 行程得以尽快的被执行。下面的图例说明了 NMT RT-Linux 和其它类似产品的系统架构。
你可以看到基本上RT-Linux 中的实时工作(realtime task) 其实并不是 一个 Linux 的行程,而是一个 Linux 的可加载式核心模块( loadable kernel module)。
之所以要如此做的原因在于 Linux 是一个很大的系统,且在设计的时候并没 有考虑 real-time 的需求。举个例说,单一个 Linux 系统呼叫可能会花上超过 10ms 的时间。对有些像工业控制的应用而言,它们对时间的要求通常在 1ms 的 等级上,Linux 根本无法满足这种需求。所以 NMT RT-Linux 采用一个比较简单 的做法,它干脆不用直接 Linux 的任何功能,而把需要高度时间精确度的工作 写成一个驱动程序的型式,然后直接用 PC 时序芯片 (timer chip) 所产生的中 断呼叫这个驱动程序。如此一来,不管 Linux 系统呼叫的时间有多长都没有关系 了。
从这个角度看,NMT RT-Linux 其实是一个实时驱动程序的架构,算不上是真 正的 real-time Linux. 但由于它出现的早,且其架构很符合自动控制的需求。 使用者非常的多,且多半是有关自动控制的应用。

(1) 什么是RTLinux?
RTLinux(Real Time Linux)一个小的POSIX 1003.13/PSE51兼容的硬实时操作系统,它运行Linux就象它自己的最低级的线程一样。它有点象在一个裸机上运行的单POSIX进程。Linux作为RTLinux核心的最低优先级线程来运行,而且它总是被抢占的。RTLinux时应用程序包括实时线程,在RT环境中运行的单个处理器和在Linux用户层运行的进程。
RTLinux的设计模型应该满足:有严格时间条件的应该作为线程或单处理器(中断处理器)被编写,不需要硬实时那些应该进入Linux。这使我们保持了RT方面的小型化,确定性,尽可能象硬件容许的那样快,但仍然可以为精确的服务和应用程序对Linux进行操作。
(2)RTLinux运行平台及硬件需求
可以运行在几乎所有的x86(SMP 和单处理机),plus PowerPC和Alpha上。只在V3版本上支持PowerPc和Alpha。
RTLinux仍然工作在i486上。MiniRTL在一张软盘上装入了RTLinux,Linux和一些应用程序,只需4M内存。
(3)RTLinux同其他实时操作系统相比有什么不同?
RTLinux相比早期的RTOS设计优点在于它容许程序员编写同时包含一个瘦的,硬实时操作系统在硬件速度上的优点和一个普通操作系统的所有特征的应用程序。RTLinux强调的是性能而不是特征。它基于提供所有软实时能力和特征(GUI,软实时网络,绘图,磁盘访问等)的根本的Linux系统,而RTLinux自己确定了所有硬实时任务的时间正确性。
在RTLinux之前,RTOS需要程序员进行妥协:或者使用一个没有任何特征的简单的RTOS,或者使用一个带有各种非实时服务的RTOS,并且接受在性能和可靠性上的一个重大的损失。RTLinux的将Linux作为一个线程来运行的方法避免了这样的选择。硬实时软件在实时核心中运行而使用运行在非实时线程上的程序,而且实时软件从来不会被非实时软件延迟或减缓。RTLinux出现之后,一些其他的操作系统采用了这种方法:Venturcom使其作为非实时线程在WinNT上使用,RTAI(RTLinux的一个变体)在Linux中使用。Venturcom的产品正在经受高的价格,低可靠性,和Windows NT下的复杂的编程环境。RTAI的开发者致力于使他们的系统有更多的特征以使实时编程更加容易。RTLinux的目标是使Linux作为一个线程以保持RT核心的简单和可靠性。对在Linux的基础上制作第二个通用目标不感兴趣。
(4)RTLinux工作的怎么样?
在一个generic x86 PC上从一个中断的声明到实时处理器的开始最坏的情况是15微秒,在Alpha和PowerPC平台上更好一些。这些参数接近硬件容许的极限,然而所有Linux的性能仍然可以很容易的受编程者的影响。
(5) RTAI是RTLinux的变体,它走了自己的道路.GPL支持了这样的改变.虽然一些不同实际上只是表面的,在两个系统对于特征的态度上却有本质的不同。RTLinux的开发者已经在操作系统开发上工作了很多年,相信RTOS的实时方面应该是越小越好,加入过多的特征只会导致系统不易于维护,缓慢和容易出错。在加入新的特征或系统时很保守,主要的工作在于确定加入的功能仍然是可以选择的:用户不会需要多余的功能和为此付出多余的钱。RTAI看上去有很多友好的特征。RTLinux更倾向于说“照此下去,我们不能保证三年后会不会产生问题,所以最好舍弃它们”,RTAI可能会说“现在这看上去十分有用”,正象在互联网上说的“你们的路很长”。
另一个重要的区别是,RTLinux运行在x86,PowerPC和Alpha 平台上,支持的Linux版本从1.3-2.3/2.4。早期的版本甚至支持PalmPilot处理器。RTAI在x86 Linux2.2上运行
51 c8051f(f020,f040) msp430 arm(2410,2510) fpga(xc3s4000) dsp(5116 dm642) keilc vc++ matlab linux protel Ten_layerPCB mpegx h.26x Rscode Turbocode ofdm VideoBroadcasting ldpc_code(now!)
2.2 RTAI
RTAI 是 Real-Time Application Interface 的缩写。顾名思义知道它是一套可 以用来写实时应用程序的界面。大致而言,RTAI 和 NMT RT-Linux 是相同的东西。 它同样的架空了 Linux,而直接用可加载式核心模块( loadable kernel module) 实作 real-time process。每一个实时行程实际上就是一个可加载式核心模块。
RTAI 和 NMT RT-Linux 最大的不同地方在于它非常小心的在 Linux 上定义了 一组 RTHAL (Real-Time Hardware Abstraction Layer)。RTHAL 将 RTAI 需要 在 Linux 中修改的部份定义成一组程序界面,RTAI 只使用这组界面和 Linux 沟通。这样做的好处在于我们可以将直接修改 Linux 核心的程序代码减至最小, 这使得将 RTHAL 移植到新版 Linux 的工作量减至最低。
RTAI 采取这种途径最大的原因在于 NMT RT-Linux 在由 2.0 版移植至 2.2 版 的过程序遇到问题,使得基于 2.2 版核心的 NMT RT-Linux 一直无法完成。所以 在 Dipartimento di Ingegneria Aerospaziale Politecnico di Milano 的 Paolo Mantegazza 和他的同事们就决定自行做移植的工作,但由 NMT RT-Linux 的困境他们体认到必须采取上述的途径以解决将来可能再度面临的兼容性问题。
于是 RTAI 便诞生了,它是一个比 NMT RT-Linux 更好的 NMT RT-Linux,虽 然后来 NMT RT-Linux 也随后完成移植的工作,但那已经是 RTAI 诞生半年以 后的事了。
LXRT
  由于 RTAI 无法直接使用 Linux 的系统呼叫,解决的方法是使用 RT-FIFO 将一个 RTAI real-time kernel module 和真正的 Linux 行程连接在一起,由这个行程做 代理人的工作为其呼叫 Linux 系统呼叫。
你可以了解,当 proxy 激活后,它不再可以被任何的抢先 (preempt), 所以原本有的优势就不再保有了。
(1) 什么是RTAI
RTAI就是实时应用程序接口。严格的说,它不是一个实时操作系统,比如Vxworks或QNX。它是基于Linux核心的。提供了一种能力使它可以完全可抢占。
Linux是一个标准的分时操作系统,提供了一些很好的普通性能和高精度的服务。象其它的OS,它提供给应用程序的服务至少包括以下这些:
-硬件管理层,处理事件选择和处理器/外围设备中断;
-调度类,处理进程激发,优先级,时间片;
-应用程序间的通信方法。
Linux忍受着实时支持的缺乏。为了包括一个时间正确性的行为,有必要在核心资源中做一些改变,例如,在中断处理和调度策略中。以这种方式,你可以有一个实时平台,包括短的反应时间和高的可预测性的需求,包括全部的非实时Linux环境(可以使用TCP/IP,图形显示和视窗系统,文件和数据库系统等)。
RTAI提供了和Linux核心相同的服务,加入了一个工业实时操作系统的特征。他基本包括了一个中断调度程序:RTAI主要携带了外围设备的中断,如果需要可以重新向Linux发送。他并不是对核心的插入式的修改;它使用了HAL(硬件抽象层)的概念,从Linux获取信息和捕捉一些基础函数。HAL对Linux的核心依赖性很小。这导致了对Linux核心的修改可以很小,不同版本Linux中RTAI端口很容易移植,很容易使用其它的操作系统代替RTAI。RTAI在没有实时活动发生时把Linux看作一个后台运行的任务。
(2)RTAI模块简介
为了使用RTAI,你必须加载一些模块以实现你需要一些功能,有效的核心模块如下:
1) rtai
2) rtai_sched
3) rtai_fifos
4) rtai_shm
5) lxrt
6a) rtai_pqueue.o
6b)rtai_pthread.o
6c)rtai_utils.o
让我们一一说明:
1)它是真正的核心模块,没有它任何有关实时的服务都不能完成。rtai初始化了它的所有控制变量和结构体,对idt_table和Linux中断请求处理的入口地址进行复制,初始化了中断芯片(ic)管理特定的函数。但是当你用常用的insmod rtai命令安装rtai时没有任何事情发生,因为rtai是一个隐藏的模块。当其它模块需要时你必须调用rt_mount_rtai()来激活并挂装它。你不再需要时你也应该通过调用rt_umount_rtai()来卸载它,使rtai回到床上睡觉。挂装调用激活了rtai,即使你不需要使用它的任何服务,Linux对于硬件的工作仍被rtai过滤。当你挂装RTAI时最重要的事是从此非常紧急的Linux不再有能力使中断无效/有效。从此rtai将确保使中断无效/有效将是相容的内部的Linux,但是Linux在任何时候都不能被rtai这个硬件的唯一支配者的更高优先级抢断。
2)实时调度模块,用来控制向系统中现在的不同的任务分配CPU,包括Linux。当任务执行特定的系统调用时和时间处理发生时(每一个8254中断)调度发生。调度选择第一个最高优先级的任务置于READY状态。RTAI认为优先级0是最高优先级,0×3fffFfff是最低的。Linux被给与0×7fffFfff的优先级。被赋予优先级后,第一个初始化的任务将首先被选择然后运行完成,除非有更高优先级的任务被选择或者它终止了或者任务调用了一个模块化的系统函数。用于实时调度,RTAI同时支持周期的和一次的模式。你有三种不同的调度:
-UP,只用于单处理器
-SMP,由于多处理器
-MUP,只用于多处理器
调度服务是:
-任务函数
-时间函数
-信号函数
-邮箱函数
-任务间通信函数
所有的函数都可被任何调度使用。注意当你加载rtai_sched时,rtai被自动挂装。
51 c8051f(f020,f040) msp430 arm(2410,2510) fpga(xc3s4000) dsp(5116 dm642) keilc vc++ matlab linux protel Ten_layerPCB mpegx h.26x Rscode Turbocode ofdm VideoBroadcasting ldpc_code(now!)
3)对于RTAI实现fifo服务的模块。很多应用程序显得受益于实时系统一方和Linux一方的共同作用,比如管理数据的登陆和显示。简单的fifo缓冲用来做这些事情;他们被叫做实时fifo。实时任务接口包括创建,销毁,读和写函数,被rtai_fifos模块执行。Linux用户进程,换一种说法,把rt-fifos看作普通的字符设备。注意到从模块的角度看,你一直只有非模块化的传送/获取,因此任何不同的策略都被迫使用适当的用户处理函数。可用的有一个旧的和新的(强烈推荐)fifo实现。后者基于邮箱的概念,同时用于核心模块和Linux进程。即使严格的说,fifo在RTAI中不需要再使用,因为LXRT的有用性,fifos仍被保留,由于兼容性的原因和他在同中断处理通信上是很有用的工具,因为它们不需要安装任何调度。从这点来讲,你可以把这个新的fifos的实现看做设备驱动的一类通用方式,因为一旦你安装了你的中断处理,你可以使用fifo服务做其余的事情。
4)RTAI特定的模块,容许在不同的实时任务和Linux进程中同时共享内存,(这是除了fifo以外对使用者有用的另一个机制)。服务是对称的,也就是说,同样的调度可以同时被实时任务使用,也就是在核心中和Linux进程中。最初的分配是一个实时的分配,任何后来的被分配的来自Linux进程的有同样名字的调用只是向使用者模式映射了范围或者向核心模式中已经被分配的空间返回相关的指针。同样的,释放的调用只是产生非映射的结果,直到最后的一个被完成时,那就是真正释放被分配过的内存的一个。
5)LXRT(Linux实时模块),用来实现任何RTAI调度函数对Linux进程都是有效的这个服务,以便一个完全对称的实时服务的实现是可能的。说的更清楚些,你可以共享内存,发送消息,使用信号机和计时器:Linux<->Linux, Linux<->RTAI自然还有RTAI<->RTAI
6)Posix RTAI模块,rtai_pthred.o提供了硬实时线程,每一个线程就是一个RTAI任务。所有的线程在同样的地址空间内执行,因此可以在共享的数据上工作。Rtai_pqueue.o提供了核心安全队列。
2.3 KURT
(1)什么是KURT?
今年的早些时候(1998)发布了一个基于Linux的一个新的实时操作系统。KURT 是由 kansas 大学所创造的系统,它和 NMT RT-Linux 及 RTAI 有很大的不同。KURT 是第一个可以使用系统呼叫的 real-time Linux。由于 KURT只是简单的将 Linux 的排程器用一个很简单的时间驱动式(time driven)排程器加以取代,实时行程的执行很容易很其它非实时行程的影响。
(2)KURT的特征?
KURT是一个软实时操作系统。KURT的实时任务运用了Linux的所有工具,不同于RT-Linux的任务,对核心所作的提高和修正是:
-改进了系统时钟的解决方案。在Linux-i386中,时钟的中断频率是10ms (每秒100次),而且用这个核心产生的时间分辨率来控制结果和测量时间。KURT象RT-Linux一样使用同样的结构来管理时间。它在需要的时候对一个时钟碎片(8254)编程来产生中断,周期性的代替。这种方式能够得到微秒的时间解析度。
-调度程序已经被修改成包含一个新的调度策略,SCHED_KURT,除了那些已经被POSIX定义的Linux核心所实现的:SCHED_FIFO,SCHED_RR,SCHED_OTHER。
-新的系统调用已经被加入以便运用新的实时功能。
-实时任务作为组件动态的被加载。
KURT最重要的性格特征之一是它的调度策略。一个结果被产生以便实现一个周期的调度,这种类型的调度使用一个叫做plan的列表,包含所有的调度动作:激活时刻,将要执行的任务,任务的过程,等等。列表在系统设计阶段被创建。之后在运行时,调度的工作只是在于顺着它的结构来顺序的读取列表。当到达列表的底部时,调度回到开始继续执行任务——因此这就是周期调度的由来。这种类型的调度有很多优点:
-调度的实现非常简单
-效率很高
-计划之后系统的可行性就可以立即决定(一些到来者保持了这个100%保证一个STR纠正性能的唯一途径)。主要的困难除了产生计划本身外,进一步说,每一时刻每一任务的参数都被修改,必须重建计划,也必须保存大量的内存,这通常十分庞大
§3实时Linux的最后选择
这里选择了RTAI,主要由于他是硬实时操作系统,有很多功能很有用,使Linux实时程序的开发变得容易,由于这次开发主要在Linux系统中进行,选择RTAI与Linux核心2.2.16配合,兼容性很好,而且易于安装。
§4构造嵌入式Linux需要了解的几个概念
4.1 Frame Buffer的配置方法--XWindow显卡配置通用解决方法
MiniGUI使用的LibGGI库其中一个好处就是在 Linux 控制台上,它可以运行在 Linux 2.2 内核所提供的 FrameBuffer 驱动程序之上,而不需要对显示芯片进行直接的硬件编程,因而也不需要超级用户权限去运行程序。这点和 SVGALib 不同,SVGALib 不支持 FrameBuffer,同时需要超级用户权限。 所以我们经常需要配置Frame buffer显示模式,可让XWindow用高分辨率和高/真彩。现在市面上绝大部分新出的显卡都支持VESA 2.0标准。
  具体实现涉及四方面:
 (1).一个支持 VESA frame buffer的内核(2.2 以上的版本即可);
(2).配置 lilo 的启动选项,使内核启动时能切换到指定的显示模式;
(3).XFree86的 frame buffer服务器(XF86_FBDev);
(4).在 XF86Config文件中为其配置一个Screen。
  所需文件得到途径:
  (1)、Linux 2.2.x kernel source (2.2.x内核原代码,如果你的Linux发行版是Kernel 2.2以上,那么你需要到/usr/src/linux去重新编译内核。如果你系统的kernel版本比较低,请在RedHat6.2等新版本Linux的安装盘中找,一般在RPMS里);
  (2)、XFree86 Framebuffer Server: XF86_FBDev (RedHat6.2,蓝点Linux2.0);如:RedHat6.2在光盘的/RedHat/RPMS/XFree86-FBDev-3.3.6-20.i386.rpm
安装这个RPM包:
#rpm -ivh XFree86-FBDev-3.3.6-20.i386.rpm
这个包会在/usr/X11R6/bin下安装一个XF86_FBDev的服务器,后面我们会用到。
51 c8051f(f020,f040) msp430 arm(2410,2510) fpga(xc3s4000) dsp(5116 dm642) keilc vc++ matlab linux protel Ten_layerPCB mpegx h.26x Rscode Turbocode ofdm VideoBroadcasting ldpc_code(now!)
(3)、gcc 等编译工具(默认就有,有时会有版本太低的问题)。
  编译一个支持 VESA frame buffer的内核
  如果有现成的支持 VESA frame buffer的内核可跳过这一步。如蓝点2.0内核就支持frame buffer。
  配置内核编译选项
#cd /usr/src/linux
#make menuconfig(命令行下),或xconfig(XWindow下)。
  与 frame buffer device有关的选项有(用空格键来进行选中或去处,其余编译选项请参考其它资料):
  Code maturity level opetions
  
  • Prompt for development and/or incomplete codes/drivers
       Console drivers
      
  • Video mode selection support
       ...
      
  • Support for frame buffer devices
       ...
      
  • VESA VGA graphics console
       ...
      
  • Advance low level driver options
       ...
    [Exit]
    [Exit]
    Do you wish to save your new kernel configuration?
    [Yes]
      编译安装内核:
    # make dep
    # make bzImage
    # make modules
    # make modules_install
      把编译好的内核拷到 /boot目录,文件名可自定,如 
      # cp /usr/src/linux/arch/i386/boot/bzImage /boot/vmlinuz-2.2.16-fb
      配置 lilo 的启动选项
      添加lilo启动配置
      下面是典型的/etc/lilo.conf文件
      boot = /dev/hda2
      timeout = 50
      prompt
      read-only
      image = /boot/vmlinuz-2.2.16-22
      label = linux
      root = /dev/hda2
      other = /dev/hda1
      label = dos
      添加一新配置需添加 image,label,root及配合VESA frame buffer的 vga等四项:
      boot = /dev/hda2
      timeout = 50
      prompt
      read-only
      image = /boot/vmlinuz-2.2.16-22
      label = linux
      root = /dev/hda2
    image = /boot/vmlinuz-2.2.16-fb (新编译的支持Frame Buffer内核)
      label = linuxfb (启动标号,可自定)
      root = /dev/hda2 (你的根文件系统,具体会有不同)
      vga = 0x314 (显示模式,参照下表)
      other = /dev/hda1
      label = dos
     显示模式参照表
      640x480 800x600 1024x768 1280x1024
      256 0x301 0x303 0x305 0x307
      32k 0x310 0x313 0x316 0x319
      64k 0x311 0x314 0x317 0x31A
      16M 0x312 0x315 0x318 0x31B
      更新启动程序
      运行lilo
      重启,出现 lilo: 时键入linuxfb (或自定的标号)。
      这时如果linux切换成图形模式,并有一小企鹅logo出现,那就大功告成一半。
      配置frame buffer Server
      修改/etc/X11/XF86Config 这个配置文件。
     #vi /etc/X11/XF86Config
    查找一下字符Screen
    在Screen sections的开始增加如下几行  Section "Screen"
      Driver "fbdev"
      Device "My Video Card"
      Monitor "My Monitor"
      Subsection "Display"
      Depth 16 (色彩深度,必须与前面所选的显示模式的色彩深度一致,必须!)
      Modes "default"
      ViewPort 0 0
      EndSubsection
      EndSection
      让X 指向 XF86_FBDev
      cd /etc/X11
      rm -f X
      ln -snf /usr/X11R6/bin/XF86_FBDev X
  • 51 c8051f(f020,f040) msp430 arm(2410,2510) fpga(xc3s4000) dsp(5116 dm642) keilc vc++ matlab linux protel Ten_layerPCB mpegx h.26x Rscode Turbocode ofdm VideoBroadcasting ldpc_code(now!)
    4.2 Linux下创建和使用RamDisk的技巧
    先介绍一下什么是RamDisk。RamDisk实际是从内存中划出一部分作为一个分区使用,换句话说,就是把内存一部分当做硬盘使用,你可以向里边存文件。那么为什么要用RamDisk呢?假设有几个文件要频繁的使用,你如果将它们加到内存当中,程序运行速度会大副提高,因为内存的读写速度远高于硬盘。况且内存价格低廉,一台PC有128M或256M已不是什么新鲜事。划出部分内存提高整体性能不亚于更换新的CPU。何乐而不为呢?象WEB服务器这样的计算机,需要大量的读取和交换特定的文件,因此,在WEB服务器上建立RamDisk会大大提高网络读取速度。
    (1)创建和使用RamDisk的方法。
    使用RamDisk非常方便,缺省安装的RedHat6.0就支持RamDisk。你所要作的就是格式化RamDisk并把它装载到一个目录下。要想查看RamDisk的数目,用命令"ls -al /dev/ram*",它会给出所有当前情况下可用的RamDisk。这些RamDisk只有使用的时候才占用内存。下面是使用RamDisk的几个命令:
    #创建装载点
    mkdir /tmp/ramdisk0
    # 创建一个文件系统
    mke2fs /dev/ram0
    #装载ramdisk:
    mount /dev/ram0 /tmp/ramdisk0
      这三个命令将会为RamDisk创建一个目录、格式化RamDisk(创建文件系统)并把RamDisk装载到目录"/tmp/ramdisk0"中。现在,你就可以把它作为一个磁盘分区使用了。
      如果格式化RamDisk失败,可能是因为你没有把对RamDisk的支持编译进内核中去。内核中对RamDisk的配置选项是 CONFIG_BLK_DEV_RAM。
      缺省的RamDisk为4M。使用mke2fs命令可以查知你所获RamDisk的大小。命令mke2fs /dev/ram0会产生以下信息:
    mke2fs 1.14, 9-Jan-1999 for EXT2 FS 0.5b, 95/08/09
    Linux ext2 filesystem format
    Filesystem label=
    1024 inodes, 4096 blocks
    204 blocks (4.98%) reserved for the super user
    First data block=1
    Block size=1024 (log=0)
    Fragment size=1024 (log=0)
    1 block group
    8192 blocks per group, 8192 fragments per group
    1024 inodes per group
    使用命令df -k /dev/ram0可以查到你实际能用的RamDisk的大小(文件系统也占用一定空间):
    >df -k /dev/ram0
    Filesystem 1k-blocks Used Available Use% Mounted on
    /dev/ram0 3963 13 3746 0% /tmp/ramdisk0
    不过要记住,RamDisk中的数据会在机器重新启动后消失,因此应把其中有用的数据及时备份到硬盘中。
    (2)改变RamDisk大小的技巧?
      为使用RamDisk,你或者要将对RamDisk的支持编译到内核中去,或者把它编译为一个可装载模块。编译为一个可装载模块有一个好处,就是可以在装载时任意指定RamDisk的大小。
      把下面这一行加到你的lilo.conf 文件中去:
    ramdisk_size=10000 (或对老内核写作ramdisk=10000)
      这样你键入LILO命令并重新启动后,缺省的RamDisk的大小将为10M,下面是我的/etc/lilo.conf文件:
    boot=/dev/hda
    map=/boot/map
    install=/boot/boot.b
    prompt
    timeout=50
    image=/boot/vmlinuz
    label=linux
    root=/dev/hda2
    read-only
    ramdisk_size=10000
    实际上,我只获得了9M多一点的RamDisk,其余被文件系统占用。当你编译为一个可装载模块后,你可以在模块装载时决定RamDisk的大小,这可以通过 /etc/conf中的选项设置来设定。或者通过作为ismod命令行参数来实现。
    options rd rd_size=10000
    insmod rd rd_size=10000
    51 c8051f(f020,f040) msp430 arm(2410,2510) fpga(xc3s4000) dsp(5116 dm642) keilc vc++ matlab linux protel Ten_layerPCB mpegx h.26x Rscode Turbocode ofdm VideoBroadcasting ldpc_code(now!)
    (3)两个例子
    下面是使用模块的例子:
    - 卸载下上一章装载的RamDisk, umount /tmp/ramdisk0.
    - 卸载模块rmmod rd。
    - 装载RamDisk模块并设置大小为20M,insmod rd rd_size=20000。
    - 创建文件系统,mke2fs /dev/ram0。
    - 装载RamDisk ,mke2fs /dev/ram0。
    在WEB服务器上使用RamDisk的实例?
      本例介绍在WEB服务器上使用3个RamDisk的方法。所用的WEB服务器是RedHat 6.0 自带的Apache。
      首先,把WEB根目录中所有文件移到其它目录中,然后创建RamDisk的装载点:
    mv /home/httpd/ /home/httpd_real
    mkdir /home/httpd
    mkdir /home/httpd/cgi-bin
    mkdir /home/httpd/html
    mkdir /home/httpd/icons
      然后,把以下命令加到你的/etc/rc.d/init.d/httpd.init文件中去:
    ### 创建3个RamDisk
    /sbin/mkfs -t ext2 /dev/ram0
    /sbin/mkfs -t ext2 /dev/ram1
    /sbin/mkfs -t ext2 /dev/ram2
    ### 加载RamDisk到开始创建的目录中
    mount /dev/ram0 /home/httpd/cgi-bin
    mount /dev/ram1 /home/httpd/icons
    mount /dev/ram2 /home/httpd/html
    ### 拷贝真正的目录中的所用文件到RamDisk 中
    tar -C /home/httpd_real -c . | tar -C /home/httpd -x
      最后,重新启动WEB服务器即可生效,试一下速度是否有所改变。
    后语:
    - 一定要记住保存RamDisk中有用的东西,否则,重新启动后将化为乌有。你可以用cron设定一个计划,每隔10分钟扫描一下RamDisk中的文件是否发生变化,如有,拷贝到硬盘中,这会比较安全。
    -最酷的应用是如果你有1G的内存,划出256M来作为暂存区/tmp,如果很多程序用到/tmp,那么你的系统性能会大大提高,而且重新启动后垃圾消失,真是一举两得。
    51 c8051f(f020,f040) msp430 arm(2410,2510) fpga(xc3s4000) dsp(5116 dm642) keilc vc++ matlab linux protel Ten_layerPCB mpegx h.26x Rscode Turbocode ofdm VideoBroadcasting ldpc_code(now!)
    4.3 LINUX下的设备驱动程序
    (1)UNIX系统下的设备驱动程序
    UNIX下设备驱动程序的基本结构:
    在UNIX系统里,对用户程序而言,设备驱动程序隐藏了设备的具体细节,对各种不同设备提供了一致的接口,一般来说是把设备映射为一个特殊的设备文件,用户程序可以象对其它文件一样对此设备文件进行操作。UNIX对硬件设备支持两个标准接口:块特别设备文件和字符特别设备文件,通过块(字符)特别设备文件存取的设备称为块(字符)设备或具有块(字符)设备接口。块设备接口仅支持面向块的I/O操作,所有I/O操作都通过在内核地址空间中的I/O缓冲区进行,它可以支持几乎任意长度和任意位置上的I/O请求,即提供随机存取的功能。
    字符设备接口支持面向字符的I/O操作,它不经过系统的快速缓存,所以它们负责管理自己的缓冲区结构。字符设备接口只支持顺序存取的功能,一般不能进行任意长度的I/O请求,而是限制I/O请求的长度必须是设备要求的基本块长的倍数。显然,本程序所驱动的串行卡只能提供顺序存取的功能,属于是字符设备,因此后面的讨论在两种设备有所区别时都只涉及字符型设备接口。
    设备由一个主设备号和一个次设备号标识。主设备号唯一标识了设备类型,即设备驱动程序类型,它是块设备表或字符设备表中设备表项的索引。次设备号仅由设备驱动程序解释,一般用于识别在若干可能的硬件设备中,I/O请求所涉及到的那个设备。
    设备驱动程序可以分为三个主要组成部分:
    -自动配置和初始化子程序,负责检测所要驱动的硬件设备是否存在和是否能正常工作。如果该设备正常,则对这个设备及其相关的、设备驱动程序需要的软件状态进行初始化。这部分驱动程序仅在初始化的时候被调用一次。
    - 服务于I/O请求的子程序,又称为驱动程序的上半部分。调用这部分是由于系统调用的结果。这部分程序在执行的时候,系统仍认为是和进行调用的进程属于同一个进程,只是由用户态变成了核心态,具有进行此系统调用的用户程序的运行环境,因此可以在其中调用sleep()等与进程运行环境有关的函数。
    - 中断服务子程序,又称为驱动程序的下半部分。在UNIX系统中,并不是直接从中断向量表中调用设备驱动程序的中断服务子程序,而是由UNIX系统来接收硬件中断,再由系统调用中断服务子程序。中断可以产生在任何一个进程运行的时候,因此在中断服务程序被调用的时候,不能依赖于任何进程的状态,也就不能调用任何与进程运行环境有关的函数。因为设备驱动程序一般支持同一类型的若干设备,所以一般在系统调用中断服务子程序的时候,都带有一个或多个参数,以唯一标识请求服务的设备。
    在系统内部,I/O设备的存取通过一组固定的入口点来进行,这组入口点是由每个设备的设备驱动程序提供的。一般来说,字符型设备驱动程序能够提供如下几个入口点:
    - open入口点。打开设备准备I/O操作。对字符特别设备文件进行打开操作,都会调用设备的open入口点。open子程序必须对将要进行的I/O操作做好必要的准备工作,如清除缓冲区等。如果设备是独占的,即同一时刻只能有一个程序访问此设备,则open子程序必须设置一些标志以表示设备处于忙状态。
    - close入口点。关闭一个设备。当最后一次使用设备终结后,调用close子程序。独占设备必须标记设备可再次使用。
    - read入口点。从设备上读数据。对于有缓冲区的I/O操作,一般是从缓冲区里读数据。对字符特别设备文件进行读操作将调用read子程序。
    - write入口点。往设备上写数据。对于有缓冲区的I/O操作,一般是把数据写入缓冲区里。对字符特别设备文件进行写操作将调用write子程序。
    - ioctl入口点。执行读、写之外的操作。
    - select入口点。检查设备,看数据是否可读或设备是否可用于写数据。select系统调用在检查与设备特别文件相关的文件描述符时使用select入口点。
    如果设备驱动程序没有提供上述入口点中的某一个,系统会用缺省的子程序来代替。对于不同的系统,也还有一些其它的入口点。

    (2)LINUX系统下的设备驱动程序
    具体到LINUX系统里,设备驱动程序所提供的这组入口点由一个结构来向系统进行说明,此结构定义为:
    #include
    struct file_operations {
    int (*lseek)(struct inode *inode,struct file *filp,
    off_t off,int pos);
    int (*read)(struct inode *inode,struct file *filp,
    char *buf, int count);
    int (*write)(struct inode *inode,struct file *filp,
    char *buf,int count);
    int (*readdir)(struct inode *inode,struct file *filp,
    struct dirent *dirent,int count);
    int (*select)(struct inode *inode,struct file *filp,
    int sel_type,select_table *wait);
    int (*ioctl) (struct inode *inode,struct file *filp,
    unsigned int cmd,unsigned int arg);
    int (*mmap) (void);

    int (*open) (struct inode *inode, struct file *filp);
    void (*release) (struct inode *inode, struct file *filp);
    int (*fsync) (struct inode *inode, struct file *filp);
    };
    其中,struct inode提供了关于特别设备文件/dev/driver(假设此设备名为driver)的信息,它的定义为:
    #include
    struct inode {
    dev_t i_dev;
    unsigned long i_ino; /* Inode number */
    umode_t i_mode; /* Mode of the file */
    nlink_t i_nlink;
    uid_t i_uid;
    gid_t i_gid;
    dev_t i_rdev; /* Device major and minor numbers*/
    off_t i_size;
    time_t i_atime;
    time_t i_mtime;
    time_t i_ctime;
    unsigned long i_blksize;
    unsigned long i_blocks;
    struct inode_operations * i_op;
    struct super_block * i_sb;
    struct wait_queue * i_wait;
    struct file_lock * i_flock;
    struct vm_area_struct * i_mmap;
    struct inode * i_next, * i_prev;
    struct inode * i_hash_next, * i_hash_prev;
    struct inode * i_bound_to, * i_bound_by;
    unsigned short i_count;
    unsigned short i_flags; /* Mount flags (see fs.h) */
    unsigned char i_lock;
    unsigned char i_dirt;
    unsigned char i_pipe;
    unsigned char i_mount;
    unsigned char i_seek;
    unsigned char i_update;
    union {
    struct pipe_inode_info pipe_i;
    struct minix_inode_info minix_i;
    struct ext_inode_info ext_i;
    struct msdos_inode_info msdos_i;
    struct iso_inode_info isofs_i;
    struct nfs_inode_info nfs_i;
    } u;
    };
    51 c8051f(f020,f040) msp430 arm(2410,2510) fpga(xc3s4000) dsp(5116 dm642) keilc vc++ matlab linux protel Ten_layerPCB mpegx h.26x Rscode Turbocode ofdm VideoBroadcasting ldpc_code(now!)
    struct file主要用于与文件系统对应的设备驱动程序使用。当然,其它设备驱动程序也可以使用它。它提供关于被打开的文件的信息,定义为:
    #include
    struct file {
    mode_t f_mode;
    dev_t f_rdev; /* needed for /dev/tty */
    off_t f_pos; /* Curr. posn in file */
    unsigned short f_flags; /* The flags arg passed to open */
    unsigned short f_count; /* Number of opens on this file */
    unsigned short f_reada;
    struct inode *f_inode; /* pointer to the inode struct */
    struct file_operations *f_op;/* pointer to the fops struct*/
    };

    在结构file_operations里,指出了设备驱动程序所提供的入口点位置,分别是:
    - lseek,移动文件指针的位置,显然只能用于可以随机存取的设备。
    - read,进行读操作,参数buf为存放读取结果的缓冲区,count为所要读取的数据长度。返回值为负表示读取操作发生错误,否则返回实际读取的字节数。对于字符型,要求读取的字节数和返回的实际读取字节数都必须是inode->i_blksize的的倍数。
    - write,进行写操作,与read类似。
    -readdir,取得下一个目录入口点,只有与文件系统相关的设备驱动程序才使用。
    - selec,进行选择操作,如果驱动程序没有提供select入口,select操作将会认为设备已经准备好进行任何的I/O操作。
    - ioctl,进行读、写以外的其它操作,参数cmd为自定义的的命令。
    -mmap,用于把设备的内容映射到地址空间,一般只有块设备驱动程序使用。
    - open,打开设备准备进行I/O操作。返回0表示打开成功,返回负数表示失败。如果驱动程序没有提供open入口,则只要/dev/driver文件存在就认为打开成功。
    - release,即close操作。
    设备驱动程序所提供的入口点,在设备驱动程序初始化的时候向系统进行登记,以便系统在适当的时候调用。LINUX系统里,通过调用register_chrdev向系统注册字符型设备驱动程序。register_chrdev定义为:
    #include
    #include
    int register_chrdev(unsigned int major, const char *name,
    struct file_operations *fops);
    其中,major是为设备驱动程序向系统申请的主设备号,如果为0则系统为此驱动程序动态地分配一个主设备号。name是设备名。fops就是前面所说的对各个调用的入口点的说明。此函数返回0表示成功。返回-EINVAL表示申请的主设备号非法,一般来说是主设备号大于系统所允许的最大设备号。返回-EBUSY表示所申请的主设备号正在被其它设备驱动程序使用。如果是动态分配主设备号成功,此函数将返回所分配的主设备号。如果register_chrdev操作成功,设备名就会出现在/proc/devices文件里。
    初始化部分一般还负责给设备驱动程序申请系统资源,包括内存、中断、时钟、I/O端口等,这些资源也可以在open子程序或别的地方申请。在这些资源不用的时候,应该释放它们,以利于资源的共享。
    在UNIX系统里,对中断的处理是属于系统核心的部分,因此如果设备与系统之间以中断方式进行数据交换的话,就必须把该设备的驱动程序作为系统核心的一部分。设备驱动程序通过调用request_irq函数来申请中断,通过free_irq来释放中断。它们的定义为:
    #include
    int request_irq(unsigned int irq,
    void (*handler)(int irq,void dev_id,struct pt_regs *regs),
    unsigned long flags,
    const char *device,
    void *dev_id);
    void free_irq(unsigned int irq, void *dev_id);
    参数irq表示所要申请的硬件中断号。handler为向系统登记的中断处理子程序,中断产生时由系统来调用,调用时所带参数irq为中断号,dev_id为申请时告诉系统的设备标识,regs为中断发生时寄存器内容。device为设备名,将会出现在/proc/interrupts文件里。flag是申请时的选项,它决定中断处理程序的一些特性,其中最重要的是中断处理程序是快速处理程序(flag里设置了SA_INTERRUPT)还是慢速处理程序(不设置SA_INTERRUPT),快速处理程序运行时,所有中断都被屏蔽,而慢速处理程序运行时,除了正在处理的中断外,其它中断都没有被屏蔽。在LINUX系统中,中断可以被不同的中断处理程序共享,这要求每一个共享此中断的处理程序在申请中断时在flags里设置SA_SHIRQ,这些处理程序之间以dev_id来区分。如果中断由某个处理程序独占,则dev_id可以为NULL。request_irq返回0表示成功,返回-INVAL表示irq>15或handler==NULL,返回-EBUSY表示中断已经被占用且不能共享。
    作为系统核心的一部分,设备驱动程序在申请和释放内存时不是调用malloc和free,而代之以调用kmalloc和kfree,它们被定义为:
    #include
    void * kmalloc(unsigned int len, int priority);
    void kfree(void * obj);
    参数len为希望申请的字节数,obj为要释放的内存指针。priority为分配内存操作的优先级,即在没有足够空闲内存时如何操作,一般用GFP_KERNEL。与中断和内存不同,使用一个没有申请的I/O端口不会使CPU产生异常,也就不会导致诸如“segmentation fault"一类的错误发生。任何进程都可以访问任何一个I/O端口。此时系统无法保证对I/O端口的操作不会发生冲突,甚至会因此而使系统崩溃。因此,在使用I/O端口前,也应该检查此I/O端口是否已有别的程序在使用,若没有,再把此端口标记为正在使用,在使用完以后释放它。这样需要用到如下几个函数:
    int check_region(unsigned int from, unsigned int extent);
    void request_region(unsigned int from, unsigned int extent,
    const char *name);
    void release_region(unsigned int from, unsigned int extent);
    调用这些函数时的参数为:from表示所申请的I/O端口的起始地址;extent为所要申请的从from开始的端口数;name为设备名,将会出现在/proc/ioports文件里。check_region返回0表示I/O端口空闲,否则为正在被使用。
    51 c8051f(f020,f040) msp430 arm(2410,2510) fpga(xc3s4000) dsp(5116 dm642) keilc vc++ matlab linux protel Ten_layerPCB mpegx h.26x Rscode Turbocode ofdm VideoBroadcasting ldpc_code(now!)
    在申请了I/O端口之后,就可以如下几个函数来访问I/O端口:
    #include
    inline unsigned int inb(unsigned short port);
    inline unsigned int inb_p(unsigned short port);
    inline void outb(char value, unsigned short port);
    inline void outb_p(char value, unsigned short port);
    其中inb_p和outb_p插入了一定的延时以适应某些慢的I/O端口。在设备驱动程序里,一般都需要用到计时机制。在LINUX系统中,时钟是由系统接管,设备驱动程序可以向系统申请时钟。与时钟有关的系统调用有:
    #include
    #include
    void add_timer(struct timer_list * timer);
    int del_timer(struct timer_list * timer);
    inline void init_timer(struct timer_list * timer);
    struct timer_list的定义为:
    struct timer_list {
    struct timer_list *next;
    struct timer_list *prev;
    unsigned long expires;
    unsigned long data;
    void (*function)(unsigned long d);
    };
    其中expires是要执行function的时间。系统核心有一个全局变量JIFFIES表示当前时间,一般在调用add_timer时jiffies=JIFFIES+num,表示在num个系统最小时间间隔后执行function。系统最小时间间隔与所用的硬件平台有关,在核心里定义了常数HZ表示一秒内最小时间间隔的数目,则num*HZ表示num秒。系统计时到预定时间就调用function,并把此子程序从定时队列里删除,
    因此如果想要每隔一定时间间隔执行一次的话,就必须在function里再一次调用add_timer。function的参数d即为timer里面的data项。
    在设备驱动程序里,还可能会用到如下的一些系统函数:
    #include
    #define cli() __asm__ __volatile__ ("cli":
    #define sti() __asm__ __volatile__ ("sti":
    这两个函数负责打开和关闭中断允许。
    #include
    void memcpy_fromfs(void * to,const void * from,unsigned long n);
    void memcpy_tofs(void * to,const void * from,unsigned long n);
    在用户程序调用read 、write时,因为进程的运行状态由用户态变为核心态,地址空间也变为核心地址空间。而read、write中参数buf是指向用户程序的私有地址空间的,所以不能直接访问,必须通过上述两个系统函数来访问用户程序的私有地址空间。memcpy_fromfs由用户程序地址空间往核心地址空间复制,memcpy_tofs则反之。参数to为复制的目的指针,from为源指针,n为要复制的字节数。
    在设备驱动程序里,可以调用printk来打印一些调试信息,用法与printf类似。printk打印的信息不仅出现在屏幕上,同时还记录在文件syslog里。
    (3)LINUX系统下的具体实现
    在LINUX里,除了直接修改系统核心的源代码,把设备驱动程序加进核心里以外,还可以把设备驱动程序作为可加载的模块,由系统管理员动态地加载它,使之成为核心地一部分。也可以由系统管理员把已加载地模块动态地卸载下来。
    LINUX中,模块可以用C语言编写,用gcc编译成目标文件(不进行链接,作为*.o文件存在),为此需要在gcc命令行里加上-c的参数。在编译时,还应该在gcc的命令行里加上这样的参数:-D__KERNEL__ -DMODULE。由于在不链接时,gcc只允许一个输入文件,因此一个模块的所有部分都必须在一个文件里实现。
    编译好的模块*.o放在/lib/modules/xxxx/misc下(xxxx表示核心版本,如在核心版本为2.0.30时应该为/lib/modules/2.0.30/misc),然后用depmod -a使此模块成为可加载模块。模块用insmod命令加载,用rmmod命令来卸载,并可以用lsmod命令来查看所有已加载的模块的状态。
    编写模块程序的时候,必须提供两个函数,一个是int init_module(void),供insmod在加载此模块的时候自动调用,负责进行设备驱动程序的初始化工作。init_module返回0以表示初始化成功,返回负数表示失败。另一个函数是void cleanup_module (void),在模块被卸载时调用,负责进行设备驱动程序的清除工作。
    在成功的向系统注册了设备驱动程序后(调用register_chrdev成功后),就可以用mknod命令来把设备映射为一个特别文件,其它程序使用这个设备的时候,只要对此特别文件进行操作就行了。
    51 c8051f(f020,f040) msp430 arm(2410,2510) fpga(xc3s4000) dsp(5116 dm642) keilc vc++ matlab linux protel Ten_layerPCB mpegx h.26x Rscode Turbocode ofdm VideoBroadcasting ldpc_code(now!)
    4.4 Linux可卸载内核模块
    (1)什么是LKMs
    LKMs就是可卸载的内核模块(Loadable Kernel
    Modules)。这些模块本来是Linux系统用于扩展他的功能的。使用LKMs的优点有:他们可以被动态的加载,而且不需要重新编译内核。由于这些优点,他们常常被特殊的设备(或者文件系统),例如声卡等使用。
    每个LKM至少由两个基本的函数组成:
    int init_module(void) /*用于初始化所有的数据*/
    {
    ...
    }
    void cleanup_module(void) /*用于清除数据从而能有一个安全的退出*/
    {
    ...
    }
    (2)使用时用到的命令
    加载一个模块(常常只限于root能够使用)的命令是:
    # insmod module.o
    这个命令让系统进行了如下工作:
    加载可执行的目标文件(在这儿是module.o)
    调用 create_module这个系统调用(至于什么叫系统调用,见1.2)来分配内存.
    不能解决的引用由系统调用get_kernel_syms进行查找引用.
    在此之后系统调用init_module将会被调用用来初始化LKM->执行 int inti_module(void) 等等
    OK,现在我们的模块已经被加载了并且给我们打印出了那句很经典的话.现在你可以通过下面这个命令来确认你的LKM确实运行在内核级别中:
    # lsmod
    Module     Pages  Used by
    helloworld     1    0
    这个命令读取在 /proc/modules 的信息来告诉你当前那个模块正被加载."Pages"
    显示的是内存的信息(这个模块占了多少内存页面)."Used by"显示了这个模块被系统使用的次数(引用计数).这个模块只有当这个计数为0时才可以被除去.在检查过这个以后,你可以用下面的命令卸载这个模块
    # rmmod helloworld
    4.5什么是Busybox?
    Busybox包含了许多小的通用UNIX工具,然后把它们连接到一个单一的命令busybox上。他提供了最小的代替品,代替了你经常可以看到得文件工具,外壳工具,查找工具,文本工具,grep,gzip,tar等等。Busybox为很多小的或嵌入式的系统提供了还算完整的POSIX环境。这些工具对于他们完整的GUI版本相比具有的功能较少;但是包含的选项提供了期望的功能,运行起来很象它们的GNU的复制品。
    Busybox编写的思路是大小的优化和限制性的资源。他也十分的模块化,因此在编译的时候你很容易包括或剔除命令(或特征)。这是你可以很容易的定制你的嵌入式系统。要创建一个工作系统,只需要加入/dev,一个内核,一个外壳。对于一个真正的小型系统,你甚至可以使用Busybox外壳(不是Bourne兼容的,但很小很实用)和Busybox vi编辑器。 
    下面介绍如何加入自己书写的命令到Busybox
    1) 开始书写代码
    首先,书写你自己的applet。确认开头包括版权信息,比如你从那里摘抄的代码。也要包括迷你GPL样本文件。确定把主函数命名为_main。确定把它保存为 .c。下边的例子是一个新的applet叫mu,代码为mu.c:
    /* vi: set sw=4 ts=4: */
    /*
    * Mini mu implementation for busybox
    *
    *
    * Copyright (C) [YEAR] by [YOUR NAME]
    *
    * This program is free software; you can redistribute it and/or modify
    * it under the terms of the GNU General Public License as published by
    * the Free Software Foundation; either version 2 of the License, or
    * (at your option) any later version.
    *
    * This program 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. See the GNU
    * General Public License for more details.
    *
    * You should have received a copy of the GNU General Public License
    * along with this program; if not, write to the Free Software
    * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    * 02111-1307 USA
    *
    */

    #include "busybox.h"

    int mu_main(int argc, char **argv)
    {
    int fd;
    char mu;

    if ((fd = open("/dev/random", O_RDONLY)) < 0)
    perror_msg_and_die("/dev/random");

    if ((n = safe_read(fd, &mu, 1)) < 1)
    perror_msg_and_die("/dev/random");

    return mu;
    }
    51 c8051f(f020,f040) msp430 arm(2410,2510) fpga(xc3s4000) dsp(5116 dm642) keilc vc++ matlab linux protel Ten_layerPCB mpegx h.26x Rscode Turbocode ofdm VideoBroadcasting ldpc_code(now!)
    返回列表