ARM Linux启动过程分析
序的入口函数 start_kernel()处,开始之后的内核初始化工作:
b SYMBOL_NAME(start_kernel)
3.2 start_kernel函数
start_kernel是所有 Linux 平台进入系统内核初始化后的入口函数,它主要完成剩余的与硬件平台相关的初始化工作,在进行一系列与内核相关的初始化后,调用第一个用户进程-init 进程并等待用户进程的执行,这样整个 Linux 内核便启动完毕。该函数所做的具体工作有[4][5]
:
1) 调用 setup_arch()函数进行与体系结构相关的第一个初始化工作;
对不同的体系结构来说该函数有不同的定义。对于 ARM 平台而言,该函数定义在arch/arm/kernel/Setup.c。它首先通过检测出来的处理器类型进行处理器内核的初始化,然后通过 bootmem_init()函数根据系统定义的 meminfo 结构进行内存结构的初始化,最后调用paging_init()开启 MMU,创建内核页表,映射所有的物理内存和 IO空间。
2) 创建异常向量表和初始化中断处理函数;
3) 初始化系统核心进程调度器和时钟中断处理机制;
4) 初始化串口控制台(serial-console);
ARM-Linux 在初始化过程中一般都会初始化一个串口做为内核的控制台,这样内核在启动过程中就可以通过串口输出信息以便开发者或用户了解系统的启动进程。
5) 创建和初始化系统 cache,为各种内存调用机制提供缓存,包括;动态内存分配,虚拟文件系统(VirtualFile System)及页缓存。
6) 初始化内存管理,检测内存大小及被内核占用的内存情况;
7) 初始化系统的进程间通信机制(IPC);
当以上所有的初始化工作结束后,start_kernel()函数会调用 rest_init()函数来进行最后的初始化,包括创建系统的第一个进程-init 进程来结束内核的启动。Init 进程首先进行一系列的硬件初始化,然后通过命令行传递过来的参数挂载根文件系统。最后 init 进程会执行用 户传递过来的“init=”启动参数执行用户指定的命令,或者执行以下几个进程之一:
execve("/sbin/init",argv_init,envp_init);
execve("/etc/init",argv_init,envp_init);
execve("/bin/init",argv_init,envp_init);
execve("/bin/sh",argv_init,envp_init)。
当所有的初始化工作结束后,cpu_idle()函数会被调用来使系统处于闲置(idle)状态并等待用户程序的执行。至此,整个 Linux 内核启动完毕。
4. 结论
Linux 内核是一个非常庞大的工程,经过十多年的发展,它已从从最初的几百 KB 大小发展到现在的几百兆。清晰的了解它执行的每一个过程是件非常困难的事。但是在嵌入式开发过程中,我们并不需要十分清楚 linux 的内部工作机制,只要适当修改 linux 内核中那些与硬件相关的部分,就可以将 linux 移植到其它目标平台上。通过对 linux 的启动过程的分 析,我们可以看出哪些是和硬件相关的,哪些是 linux 内核内部已实现的功能,这样在移植linux 的过程中便有所针对。而 linux内核的分层设计将使 linux 的移植变得更加容易。
参考文献
[1] 詹荣开.嵌入式系统bootloader技术内幕[EB/OL]. /index.html,2003.12.
[2] Russell King.Booting ARM Linux[Z].Linux Documentation.May 2002
[3] 刘淼.嵌入式系统接口设计与Linux驱动程序开发[M].北京航空航天大学出版社.2006.6
[4] William Gatliff. The Linux 2.4 Kernel’s Startup Procedure[DB/CD]. 2002 Embedded System Conference San Francisco,March..2002
ARM Linux bootloader 启动过程 相关文章:
- Linux嵌入式系统开发平台选型探讨(11-09)
- 基于ARM体系的嵌入式系统BSP的程序设计方案(04-11)
- 在Ubuntu上建立Arm Linux 开发环境(04-23)
- 达芬奇数字媒体片上系统的架构和Linux启动过程(06-02)
- SQLite嵌入式数据库系统的研究与实现(02-20)
- 革新2410D开发板试用手记(04-21)