1、前言
这篇文章介绍了msm8916平台的Little Kernel(LK)的启动流程。Little Kernel的作用是在启动的时候初始化硬件,从存储器中载入Linux内核和ramdisk到RAM中,配置初始化寄存器和命令行参数,最后跳转到内核中运行。LK源于www.kernel.com的开源项目。
2、LittleKernel
2.1 概述
Bootloader是嵌入式系统在加电后执行的第一段代码,在它完成CPU和相关硬件的初始化之后,再将操作系统映像或固化的嵌入式应用程序装在到内存中然后跳转到操作系统所在的空间,启动操作系统运行。基于安卓平台的的bootloader即为LK bootloader。
Bootloader有以下的作用:
1)硬件的初始化:建立起中断向量表、MMU、缓存,初始化外设,如存储单元、USB,加密等等;
2)从存储单元加载boot.img;
3)支持烧写和recovery。
注意:LK在32位模式下运行,即使在64位的硬件架构中也是。从32位LK跳转到64位内核须通过安全模式。
2.2 LK的调用流程
LK的代码在bootable/bootloadler/lk目录下可以找到。其中代码又通过各个子文件夹分为:
app——应用相关
arch——硬件架构相关
dev ——设备相关
Include——头文件
Kernel——lk系统相关
Platform——相关驱动
Projiect——makefile文件
Scripts——Jtag脚本
target ——具体板子相关
1)LK代码的运行流程从arch/arm/crt0.S文件的_start.开始。其完成了以下的工作:
A.初始化CPU;
B.如果(平台相关的流程)需要,会调用__cpu_early_init()函数。该函数位置:platform/msm8916/(arch_init.S):__cpu_early_init.;
C.如果需要,LK会重新配置(Relocate);
D.建立栈;
E.调用kmain()函数。
从kmain()开始的调用流程如图1所示:
2)bootstrap2()的调用流程:
A.由arch/arm/arch.c的arch_init()函数开始,此函数为一个桩函数(stub);
B.platform/<platform>/(platform.c) 的platform_init()函数,同样是一个桩函数;
C.target/<target>/(init.c) 的target_init() 。完成如下工作:初始化SPMI总线,初始化keypad,配置SDC引脚的驱动强度(drive strength)和上拉配置,初始化SD/MMC卡的主控制器,识别MMC卡,设置时钟等等,之后mmc_init(),读取eMMC的分区表,partition_read_table();
D.app/init.c的apps_init()函数,完成以下工作:用宏APP_START和APP_END初始化app, 调用aboot_init(),如果有.entry分区,就用另外一个线程运行app;
E.app/aboot/aboot.c的aboot_init()函数,根据环境配置,以不同模式启动:常规模式,fastboot模式,recovery模式。
2.3 LK 常规启动模式
启动条件:Recovery标志或者fastboot键值没有设置。
1)从MMC中复制boot.img载入到scratch区(基地址为0x80000000,在target/msm8916/rules.mk指定);
2)从scratch区载入内核到KERNEL_ADDR(从boot image的header中检索到)。载入设备树到TAGS_ADDR(从boot image的header中检索到),然后更新设备树;
3)把命令行(cmd line)作为启动参数,加到设备树的“/chosen”节点。将RAM属性作为“linux, initrd-start” 和“linux, initrd-end”加到设备树的“/chosen”节点;
4)失能缓存、中断,跳转至内核。
2.4 LK fastboot模式
1)aboot_init()函数会检查boot.img是否存在,以及音量下键是否被按下;
2)通过check_reboot_mode检测启动的原因;
3)fastboot命令的寄存器处理程序:fastboot_register(cmd_list[i].name,cmd_list[i].cb);
4)初始化fastboot:fastboot_init(void *base, unsigned size) ,创建一个进程跟fastboot_handler()关联,该进程会等待USB事件。
2.5 LK recovery模式
1)aboot_init()检查HOME键(KEY_HOME)和音量上键(VOLUME UP)被按下;
2)check_reboot_mode()函数检测启动原因。如果启动原因是RECOVERY_MODE,设置boot_into_recovery = 1;
3)boot_linux_from_mmc()函数会检查:
if (!boot_into_recovery) {
……
else {
index = partition_get_index(“recovery”);
ptn = partition_get_offset(index);
…….
}
4)从recovery分区获取image:
gned int target_freq, unsigned int relation);