本篇文章是对初步学习Android系统lk启动流程的一个大致简介。方便掌握lk启动流程的大致框架,具体细节后续再进行更新
1. 前言
需要了解的文件类型:
1)编译LK的链接文件(.ld)
2)汇编文件(.s、.S文件)
3).mk文件(用来向编译系统描述源代码,并将源文件分组为模块。可用于预定义变量)
4)makefile文件(包含一些规则告诉make编译哪些文件以及怎样编译这些文件)
5)Kconfig文件(编译前的文件,其中主要作用是在内核配置的时候,作为配置选项)
6).config文件(文件是在进行内核配置的时候,经过配置后生成的内核编译参考文件)
文件之间的顺序关系:
编写Kconfig—>进行make menuconfig---->生成.config----->编写Makefile---->按照Makefile编译规则进行编译---->编译成功
1、lk加载完成后,linux kernel又是怎样加载的?里面又做了些什么操作?
2、关于boot、kernel、HAL等不同层级,程序是怎样被加载、不同层级如何分化完成上层应用的请求任务?
2. LK入口
确定LK的入口,必须要先知道编译LK的链接文件
相关的链接文件为:
bootable/bootloader/lk/arch/arm/system-onesegment.ld
从链接文件中,可以确定LK启动入口为_start函数,该函数的定义在汇编文件:
_start函数的定义在汇编文件:
bootable/bootloader/lk/arch/arm/ctr0.S
_start函数的主要功能是设置中断向量表、初始化bss段、初始化与处理器架构的相关寄存器、搭建C运行环境等;
3. kmain函数
当_start函数设置完成后,然后开始运行bl kmain代码,跳转到kmain函数处运行,进入的C语言的世界
kmain入口(ctr0.S文件,line.187行)
bl kmain /*跳到kmain函数执行*/b .
在_start函数的最后,将会调用kmain函数,该函数的定义在文件:
bootable/bootloader/lk/kernel/main.c
对于kmain函数实现的主要功能:
1)函数调用后,首先是对早期的thread线程系统进行初始化,
2)接下来则是调用arch_early_init()函数,对CPU处理器架构相关的早期初始化,例如关闭cache,使能mmu等功能,
3)然后开始调用与平台早期初始化的相关函数,对早期需要使用的外设进行初始化,例如中断控制器、debug串口等外设,
4)接下来,则是调用函数搭建出一个完整的thread线程系统,并对lk中的定时器进行初始化,
5)调用thread_create()函数创建出"bootstrap2"线程,并调用thread_resume()函数,让该线程在系统中工作,
6)最后,则是设置kmain线程为idle状态。
拓展思考(boot程序加载流程)
- 复位键,早期的硬件初始化;
- 对CPU处理器架构相关的早期初始化,调用与平台、外设早期初始化的相关函数(如:中断控制器、debug串口等外设)
- 调用函数,搭建出一个完整的thread线程系统,并对lk中的定时器进行初始化
- 调用thread_create()函数创建出"bootstrap2"线程,并调用thread_resume()函数,让该线程在系统中工作,
- 线程设置中断响应请求,完成请求后,设置kmain线程为idle状态,等待下一个中断请求任务。
4. bootstrap2线程分析
1)使用thread_create()函数创建出"bootstrap2"线程后,并使用thread_resume()启动该线程后,接下来将会运行bootstrap2()函数,该函数可以看成是lk启动的第二阶段,它将会继续完成外设的初始化和启动。
2)在kmain函数的最后阶段,在thread线程系统搭建完成后,将会运行下面的代码创建出bootstrap2线程:
thread_resume(thread_create("boo