【AG35源代码分析】01 之 ql-ol-bootloader 源码分析

  • 一、ql-ol-bootloader 源码分析
    • 1.1 ql-ol-bootloader\arch\arm\crt0.S
    • 1.2 ql-ol-bootloader\kernel\main.c:kmain()
    • 1.3 ql-ol-bootloader\kernel\main.c:bootstrap2()

一、ql-ol-bootloader 源码分析

1.1 ql-ol-bootloader\arch\arm\crt0.S

crt0.S主要作用是:

  1. 初始化中断向量表
  2. 初始化CPU、MMU、Cache等相关配置
  3. 初始 BSS 栈,为运行C 代码创建环境
  4. 跳转进入kmain()开始运行C代码
@ ql-ol-bootloader\arch\arm\crt0.S.globl _start_start:bresetreset:    …… 做一系列的CPU、Cache、BSS 初始化操作……blkmainb.

1.2 ql-ol-bootloader\kernel\main.c:kmain()

主要工作如下:

  1. 初始化thread_list,当前线程命令为bootstrap
  2. 初始化mmu,关闭cache,初始化mmu,后再使能cache
  3. 获取platform平台硬件相关版本号等信息,保存在struct board_data board结构体中
  4. 初始化mdm_clocks_9607[]数组中的clock,如Uart5、Uart2、USB、ce1等clock
  5. 初始化通用中断控制器
  6. 初始化scm_call,主要是发送 IS_CALL_AVAIL_CMD 命令检查SCM功能能不能用
  7. 初始化UART调试口
  8. 初始化 heap 堆空间
  9. 生成一个随机数,保存在全局变量__stack_chk_guard中,用作栈顶填充使用
  10. 创建一个dpc 线程,线程中一直死循环等dpc_event event,然后处理 dpc cb函数
  11. 初始kernel timer_tick为10ms
  12. 创建bootstrap2线程,运行bootstrap2()函数
  13. 将当前线程设置为 idle线程,设置优先级为 LOWEST_PRIORITY=0

代码分析如下:

/* called from crt0.S */void kmain(void) __NO_RETURN __EXTERNALLY_VISIBLE;void kmain(void){// 初始化thread_list,当前线程命令为bootstrapthread_init_early();    // 关闭cache,初始化mmu后再使能cachearch_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.cvoid 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等clockplatform_clock_init();// 初始化通用中断控制器qgic_init();// 获取时钟频率 timer frequencyqtimer_init();// 初始化scm_call,主要是发送 IS_CALL_AVAIL_CMD 命令检查SCM功能能不能用scm_init();// 将DDR内存映射到MMUboard_ddr_detect();}<==========//初始化UART调试口target_early_init();    // do any super early target initializationdprintf(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 heapdprintf(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 systemdprintf(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 timersdprintf(SPEW, "initializing timers\n");timer_init();// 创建bootstrap2线程,运行bootstrap2()函数// create a thread to complete system initializationdprintf(SPEW, "creating bootstrap completion thread\n");thr = thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);thread_resume(thr);// enable interruptsexit_critical_section();// 将当前线程设置为 idle线程,设置优先级为 LOWEST_PRIORITY=0 , become the idle threadthread_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_BIObio_init();#endif#if WITH_LIB_FSfs_init();#endif// initialize the rest of the platformdprintf(SPEW, "initializing platform\n");platform_init();// initialize the targetdprintf(SPEW, "initializing target\n");target_init();dprintf(SPEW, "calling apps_init()\n");apps_init();return 0;}