MSM8909+Android5.1.1启动流程(3)---kmain()
1. thread_init_early()
// get us into some sort of thread context
thread_init_early();
让我们进入某种线程上下文,初始化线程系统,此函数只被调用一次。主要的工作如下:
(1) 初始化运行队列list_initialize(&run_queue[i])
(2) 初始化线程列表list_initialize(&thread_list)
(3) 创建一个线程来覆盖当前的运行状态,并初始化次线程的结构体。
/* create a thread to cover the currentrunning state */
thread_t*t = &bootstrap_thread;
init_thread_struct(t,"bootstrap");
/* half construct this thread, since we'realready running */
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. arch_early_init()
做一些关闭cache,使能MMU的arm相关工作。
void arch_early_init(void)
{
/*turn off the cache */
arch_disable_cache(UCACHE);
/*set the vector base to our exception vectors so we dont need to double map at 0*/
#if ARM_WITH_MMU
arm_mmu_init();
#endif
/*turn the cache back on */
arch_enable_cache(UCACHE);
#if ARM_WITH_NEON
/*enable cp10 and cp11 */
uint32_tval;
__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));
/*set enable bit in 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
}
3. platform_early_init()
平台的早期初始化
void platform_early_init(void)
{
board_init();
platform_clock_init();
qgic_init();
qtimer_init();
}
3.1 board_init()
void board_init()
{
platform_detect();
target_detect(&board);//对于msm8909是空函数,在platform_detect()实现
target_baseband_detect(&board);//填充board->baseband = BASEBAND_MSM;
}
platform_detect()
Smem:共享内存
struct smem {
structsmem_proc_comm proc_comm[4];
unsignedversion_info[32];
structsmem_heap_info heap_info;
structsmem_alloc_info alloc_info[SMEM_MAX_SIZE];
};
共享内存对应的结构体
SMEM :sharedmemory,是高通平台各子系统共享信息的一种机制,通过SMEM机制,PBL可以将信息传递给SBL1,SBL1可以将信息传递给RPM、LK。下面分析一个SMEM信息传递的具体实现过程。
Platform id信息
SBL1会将board levelplatform id信息通过SMEM机制保存,LK在启动过程中会自动platform detect,检测当前平台board infor信息,然后填充board结构体实例的值
struct board_data {
uint32_tplatform;
uint32_tfoundry_id;
uint32_tplatform_version;
uint32_tplatform_hw;
uint32_tplatform_subtype;
uint32_ttarget;
uint32_tbaseband;
structboard_pmic_data pmic_info[MAX_PMIC_DEVICES];
uint32_tplatform_hlos_subtype;
};
根据检测到的board infor加载相应的device tree。
3.2 platform_clock_init()
调用clk_init(msm_clocks_msm8909,ARRAY_SIZE(msm_clocks_msm8909))初始化时钟查询表
/* Clock lookup table */
static struct clk_lookup msm_clocks_msm8909[]=
{
CLK_LOOKUP("sdc1_iface_clk",gcc_sdcc1_ahb_clk.c),
CLK_LOOKUP("sdc1_core_clk", gcc_sdcc1_apps_clk.c),
CLK_LOOKUP("sdc2_iface_clk",gcc_sdcc2_ahb_clk.c),
CLK_LOOKUP("sdc2_core_clk", gcc_sdcc2_apps_clk.c),
CLK_LOOKUP("uart1_iface_clk",gcc_blsp1_ahb_clk.c),
CLK_LOOKUP("uart1_core_clk", gcc_blsp1_uart1_apps_clk.c),
…
}
3.3 qgic_init()
QGIC:Qualcomm GenericInterrupt Controller高通通用中断控制器
初始化QGIC,包括初始化QGIC的分配器(distributor)和初始化CPU具体的控制器。
3.4 qtimer_init()
获取定时器的频率
4. target_early_init()
这里就是串口初始化uart_dm_init(1, 0,BLSP1_UART0_BASE)---> uart_dm_init()
从时钟查找表msm_clocks_msm8909[]串口并配置其时钟频率、配置GPIO为串口、配置串口寄存器等。
5. bs_set_timestamp(BS_BL_START)
设置时间戳,这里的bs指boot stats,引导统计。
6. call_constructors()
构造函数相关初始化
bootloader的构造器一般完成的是初始化设备对象的操作,由于不同的系统在bootloader阶段需要初始化的设备不同,所以需要用户自己调用这些初始化函数。
根据函数名称,就是字面意思——调用构造器,构造器是定义在__ctor_list和__ctor_end之间的函数指针。至于__ctor_list和__ctor_end之间有哪些函数你可以看编译之后输出的map文件,或者链接脚本里面可能也有定义。
7. heap_init()
启动内核堆。
8. __stack_chk_guard_setup()
负责生成canary值
http://toutiao.com/a6244754891979129089/
9. thread_init()
初始化线程系统。
10. dpc_init()
dpc:DelayedProcedure Call 延迟过程调用的缩写,初始化dpc系统,相关事件初始化、创建名字为dpc的线程并调用。
11. timer_init()
初始化lk定时器。
12. bootstrap2
thread_resume(thread_create("bootstrap2",&bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
// enable interrupts
exit_critical_section();
// become the idle thread
thread_become_idle();
创建名字为bootstrap2的线程并调用,调用thread_become_idle()让当前线程处于idle状态。
后面接着学习线程bootstrap2。