Android lk启动流程

Andorid 7.1.1 lk启动流程

little kernel 是小内核小操作系统,简称lk,主要用来引导运行OS系统,lk启动后根据一些参数值,引导启动进入不同模式。其实Android手机有四种启动方式,四种方式分别为:

  1. 正常开机启动;
  2. recovery启动;
  3. fastboot启动;
  4. ffbm启动

下面就以高通代码为例,分析下这四种启动方式分别是在什么条件下启动的手机上电后,会从固定的地址(固化在ROM中)加载bootloader到RAM,然后跳转到bootloader的入口函数开始执行

bootable/bootloader/lk/arch/arm/crt0.S
blkmain

kmain的代码位于bootable/bootloader/lk/kernel/main.c

/* called from crt0.S */
void kmain(void) __NO_RETURN __EXTERNALLY_VISIBLE;
void kmain(void)
{
    thread_t *thr;

    // get us into some sort of thread context
    thread_init_early();  //初始化线程上下文

    // early arch stuff
    arch_early_init(); //架构初始化,如关闭cache,使能mmu

    // 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(); //lk系统控制器初始化

    // initialize kernel timers
    dprintf(SPEW, "initializing timers\n");
    timer_init(); //kernel时钟初始化

#if (!ENABLE_NANDWRITE)
    // 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);
    if (!thr)
    {
        panic("failed to create thread bootstrap2\n");
    }
    thread_resume(thr); //创建一个线程初始化系统


    // enable interrupts
    exit_critical_section(); //使能中断

    // become the idle thread
    thread_become_idle();//本线程切换成idle线程,idle为空闲线程,当没有更高优先级的线程时才执行
#else
bootstrap_nandwrite(); 
#endif
}

如果定义了ENABLE_NANDWRITE在timer_init之后将执行bootstrap_nandwrite。我们接下来先以没有定义ENABLE_NANDWRITE来进行分析。从代码可知,会创建一个bootstrap2线程,并使能中断

bootable/bootloader/lk/kernel/main.c
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();  //目标设备初始化,主要初始化Flash,整合分区表等

    dprintf(SPEW, "calling apps_init()\n");
    apps_init();   //应用功能初始化,主要调用boot_init,启动kernel,加载boot/recovery镜像等

    return 0;
}

在app.c中定义了apps_init如下:

bootable/bootloader/lk/app/app.c
/* one time setup */
void apps_init(void)
{
    const struct app_descriptor *app;

    /* call all the init routines */
    for (app = &__apps_start; app != &__apps_end; app++) {
        if (app->init)
            app->init(app);
    }

    /* start any that want to start on boot */
    for (app = &__apps_start; app != &__apps_end; app++) {
        if (app->entry && (app->flags & APP_FLAG_DONT_START_ON_BOOT) == 0) {
            start_app(app);
        }
    }
}

static void start_app(const struct app_descriptor *app)
{
    thread_t *thr;
    printf("starting app %s\n", app->name);

    thr = thread_create(app->name, &app_thread_entry, (void *)app, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
    if(!thr)
    {
        return;
    }
    thread_resume(thr);
}

__apps_start和__apps_end都是在连接脚本中定义的, 在 bootable/bootloader/lk/arch/arm/system-onesegment.ld中有:

__apps_start = .;
KEEP (*(.apps))
__apps_end = .;

__apps_start和__apps_end都代表两个链接地址,KEEP (*(.apps))表示所有.apps段都链接在__apps_start和__apps_end之间。
因为在bootable/bootloader/lk/include/app.h中有定义

bootable/bootloader/lk/include/app.h
#define APP_START(appname) struct app_descriptor _app_##appname __SECTION(".apps") = { .name = #appname,
#define APP_END };

所以这里将会执行在APP_START(appname)中定义的appname函数。在代码里搜索APP_START,会发现在bootable/bootloader/lk/app/aboot/aboot.c中调用APP_START来执行aboot_init函数

bootable/bootloader/lk/app/aboot/aboot.c
APP_START(aboot)
    .init = aboot_init,
APP_END

接下来就是这篇文章的重点aboot.c中的aboot_init,如下:

void aboot_init(const struct app_descriptor *app)
{
    unsigned reboot_mode = 0;
    unsigned hard_reboot_mode = 0;//bug 8046
    int ret;

    /* Initialise wdog to catch early lk crashes */
#if WDOG_SUPPORT
    msm_wdog_init();
#endif

    /* Setup page size information for nv storage */
    if (target_is_emmc_boot()) ////检测是emmc还是flash存储,并设置页大小,一般是2048
    {
        page_size = mmc_page_size();
        page_mask = page_size - 1;
        mmc_blocksize = mmc_get_device_blocksize();
        mmc_blocksize_mask = mmc_blocksize - 1;
    }
    else
    {
        page_size = flash_page_size();
        page_mask = page_size - 1;
    }
    ASSERT((MEMBASE + MEMSIZE) > MEMBASE); //断言,如果内存基地址+内存大小小于内存基地址,则直接终止错误

    read_device_info(&device); //从devinfo分区表read data到device结构体    
    read_allow_oem_unlock(&device); //devinfo分区里记录了unlock状态,从device中读取此信息



     if(target_enter_ffbm_mode()) //判断是否进入ffbm模式
    {
        boot_into_ffbm = true;
        dprintf(ALWAYS," gpio24 lcd te pull up  ------boot_into_ffbm----\n");
    }


    /* Display splash screen if enabled */
#if DISPLAY_SPLASH_SCREEN
#if NO_ALARM_DISPLAY
    if (!check_alarm_boot()) { //检测开机原因是否是由于关机闹钟导致
#endif
        dprintf(SPEW, "Display Init: Start\n");
#if DISPLAY_HDMI_PRIMARY
    if (!strlen(device.display_panel))
        strlcpy(device.display_panel, DISPLAY_PANEL_HDMI,
            sizeof(device.display_panel));
#endif
#if ENABLE_WBC
        /* Wait if the display shutdown is in progress */
        while(pm_app_display_shutdown_in_prgs());
        if (!pm_appsbl_display_init_done())
            target_display_init(device.display_panel); //显示splash,Splash也就是应用程序启动之前先启动一个画面,上面简单的介绍应用程序的厂商,厂商的LOGO,名称和版本等信息,多为一张图片 
        else
            display_image_on_screen();
#else
        target_display_init(device.display_panel);
#endif
        dprintf(SPEW, "Display Init: Done\n");
#if NO_ALARM_DISPLAY
    }
#endif
#endif

    target_serialno((unsigned char *) sn_buf);
    dprintf(SPEW,"serial number: %s\n",sn_buf);

    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()) //如果强制重启,直接进入normal_boot
        goto normal_boot;

    /* Check if we should do something other than booting up */
    if (keys_get_state(KEY_VOLUMEUP) && keys_get_state(KEY_VOLUMEDOWN))//同时按住音量上下键进入fastboot 模式
    {
        dprintf(ALWAYS,"dload mode key sequence detected\n");
        reboot_device(EMERGENCY_DLOAD);
        dprintf(CRITICAL,"Failed to reboot into dload mode\n");

        boot_into_fastboot = true;
    }
    if (keys_get_state(KEY_VOLUMEUP))  //按住音量上键进入recovery 模式
    {
        dprintf(ALWAYS,"KEY_VOLUMEUP------------------\n");
        boot_into_recovery = true;
    }

    if (keys_get_state(KEY_VOLUMEDOWN)) //按住音量下键进入fastboot 模式
    {
        dprintf(ALWAYS,"KEY_VOLUMEDOWN------------------\n");
        boot_into_fastboot = true;  
    }


    if (!boot_into_fastboot)
    {
        if (keys_get_state(KEY_HOME) || keys_get_state(KEY_VOLUMEUP))
            boot_into_recovery = 1;
        if (!boot_into_recovery &&
            (keys_get_state(KEY_BACK) /*|| keys_get_state(KEY_VOLUMEDOWN)*/)) 
            boot_into_fastboot = true;
    }
    #if NO_KEYPAD_DRIVER
    if (fastboot_trigger())
        boot_into_fastboot = true;
    #endif


    hard_reboot_mode = check_hard_reboot_mode();

    reboot_mode = check_reboot_mode();//检查重启原因
    dprintf(CRITICAL,"aboot_init  reboot_mode=%x,hard_reboot_mode=%x\n",reboot_mode,hard_reboot_mode);
    if (reboot_mode == RECOVERY_MODE || hard_reboot_mode == RECOVERY_HARD_RESET_MODE)
    {
        boot_into_recovery = 1;
    }
    else if(reboot_mode == FASTBOOT_MODE || hard_reboot_mode == FASTBOOT_HARD_RESET_MODE)
    {
        boot_into_fastboot = true;
    }
    else if(reboot_mode == ALARM_BOOT || hard_reboot_mode == RTC_HARD_RESET_MODE)
    {
        boot_reason_alarm = true;
    }

normal_boot:
    if (!boot_into_fastboot) //如果不是fastboot模式
    {

        if (target_is_emmc_boot())
        {
            if(emmc_recovery_init())
                dprintf(ALWAYS,"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(); //程序会跑到这里,又一个重点内容,下面会独立分析这个函数。
        }
        else
        {
            recovery_init();
    #if USE_PCOM_SECBOOT
        if((device.is_unlocked) || (device.is_tampered))
            set_tamper_flag(device.is_tampered);
    #endif
            boot_linux_from_flash();
        }
        dprintf(CRITICAL, "ERROR: Could not do normal boot. Reverting "
            "to fastboot mode.\n");
    }
     //下面的代码是fastboot的准备工作,从中可以看出,进入fastboot模式是不启动kernel的
    /* We are here means regular boot did not happen. Start fastboot. */

    /* register aboot specific fastboot commands */
    aboot_fastboot_register_commands();  //注册fastboot命令,建议看下此函数的源码,此函数是fastboot支持的命令,如flash、erase等等

    /* dump partition table for debug info */
    partition_dump();

    dprintf(0,"run in fastboot %s %s\r\n",__DATE__,__TIME__);
    display_image_on_screen_fastboot(); //显示fastboot界面
    /* initialize and start fastboot */
    fastboot_init(target_get_scratch_address(), target_get_max_flash_size());
#if FBCON_DISPLAY_MSG
    display_fastboot_menu();
#endif
}

从上面可以看出boot_init主要工作如下:

1、确定page_size大小;

2、从devinfo分区获取devinfo信息;

3、根据条件判断进入不同模式,设置对应标志位boot_into_xxx;

4、进入fastboot模式,初始化fastboot命令等

相关文章
相关标签/搜索