Linux 2.6内核的研究

时间:2011-09-04

 Linux 的 initrd 技术是一个非常普遍使用的机制,linux2.6 内核的 initrd 的文件格式由原来的文件系统镜像文件转变成了 cpio 格式,变化不仅反映在文件格式上, linux 内核对这两种格式的 initrd 的处理有着截然的不同。本文首先介绍了什么是 initrd 技术,然后分别介绍了 Linux2.4 内核和 2.6 内核的 initrd 的处理流程。通过对 Linux2.6 内核的 initrd 处理部分代码的分析,使读者可以对 initrd 技术有一个全面的认识。为了更好的阅读本文,要求读者对 Linux 的 VFS 以及 initrd 有一个初步的了解。

  Linux 操作系统是UNIX 操作系统的一种克隆系统。它诞生于1991 年的10 月5 日(这是次正式向外公布的时间)。以后借助于Internet 网络,并经过全世界各地计算机爱好者的共同努力下,现已成为今天世界上使用多的一种UNIX 类操作系统,并且使用人数还在迅猛增长。   Linux 操作系统的诞生、发展和成长过程始终依赖着以下五个重要支柱:UNIX 操作系统、MINIX 操作系统、GNU 计划、POSIX 标准和Internet 网络。   下面主要根据这五个基本线索来追寻一下Linux 的开发历程,它的酝酿过程,初的发展经历。首先分别介绍其中的四个基本要素(UNIX、MINIX、GNU 和POSIX,Internet 的重要性显而易见,所以不用对其罗嗦),然后根据Linux 的创始人Linus Toravlds 从对计算机感兴趣而自学计算机知识,到心里开始酝酿编制一个自己的操作系统,到初Linux 内核0.01 版公布,以及从此如何艰难地一步一个脚印地在全世界hacker 的帮助下推出比较完善的1.0 版本这段时间的发展经过,也即对Linux 的早期发展历史进行详细介绍。

  Linux内核2.6版的开发已经接近尾声,2.6测试版发布已经二个月了,正式版预计明年年初发布。作为一个主要发布版本,2.6相对于2.4有很大的改动;它引入了许多新的特性,同样也去除很多过时的特性。它在哪些方面有大的改动?它对Linux的开发人员以及其他层面的Linux用户可能有什么样的影响?阅读本文,您将得到答案。

  Linux 2.6内核的特性

  使用了心的调度算法,称为哦0/I算法在高负载的情况的执行非常出色,并且在有很多处理器时可以很好夫人扩展,而2.4内核用的是时间片重算法,严重影响效率。

  采用抢占式内核,使互式操作,多媒体应用程序的响应速度大大提高。

  改进的虚拟内存

  修改了I/O 子系统部分,保证在各种工作负荷下I/O 都有很好的响应速度。

  大量改进文件系统,比如支持Windows的逻辑卷管理器,重写对NTFS文件系统的支持,改进HPFS等。、

  改进和部分重写了Moduies功能,使之更稳定。

  尽管我们次启动Linux 2.4似乎只是昨天的事,时间已经流走,内核开发团队的2.6版内核开发工作已经接近完成了。本文将试图描述2.6内核中的许多新特性(侧重i386平台的Linux)。和封闭源码的软件的预发布不一样的是,这里所描述的所有特性当前都是2.5版内核开发树中可用的(其中一些的bug少一些,另一些bug多一些)。(按照Linux的传统,偶数版本的内核是稳定的,奇数版本的只是开发用的)。然而内核当前处于特性冻结(feature-freeze)时期,终的发行版本应该不大可能过于偏离这里的描述。同时也应该清楚这里描述的一些"新"特性在次出现在2.6系列内核后,可能被向后移植到了的或者发行版供应商的2.4版内核之中。

  多种平台支持

  也能够支持相当广泛的硬件和平台,是采用Linux作为内核的操作系统(比如 GNU操作系统, 系统和环境常常是和Linux一块分发。Linux一般不被认为是独立的操作系统,只是操作系统的内核。)的优势之一。Linux自1.2版就开始包含对新的处理器类型和特性的支持,的Linux 2.6内核发布版本也不例外。这种趋势不会直接影响到Linux在Intel平台下的使用,同时使得Linux能在尽可能大的范围内被使用,这一点非常重要。

  Linux 2.6 扩展多平台支持的一个主要途径就是把uClinux的大部并入了主流内核。uCLinux(可以发音为"you-see-Linux",但更正确的拼写,首字母应该式希腊字母"mu")是将Linux应用在微控制器平台的项目。很多年来,这个Linux分支为许多嵌入式芯片提供了支持,把它更多的集成到主流内核中是一件非常有意义的事。

  在对嵌入式处理器支持上,Linux 2.6有四个主要的新进步。首先是对Motorola的新型嵌入式m68k系列处理器移植。这些被命名为Dragonball或是ColdFire的处理器可以在Motorola,Lineo,Arcturus或是其他厂商生产的系统或是评估板上找到。大多数Linux用户应该对这些处理器相当熟悉,因为从Palm 1000到的Palm III,他们一直是Palm Pilots的心脏。不幸的是,对早期没有MMU的m68k处理器(比如早期苹果机上使用的68000系列)还没有支持。支持的嵌入式平台还包括日立(Hitachi)的H8/300系列(不包含H8S,但可能会尽快地集成进来)以及NEC v850处理器。

  无论怎么强调Linux 2.6旨在支持无MMU系统的主要体系结构变化,都不为过分。所有Linux的前期版本,不论直接或是间接,都起源于Linus初在Intel 80386上的工作,局限性是固有的。沿着这个方向将来也许会有更多的其他早期的硬件被支持(事实上,已经有关于此目的的项目启动)。但是,不像为现代的以及仍在生产中的嵌入式处理器的提供支持,对早期的硬件的支持被更多地认为是基于某种爱好,并且对于终用户而言很可能是无用的。

  的Linux版本包含了对Axis通信公司的ETAX CRIS("Code Reduced Instruction Set")处理器的支持(更确切地说,支持ETRAX 100LX及更新的产品),它从技术的角度而言不是uCLinux合并的一部分。实际上对这款处理器的支持在2.4开发周期就已经有了,但它在2.4.0以后才被引入,所以现在应该提到它。它是主要用于网络设备的嵌入式处理器。与此相关的ETRAX 100,是得到uClinux支持的无MMU处理器,但是在主流的Linux内核中相关支持却没有集成进来。

  Opteron支持 - 消费级的64位Linux 另一个在2.4.x开发环节就已经并入但这里仍然值得提及的是对AMD Opteron芯片(基于AMD64体系结构)的支持。Opteron向后与Intel-clone的处理器兼容,并且,甚至可能得到微软的支持。是它还是Intel的Itanium家族的某一成员成为64位消费级产品的事实标准现在还很难下定论。

  尽管2.4系列内核的后期版本已经可以在该芯片上运行,但作为产品应用仍受到了很大限制。对高端用户来说,严重的问题是,每个应用程序的RAM的使用都被限制在512MB以内。另一方面,新内核对在该平台上运行x86(32位)的程序的支持得到了改进。

  系统子体系结构(Subarchitecture)支持 Linux 2.6除了对许多新的处理器体系结构外,还包含了一个称为子体系结构(Subarchitecture)的新概念。以前,Linux通常假设处理器和其他硬件是配套的。也就是说,i386系列处理器只会在PC/AT服务器上使用。这条针对i386的假设在Linux 2.4中就被打破,因为i386的额外支持使其可以在SGI的视频工作站(Visual Workstation)中使用。(事实上,在其他非i386体系结构上,这个假设早被打破了。比如,m68k很早就支持Amiga,Michintosh等平台。)Linux 2.6对于此的变化就是,让这个特性以及概念成为标准,以便所有的体系结构都可以用相似而健全的方法来处理,以便更清晰地划分模块。

  标准的确立使得i386可以运用于两个新的平台。个是NCR的Voyager体系。这是一个对称多处理器(SMP)系统(在Intel的MP规范标准确定之前就已经开发出来了),它支持多达32个486-686的处理器配置。实际采取这种体系结构的产品处理器的配置数目要相对少一些,而且目前并不是所有的型号都得到了Linux的支持(早的就不支持)。第二种得到支持的体系结构是更为广泛使用的由NEC开发的PC-9800平台,它曾是日本市场占统治地位的PC平台,一直到近几年。初的PC-9800装载的是8086处理器,终发展到奔腾级处理器和SMP支持。(当然,Linux对它的支持局限在386以上。)尽管在美国它完全不为人所知,微软的Windows 95之前的版本曾移植到这个平台上。该平台由于生产商对标准PC的偏爱,生产已经中止。

  Linux对差异细微的硬件类型支持的形式化,使得操作系统能更容易的移植到其他平台上,比如移植到专为存储设计的硬件或者是使用在工业领域的主流处理器。需要澄清的是,子体系结构也不是任何时候都管用的,它能够发挥作用是因为这些可移植的系统非常底层构件有或多或少的不同。比起在X-box上运行Linux的差别来说,驱动程序等相对小的差别还不足以把它们从传统的i386系统中分开。Linux对X-box的支持,就不是子体系结构的问题。

  大规模 - 非一致存储访问体系结构(NUMA)和大型机除了以上所提及的新硬件类型的支持之外,新的Linux内核发行版也包含了对大型服务器(一些运行i386处理器,也有些运行其他处理器)更多的支持。对Linux来说,这样的特性是新近加入的,还有许多优化工作需要完成。这是一个Linux发展相当迅速的领域,我们能够预计在不久的将来,Linux将成为此领域的有力竞争者。

  在此方面的改变就是Linux对NUMA服务器的支持。NUMA(非一致存储访问)在多进程世界里是超越SMP以及提升多处理器系统效率的一个进步。SMP系统的设计上有着许多和对应单处理器系统类似的局限性。其中的设计局限之一就是系统中只有的一块内存区,所有的处理器对它都平等地对它进行访问。在多处理器系统里,这样会在同一条内存总线上的多处理器之间引起相当高的竞争,导致性能瓶颈。NUMA服务器,通过引入了以下的理念解决了这个问题:对于某个特定的处理器,一些内存比其他一些的更为接近(close)。可以这样简单地设想(同时技术上也不会有严重错误),你的系统有许多包含了处理器、内存以及其他元件(比如I/O扩展卡)。系统中有很多这样的卡,它们可以相互通讯;显而易见,相对其他卡上的内存,每块卡上的处理器能更快的访问本地内存(自己的卡上内存)。从许多角度上看,NUMA体系结构就是一个紧密耦合的集群特例。

  为了给NUMA主机提供良好的支持,Linux十分必要在许多方面进行调整,以使新模型更具效率。首先,建立了一个内部拓扑API,以使内核知道处理器和内存以及其他IO设备间的相互关系。有了内部拓扑API的支持,Linux的进程调度器可以理解这些关系,并且会尝试优化任务以达到的本地资源使用。此外,许多NUMA主机在各个节点(nodes)的线性内存区域之间存在空洞(holes)。新内核已经能够合理的处理这种不连续情况。内核还有许多其他使得Linux可以支持高端(high-end)主机的变化,这也是内核发展的一个明确方向。再过一年,我们可以期待Linux在高端机型上效率以及其他方面的进步。

  本文以64位PCI总线接口芯片PCI9656的设备驱动程序为基础,比较了Linux2.6内核与2.4内核的区别,设计与开发了在Linux 2.6内核下PCI9656设备驱动程序,进而研究了2.6内核的内存和中断管理机制。

  关键字:Linux2.6;设备驱动程序;PCI9656 1 引言 Linux操作系统因为其高效、安全、可动态加载及源代码开放等特点,深受设备驱动程序开发人员的喜爱。系统内核大部分独立于底层硬件运行,用户无需关心硬件问题,而用户操作是通过一组标准化的调用来完成。设备驱动程序的任务是将这些调用映射到作用于实际硬件设备的特定操作上,该编程接口能够使得驱动程序独立于内核的其他部分来搭建,在需要时才动态加载到内核。这种模块化的特点,使得Linux设备驱动程序的编写过程变得清晰简单。 目前,为满足日益庞大的数据处理需要,基于64位PCI总线接口设备的研究开发显得尤为重要。因而本文将基于PLX公司推出的PCI总线接口芯片PCI9656,设计开发在Linux2.6内核下的设备驱动程序,进而对2.6内核的内存和中断管理机制进行分析研究。 2 Linux2.6与2.4内核的比较 2.1  系统稳定性 为了彻底防止对正在被使用的内核模块进行错误操作,2.6内核在加载和导出内核模块方面都较2.4内核进行了改进,避免了用户执行将导致系统崩溃的操作,例如强制删除模块等。同时,当驱动程序需要在多个文件中包含<linux/module.h>头文件时,不必定义宏__NO_VERSION__来检查内核的版本。 2.2  统一设备模型 统一设备模型的创建是2.6内核重要的变化之一。它促进了模块接口的标准化,其目的是更好地控制和管理设备,主要包括:更准确地确定系统设备,更高效的进行电源管理以及改进的系统总线结构管理。 2.3  内核基础设施 2.6内核为了区别以。o为扩展名的常规对象文件,将内核模块的扩展名改为。ko。相对于2.4内核下系统所支持的RAM为4GB而言,2.6内核下系统支持更大数量的RAM,在分页模式下可达64GB。同时,2.6内核优化了I/O调度器,确保不会有进程驻留在队列中过长时间等待输入/输出操作,使得I/O操作的响应更为迅速。 2.4  外部设备 在2.4内核中有约束大型系统的限制,比如支持的每一类设备的数量为256。而2.6内核则彻底地打破了这些限制,可以支持4095种主要的设备类型,每一个单独的类型又可以支持超过一百万个的子设备。 3 Linux2.6内核下PCI设备驱动程序的设计 3.1  PCI设备驱动程序中数据结构 在2.6内核下使用file_operations数据结构,来建立设备驱动程序中的函数与主设备号(major number)之间的对应关系。该数据结构中包含了指向驱动程序内部大多数函数的指针,描述了虚拟文件系统如何操作一个打开的外围设备。因而file _operations结构是驱动程序向内核其他部分提供的一个统一的标准设备接口。 file结构是设备驱动程序使用的另一个重要的数据结构,指示当前系统中已打开的文件。它在C语言库中定义,在调用内核open函数时创建,并传递给在该设备上进行操作的所有函数,直到的close函数。file结构中还包含了指向它所拥有的file_operations结构的指针。 inode结构由内核自动生成,代表已打开文件的描述符,与每个打开的文件一一对应。它包含了两个重要的结构成员:dev_t扩展到32位,其中12位主设备号,20位从设备号,而cdev用于存储一个指向字符设备文件的指针。 3.2  驱动程序与内核和外部设备间的关系 (1) 通过Linux提供的系统调用函数(例如init_module等)进入内核,这些函数在2.6内核版本下总共有两百多个,提供了几乎所有应用程序进入内核所需要执行的操作。 (2) 系统的内核函数都有“sys_”前缀(例如函数sys_init_module),应用程序通过访问设备文件系统来调用这些函数。这一层主要是“devfs”(device filesystem)文件管理机制,它是从普通文件和设备文件抽象出来的一个文件系统层,完成进入具体的设备文件操作之前的准备工作。 (3) 由设备驱动程序提供具体的函数,来完成对硬件设备的各种操作。特别的对于PCI9656来说,就是通过PCI接口对设备的寄存器和存储器进行访问操作,例如调用register_chrdev等函数来初始化芯片内部的状态寄存器和配置寄存器。 3.3  PCI9656芯片的操作流程

  PCI总线是目前常用的外设总线之一,Linux的PCI内核代码为PCI设备驱动程序的开发提供了强大的支持。PCI9656的驱动程序主要包括以下几个方面:设备初始化,为PCI芯片分配内存资源,实现数据的读写功能,中断处理,系统收回内存资源,关闭设备等。 4.Linux2.6内核下内存和中断管理的研究 2.6内核应用了许多新技术来实现对各类外部设备驱动程序的更好支持。下面结合PCI9656驱动程序中的内存和中断管理,进一步分析和研究2.6内核对内存和中断进行的改进和优化。 4.1  内存管理 在Linux内存管理器中,页表保持对进程使用的内存物理页的追踪,它将虚拟页映射到物理页上。系统必须找到映射到该页的每一个进程,将使用较少的页置换出去,这样进程中相应页的页表条目才能被更新。随着在系统中运行的进程数量的增加,将这些页置换出去的工作量也会急剧增加。

  为解决此问题,2.6内核引入了反向映射机制(reverse mapping),内存管理器为每一个物理页建立一个链表,包含指向当前映射页的每个进程的页表条目(page-table entry)的指针。该链表叫PTE链,它极大地提高了找到那些映射某个页的进程的速度,如图2所示。驱动程序调用下列内核函数来为PCI9656分配内存空间。   get_free_page(GFP_NOIO,PGD_ORDER); alloc_pages(gfp_mask,size); //查找并为PCI9656分配空闲内存物理页 mempool_alloc(pool,gfp_mask); request_mem_region(pdx->Pci9656); remap_page_range(*mem_area,PCI9656,kernel_address,mem_size,prot); //请求分配内存空间,实现PCI9656物理地址到内存地址的映射 mempool_free(*element,pool);//释放内存 2.6内核中将头文件malloc.h改为slab.h,分配标志GFP_BUFFER改为GFP_NOIO和GFP_NOFS,并新增了文件mempool.h。这些变化一起促生了2.6内核中的内存管理器,其设计目标是更高的性能、效率和稳定性。

  另一方面,使用反向映射获得性能的提高也要付出代价,即系统不得不占用一些低端内存来保持对所有反向映射的追踪,这势必在32位硬件上成为内存空间的瓶颈。因此2.6内核引入了高端内存页表(Highmem PTE)机制,让页表条目存放在高端内存中,释放出更多的低端内存区给必须放在这里的内核数据结构。同时,较以前版本的内核而言,2.6内核重新构建了一个更为简单的内存管理器,提高了整个系统的稳定性。 4.2  中断处理 Linux处理中断的方式很大程度上与它在用户空间处理信号的方式一样,驱动程序只需为设备所对应的中断注册一个处理程序,并在中断到达时进行正确的处理。 在2.4内核之前,Linux系统一直采用cli和sti函数来禁用和启用中断,然而对于任意某个例程,想要知道在它被调用时中断是否被启用,已变得越来越困难。因而2.6内核定义了函数local_irq_enable和local_irq_disable,用来使能和无效处理器控制的所有中断,定义函数local_irq_save来将当前中断的状态存入flags变量,避免了查询中断的状态信息。 中断处理程序的作用就是将有关中断接收的信息反馈给设备,并根据正在服务的中断的不同含义对数据进行相应的读或写。由于PC机只有0-15的中断号,设备都是以共享的形式申请中断号,2.6内核改进了PCI设备中断请求队列的组织方式,通过设置flags变量中的SA_SHIRQ标志位,并保证内核中所有中断号(dev_id)的性,来实现中断的共享。 if(!(inb(card->iobase+CODEC_CMD_INT_STATUS)&0x80000000)) return;//识别中断类型 request_irq(irq,*handler,flags,PCI9656,*dev_id);//向系统注册PCI9656的中断 如果中断注册成功,则返回值IRQ_RETVAL为0,这时在/proc/interrupts文件中可以看申请成功的中断。在2.6内核下,request_irq和free_irq从sched.h改到了interrupt.h中定义。 synchronize_irq(irq);//中断同步 if(wait_event_interruptible(waitqueue,condition)>0) return;//判断中断等待使能 outb(intstat&card->iobase+CODEC_CMD_INT_HLDCLR+2);//使能并行端口的中断 //系统响应PCI9656的中断,执行数据读写、寄存器访问等操作 free_irq(irq,*dev_id);//释放设备中断、I/O资源和缓冲区

  实验与测试 我们设计了Makefile文件和一个简单的应用程序,在动态加载驱动程序后,对PCI9656开发板进行了大批量数据的读写实验。基于64位PCI总线和100MHz的时钟频率,我们对芯片的数据读写速率进行了采集,实验结果统计如图3所示。 从上图可以看到,在2.6内核下应用PCI9656作为总线接口芯片,数据的读写传输速率随着数据包的大小有大幅度的提高,这在工程应用中有很大的现实意义。 6 结束语 本文通过Linux2.6内核所提供的一系列标准函数调用接口,用C++语言开发了PCI9656的设备驱动程序,并在Fedora Core2平台下调试通过,能正确发送和接收各种大小的数据包。当通信的数据包大小为64KB时,DMA通道的读写速度可达1.8Gbps,能够很好的满足日益庞大的数据处理需要。同时,Linux操作系统源代码的开放性还能较好的保证数据存储运算和通信的安全性。



  
上一篇:WinCE 5.0下鼠标键盘驱动完全解析(上)
下一篇:Linux系统环境变量

免责声明: 凡注明来源本网的所有作品,均为本网合法拥有版权或有权使用的作品,欢迎转载,注明出处。非本网作品均来自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

相关技术资料