此博客是刚刚开始学习LK的时候写的,现在看来十分粗糙,重新写了一个LK系列(大多数参考了网上资料),故此篇作废。
此篇博客有很多参考其他文章的内容,由于参考内容繁杂,不一一标注角标了,在末尾会贴上所有参考博客的link,如有侵权,请联系本人处理,谢谢。
深入,并且广泛
-沉默犀牛
step1 从哪里开始执行,目前还不清楚,不作分析了。
step2 Bootloader(LK)
LK的代码在bootable/bootloader/lk目录下
在 bootable/bootloadler/lk/arch/arm/ssystem-onesegment.ld 连接文件中ENTRY(_start)
指定 LK 从_start 函数开始,_start 在 lk/arch/crt0.S中,下面我们来看一下这个文件中的内容:
.globl _start
_start: //这里就是ENTRY(_start)中的_start
...
/*启动CPU*/
这里的指令都是有关CPU初始化的一些指令,不展开了
/* we are relocated, jump to the right address */
ldrr0, =.Lstack_setup
...
.Lstack_setup:
/*为irq、fiq、abort、undefined、system/user和last supervisor模式设置堆栈*/
/* 清除BSS *
bl kmain //注意这里!
上文说过bootloader分为stage1和stage2,从这个汇编文件来看,应该已经包含了stage1,和stage2。只是stage2还没有结束,kmain也算是stage2里面的一部分。如果这里理解有误,请留言告知,感激不尽。
汇编中的最后一个有注释的指令bl kmain
,跳转到了如下的代码中,代码路径为 lk/kernel/main.c
void kmain(void) __NO_RETURN __EXTERNALLY_VISIBLE;
void kmain(void) {
thread_t *thr;
thread_init_early(); //初始化thread(lk 中的简单进程)相关结构体。
arch_early_init(); //做一些如 关闭 cache,使能 mmu 的 arm 相关工作。
platform_early_init(); // 相关平台的早期初始化
target_early_init(); // 现在就一个函数跳转,初始化UART(板子相关)
dprintf(INFO, "welcome to lk\n\n");
bs_set_timestamp(BS_BL_START);
dprintf(SPEW, "calling constructors\n");
call_constructors();
dprintf(SPEW, "initializing heap\n");
heap_init(); // lk系统相关的堆栈初始化
__stack_chk_guard_setup();
dprintf(SPEW, "initializing threads\n");
thread_init(); // 线程初始化
dprintf(SPEW, "initializing dpc\n");
dpc_init(); // lk系统控制器初始化(相关事件初始化)
dprintf(SPEW, "initializing timers\n");
timer_init(); // 初始化lk中的定时器
#if (!ENABLE_NANDWRITE)
dprintf(SPEW, "creating bootstrap completion thread\n");
thr = thread_create("bootstrap2",&bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); // 新建线程入口函数
if (!thr) {
panic("failed to create thread bootstrap2\n");
}thread_resume(thr);
exit_critical_section(); // 使能中断
thread_become_idle(); // 使自己成为idle进程
#else //对应上面的#if (!ENABLE_NANDWRITE) ,我们一般走if,不会走else
bootstrap_nandwrite();
#endif
}
这里可以看到,kmain主要做了两件事:1.本身lk的初始化 2.boot启动初始化
以上与 boot 启动初始化相关函数是arch_early_init、platform_early_init 、bootstrap2,这些是启动的重点,我们下面慢慢来看。
arch_early_init
void arch_early_init(void)
{
/* turn off the cache */
arch_disable_cache(UCACHE); // 关闭 cache
/* set the vector base to our exception vectors so we dont need to double map at 0 */
#if ARM_CPU_CORTEX_A8
set_vector_base(MEMBASE); //设置异常向量基地址
#endif
#if ARM_WITH_MMU
arm_mmu_init(); //初始化MMU
#endif
/* turn the cache back on */
arch_enable_cache(UCACHE); /*开启cache */
#if ARM_WITH_NEON
/* enable cp10 and cp11 */
/* 使能 cp10 和 cp11*/
uint32_t val;
__asm__ volatile("mrc p15, 0, %0, c1, c0, 2" : "=r" (val));
val |= (3<<22)|(3<<20);
__asm__ volatile("mcr p15, 0, %0, c1, c0, 2" :: "r" (val));
isb();
/* set enable bit in fpexc */
/*设置使能 fpexc 位(中断相关)*/
__asm__ volatile("mrc p10, 7, %0, c8, c0, 0" : "=r" (val));
val |= (1<<30);
__asm__ volatile("mcr p10, 7, %0, c8, c0, 0" :: "r" (val));
#endif
#if ARM_CPU_CORTEX_A8
/* enable the cycle count register */
/* 使能循环计数寄存器 */
uint32_t en;
__asm__ volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (en));
en &= ~(1<<3); /*循环计算每个周期*/
en |= 1; /* 启动所有的 performance 计数器 */
__asm__ volatile("mcr p15, 0, %0, c9, c12, 0" :: "r" (en));
/* enable cycle counter */
en = (1<<31);
__asm__ volatile("mcr p15, 0, %0, c9, c12, 1" :: "r" (en));
#endif
}
platform_early_init
void platform_early_init(void)
{
/* initialize the interrupt controller */
/*1.初始化中断*/
platform_init_interrupts();
/* initialize the timer block */
/*初始化定时器*/
platform_init_timer();
}
bootstrap2
static int bootstrap2(void *arg)
{
dprintf(SPEW, "top of bootstrap2()\n");
arch_init(); //此函数为空
// XXX put this somewhere else
#if WITH_LIB_BIO
bio_init();
#endif
#if WITH_LIB_FS
fs_init();
#endif
// initialize the rest of the platform
dprintf(SPEW, "initializing platform\n");
platform_init(); // 平台初始化,不同的平台要做的事情不一样,可以是初始化系统时钟,超频等
// initialize the target
dprintf(SPEW, "initializing target\n");
target_init(); //目标设备初始化,主要初始化Flash,整合分区表等
dprintf(SPEW, "calling apps_init()\n");
apps_init();//应用功能初始化,主要调用aboot_init,启动kernel,加载boot/recovery镜像等
return 0;
}
platform_init 中主要是函数 acpu_clock_init,在 acpu_clock_init 对 arm11 进行系统时钟设置,超频 。
target_init 针对硬件平台进行设置。主要对 arm9 和 arm11 的分区表进行整合,初始化flash和读取FLASH信息。
apps_init 是关键,对 LK 中所有 app 初始化并运行起来,而 aboot_init 就将在这里开始被运行,android linux 内核的加载工作就在 aboot_init 中完成的 。
void apps_init(void)
{
const struct app_descriptor *app;
/* call all the init routines */
for (app = &__apps_start; app != &__apps_end; app++) {
if (app->init) //如果app有init成员,就执行app->init
app->init(app);
}
/* start any that want to start on boot */
for (app = &__apps_start; app != &__apps_end; app++) {
if (app->entry && (app->flags & APP_FLAG_DONT_START_ON_BOOT) == 0) {
start_app(app);
}
}
}
apps_init()的逻辑很简单,可以猜测aboot_init一定是aboot->init,for循环轮到aboot的时候,就自然调用了aboot_init。
以下代码也证实了我们的猜测:
APP_START(aboot) // 增加一个name为aboot的app
.init = aboot_init, //该app的ini赋值为ab