A4. MTK开机流程

2020-08-06  本文已影响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!

上一篇 下一篇

猜你喜欢

热点阅读