Android lk启动流程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yin1031468524/article/details/78984805

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命令等

猜你喜欢

转载自blog.csdn.net/yin1031468524/article/details/78984805