Linux内核是如何启动的

310 阅读3分钟

第一阶段:BIOS

计算机加电后,有一个特殊的硬件电路在CPU的一个引脚上产生一个RESET逻辑值,把处理器的一些寄存器设置成固定的值,并执行在物理地址0XFFFFFFF0处的代码(BIOS)。

BIOS的工作内容:

1. 上电自检。对计算机硬件执行一系列测试,检测设备是否正常工作。

2. 初始化硬件设备。

3. 搜索一个操作系统来启动。

4. 把第一个扇区的内容拷贝到内存中物理地址0X00007C00开始的位置,然后跳转到这个地址处,开始执行刚才装载进来的代码。

第二阶段:引导装入程序

引导装入程序是由BIOS用来把操作系统内核映像长在到RAM中所调用的一个程序。一般有LILO和GRUB。

LILO执行的主要步骤:

1. 显示“loading”信息。

2. 从磁盘装入内核映像的初始部分,即将内核映像的第一个512字节从地址0x00090000开始存入RAM中,而将setup()函数的代码从地址0x00090200开始存入RAM中。

3. 从磁盘中装载其余的内核映像。

4. 跳转到setup()代码。

第三阶段:setup()函数

汇编语言函数,主要功能是初始化大部分硬件设备,虽然在BIOS阶段已经初始化了大部分硬件设备,但是LINUX不依赖于BIOS,以自己的方式重新初始化设备以增强可移植性和健壮性。

跳转到startup_32()汇编语言函数。

第四阶段:startup_32()函数

有两个不同的startup_32()函数,此处我们指的是arch/i386/boot/compressed/head.S文件中实现的那个。

主要执行以下操作:

1. 初始化段寄存器和一个临时堆栈。

2. 清零eflags寄存器的所有位。

3. 用0填充内核未初始化数据区。

4. 调用decompress_kernel()函数来解压内核映像。一般解压后的内核放在物理地址0x00100000处。

5. 跳转到物理地址0x00100000。

解压后的内核映像以包含在arch/i386/kerner/head.S中的另一个startup_32()函数开始。

该函数执行完以后,跳转到start_kernel()函数执行。

第五阶段:start_kerner()函数

这个函数完成linux内核的初始化工作。

主要操作有:

1. 调用sched_init()函数初始化调度程序。

2. 调用build_all_zonelists()函数初始化内存管理区。

3. 调用page_alloc_init()函数来初始化伙伴系统分配程序。

4. 调用trap_init()函数完成IDT初始化。

5. 调用time_init()函数来初始化系统日期和时间。

6. 调用kmem_cache_init()函数来初始化slab分配器。

7. 调用calibrate_delay()函数以确定CPU时钟的速度。

8. 调用kernel_thread()函数为进程1创建内核进程。这个内核进程又会创建其他的内核进程并执行sbin/init程序。

在start_kernel()开始执行后会显示版本信息,除此之外,在init程序和内核线程执行的最后阶段还会显示很多其他信息。最后就会在控制台上出现熟悉的登录提示符了。