APP下载

多处理器平台下Linux 2.6启动过程中的位图分析

2010-09-21陈小兰

成都信息工程大学学报 2010年1期
关键词:源代码内核调用

陈小兰, 杨 斌

(西南交通大学信息科学与技术学院,四川成都 610031)

1 引言

顺应对称多处理器(Symmetric Multi-Processor,SMP)及多核的出现,Linux操作系统经过不断地完善和发展,早就针对SMP体系结构作了很大的改动,实现了对多处理器的支持,但目前针对多处理及多核平台的系统移植及多核平台的应用程序多核化还存大很大的空白,因此有必要深入理解内核级的多处理器支持。位图是内核中进行操作系统资源管理分配的重要手段之一,文中分析的多处理器平台下Linux 2.6启动过程中的位图,就是希望能为多处理及多核平台的系统移植及多核平台的应用程序开发提供一些指导。

分析基于Intel X86 SMP体系结构,Linux操作系统内核为2.6.10。

2 Linux下的位图及类型

2.1 单处理器结构下Linux中的位图及类型

位图是Linux内核中一个32位的全局变量,其中的每一位对应一种状态,在单处理器结构下,位图主要用于调度、内存管理等,以更快地索引当前应投入运行的任务或是查找空闲块等。

2.2 多处理器结构下Linux中的位图及类型

在多处理器结构下也有上述单处理器结构中的位图,但却增加了与多处理器启动过程相关的位图,这些位图是Linux内核中32位的全局CPU变量,其中每一位都与某一个特定的CPU相对应,分别对应0和1两种状态,但所起的作用在多处理器启动过程中的不同阶段却各不相同。随着Linux操作系统对SMP支持的不断完善和发展,2.6版本的内核中还增加了新的和SMP启动相关的位图,所有这些位图都将在下面进行详细分析。

3 多处理器结构下的位图建立

3.1 多处理器系统启动的总体流程

位图是在系统启动过程中依次建立起来的,因此,要分析位图的作用首先要弄清系统启动的整个过程。

系统启动过程主要包括以下几个步骤:

(1)系统加电后,BIOS初始化,自检(屏蔽AP);

(2)BIOS将MBR里面的引导程序(Grub,Lilo等)调入内存,并由该引导程序将Linux内核调入;

(3)Linux操作系统启动部分运行setup.S和head.S,将内核解压到内存,并进行实模式下及保护模式下的初始化[1];

(4)进入执行内核中的start-kernel()函数,对系统的各种资源进行初始化,创建BSP的空闲进程;(5)init()函数的执行,首先完成对SMP系统的初始化,再进行上层应用的初始化。

3.2 Linux SMP初始化过程中的位图处理机制

在SMP体系结构下,SMP的初始化包括主CPU(BSP)和次CPU(AP)的初始化,相关位图就是在这两个过程中依次建立起来的。

从BIOS初始化到start-kernel函数的执行,系统都还没有对AP做任何处理,一直是BSP在运行,BSP在start-kernel()中进行自身的初始化工作,并设置好自己相应的cpu-online-map位图和 cpu-callout-map位图[2]。cpu-online-map表示当前联机的CPU,仅在CPU已经可以用于内核调度或接收设备中断时设置。而cpu-callout-map是每次CPU启动后向主CPU发出通知时,由主CPU负责设置,而主CPU自身所对应的这个位图的相应位则由主CPU自己在此进行设置。BSP在start-kernel()中调用smp-prepare-boot-cpu()就是将cpu-online-map位图和cpu-callout-map位图中与主CPU相对应的那一位设置为1,表示BSP已经初始化。

在start-kernel函数中,主要处理例如cache、内存等初始化工作,最后在进入BSP的空闲进程前要调用kernel-thread()创建init内核线程[3],在init()函数里,具体实现SMP系统各CPU的初始处理机制。分析相关的SMP初始化函数,源代码在linux/init/main.c中:

在函数smp-prepare-cpus中,调用smp-boot-cpus函数启动并初始化各AP,源代码在linux/arch/i386/kernel/Smpboot.c中,这个函数的重点是对每个AP依次调用do-boot-cpu函数,下面来看在do-boot-cpu中做了什么工作,关键代码在linux/arch/i386/kernel/smpboot.c中。这一函数首先创建自己的idle进程(即0号进程),然后BSP将AP在一开始被唤醒后需要执行的代码(trampoline.S)的首地址写入热启动向量。这样,当BSP对AP发送IPI时,AP受到启动后响应中断,自动跳入这个trampoline.S代码部分继续执行。为了AP有足够的时间响应中断,BSP在发送中断请求后要延迟一段时间。在这期间,BSP是怎样得知AP是否初始化完了呢?AP又是怎样知道自已可以继续往下执行直到进入空闲进程呢?这就得依靠两个全局位图cpu-callout-map和cpucallin-map了,具体实现流程如图1所示。

引入cpu-callin-map和cpu-callout-map两个位图后,主CPU和次CPU之间的应答变得非常容易,否则,主CPU和相应的次CPU都无法继续往下执行,而需要靠处理器间中断(IPI)来完成。

AP在跳入 trampoline.S代码后,将载入符号表(gdt)和局部符号表(ldt),然后进入保护模式并跳至head.S的入口处,以下是进入保护模式并跳至head.S的入口处的代码片断:源代码在linux/arch/i386/kernel/trampoline.S中:

图1 位图cpu-callout-map和cpu-callin-map的设置

这段代码通过将ax(第0位已置1)所指示的控制字装入机器状态字(即CR0的低5位)使处理器进入保护模式运行,然后通过一个长跳转,到0x10:0x00100000,即内核被解压后的起始地址,也就是head.S的startup-32()函数。

由此,各AP转入head.S继续执行,在这一步中要依次为各个AP设置其相应的0号进程的task-struct和内核堆栈,在支持SMP的Linux中,每个进程相应的task-struct结构中新增加了一个cpus-allowed位图,通过这个位图,可以设置进程在所希望的CPU上运行。进程迁移就是利用这个位图进行的。默认情况下cpus-allowed的所有位都被设置为1,进程可以在系统中所有可用的处理器上执行[4]。当然,这个位图也可以在系统启动完成后由用户通过相应的系统调用设置一个不同的由一个或几个位组合的位掩码。当这一处理器绑定关系改变时,内核就会采用迁移线程把任务推到合法的处理器上。在head.S中,AP执行的代码与BSP所执行的并不完全一致,源代码在linux/arch/i386/kernel/head.S中:

AP执行head.S时,当执行到上述代码的时候,由于ready的值被改变,不再等于1,所以就继续向前执行,调用initialize-secondary函数,而不是象BSP一样执行标号1处的代码(调用start-kernel函数)[5]。initializesecondary函数里面的代码很简单,源代码在linux/arch/i386/kernel/smpboot.c中:

这是一段内嵌汇编程序,将程序跳转至current->thread.eip(即前面的idle->thread.eip)处。CPU执行start-secondary函数,对相应的AP进行初始化。初始化完成后,则向主CPU一样对cpu-online-map中与初始化目标CPU相对应的那一位进行设置,表示该AP已经初始化。最终,这个AP将进入自己的空闲状态。

这样,一个AP的启动过程就完成了。每个AP的启动就是依次经历上述过程,并在上述过程中依次对相应位图进行设置。

AP启动完成后,从函数调用返回到smp-boot-cpus(),即回到主CPU的运行中,这时,所有次CPU都已启动,接下来就是构造cpu-sibling-map[]位图数组,数组中的每一位保存同属CPU的逻辑CPU号,当CPU支持超线程技术时就会表现出该位图的优势,利用它可以很快地找到当前CPU核的兄弟CPU。当然,如果一个物理CPU中只有一个逻辑核,则该位图数组各元素的值就是自身的逻辑CPU号。图2是以一个物理CPU中含有两个逻辑核的体系结构为例来说明。

图2 cpu-sibling-map位图示例

smp-boot-cpus()执行完后,将调用下一函数fixup-cpu-present-map(),该函数的作用是设置cpu-presentmap位图。在Linux内核不支持热插拨时,cpu-present-map可以用cpu-possible-map来代替,cpu-presentmap表示某一时刻计算机中使用的CPU位图,而cpu-possible-map位图是从开机系统启动到某一时刻所有曾经使用过的CPU位图,这两者在Linux内核不支持热插拨时代表相同的含义,但从2.6支持热插拨以后,以前在smp-init()中要激活所有CPU的,现在则只需根据cpu-present-map来激活相应CPU即可。因此当一个热插拨CPU被插入时,就要更新cpu-present-map的相应位。

4 结束语

多处理器结构下,位图是很重要的。它在整个Linux内核的引导过程中,起着重要的作用。

启动过程中位图的使用使得CPU之间协调变得更加容易,不必处处都采用处理间中断,从系统使用者的角度来讲,则可以通过查看位图来了解CPU的相关信息,使操作更加容易。通过剖析BSP和AP各自的启动过程,对其中所用到的位图作了详细分析,使整个BSP和AP的启动过程变得清晰明了,在此基础上进行多处理器结构下不同平台间的Linux系统移植也将变得更加容易。

[1] 贾秋亭,侯瑞莲.嵌入式Linux的开发[J].山东轻工业学院学报(自然科学版),2006,(4).

[2] 何志宏,何为民.嵌入式Linux在开发板gec2410上的完全启动过程[J].科技广场,2008,(8).

[3] (美)BOVET&CESATI.陈莉君,冯锐,牛欣源译.深入理解LINUX内核[M].北京:中国电子出版社,2001:127.

[4] (美)Robert Love.陈莉君,康华,张波译.Linux内核设计与实现[M].北京:机械工业出版社,2006:47.

[5] 毛德操,胡希明.Linux内核源代码情景分析[M].杭州:浙江大学出版社,2009:1511.

猜你喜欢

源代码内核调用
强化『高新』内核 打造农业『硅谷』
基于TXL的源代码插桩技术研究
核电项目物项调用管理的应用研究
基于嵌入式Linux内核的自恢复设计
Linux内核mmap保护机制研究
LabWindows/CVI下基于ActiveX技术的Excel调用
软件源代码非公知性司法鉴定方法探析
基于语法和语义结合的源代码精确搜索方法
基于系统调用的恶意软件检测技术研究
微生物内核 生态型农资