作者: 来自:
Linux是一个可移植性非常好的操作系统,它广泛支持了许多不同体系结构的计算机。可移植性是指代码从一种体系结构移植到另外一种不同的体系结构上的方便程度。我们都知道Linux是可移植的,因为它已经能够在各种不同的体系结构上运行了。但这种可移植性不是凭空得来的—它需要在做设计时就为此付出诸多努力。现在,这种努力已经开始得到回报了,移植Linux到新的系统上就很容易(相对来说)完成。本系列中我们将讨论的是如何编写可移植的代码—在编写内核代码和驱动程序时,你必须时刻牢记这个问题。
有些操作系统在设计时把可移植性作为头等大事之一。尽可能少地涉及与机器相关的代码。汇编代码用得少之又少,为了支持各种不同类别的体系结构,界面和功能在定义时都尽最大可能地具有普适性和抽象性。这么做最显著的回报就是需要支持新的体系结构时,所需完成的工作要相对容易许多。一些移植性非常高而本身又比较简单的操作系统在支持新的体系结构时,可能只需要为此体系结构编写几百行专门的代码就行了。问题在于,体系结构相关的一些特性往往无法被支持,也不能对特定的机器进行手动优化。选择这种设计,就是利用代码的性能优化能力换取代码的可移植性。Minix、NetBSD和许多研究用的系统就是这种高度可移植操作系统的实例。
与之相反,还有一种操作系统完全不顾及可移植性,它们尽最大的可能追求代码的性能表现,尽可能多地使用汇编代码,压根就是为在一种硬件体系结构使用。内核的特性都是围绕硬件提供的特性设计的。因此,将其移植到其他体系结构就等于从头再重新编写一个新的操作内核。选择这种设计,就是用代码的可移植性换取代码的性能优化能力。这样的系统往往比移植性好的系统难于维护(DOS和Windows 9x就是这样的典型)。虽然目前看来这些系统对性能的要求不见得比对可移植性要求更强,不过它们还是愿意牺牲可移植性,而不乐意让设计打折扣。
Linux在可移植性这个方面走的是中间路线。差不多所有的接口和核心代码都是独立于硬件体系结构的C语言代码。但是,在对性能要求很严格的部分,内核的特性会根据不同的硬件体系进行调整。举例来说,需要快速执行和底层的代码都是与硬件相关并且是用汇编语言写成的。这种实现方式使Linux在保持可移植性的同时兼顾对性能的优化。当可移植性妨碍性能发挥的时候,往往性能会被优先考虑。除此之外,代码就一定要保证可移植性。
一般来说,暴露在外的内核接口往往是与硬件体系结构无关的。如果函数的任何部分需要针对特殊的体系结构(无论是出于优化的目的还是作为一种必需的选择)提供支持的时候,这些部分都会被安置在独立的函数中,等待调用。每种被支持的体系结构都实现了一个与体系结构相关的函数,而且会被链接到内核映像之中。调度程序就是一个好例子。调度程序的主体程序存放在kernel/sched.c文件中,用C语言编写的,与体系结构无关。可是,调度程序需要进行的一些工作,比如说切换处理器上下文和切换地址空间等,却不得不依靠相应的体系结构完成。于是,内核用C语言编写了函数context_switch()用于实现进程切换,而在它的内部,会调用switch_to()和switch_mm()分别完成处理器上下文和地址空间的切换。
而对于Linux支持的每种体系结构,它们的switch_to()和switch_mm()实现各不相同。所以,当Linux需要移植到新的体系结构上的时候,只需要重新编写和提供这样的函数就可以了。
与体系结构相关的代码都存放在arch/architecture/和include/asm-architecture/目录中,architecture是Linux支持的体系结构的简称。比如说,Intel X86体系结构对应的简称是i386。与这种体系结构相关的代码都存放在arch/i386/以及include/asm-i386/目录下。2.6系列内核支持的体系结构包括alpah、arm、cris、h8300、i386、ia64、m32r、m68k、m68knommu、mips、mips64、parisc、ppc、ppc64、s390、sh、sparc、sparc64、um、v850和x86-64。稍后给出的表1是一份更详尽的清单。
重读我们翻译的《Linux kernel development》,觉得这一部分内容相对独立而又实用,拿出来共享。
阅读(177) | 评论(0) | 转发(0) |