美文网首页
A4. MTK开机流程

A4. MTK开机流程

作者: 拂去尘世尘 | 来源:发表于2020-08-06 16:23 被阅读0次

    preloader流程:

    路径: vendor/mediatek/proprietary/bootable/bootloader/preloader/platform/mt6761/src/core/main.c

    入口函数: main()

    void main(u32 *arg)
    {
        struct bldr_command_handler handler;
        u32 jump_addr, jump_arg;
    
        /* get the bldr argument */
        p_bldr_param = &bldr_param;
        memcpy((void *)p_bldr_param, (void *)*arg, sizeof(bl_param_t));
    
    /* 初始化uart*/
        mtk_uart_init(UART_SRC_CLK_FRQ, CFG_LOG_BAUDRATE);
    
    /* 平台硬件初始化platform_init()
     * 设置g_boot_mode初值NORMAL_BOOT
    */
    bldr_pre_process();
    
        handler.priv = NULL;
        handler.attr = 0;
        handler.cb   = bldr_cmd_handler;
    
    #if MT6370_PMU
        BOOTING_TIME_PROFILING_LOG("mtk db_pos discharge");
        mtk_dbpos_discharge();
    #endif
    
    //代码与平台设计相关
        BOOTING_TIME_PROFILING_LOG("before bldr_handshake");
        bldr_handshake(&handler);
        BOOTING_TIME_PROFILING_LOG("bldr_handshake");
    
    #if BOOTROM_INTEGRITY_CHECK
        /* if rom integrity check fails, device halts, so don't put it before bootloader
           handshake, this could make device bricked */
        rom_integrity_check();
    #endif
    
    #if !CFG_FPGA_PLATFORM
        /* security check */
        device_APC_dom_setup();
    #endif
        BOOTING_TIME_PROFILING_LOG("sec_boot_check");
    
    #if CFG_ATF_SUPPORT
        trustzone_pre_init();
        BOOTING_TIME_PROFILING_LOG("trustzone pre init");
    #endif
    
    #if (defined(MTK_AB_OTA_UPDATER) && !CFG_DRAM_CALIB_OPTIMIZATION)
        ab_ota_boot_check();
    #endif
    
    #if !(CFG_BYPASS_LOAD_IMG_FORCE_ATF)
        /* Do not load ATF, lk, load by JTAG */
        if (0 != bldr_load_images(&jump_addr)) {
            pal_log_err("%s Second Bootloader Load Failed\n", MOD);
    #if !CFG_BYPASS_EMI
            goto error;
    #endif
        }
    #else
        jump_addr = CFG_UBOOT_MEMADDR;
    #endif
        BOOTING_TIME_PROFILING_LOG("load images");
    
        bldr_post_process();
    #ifdef SLT
        mt_usb_phy_recover();
        //mu3d_hal_rst_dev();
    #endif
    
    #if CFG_ATF_SUPPORT
        trustzone_post_init();
        BOOTING_TIME_PROFILING_LOG("trustzone post init");
    #endif
    
    //获取lk地址,跳转到lk
    #if CFG_BOOT_ARGUMENT_BY_ATAG
        jump_arg = (u32)&(g_dram_buf->boottag);
    #else
        jump_arg = (u32)&bootarg;
    #endif
    
    
        /* 64S3,32S1,32S1 (MTK_ATF_BOOT_OPTION = 0)
         * re-loader jump to LK directly and then LK jump to kernel directly */
    #if CFG_ATF_SUPPORT
        pal_log_info("%s Others, jump to ATF\n", MOD);
        bldr_jump64(jump_addr, jump_arg, sizeof(boot_arg_t));
    #else
        bldr_jump(jump_addr, jump_arg, sizeof(boot_arg_t)); 
    #endif
    
    }
    

    总结preloader的功能:
    ① 硬件属性初始化
    ② 相关配置参数初始化
    ③ 安全检测
    ④ lk运行地址获取
    ⑤ 跳转到lk

    lk流程分析

    路径:vendor/mediatek/proprietary/bootable/bootloader/lk/kernel/main.c
    入口函数: kmain()

    void kmain(void)
    {
    #if !defined(MACH_FPGA) && !defined(SB_LK_BRINGUP)
        boot_time = get_timer(0);
    #endif
    
      /* 早起初始化线程池: 运行队列、线程链表建立等
       * lk架构支持多线程,当前仅有一个cpu运行,所以仅有一条代码执行顺序
       */
        thread_init_early();
    
        // early arch stuff
        arch_early_init();
    
        /* 平台初始化,包括irq,timer,wdt,uart,led,pmic等硬件平台*/
        platform_early_init();
    
    #if defined(MACH_FPGA) || defined(SB_LK_BRINGUP)
        boot_time = get_timer(0);
    #endif
    
        // do any super early target initialization
        target_early_init();
    
        dprintf(INFO, "welcome to lk\n\n");
    
        // deal with any static constructors
        dprintf(SPEW, "calling constructors\n");
        call_constructors();
    
        // bring up the kernel heap
        dprintf(SPEW, "initializing heap\n");
        heap_init();
    
        // 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();
    
    #ifdef  MTK_LK_IRRX_SUPPORT
       mtk_ir_init(0);
    #endif
    
    
    #if (!ENABLE_NANDWRITE)
        // create a thread to complete system initialization
        dprintf(SPEW, "creating bootstrap completion thread\n");
    /* 重新创建一个bootstrap2线程
     * 并执行bootstrap2线程
    */
        thread_t *thread_bs2 = thread_create("bootstrap2", &bootstrap2, NULL,
            DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
        if (thread_bs2)
            thread_resume(thread_bs2);
        else {
            dprintf(CRITICAL, "Error: Cannot create bootstrap2 thread!\n");
            assert(0);
        }
    
        thread_t *thread_io = thread_create("iothread", &iothread, NULL,
            IO_THREAD_PRIORITY, DEFAULT_STACK_SIZE);
        if (thread_io)
            thread_resume(thread_io);
        else {
            dprintf(CRITICAL, "Error: Cannot create I/O thread!\n");
            assert(0);
        }
    
        // enable interrupts
        exit_critical_section();
    
    /* 当前线程跑完便置于空闲状态 */
        // become the idle thread
        thread_become_idle();
    #else
            bootstrap_nandwrite();
    #endif
    }
    

    kmain:
    ① 初始化系统任务所需的线程、链表和相关队列。
    ② 初始化硬件平台,搭建lk基本运行环境
    ③ 初始化定时器等
    ④ 创建一个新线程bootstrap2,并执行。当前线程置于空闲状态

    bootstrap2():

    static int bootstrap2(void *arg)
    {
        dprintf(SPEW, "top of bootstrap2()\n");
    
        print_stack_of_current_thread();
    
        arch_init();
    
        // XXX put this somewhere else
    #if WITH_LIB_BIO
        bio_init();
    #endif
    #if WITH_LIB_FS
        fs_init();
    #endif
        // Allocate LK memory from mb, free before jump to kernel
        mboot_allocate_lk_scratch_from_mblock();
    
        // initialize the rest of the platform
        dprintf(SPEW, "initializing platform\n");
        platform_init();
    
        // initialize the target
        dprintf(SPEW, "initializing target\n");
        target_init();
    
        dprintf(SPEW, "calling apps_init()\n");
        apps_init();
    
        return 0;
    }
    

    bootstrap2():
    ① 初始化硬件
    ② 跳转到app_init()
    ③ 运行platform_init后,会更新g_boot_mode

    app_init:
    路径: vendor/mediatek/proprietary/bootable/bootloader/lk/app/app.c

    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);
            }
        }
    }
    

    这里start_app()会跳转到mt_boot_init
    APP_START(mt_boot)
    .init = mt_boot_init,
    APP_END

    mt_boot_init:
    路径: vendor/mediatek/proprietary/bootable/bootloader/lk/app/mt_boot/mt_boot.c

    void mt_boot_init(const struct app_descriptor *app)
    {
        unsigned usb_init = 0;
        unsigned sz = 0;
    #ifdef MTK_AB_OTA_UPDATER
        int ret;
    #endif
    
        set_serial_num();
    
        if (g_boot_mode == FASTBOOT)
            goto fastboot;
    
    #ifdef MTK_SECURITY_SW_SUPPORT
    #if MTK_FORCE_VERIFIED_BOOT_SIG_VFY
        /* verify oem image with android verified boot signature instead of mediatek proprietary signature */
        /* verification is postponed to boot image loading stage */
        /* note in this case, boot/recovery image will be verified even when secure boot is disabled */
        g_boot_state = BOOT_STATE_RED;
    #else
        if (0 != sec_boot_check(0))
            g_boot_state = BOOT_STATE_RED;
    #endif
    #endif
    
        /* Will not return */
        boot_linux_from_storage();
    
    fastboot:
        target_fastboot_init();
        if (!usb_init)
            udc_init(&surf_udc_device);
    
        mt_part_dump();
        sz = target_get_max_flash_size();
        fastboot_init(target_get_scratch_address(), sz);
        udc_start();
    
    }
    

    再次跳转到boot_linux_from_storage
    boot_linux_from_storage:
    路径: vendor/mediatek/proprietary/bootable/bootloader/lk/app/mt_boot/mt_boot.c

    int boot_linux_from_storage(void)
    {
        int ret = 0;
        uint32_t kernel_target_addr = 0;
        uint32_t ramdisk_target_addr = 0;
        uint32_t tags_target_addr = 0;
        uint32_t ramdisk_addr = 0;
        int32_t ramdisk_sz = 0;
        uint32_t ramdisk_real_sz = 0;
    
    #define CMDLINE_TMP_CONCAT_SIZE 110
        char cmdline_tmpbuf[CMDLINE_TMP_CONCAT_SIZE];
        switch (g_boot_mode) {
        case NORMAL_BOOT:
        case META_BOOT:
        case ADVMETA_BOOT:
        case SW_REBOOT:
        case ALARM_BOOT:
    #ifdef MTK_KERNEL_POWER_OFF_CHARGING
        case KERNEL_POWER_OFF_CHARGING_BOOT:
        case LOW_POWER_OFF_CHARGING_BOOT:
    #endif
            PROFILING_START("load boot image");
    #if defined(CFG_NAND_BOOT)
            snprintf(cmdline_tmpbuf, CMDLINE_TMP_CONCAT_SIZE, "%s%x%s%x",
                 NAND_MANF_CMDLINE, nand_flash_man_code, NAND_DEV_CMDLINE, nand_flash_dev_id);
            cmdline_append(cmdline_tmpbuf);
    #endif
            ret = load_vfy_boot(BOOTIMG_TYPE_BOOT, CFG_BOOTIMG_LOAD_ADDR);
    
            PROFILING_END();
            break;
    
        case RECOVERY_BOOT:
            /* it's boot.img when system as root is enabled, and is *
             * recovery.img when system as root is disabled. *
             */
            PROFILING_START("load recovery image");
    
            ret = load_vfy_boot(BOOTIMG_TYPE_RECOVERY, CFG_BOOTIMG_LOAD_ADDR);
    
            PROFILING_END();
            break;
    
        case FACTORY_BOOT:
        case ATE_FACTORY_BOOT:
            /* it's boot.img, we don't have standalone factory image now */
            PROFILING_START("load factory image");
    #if defined(CFG_NAND_BOOT)
            snprintf(cmdline_tmpbuf, CMDLINE_TMP_CONCAT_SIZE, "%s%x%s%x",
                 NAND_MANF_CMDLINE, nand_flash_man_code, NAND_DEV_CMDLINE, nand_flash_dev_id);
            cmdline_append(cmdline_tmpbuf);
    #endif
            ret = load_vfy_boot(BOOTIMG_TYPE_BOOT, CFG_BOOTIMG_LOAD_ADDR);
    
            PROFILING_END();
            break;
    
        case FASTBOOT:
        case DOWNLOAD_BOOT:
        case UNKNOWN_BOOT:
            break;
    
        }
    
        kernel_target_addr = get_kernel_target_addr();
        ramdisk_target_addr = get_ramdisk_target_addr();
        ramdisk_addr = get_ramdisk_addr();
        ramdisk_sz = get_ramdisk_sz();
        ramdisk_real_sz = get_ramdisk_real_sz();
        tags_target_addr = get_tags_addr();
    
        PAL_ASSERT(kernel_target_addr != 0);
        PAL_ASSERT(ramdisk_target_addr != 0);
        PAL_ASSERT(ramdisk_addr != 0);
    #ifndef SYSTEM_AS_ROOT
        PAL_ASSERT(ramdisk_sz != 0);
        PAL_ASSERT(ramdisk_real_sz != 0);
    #endif
    
    #ifdef MTK_3LEVEL_PAGETABLE
        /* rootfs addr */
        arch_mmu_map((uint64_t)ramdisk_target_addr,
            (uint32_t)ramdisk_target_addr,
            MMU_MEMORY_TYPE_NORMAL_WRITE_BACK | MMU_MEMORY_AP_P_RW_U_NA,
            ROUNDUP(ramdisk_sz, PAGE_SIZE));
    #endif
        /* relocate rootfs */
        memcpy((void *)ramdisk_target_addr,
            (void *)ramdisk_addr,
            (size_t)ramdisk_real_sz);
    
        // 2 weak function for mt6572 memory preserved mode
        platform_mem_preserved_load_img();
        platform_mem_preserved_dump_mem();
    
        custom_port_in_kernel(g_boot_mode, cmdline_get());
    
        snprintf(cmdline_tmpbuf, CMDLINE_TMP_CONCAT_SIZE, "%s", get_cmdline());
        cmdline_append(cmdline_tmpbuf);
    
    #ifdef SELINUX_STATUS
    #if SELINUX_STATUS == 1
        cmdline_append("androidboot.selinux=disabled");
    #elif SELINUX_STATUS == 2
        cmdline_append("androidboot.selinux=permissive");
    #endif
    #endif
    
        /* This is patch for Android Test Mode(ATM). */
        /* 1. Sets kernel cmdline for ATM only in normal mode
        * 2. Bypass write protect in boot mode "normal" when ATM is enabled.
        * Background:
        * "proinfo" partition is write protected in boot mode "normal". When ATM is enabled,
        * we bypass write protection since we needs to write to proinfo. Whether device is in ATM
        * should also be passed to kernel through cmdline, only seen in normal mode
        */
        if (g_boot_mode == NORMAL_BOOT) {
            if (true == get_atm_enable_status()) {
                cmdline_append("androidboot.atm=enable");
            } else if (false == get_atm_enable_status()) {
                write_protect_flow();
                cmdline_append("androidboot.atm=disabled");
            }
        }
    
        /* pass the meta_log_disable to user space logger, default is enable */
        if (is_meta_log_disable && (is_meta_log_disable() == 1)) {
            cmdline_append("androidboot.meta_log_disable=1");
        } else {
            cmdline_append("androidboot.meta_log_disable=0");
        }
    
        /* pass related root of trust info via SMC call */
        if (send_root_of_trust_info != NULL)
            send_root_of_trust_info();
    
        boot_linux((void *)kernel_target_addr,
                (unsigned *)tags_target_addr,
                board_machtype(),
                (void *)ramdisk_target_addr,
                ramdisk_real_sz);
    
        while (1);
    
        return 0;
    }
    

    boot_linux_from_storage主要功能:
    ① 根据g_boot_mode值加载相应的模式地址运行。例如g_boot_mode为FACTORY_BOOT、 ATE_FACTORY_BOOT跳转到Factory代码地址,为RECOVERY_BOOT则加载recovery代码地址。
    ② 如果没有检测到需要进入其他模式,则正常运行。
    注:所以需要更换进入factory模式,或者recovery模式,只需要在之前代码位置添加一个条件,然后将g_boot_mode值置为RECOVERY_BOOT。例:
    if(SOS键被按下){
    g_boot_mode = RECOVERY_BOOT; //覆盖掉之前的值
    }

    boot_linux:
    路径:vendor/mediatek/proprietary/bootable/bootloader/lk/app/mt_boot/mt_boot.c

    void boot_linux(void *kernel, unsigned *tags,
            unsigned machtype,
            void *ramdisk, unsigned ramdisk_sz)
    {
        int i;
    ……
        boot_linux_fdt((void *)kernel, (unsigned *)tags,
                   machtype,
                   (void *)ramdisk, ramdisk_sz);
    
        while (1) ;
    ……
    }
    

    boot_linux_fdt:
    路径:vendor/mediatek/proprietary/bootable/bootloader/lk/app/mt_boot/mt_boot.c
    进入内核的最后一道工序。

        boot_linux_fdt((void *)kernel, (unsigned *)tags,
                   machtype,
                   (void *)ramdisk, ramdisk_sz)
    {
      //1.解析dtb设备树
      //2.搭建内核运行环境
      //3.检测一些进入内核条件
    }
    

    正式进入kernel!

    相关文章

      网友评论

          本文标题:A4. MTK开机流程

          本文链接:https://www.haomeiwen.com/subject/unxtdktx.html