以下内容大部分来自《嵌入式Linux应用开发完全手册》
1.内核启动过程概述
如图是Linux内核的vmlinux启动过程。之所以强调是vmlinux,是因为其他格式的内核在进行与vmlinux相同的流程之前会有一些独特的操作。比如压缩格式的内核zImage,它首先进行自解压得到vmlinux,然后执行vmlinux,开始“正常的”启动流程。
第一阶段:引导阶段,通常使用汇编语言编写,它首先检查内核是否支持当前架构的处理器,然后检查是否支持当前开发板。通过检查后,就为下一阶段的start_kernel函数作准备了。
第二阶段主要使用c语言编写,它进行内核初始化的全部工作,最后调用rest_init函数启动init过程,创建系统第一个进程:init进程。
2.内核启动代码分析
由前面对Makefile的分析可知,arch/arm/kernel/head.s是内核执行的第一个文件。另外,U-Boot调用内核时,r1寄存器中存储“机器类型ID”,内核会用到它。
第82行调用_lookup_processor_type函数来确定内核是否支持当前cpu;第85行调用_lookup_machine_type函数来确定内核是否支持当前开发板。
如果_lookup_processor_type、_lookup_machine_type函数都返回成功,则引导程序将继续执行下去。其中_create_page_tables函数用来创建一级页表以建立虚拟地址到物理地址的映射关系,它用到_lookup_processor_type返回的proc_info_list结构。在引导阶段的最后,调用start_kernel函数进入内核启动的第二阶段。_lookup_machine_type函数确定的machine_desc结构将在第二阶段中多次使用。
移植U-Boot时,U-Boot传给内核的参数有两类:预先存在某个地址的tag列表和调用内核时在r1寄存器中指定的机器类型ID。后者在引导阶段的_lookup_machine_type函数已经用到,而tag列表将在setup_arch函数中进行初步处理。
1)setup_arch函数
它在arch/arm/kernel/setup.c中定义,部分代码如下:
....
2)paging_init函数分析
这个函数在setup_arch函数中的调用形式如下:
paging_init(&meminfo,mdesc);
meminfo中存放内存的信息,前面解释内存tag时确定构建了这个全局结构。
mdesc就是前面lookup_machine_type函数返回的machine_desc结构。对于S3C2440开发板,这个结构在arch/arm/mach-s3c2440/mach-smdk2440.c中有如下定义: