MTK lk源码解析7( lk 阶段aboot.c 解析)

http://blog.csdn.net/xichangbao/article/details/51484627


  1. boot_linux()。
typedef void entry_func_ptr(unsigned, unsigned, unsigned*);
void boot_linux(void *kernel, unsigned *tags,
        const char *cmdline, unsigned machtype,
        void *ramdisk, unsigned ramdisk_size)
{
    unsigned char *final_cmdline;
#if DEVICE_TREE
    int ret = 0;
#endif

    void (*entry)(unsigned, unsigned, unsigned*) = (entry_func_ptr*)(PA((addr_t)kernel)); // 将kernel的起始内存地址转化成entry_func_ptr函数类型 ;  在C语言中规定,一个函数总是占用一段连续的内存区,而函数名就是该函数所占内存区的首地址;对这一块c代码感到困惑,反汇编后看了下汇编代码,逻辑是没有问题的。

    uint32_t tags_phys = PA((addr_t)tags);
    struct kernel64_hdr *kptr = (struct kernel64_hdr*)kernel;

    ramdisk = (void *)PA((addr_t)ramdisk);

    final_cmdline = update_cmdline((const char*)cmdline); // 更新cmdline,这里可以动态增加修改默认cmdline的内容

#if DEVICE_TREE
    dprintf(INFO, "Updating device tree: start\n");

    /* Update the Device Tree */
    ret = update_device_tree((void *)tags,(const char *)final_cmdline, ramdisk, ramdisk_size); // 更新device tree内容,主要是三部分:memory,cmdline,ramdisk
    if(ret)
    {
        dprintf(CRITICAL, "ERROR: Updating Device Tree Failed \n");
        ASSERT(0);
    }
    dprintf(INFO, "Updating device tree: done\n");
#else
    /* Generating the Atags */
    generate_atags(tags, final_cmdline, ramdisk, ramdisk_size); // Atags已经基本被废弃
#endif

    free(final_cmdline); // 由于cmdline内容已经打包进device tree中,这里可以释放cmdline临时占用的内存

#if VERIFIED_BOOT
    /* Write protect the device info */
    if (target_build_variant_user() && mmc_write_protect("devinfo", 1)) // 对devinfo分区写保护,注意 devinfo分区的起始地址和大小,避免写保护越界
    {
        dprintf(INFO, "Failed to write protect dev info\n");
        ASSERT(0);
    }
#endif

    /* Perform target specific cleanup */
    target_uninit(); // 完成目标板级清除动作

    /* Turn off splash screen if enabled */
#if DISPLAY_SPLASH_SCREEN
    target_display_shutdown(); // 关闭lcd
#endif


    dprintf(INFO, "booting linux @ %p, ramdisk @ %p (%d), tags/device tree @ %p\n",
        entry, ramdisk, ramdisk_size, (void *)tags_phys);

    enter_critical_section(); // 关闭中断

    /* do any platform specific cleanup before kernel entry */
    platform_uninit();  // 完成平台级清除动作

    arch_disable_cache(UCACHE); // 禁用cache

#if ARM_WITH_MMU
    arch_disable_mmu(); // 关闭mmu
#endif
    bs_set_timestamp(BS_KERNEL_ENTRY); // 设置kernel入口时间戳

    if (IS_ARM64(kptr))
        /* Jump to a 64bit kernel */
        scm_elexec_call((paddr_t)kernel, tags_phys); // 64位kernel
    else
        /* Jump to a 32bit kernel */
        entry(0, machtype, (unsigned*)tags_phys); // 32位kernel直接跳转到kernel入口函数执行;r0 = 0; r1 =  machtype; r2 = device tree的物理内存地址
}


  1. scm_elexec_call()。
void scm_elexec_call(paddr_t kernel_entry, paddr_t dtb_offset)
{
    uint32_t svc_id = SCM_SVC_MILESTONE_32_64_ID; // 标志从lk的32位切换到kernel的64位
    uint32_t cmd_id = SCM_SVC_MILESTONE_CMD_ID;
    void *cmd_buf;
    size_t cmd_len;
    static el1_system_param param __attribute__((aligned(0x1000)));
    scmcall_arg scm_arg = {0};

    param.el1_x0 = dtb_offset; // device tree的物理内存地址
    param.el1_elr = kernel_entry; // kernel入口的物理内存地址

    /* Response Buffer = Null as no response expected */
    dprintf(INFO, "Jumping to kernel via monitor\n");

    if (!is_scm_armv8_support())
    {
        /* Command Buffer */
        cmd_buf = (void *)&param;
        cmd_len = sizeof(el1_system_param);

        scm_call(svc_id, cmd_id, cmd_buf, cmd_len, NULL, 0); // Secure Monitor Call
    }
    else
    {
        scm_arg.x0 = MAKE_SIP_SCM_CMD(SCM_SVC_MILESTONE_32_64_ID, SCM_SVC_MILESTONE_CMD_ID); // scm命令
        scm_arg.x1 = MAKE_SCM_ARGS(0x2, SMC_PARAM_TYPE_BUFFER_READ); // scm参数
        scm_arg.x2 = (uint32_t ) &param; // EL1的系统参数
        scm_arg.x3 = sizeof(el1_system_param); //  EL1的系统参数的大小

        scm_call2(&scm_arg, NULL); // Secure Monitor Call;传递合适的参数,最终通过smc #0指令切换到TrustZone模式完成到kernel的跳转,由于tz没有源码,其具体实现就不清楚了
    }

    /* Assert if execution ever reaches here */
    dprintf(CRITICAL, "Failed to jump to kernel\n");
    ASSERT(0);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值