andoid的启动过程
通过audio口所吐出的log,我们可以发现android的启动还是非常之有趣的,因而在此对它的启动做相应的分析。
在此分析LK的启动过程,LK就是bootloader。
现在只截取一部分的Log
[0] welcome to lk
[10] platform_init()
[10] target_init()
[60] SDHC Running in HS400 mode
[60] Done initialization of the card
[70] pm8x41_get_is_cold_boot: Warm boot
[70] Unsupported platform id
[70] Qseecom Init Done in Appsbl
[70] secure app region addr=0x85b00000 size=0x800000[80] TZ App region notif returned with status:0 addr:85b00000 size:8388608
[90] TZ App log region register returned with status:0 addr:8f6a9000 size:4096
[90] Qseecom TZ Init Done in Appsbl
[100] Loading cmnlib done
[110] qseecom_start_app: Loading app keymaster for the first time'
[120] <8>keymaster: "\"KEYMASTER Init \""
[130] Waiting for the RPM to populate smd channel table
现在可以根据这部分的log来看LK是如何加载的。
当android加载完fileware时,LK会通过crt0.s的跳转命令,跳转到main.c中的kmain函数中去。
#ifdef ARM_CPU_CORTEX_A8
DSB
ISB
#endif
bl kmain
b .
.ltorg
那么kmain又做了什么?
/* called from crt0.S */
void kmain(void) __NO_RETURN __EXTERNALLY_VISIBLE;
void kmain(void)
{
// get us into some sort of thread context
thread_init_early();
// early arch stuff
arch_early_init();
// do any super early platform initialization
platform_early_init();
// do any super early target initialization
target_early_init();
dprintf(INFO, "welcome to lk\n\n");
bs_set_timestamp(BS_BL_START);
// deal with any static constructors
dprintf(SPEW, "calling constructors\n");
call_constructors();
// bring up the kernel heap
dprintf(SPEW, "initializing heap\n");
heap_init();
__stack_chk_guard_setup();
// initialize the threading system
dprintf(SPEW, "initializing threads\n");
thread_init();
// initialize the dpc system
dprintf(SPEW, "initializing dpc\n");
dpc_init();
// initialize kernel timers
dprintf(SPEW, "initializing timers\n");
timer_init();
#if (!ENABLE_NANDWRITE)
// create a thread to complete system initialization
dprintf(SPEW, "creating bootstrap completion thread\n");
thread_resume(thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
// enable interrupts
exit_critical_section();
// become the idle thread
thread_become_idle();
#else
bootstrap_nandwrite();
#endif
}
在这里,我们充分看到了Lk在kmain()中做了大量的初始化动作,其中thread_init_early()主要的工作是初始化线程系统,就是创建队列,然后系统根据CPU的不同架构进入不同的init线程
/**
* @brief Initialize threading system
*
* This function is called once, from kmain()
*/
void thread_init_early(void)
{
int i;
/* initialize the run queues */
for (i=0; i < NUM_PRIORITIES; i++)
list_initialize(&run_queue[i]);
/* initialize the thread list */
list_initialize(&thread_list);
/* create a thread to cover the current running state */
thread_t *t = &bootstrap_thread;
init_thread_struct(t, "bootstrap");
/* half construct this thread, since we're already 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;
}
arch_early_init()函数,一般采用的高通的芯片,因而会导向lk/arch/arm/arch.c,那么其主要的工作设置基本CPU属性
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_CPU_CORTEX_A8
set_vector_base(MEMBASE);
#endif
#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_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 */
__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); /* cycle count every cycle */
en |= 1; /* enable all performance counters */
__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
}
/lk/platform/msmtitanium/platform.c中的platform_early_init()首先会调用board_init(),它会去调用lk/platform/msm_shared/board.c中的Platform_detect函数来检测平台信息,平台信息包含主要信息(format_major)与次要信息(format_minor)。通过信息来初始化平台版本\hw\type,lk/target/msmtitanium/init.c中target_detect()不做任何事情,而target_baseband_detect函数会测试modem type
void platform_early_init(void)
{
board_init();
platform_clock_init();
qgic_init();
qtimer_init();
scm_init();
}
platform_clock_init会初始化一些时钟信息,qgic_init(void)初始化qgic(qgic是什么?),qtimer_init()提供初始化频率,scm_init()是scm的初始化函数(表示小编并不了解什么是scm机制)
target_early_init()函数是对串口的初始化,因而此时可以看到lk的第一条log:welcome to lk,后面的几个函数就是对一些时序,状态等等的初始化。