linux内核启动流程

来源:
导读 大家好,我是本期栏目编辑小友,现在为大家讲解linux内核启动流程问题。 Linux的启动代码真的很大。从汇编到C

大家好,我是本期栏目编辑小友,现在为大家讲解linux内核启动流程问题。

Linux的启动代码真的很大。从汇编到C,从Makefile到LDS文件,有很多东西需要理解。毕竟Linux内核是很多人写的,花了很多时间和精力。而直到现在,世界上仍然有成千上万的程序员在不断改进Linux内核代码。

Linux内核启动和文件系统加载过程。

当u-boot开始执行bootcmd命令时,将进入Linux内核启动阶段。与u-boot类似,普通Linux内核的启动过程可以分为两个阶段,但对于uImage这样的压缩内核,应该包含内核自解压过程。本文以linux-2.6.37的源代码为例,分三个阶段描述了内核启动的全过程。第一阶段是内核自解压过程,第二阶段主要是设置ARM处理器的工作模式,启用MMU,设置一级页表等。而第三阶段主要是C代码,包括内核初始化的所有工作。

Linux内核启动过程。

拱门/手臂/内核/头臂。S

该文件是内核执行的第一个文件,包括从ENTRY(stext)到start_kernel的初始化代码。

主要功能是检查CPU ID,架构类型,初始化BSS,跳转到start_kernel函数。执行前,处理器应满足以下条件:

r0 -应该是0

r1 -唯一的体系结构号

MMU关闭

I-缓存打开或关闭

d缓存关闭

1 /*部分源代码分析*/

2 /*内核入口点*/

3 ENTRY(stext)

4 /*程序状态,禁止FIQ和IRQ,设置SVC模式*/

5 mov r0,#F_BIT | I_BIT | MODE_SVC@确保SVC模式

6 /*设置当前程序状态寄存器*/

7 msr cpsr_c,r0 @和所有IRQ禁用

8 /*判断CPU类型,找出正在运行的CPU ID值和Linux编译支持的ID值是否支持*/

9 bl _ _ lookup _ processor _ type

10 /*跳到_ _错误*/

11 teq r10,#0 @无效处理器?

12 moveq r0,p ' @是,错误p '

13 beq _ _错误

14 /*判断系统类型,看R1寄存器的架构类型值是否支持*/

15 bl _ _ lookup _ architecture _ type

16 /*不支持,跳转到*时出错/

17 teq r7,#0 @无效架构?

18 moveq r0,a ' @是,错误a '

19 beq _ _错误

20 /*创建核心页表*/

21 bl __create_page_tables

22 adr lr,__ret @返回地址

23添加pc、r10、# 12 @ iniTIalise处理器

24 /*跳转到start_kernel函数*/

25 b start_kernel

Linux内核开始第一阶段1。

因此,这里的第一阶段阶段1意味着内核被解压缩.出现。完成,引导内核。这部分代码是在头部实现的。拱形/臂形/内核。这个文件中的汇编代码通过查找处理器内核类型和机器码类型调用相应的初始化函数,然后构建页表,最后跳转到start_kernel()函数开始内核的初始化。测试处理器类型是在汇编子函数__lookup_processor_type中完成的,可以通过以下代码调用:bl__lookup_processor_type(在文件head-commom中实现。s)。当__lookup_processor_type调用结束并返回到原始程序时,返回的结果将保存在寄存器中。r5寄存器返回描述处理器的结构地址,并判断r5。如果r5的值为0,则表示不支持该处理器,将输入__error_p。R8存储页表的标志位,r9存储处理器的ID号,r10存储与处理器相关的struct proc_info_list结构地址。头。的核心代码如下:

 

  

  Linux内核启动第二阶段stage2   从start_kernel函数开始

  Linux内核启动的第二阶段从start_kernel函数开始。start_kernel是所有Linux平台进入系统内核初始化后的入口函数,它主要完成剩余的与 硬件平台相关的初始化工作,在进行一系列与内核相关的初始化后,调用第一个用户进程- init 进程并等待用户进程的执行,这样整个 Linux内核便启动完毕。该函数位于init/main.c文件中,主要工作流程如图3所示:

 

  该函数所做的具体工作有 :

  1) 调用setup_arch()函数进行与体系结构相关的第一个初始化工作;对不同的体系结构来说该函数有不同的定义。对于ARM平台而言,该函数定义在 arch/arm/kernel/setup.c。它首先通过检测出来的处理器类型进行处理器内核的初始化,然后 通过bootmem_init()函数根据系统定义的meminfo结构进行内存结构的初始化,最后调用 paging_init()开启MMU,创建内核页表,映射所有的物理内存和IO空间。

  2) 创建异常向量表和初始化中断处理函数;

  3) 初始化系统核心进程调度器和时钟中断处理机制;

  4) 初始化串口控制台(console_init);

  ARM-Linux 在初始化过程中一般都会初始化一个串口做为内核的控制台,而串口Uart驱动却把串口设备名写死了,如本例中linux2.6.37串口设备名为ttyO0,而不是常用的ttyS0。有了控制台内核在启动过程中就可以通过串口输出信息以便开发者或用户了解系统的启动进程。

  5) 创建和初始化系统cache,为各种内存调用机制提供缓存,包括;动态内存分配,虚拟文件系统(VirtualFile System)及页缓存。

  6) 初始化内存管理,检测内存大小及被内核占用的内存情况;

  7) 初始化系统的进程间通信机制(IPC); 当以上所有的初始化工作结束后,start_kernel()函数会调用rest_init()函数来进行最后的初始化,包括创建系统的第一个进程-init进程来结束内核的启动。

  挂载根文件系统并启动init

  Linux内核启动的下一过程是启动第一个进程init,但必须以根文件系统为载体,所以在启动init之前,还要挂载根文件系统。

标签:

版权声明:转载此文是出于传递更多信息之目的。若有来源标注错误或侵犯了您的合法权益,请作者持权属证明与本网联系,我们将及时更正、删除,谢谢您的支持与理解。