LK 初始化流程

LK的全称是litter kernel,同u-boot类似,它也是一种bootloader程序。

lk代码通常位于bootable/bootloader/lk目录,其树结构如下:
├── AndroidBoot.mk
├── app :lk中应用,如fastboot,shell等
├── arch :架构相关,如arm,x86等
├── dev :通用设备接口,如usb,lcm等
├── include :头文件
├── kernel :lk核心模块,包括thread,timer等
├── lib :–>一些c库
├── LICENSE
├── make :lk编译脚本
├── makefile
├── platform :不同平台/芯片对应的驱动
├── project :不同项目的makefile文件
├── scripts :JTAG脚本
├── target :具体目标设备的定义及初始化

lk主要完成以下工作:
1.初始化硬件,设置中断向量表,初始化MMU,Cache,USB等。
2.加载boot.img,引导系统启动。
3.对不同boot模式的支持,如fastboot,recovery,download mode等。

一、CPU初始化

1.1 链接文件

在链接脚本arch/arm/system-onesegment.ldarch/arm/system-twosegment.ld中定义了入口地址ENTRY:

1
2
3
4
5
6
7
ENTRY(_start)
SECTIONS
{
. = %MEMBASE%;
.text.boot : { *(.text.boot) }
...
}

1.2 汇编文件

在汇编文件arch/arm/crt0.S中定义了_start:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
//初始化向量表
.section ".text.boot"
.globl _start
_start:
b reset
b arm_undefined
b arm_syscall
b arm_prefetch_abort
b arm_data_abort
b arm_reserved
b arm_irq
b arm_fiq
...
//为irq,fiq等模式设置栈stack,最终切换到supervisor模式
.Lstack_setup:
mrs r0, cpsr
bic r0, r0, #0x1f

ldr r2, =abort_stack_top
orr r1, r0, #0x12 // irq
msr cpsr_c, r1
ldr r13, =irq_save_spot

orr r1, r0, #0x11 // fiq
msr cpsr_c, r1
mov sp, r2

orr r1, r0, #0x17 // abort
msr cpsr_c, r1
mov sp, r2

orr r1, r0, #0x1b // undefined
msr cpsr_c, r1
mov sp, r2

orr r1, r0, #0x1f // system
msr cpsr_c, r1
mov sp, r2

orr r1, r0, #0x13 // supervisor
msr cpsr_c, r1
mov sp, r2

ldr r0, =__data_start_rom
ldr r1, =__data_start
ldr r2, =__data_end

cmp r0, r1
beq .L__do_bss
...
//进入c代码入口kmain函数
bl kmain
b .
...

二、kmain初始化

C代码kernel/main.c的kmain函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
void kmain(void)
{
// 线程上下文初始化
thread_init_early();
// 架构初始化
arch_early_init();
// 超早期平台初始化
platform_early_init();
// 超早期目标设备初始化,预留空函数
target_early_init();
// 设置boot时间
// Qualcomm Platform
//bs_set_timestamp(BS_BL_START);
// 处理静态构造函数
call_constructors();
// 内核堆初始化
heap_init();
// 线程系统初始化
thread_init();
// 直接数字控制器初始化
dpc_init();
// 初始化内核定时器
timer_init();
#if (!ENABLE_NANDWRITE)
// 创建一个bootstrap2线程完成系统初始化
thread_t *thread_bs2 = thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
if (thread_bs2)
thread_resume(thread_bs2);
else {
assert(0);
}
// 使能中断
exit_critical_section();
// 成为闲置的线程
thread_become_idle();
#else
bootstrap_nandwrite();
#endif

2.1 thread_init_early函数

kernel/thread.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void thread_init_early(void)
{
int i;
// 初始化运行队列
for (i=0; i < NUM_PRIORITIES; i++)
list_initialize(&run_queue[i]);
// 初始化线程列表
list_initialize(&thread_list);
// 创建一个能cover当前运行状态的线程
thread_t *t = &bootstrap_thread;
init_thread_struct(t, "bootstrap");
// 线程已运行
t->priority = HIGHEST_PRIORITY;
t->state = THREAD_RUNNING;
t->saved_critical_section_count = 1;
list_add_head(&thread_list, &t->thread_list_node);
current_thread = t;
}

2.2 arch_early_init函数

arch/arm/arch.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
void arch_early_init(void)
{
// 关闭cache
arch_disable_cache(UCACHE);
#if ARM_CPU_CORTEX_A8
// 设置异常向量基地址,即在0处无需重复映射
set_vector_base(MEMBASE);
#endif
#if ARM_WITH_MMU
// MMU初始化
platform_init_mmu();
#endif
// 重新打开cache
arch_enable_cache(UCACHE);
#if ARM_WITH_NEON
// 启用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));
// 使能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
// 启用循环计数寄存器
uint32_t en;
__asm__ volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (en));
// 每轮循环计数
en &= ~(1<<3);
// 启用所有性能计数器
en |= 1;
__asm__ volatile("mcr p15, 0, %0, c9, c12, 0" :: "r" (en));
// 启用循环计数器
en = (1<<31);
__asm__ volatile("mcr p15, 0, %0, c9, c12, 1" :: "r" (en));
#endif
}

2.3 platform_early_init函数

platform/${PLATFORM}/platform.c

2.3.1 Qualcomm平台
1
2
3
4
5
6
7
8
9
10
11
12
13
void platform_early_init(void)
{
// 主板初始化
board_init();
// 平台时钟初始化
platform_clock_init();
// 初始化高通通用中断控制器
qgic_init();
// 高通定时器初始化
qtimer_init();
// 初始化安全通道管理
scm_init();
}

2.4 heap_init函数

lib/heap/heap.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void heap_init(void)
{
LTRACE_ENTRY;
// 设置堆范围
theheap.base = (void *)HEAP_START;
theheap.len = HEAP_LEN;
// 初始化释放列表
list_initialize(&theheap.free_list);
// 创建初始化释放块
heap_insert_free_chunk(heap_create_free_chunk(theheap.base, theheap.len));
// dump堆信息
//heap_dump();
//heap_test();
}

2.5 dpc_init函数

kernel/dpc.c

1
2
3
4
5
6
7
8
9
10
11
12
void dpc_init(void)
{
thread_t *thread_dpc;
event_init(&dpc_event, false, 0);
// 创建dpc线程
thread_dpc = thread_create("dpc", &dpc_thread_routine, NULL, DPC_PRIORITY, DEFAULT_STACK_SIZE);
if (thread_dpc)
thread_resume(thread_dpc);
else {
assert(0);
}
}

2.6 bootstrap2函数

kernel/main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static int bootstrap2(void *arg)
{
arch_init();
#if WITH_LIB_BIO
// bio初始化
bio_init();
#endif
#if WITH_LIB_FS
// fs初始化
fs_init();
#endif
// 从memory block中分配lk memory,在跳转到kernel之前释放
//mboot_allocate_lk_scratch_from_mblock();
// 初始化平台其余部分
platform_init();
// 初始化目标设备,如flash,partition等
target_init();
// 开始apps初始化
apps_init();
return 0;
}

三、app初始化

先来看看app/app.c文件的app_init定义。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void apps_init(void)
{
const struct app_descriptor *app;
// 调用所有初始化的例程
for (app = &__apps_start; app != &__apps_end; app++) {
if (app->init)
app->init(app);
}
// 启动所有boo时想启动的
for (app = &__apps_start; app != &__apps_end; app++) {
if (app->entry && (app->flags & APP_FLAG_DONT_START_ON_BOOT) == 0) {
start_app(app);
}
}
}

再搜索lk目录发现__apps_start__apps_end均在链接文件system-onesegment.lksystem-twosegment.lk有定义,KEEP (*(.apps))表示所有.apps段都定义在__apps_start__apps_end之间。

1
2
3
4
5
6
7
8
9
10
11
12
SECTIONS
{
...
.rodata : {
...
__apps_start = .;
KEEP (*(.apps))
__apps_end = .;
...
}
...
}

而头文件include/app.h中有对.apps段的定义,即此处会执行APP_START(appname)中的所有appname。再通过搜索APP_START即可发现在高通平台在app/aboot/aboot.c中有调用aboot_init函数,而联发科平台则在app/mt_boot/mt_boot.c中有调用mt_boot_init函数。

1
2
#define APP_START(appname) struct app_descriptor _app_##appname __SECTION(".apps") = { .name = #appname,
#define APP_END };