位置:
bootloader/lk/app/aboot/aboot.c
在文件结尾有如下代码:
APP_START(aboot)
.init = aboot_init,
APP_END
看一下宏APP_START的定义
#define APP_START(appname) struct app_descriptor _app_##appname __SECTION(".apps") = { .name = #appname,
#define APP_END };
将上面的展开结果为:
struct app_descriptor _app_aboot = {
.name = aboot,
.init = aboot_init,
}
那么aboot_init是在什么地方调用的呢?
bootable/bootloader/lk/kernel/main.c
static int bootstrap2(void *arg){
···
apps_init();
···
}
这里主要看一下调用的顺序,详细过程查看代码:bootable/bootloader/lk/app/app.c
void apps_init(void)
{
/* call all the init routines */
for (app = &__apps_start; app != &__apps_end; app++) {
if (app->init)
app->init(app);//此处运行aboot_init函数。
}
}
简单介绍一下aboot_init这个函数
void aboot_init(const struct app_descriptor *app)
{
/* Setup page size information for nv storage */
//读取寄存器,查看是从emmc中启动设备
if (target_is_emmc_boot())
{
page_size = mmc_page_size();
page_mask = page_size - 1;
dprintf(CRITICAL,"liyang emmc boot\n");
}
//从devinfo/aboot分区中读取设备的属性
read_device_info(&device);
read_allow_oem_unlock(&device);
/* Display splash screen if enabled */
#if DISPLAY_SPLASH_SCREEN
#if NO_ALARM_DISPLAY
if (!check_alarm_boot()) {
#endif
//初始化显示模块,在这里面读取splash分区中的数据并且显示。
//这个地方还没有打开display,所以没有显示出来
dprintf(CRITICAL, "Display Init: liyang Start %s\n", device.display_panel);
target_display_init(device.display_panel);
dprintf(CRITICAL, "Display Init: liyang Done\n");
#if NO_ALARM_DISPLAY
}
#endif
#endif
//读取设备的序列号
target_serialno((unsigned char *) sn_buf);
//此处打开设备的显示,就能看到上面从splash读取出来的开机logo
qpnp_wled_set_level(gwled, QPNP_WLED_MAX_BR_LEVEL);
memset(display_panel_buf, '\0', MAX_PANEL_BUF_SIZE);
/*
* Check power off reason if user force reset,
* if yes phone will do normal boot.
*/
if (is_user_force_reset())
goto normal_boot;
//接下来就是检测按键,根据不同的组合方式进入升级或者ELoad模式(变砖)
/* Check if we should do something other than booting up */
if (keys_get_state(KEY_VOLUMEUP) && keys_get_state(KEY_BACK))
{
//Add by Skysoft start
}else if (keys_get_state(KEY_VOLUMEDOWN) && keys_get_state(KEY_BACK))
{
//Add by Skysoft end
}else{
}
normal_boot:
if (!boot_into_fastboot)//进入正常的开机流程
{
if (target_is_emmc_boot())
{
if(emmc_recovery_init())
dprintf(CRITICAL," liyang error in emmc_recovery_init\n");
if(target_use_signed_kernel())
{
if((device.is_unlocked) || (device.is_tampered))
{
#ifdef TZ_TAMPER_FUSE
set_tamper_fuse_cmd();
#endif
#if USE_PCOM_SECBOOT
set_tamper_flag(device.is_tampered);
#endif
}
}
boot_linux_from_mmc();
dprintf(CRITICAL, "liyang after boot_linux_from_mmc\n");
}
else//如果是升级过程失败会进入这个分支。
{
dprintf(CRITICAL, "liyang recovery_init\n");
recovery_init();//获取升级状态从而决定是进入recovery/boot
#if USE_PCOM_SECBOOT
if((device.is_unlocked) || (device.is_tampered))
set_tamper_flag(device.is_tampered);
#endif
boot_linux_from_flash();//根据recovery_init进入recovery/boot
}
}else//进入fastboot模式
/* We are here means regular boot did not happen. Start fastboot. */
/* register aboot specific fastboot commands */
aboot_fastboot_register_commands();//将fastboot中的命令注册进去。也可以从这里添加fastboot命令。也就是将命令存入到类型为struct fastboot_var的链表中。
/* dump partition table for debug info */
partition_dump();//将设备的分区信息读取出来
/* initialize and start fastboot */
fastboot_init(target_get_scratch_address(), target_get_max_flash_size());//初始化fastboot。包括usb的初始化。
#if FBCON_DISPLAY_MSG
display_fastboot_menu();//显示fastboot的菜单
#endif
}
下面看一下fastboot_init这个函数,这个函数主要就是注册一些事件,初始化USB,以及开启一个Thread去检测这些事件。
int fastboot_init(void *base, unsigned size){
thr = thread_create("fastboot", fastboot_handler, 0, DEFAULT_PRIORITY, 4096);
}
static int fastboot_handler(void *arg)
{
for (;;) {
event_wait(&usb_online);
fastboot_command_loop();
}
return 0;
}
static void fastboot_command_loop(void)
{
//申请一块cache
uint8_t *buffer = (uint8_t *)memalign(CACHE_LINE, ROUNDUP(4096, CACHE_LINE));
again:
while (fastboot_state != STATE_ERROR) {//开始读取USB中的数据,并且调用前面注册进来的处理函数。
r = usb_if.usb_read(buffer, MAX_RSP_SIZE);
fastboot_state = STATE_COMMAND;
for (cmd = cmdlist; cmd; cmd = cmd->next) {
if (memcmp(buffer, cmd->prefix, cmd->prefix_len))
continue;
cmd->handle((const char*) buffer + cmd->prefix_len,
(void*) download_base, download_size);//前面介绍中已经将cmd注册到链表中了。这里调用注册进来的函数。
if (fastboot_state == STATE_COMMAND)
fastboot_fail("unknown reason");
goto again;
}
fastboot_fail("unknown command");
}
fastboot_state = STATE_OFFLINE;
dprintf(INFO,"fastboot: oops!\n");
free(buffer);
}
这就是boot的启动流程。