我知道Linux可用并且已经移植到许多不同的平台,例如X86,ARM,PowerPC等。
但是,在移植方面,究竟需要什么?
我的理解是Linux是用C语言编写的软件。因此,例如,当最初将Linux从X86移植到ARM或其他操作系统时,不仅仅是针对特定目标体系结构用编译器重新编译代码吗?
撇开用于不同外围设备的设备驱动程序,将Linux移植到新架构时还需要做其他事情。编译器会不会为我们处理所有事情?
我知道Linux可用并且已经移植到许多不同的平台,例如X86,ARM,PowerPC等。
但是,在移植方面,究竟需要什么?
我的理解是Linux是用C语言编写的软件。因此,例如,当最初将Linux从X86移植到ARM或其他操作系统时,不仅仅是针对特定目标体系结构用编译器重新编译代码吗?
撇开用于不同外围设备的设备驱动程序,将Linux移植到新架构时还需要做其他事情。编译器会不会为我们处理所有事情?
Answers:
即使Linux内核中的大多数代码都是用C编写的,但是该代码中仍有很多部分非常特定于运行它的平台,并且需要考虑到这一点。
其中一个特定的示例是虚拟内存,它在大多数体系结构(页表的层次结构)上都以类似的方式工作,但是具有每种体系结构的特定细节(例如,每种体系结构中的层数),甚至在x86上,这种情况也在不断增加。 Linux内核代码引入了宏来处理遍历这些层次结构,这些宏可以由编译器在页表级别较少的体系结构上消除(因此,代码是用C编写的,但是将体系结构的详细信息考虑。)
许多其他领域对于每种体系结构都是非常特定的,需要使用特定于架构的代码来处理。尽管其中大多数涉及汇编语言代码。例如:
上下文切换:上下文切换包括保存要退出的进程的所有寄存器的值,以及将已调度的已保存进程集中的寄存器还原到CPU中。甚至寄存器的数量和集合对于每个体系结构也是非常特定的。此代码通常以汇编形式实现,以允许完全访问寄存器并确保其尽可能快地运行,因为上下文切换的性能对于系统至关重要。
系统调用:用户空间代码可以触发系统调用的机制通常特定于体系结构(有时甚至特定于特定的CPU模型,例如Intel和AMD为此引入了不同的指令,较旧的CPU可能缺少这些指令,因此详细信息因为这些仍然是唯一的。)
中断处理程序:有关如何处理中断(硬件中断)的详细信息通常是特定于平台的,并且通常需要一些汇编级胶水来处理平台使用的特定调用约定。同样,用于启用/禁用中断的原语通常是特定于平台的,并且还需要汇编代码。
初始化:有关初始化方式的详细信息通常还包括特定于平台的详细信息,并且通常需要一些汇编代码来处理内核的入口点。在具有多个CPU(SMP)的平台上,有关如何使其他CPU联机的详细信息通常也是特定于平台的。
锁定原语:锁定原语(例如自旋锁)的实现通常还涉及特定于平台的细节,因为某些体系结构提供(或更喜欢)不同的CPU指令来有效地实现这些细节。一些将实现原子操作,一些将提供可以原子测试/更新的cmpxchg(但如果其他编写者首先进入,则失败),其他一些将包括CPU指令的“锁定”修饰符。这些通常还涉及编写汇编代码。
在内核中(或者特别是在Linux内核中)可能还需要其他特定于平台或体系结构的代码。在内核源代码树的下方arch/
和下方include/arch/
,您可以找到更多特定于体系结构的子树。例子。
有些实际上是令人惊讶的,例如,您会看到每种体系结构上可用的系统调用数量是不同的,并且某些系统调用将存在于某些体系结构中,而不存在于其他体系结构中。(即使在x86上,系统调用的列表在32位和64位内核之间也不同。)
简而言之,内核需要了解很多特定于平台的情况。Linux内核尝试抽象出大多数算法,因此可以在C语言中实现更高级别的算法(例如内存管理和调度的工作方式),并且在所有架构上都可以相同(或几乎相同)地工作。
除了移植Linux内核之外,您还需要为“用户空间”程序定义应用程序二进制接口(ABI),并移植用户空间软件堆栈的最低层。Linux通常与GNU项目中的低级用户空间组件一起使用,其中最关键的是:
许多其他软件都具有可选的平台相关组件。例如,如果您为新的CPU体系结构编写NSS和OpenSSL的手动优化密码原语,并为IonMonkey和V8编写即时编译后端,则Web浏览将大大加快。但是这些对于建立新平台不是必需的。