【AG35源代码分析】01 之 ql-ol-bootloader 源码分析
一、ql-ol-bootloader 源码分析
1.1 ql-ol-bootloader\arch\arm\crt0.S
crt0.S主要作用是:
- 初始化中断向量表
- 初始化CPU、MMU、Cache等相关配置
- 初始 BSS 栈,为运行C 代码创建环境
- 跳转进入kmain()开始运行C代码
@ ql-ol-bootloader\arch\arm\crt0.S
.globl _start
_start:
b reset
reset:
…… 做一系列的CPU、Cache、BSS 初始化操作……
bl kmain
b .
1.2 ql-ol-bootloader\kernel\main.c:kmain()
主要工作如下:
- 初始化thread_list,当前线程命令为bootstrap
- 初始化mmu,关闭cache,初始化mmu,后再使能cache
- 获取platform平台硬件相关版本号等信息,保存在struct board_data board结构体中
- 初始化mdm_clocks_9607[]数组中的clock,如Uart5、Uart2、USB、ce1等clock
- 初始化通用中断控制器
- 初始化scm_call,主要是发送 IS_CALL_AVAIL_CMD 命令检查SCM功能能不能用
- 初始化UART调试口
- 初始化 heap 堆空间
- 生成一个随机数,保存在全局变量__stack_chk_guard中,用作栈顶填充使用
- 创建一个dpc 线程,线程中一直死循环等dpc_event event,然后处理 dpc cb函数
- 初始kernel timer_tick为10ms
- 创建bootstrap2线程,运行bootstrap2()函数
- 将当前线程设置为 idle线程,设置优先级为 LOWEST_PRIORITY=0
代码分析如下:
/* called from crt0.S */
void kmain(void) __NO_RETURN __EXTERNALLY_VISIBLE;
void kmain(void){
// 初始化thread_list,当前线程命令为bootstrap
thread_init_early();
// 关闭cache,初始化mmu后再使能cache
arch_early_init();
==========> // ql-ol-bootloader\arch\arm\arch.c
{
arch_disable_cache(UCACHE); /* turn off the cache */
arm_mmu_init();
arch_enable_cache(UCACHE); /* turn the cache back on */
}
<==========
platform_early_init();
==========> // ql-ol-bootloader\platform\mdm9607\platform.c
void platform_early_init(void)
{
board_init();
--------->
// 获取主板SMEM_BOARD_INFO_LOCATION区域的major minor info,
// 初始化static struct board_data board结构体,如主板、平台、硬件、PMIC相关信息
platform_detect();
target_detect(&board);
target_baseband_detect(&board);
<---------
// 初始化mdm_clocks_9607[]数组中的clock,如Uart5、Uart2、USB、ce1等clock
platform_clock_init();
// 初始化通用中断控制器
qgic_init();
// 获取时钟频率 timer frequency
qtimer_init();
// 初始化scm_call,主要是发送 IS_CALL_AVAIL_CMD 命令检查SCM功能能不能用
scm_init();
// 将DDR内存映射到MMU
board_ddr_detect();
}
<==========
//初始化UART调试口
target_early_init(); // do any super early target initialization
dprintf(INFO, "welcome to lk\n\n");
bs_set_timestamp(BS_BL_START);
dprintf(SPEW, "calling constructors\n");
// 依次调用__ctor_list 中的所有初始化函数,调用C++的构造函数,此处忽略
call_constructors();
// 初始化 heap 堆空间,bring up the kernel heap
dprintf(SPEW, "initializing heap\n");
heap_init();
// 生成一个随机数,保存在全局变量__stack_chk_guard中,
// 它的作用为,在调用子函数时,会将__stack_chk_guard值保存在栈顶,
// 当子函数返回时,再读出这个值,如果相等,则正常返回,如果不相等,则可以判断存在栈溢出,
// 调用__stack_chk_fail() 直接宕机,由于它是随机生成的随机数,所以相对安全。
__stack_chk_guard_setup();
dprintf(SPEW, "initializing threads\n");
thread_init(); // initialize the threading system
// 创建一个dpc 线程,线程中一直死循环等dpc_event event,然后处理 dpc cb函数
// initialize the dpc system
dprintf(SPEW, "initializing dpc\n");
dpc_init();
=========>
thr = thread_create("dpc", &dpc_thread_routine, NULL, DPC_PRIORITY, DEFAULT_STACK_SIZE);
// 初始kernel timer_tick为10ms, initialize kernel timers
dprintf(SPEW, "initializing timers\n");
timer_init();
// 创建bootstrap2线程,运行bootstrap2()函数
// create a thread to complete system initialization
dprintf(SPEW, "creating bootstrap completion thread\n");
thr = thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
thread_resume(thr);
// enable interrupts
exit_critical_section();
// 将当前线程设置为 idle线程,设置优先级为 LOWEST_PRIORITY=0 , become the idle thread
thread_become_idle();
}
1.3 ql-ol-bootloader\kernel\main.c: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();
dprintf(SPEW, "calling apps_init()\n");
apps_init();
return 0;
}