Android启动流程分析之二:内核的引导

FROM:https://blog.youkuaiyun.com/ffmxnjm/article/details/70598711

http://blog.youkuaiyun.com/ly890700/article/details/54586465

 

 

继续以c6(mido)的代码为例

由于目前大部分手机不再使用nand flash,取而代之的是emmc,因此启动内核的实现以boot_linux_from_mmc为例分析。

 

 

 

一 boot_linux_from_mmc

boot_linux_from_mmc函数主要负责根据boot_into_xxx从对应的分区内读取相关信息并传给kernel,然后引导kernel。

boot_linux_from_mmc()函数的工作主要有: 

1).程序会从boot分区或者recovery分区的header中读取地址等信息,然后把kernel、ramdisk加载到内存中。

2).程序会从misc分区中读取bootloader_message结构体,如果有boot-recovery,则进入recovery模式

3).更新cmdline,然后把cmdline写到tags_addr地址,把参数传给kernel,kernel起来以后会到这个地址读取参数。

执行到boot_linux_from_mmc函数这里,说明这次启动不进入fastboot模式,可能的情况有:正常启动,进入recovery,开机闹钟启动。

bootable/bootloader/lk/app/aboot/aboot.c Collapse source

int boot_linux_from_mmc(void)

{

    struct boot_img_hdr *hdr = (void*) buf;

    struct boot_img_hdr *uhdr;

    unsigned offset = 0;

    int rcode;

    unsigned long long ptn = 0;

    int index = INVALID_PTN;

    unsigned char *image_addr = 0;

    unsigned kernel_actual;

    unsigned ramdisk_actual;

    unsigned imagesize_actual;

    unsigned second_actual = 0;

    unsigned int dtb_size = 0;

    unsigned int out_len = 0;

    unsigned int out_avai_len = 0;

    unsigned char *out_addr = NULL;

    uint32_t dtb_offset = 0;

    unsigned char *kernel_start_addr = NULL;

    unsigned int kernel_size = 0;

    int rc;

#if DEVICE_TREE

    struct dt_table *table;

    struct dt_entry dt_entry;

    unsigned dt_table_offset;

    uint32_t dt_actual;

    uint32_t dt_hdr_size;

    unsigned char *best_match_dt_addr = NULL;

#endif

    struct kernel64_hdr *kptr = NULL;

    if (check_format_bit())

        boot_into_recovery = 1;

    if (!boot_into_recovery) {

        memset(ffbm_mode_string, '\0'sizeof(ffbm_mode_string));

        rcode = get_ffbm(ffbm_mode_string, sizeof(ffbm_mode_string));

        if (rcode <= 0) {

            boot_into_ffbm = false;

            if (rcode < 0)

                dprintf(CRITICAL,"failed to get ffbm cookie");

        else

            boot_into_ffbm = true;

    else

        boot_into_ffbm = false;

    uhdr = (struct boot_img_hdr *)EMMC_BOOT_IMG_HEADER_ADDR;

    if (!memcmp(uhdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {

        dprintf(INFO, "Unified boot method!\n");

        hdr = uhdr;

        goto unified_boot;

    }

    if (!boot_into_recovery) {

        index = partition_get_index("boot");

        ptn = partition_get_offset(index);

        if(ptn == 0) {

            dprintf(CRITICAL, "ERROR: No boot partition found\n");

                    return -1;

        }

    }

    else {

        index = partition_get_index("recovery");

        ptn = partition_get_offset(index);

        if(ptn == 0) {

            dprintf(CRITICAL, "ERROR: No recovery partition found\n");

                    return -1;

        }

    }

    /* Set Lun for boot & recovery partitions */

    mmc_set_lun(partition_get_lun(index));

    if (mmc_read(ptn + offset, (uint32_t *) buf, page_size)) {

        dprintf(CRITICAL, "ERROR: Cannot read boot image header\n");

                return -1;

    }

    if (memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {

        dprintf(CRITICAL, "ERROR: Invalid boot image header\n");

                return -1;

    }

    if (hdr->page_size && (hdr->page_size != page_size)) {

        if (hdr->page_size > BOOT_IMG_MAX_PAGE_SIZE) {

            dprintf(CRITICAL, "ERROR: Invalid page size\n");

            return -1;

        }

        page_size = hdr->page_size;

        page_mask = page_size - 1;

    }

    /* ensure commandline is terminated */

    hdr->cmdline[BOOT_ARGS_SIZE-1] = 0;

    kernel_actual  = ROUND_TO_PAGE(hdr->kernel_size,  page_mask);

    ramdisk_actual = ROUND_TO_PAGE(hdr->ramdisk_size, page_mask);

    image_addr = (unsigned char *)target_get_scratch_address();

#if DEVICE_TREE

    dt_actual = ROUND_TO_PAGE(hdr->dt_size, page_mask);

    if (UINT_MAX < ((uint64_t)kernel_actual + (uint64_t)ramdisk_actual+ (uint64_t)dt_actual + page_size)) {

        dprintf(CRITICAL, "Integer overflow detected in bootimage header fields at %u in %s\n",__LINE__,__FILE__);

        return -1;

    }

    imagesize_actual = (page_size + kernel_actual + ramdisk_actual + dt_actual);

#else

    if (UINT_MAX < ((uint64_t)kernel_actual + (uint64_t)ramdisk_actual + page_size)) {

        dprintf(CRITICAL, "Integer overflow detected in bootimage header fields at %u in %s\n",__LINE__,__FILE__);

        return -1;

    }

    imagesize_actual = (page_size + kernel_actual + ramdisk_actual);

#endif

#if VERIFIED_BOOT

    boot_verifier_init();

#endif

    if (check_aboot_addr_range_overlap((uintptr_t) image_addr, imagesize_actual))

    {

        dprintf(CRITICAL, "Boot image buffer address overlaps with aboot addresses.\n");

        return -1;

    }

    /*

     * Update loading flow of bootimage to support compressed/uncompressed

     * bootimage on both 64bit and 32bit platform.

     * 1. Load bootimage from emmc partition onto DDR.

     * 2. Check if bootimage is gzip format. If yes, decompress compressed kernel

     * 3. Check kernel header and update kernel load addr for 64bit and 32bit

     *    platform accordingly.

     * 4. Sanity Check on kernel_addr and ramdisk_addr and copy data.

     */

    dprintf(INFO, "Loading (%s) image (%d): start\n",

            (!boot_into_recovery ? "boot" "recovery"),imagesize_actual);

    bs_set_timestamp(BS_KERNEL_LOAD_START);

    if ((target_get_max_flash_size() - page_size) < imagesize_actual)

    {

        dprintf(CRITICAL, "booimage  size is greater than DDR can hold\n");

        return -1;

    }

    /* Read image without signature */

    if (mmc_read(ptn + offset, (void *)image_addr, imagesize_actual))

    {

        dprintf(CRITICAL, "ERROR: Cannot read boot image\n");

        return -1;

    }

    dprintf(INFO, "Loading (%s) image (%d): done\n",

            (!boot_into_recovery ? "boot" "recovery"),imagesize_actual);

    bs_set_timestamp(BS_KERNEL_LOAD_DONE);

    /* Authenticate Kernel */

    dprintf(INFO, "use_signed_kernel=%d, is_unlocked=%d, is_tampered=%d.\n",

        (int) target_use_signed_kernel(),

        device.is_unlocked,

        device.is_tampered);

    /* Change the condition a little bit to include the test framework support.

     * We would never reach this point if device is in fastboot mode, even if we did

     * that means we are in test mode, so execute kernel authentication part for the

     * tests */

    if((target_use_signed_kernel() && (!device.is_unlocked)) || is_test_mode_enabled())

    {

        offset = imagesize_actual;

        if (check_aboot_addr_range_overlap((uintptr_t)image_addr + offset, page_size))

        {

            dprintf(CRITICAL, "Signature read buffer address overlaps with aboot addresses.\n");

            return -1;

        }

        /* Read signature */

        if(mmc_read(ptn + offset, (void *)(image_addr + offset), page_size))

        {

            dprintf(CRITICAL, "ERROR: Cannot read boot image signature\n");

            return -1;

        }

        verify_signed_bootimg((uint32_t)image_addr, imagesize_actual);

        /* The purpose of our test is done here */

        if(is_test_mode_enabled() && auth_kernel_img)

            return 0;

    else {

        second_actual  = ROUND_TO_PAGE(hdr->second_size,  page_mask);

        #ifdef TZ_SAVE_KERNEL_HASH

        aboot_save_boot_hash_mmc((uint32_t) image_addr, imagesize_actual);

        #endif /* TZ_SAVE_KERNEL_HASH */

#ifdef MDTP_SUPPORT

        {

            /* Verify MDTP lock.

             * For boot & recovery partitions, MDTP will use boot_verifier APIs,

             * since verification was skipped in aboot. The signature is not part of the loaded image.

             */

            mdtp_ext_partition_verification_t ext_partition;

            ext_partition.partition = boot_into_recovery ? MDTP_PARTITION_RECOVERY : MDTP_PARTITION_BOOT;

            ext_partition.integrity_state = MDTP_PARTITION_STATE_UNSET;

            ext_partition.page_size = page_size;

            ext_partition.image_addr = (uint32)image_addr;

            ext_partition.image_size = imagesize_actual;

            ext_partition.sig_avail = FALSE;

            mdtp_fwlock_verify_lock(&ext_partition);

        }

#endif /* MDTP_SUPPORT */

    }

#if VERIFIED_BOOT

    if(boot_verify_get_state() == ORANGE)

    {

#if FBCON_DISPLAY_MSG

        display_bootverify_menu(DISPLAY_MENU_ORANGE);

        wait_for_users_action();

#else

        dprintf(CRITICAL,

            "Your device has been unlocked and can't be trusted.\nWait for 5 seconds before proceeding\n");

#endif

    }

#endif

#if VERIFIED_BOOT

#if !VBOOT_MOTA

    // send root of trust

    if(!send_rot_command((uint32_t)device.is_unlocked))

        ASSERT(0);

#endif

#endif

    /*

     * Check if the kernel image is a gzip package. If yes, need to decompress it.

     * If not, continue booting.

     */

    if (is_gzip_package((unsigned char *)(image_addr + page_size), hdr->kernel_size))

    {

        out_addr = (unsigned char *)(image_addr + imagesize_actual + page_size);

        out_avai_len = target_get_max_flash_size() - imagesize_actual - page_size;

        dprintf(INFO, "decompressing kernel image: start\n");

        rc = decompress((unsigned char *)(image_addr + page_size),

                hdr->kernel_size, out_addr, out_avai_len,

                &dtb_offset, &out_len);

        if (rc)

        {

            dprintf(CRITICAL, "decompressing kernel image failed!!!\n");

            ASSERT(0);

        }

        dprintf(INFO, "decompressing kernel image: done\n");

        kptr = (struct kernel64_hdr *)out_addr;

        kernel_start_addr = out_addr;

        kernel_size = out_len;

    else {

        kptr = (struct kernel64_hdr *)(image_addr + page_size);

        kernel_start_addr = (unsigned char *)(image_addr + page_size);

        kernel_size = hdr->kernel_size;

    }

    /*

     * Update the kernel/ramdisk/tags address if the boot image header

     * has default values, these default values come from mkbootimg when

     * the boot image is flashed using fastboot flash:raw

     */

    update_ker_tags_rdisk_addr(hdr, IS_ARM64(kptr));

    /* Get virtual addresses since the hdr saves physical addresses. */

    hdr->kernel_addr = VA((addr_t)(hdr->kernel_addr));

    hdr->ramdisk_addr = VA((addr_t)(hdr->ramdisk_addr));

    hdr->tags_addr = VA((addr_t)(hdr->tags_addr));

    kernel_size = ROUND_TO_PAGE(kernel_size,  page_mask);

    /* Check if the addresses in the header are valid. */

    if (check_aboot_addr_range_overlap(hdr->kernel_addr, kernel_size) ||

        check_aboot_addr_range_overlap(hdr->ramdisk_addr, ramdisk_actual))

    {

        dprintf(CRITICAL, "kernel/ramdisk addresses overlap with aboot addresses.\n");

        return -1;

    }

#ifndef DEVICE_TREE

    if (check_aboot_addr_range_overlap(hdr->tags_addr, MAX_TAGS_SIZE))

    {

        dprintf(CRITICAL, "Tags addresses overlap with aboot addresses.\n");

        return -1;

    }

#endif

    /* Move kernel, ramdisk and device tree to correct address */

    memmove((void*) hdr->kernel_addr, kernel_start_addr, kernel_size);

    memmove((void*) hdr->ramdisk_addr, (char *)(image_addr + page_size + kernel_actual), hdr->ramdisk_size);

    #if DEVICE_TREE

    if(hdr->dt_size) {

        dt_table_offset = ((uint32_t)image_addr + page_size + kernel_actual + ramdisk_actual + second_actual);

        table = (struct dt_table*) dt_table_offset;

        if (dev_tree_validate(table, hdr->page_size, &dt_hdr_size) != 0) {

            dprintf(CRITICAL, "ERROR: Cannot validate Device Tree Table \n");

            return -1;

        }

        /* Its Error if, dt_hdr_size (table->num_entries * dt_entry size + Dev_Tree Header)

        goes beyound hdr->dt_size*/

        if (dt_hdr_size > ROUND_TO_PAGE(hdr->dt_size,hdr->page_size)) {

            dprintf(CRITICAL, "ERROR: Invalid Device Tree size \n");

            return -1;

        }

        /* Find index of device tree within device tree table */

        if(dev_tree_get_entry_info(table, &dt_entry) != 0){

            dprintf(CRITICAL, "ERROR: Getting device tree address failed\n");

            return -1;

        }

        if(dt_entry.offset > (UINT_MAX - dt_entry.size)) {

            dprintf(CRITICAL, "ERROR: Device tree contents are Invalid\n");

            return -1;

        }

        /* Ensure we are not overshooting dt_size with the dt_entry selected */

        if ((dt_entry.offset + dt_entry.size) > hdr->dt_size) {

            dprintf(CRITICAL, "ERROR: Device tree contents are Invalid\n");

            return -1;

        }

        if (is_gzip_package((unsigned char *)dt_table_offset + dt_entry.offset, dt_entry.size))

        {

            unsigned int compressed_size = 0;

            out_addr += out_len;

            out_avai_len -= out_len;

            dprintf(INFO, "decompressing dtb: start\n");

            rc = decompress((unsigned char *)dt_table_offset + dt_entry.offset,

                    dt_entry.size, out_addr, out_avai_len,

                    &compressed_size, &dtb_size);

            if (rc)

            {

                dprintf(CRITICAL, "decompressing dtb failed!!!\n");

                ASSERT(0);

            }

            dprintf(INFO, "decompressing dtb: done\n");

            best_match_dt_addr = out_addr;

        else {

            best_match_dt_addr = (unsigned char *)dt_table_offset + dt_entry.offset;

            dtb_size = dt_entry.size;

        }

        /* Validate and Read device device tree in the tags_addr */

        if (check_aboot_addr_range_overlap(hdr->tags_addr, dtb_size))

        {

            dprintf(CRITICAL, "Device tree addresses overlap with aboot addresses.\n");

            return -1;

        }

        memmove((void *)hdr->tags_addr, (char *)best_match_dt_addr, dtb_size);

    else {

        /* Validate the tags_addr */

        if (check_aboot_addr_range_overlap(hdr->tags_addr, kernel_actual))

        {

            dprintf(CRITICAL, "Device tree addresses overlap with aboot addresses.\n");

            return -1;

        }

        /*

         * If appended dev tree is found, update the atags with

         * memory address to the DTB appended location on RAM.

         * Else update with the atags address in the kernel header

         */

        void *dtb;

        dtb = dev_tree_appended((void*)(image_addr + page_size),

                    hdr->kernel_size, dtb_offset,

                    (void *)hdr->tags_addr);

        if (!dtb) {

            dprintf(CRITICAL, "ERROR: Appended Device Tree Blob not found\n");

            return -1;

        }

    }

    #endif

    if (boot_into_recovery && !device.is_unlocked && !device.is_tampered)

        target_load_ssd_keystore();

unified_boot:

    boot_linux((void *)hdr->kernel_addr, (void *)hdr->tags_addr,

           (const char *)hdr->cmdline, board_machtype(),

           (void *)hdr->ramdisk_addr, hdr->ramdisk_size);

    return 0;

}

进入到boot_linux_from_mmc函数后,

1 首先创建一个用来保存boot.img文件头信息的变量hdr,buf是一个4096byte的数组,hdr和hdr指向了同一个内存地址。

2 执行check_format_bit,根据bootselect分区信息判断是否进入recovery模式

3 如果不是recovery模式,此时有两种可能,正常开机/进入ffbm工厂测试模式,进入工厂测试模式是正行启动,但是向kernel传参会多一个字符串"androidboot.mode='ffbm_mode_string'"。因此这里还要调用get_ffbm,根据misc分区信息判断是否进入ffbm模式。

4 如果boot_into_recovery为true,就boot_into_ffbm置为false

5 uhdr = (struct boot_img_hdr *)EMMC_BOOT_IMG_HEADER_ADDR,计算uhdr,uhdr指向boot分区header地址

6 检查uhdr->magic 是否等于 "Android!",如果是就直接跳转到kernel,这是非正常路径

7 如果不是recovery模式,可能是正常启动或者进入ffbm,这种情况下调用partition_get_index获取boot分区索引,调用partition_get_offset获取boot分区便宜。 如果是recovery模式,读取recovery分区,并获得recovery分区的偏移量。

8 调用mmc_set_lun设置boot或recovery分区的lun号

9 调用mmc_read,从boot或者recovery分区读取1字节的内容到buf(hdr)中,我们知道在boot/recovery中开始的1字节存放的是hdr的内容。

10 调用memcmp,判断boot.img头结构体的魔数是否正确。

11 根据hdr->page_size,判断是否需要更新页大小。

12 如果有DEVICE_TREE,计算出dt所占的页的大小 dt_actual = ROUND_TO_PAGE(hdr->dt_size, page_mask); image占的页的总大小为imagesize_actual = (page_size + kernel_actual + ramdisk_actual + dt_actual);

如果没有DEVICE_TREE,imagesize_actual = (page_size + kernel_actual + ramdisk_actual);

13 检查boot.img是否与aboot的内存空间有重叠

14 调用函数update_ker_tags_rdisk_addr更新boot.img头结构体

15 将hdr中保存的物理地址转化为虚拟地址

hdr->kernel_addr = VA((addr_t)(hdr->kernel_addr));
hdr->ramdisk_addr = VA((addr_t)(hdr->ramdisk_addr));
hdr->tags_addr = VA((addr_t)(hdr->tags_addr));

16 kernel大小向上页对齐 :kernel_actual  = ROUND_TO_PAGE(hdr->kernel_size,  page_mask), ramdisk大小向上页对齐:kernel_actual  = ROUND_TO_PAGE(hdr->kernel_size,  page_mask) 

17 调用函数check_aboot_addr_range_overlap,检查kernel和ramdisk的是否与aboot的内存空间有重叠

18 将内核,randisk,和device tree在内存中移动到正确的地址

19 最后在函数返回前,将会执行到boot_linux,在boot_linux中将会完成跳转到内核的操作。

 

二 boot_linux

boot_linux的实现同样位于bootable/bootloader/lk/app/aboot/aboot.c

bootable/bootloader/lk/app/aboot/aboot.c Collapse source

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

    uint32_t tags_phys = PA((addr_t)tags);

    struct kernel64_hdr *kptr = ((struct kernel64_hdr*)(PA((addr_t)kernel)));

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

    final_cmdline = update_cmdline((const char*)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);

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

#endif

    free(final_cmdline);

#if VERIFIED_BOOT

#if !VBOOT_MOTA

    if (device.verity_mode == 0) {

#if FBCON_DISPLAY_MSG

        display_bootverify_menu(DISPLAY_MENU_LOGGING);

        wait_for_users_action();

#else

        dprintf(CRITICAL,

            "The dm-verity is not started in enforcing mode.\nWait for 5 seconds before proceeding\n");

        mdelay(5000);

#endif

    }

#endif

#endif

#if 0//VERIFIED_BOOT

    /* Write protect the device info */

    if (!boot_into_recovery && target_build_variant_user() && devinfo_present && mmc_write_protect("devinfo", 1))

    {

        dprintf(INFO, "Failed to write protect dev info\n");

        //ASSERT(0);

    }

#endif

    /* Turn off splash screen if enabled */

#if DISPLAY_SPLASH_SCREEN

    target_display_shutdown();

#endif

    /* Perform target specific cleanup */

    target_uninit();

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

#if ARM_WITH_MMU

    arch_disable_mmu();

#endif

    bs_set_timestamp(BS_KERNEL_ENTRY);

    if (IS_ARM64(kptr))

        /* Jump to a 64bit kernel */

        scm_elexec_call((paddr_t)kernel, tags_phys);

    else

        /* Jump to a 32bit kernel */

        entry(0, machtype, (unsigned*)tags_phys);

}

1 首先将kernel的起始内存地址转化成entry_func_ptr函数类型:void (*entry)(unsigned, unsigned, unsigned*) = (entry_func_ptr*)(PA((addr_t)kernel));

2 更新cmdline:final_cmdline = update_cmdline((const char*)cmdline);

3 更新device tree内容,主要是三部分:memory,cmdline,ramdisk:ret = update_device_tree((void *)tags,(const char *)final_cmdline, ramdisk, ramdisk_size);

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

5 对devinfo分区写保护:mmc_write_protect("devinfo", 1)

6 完成目标板级清除动作:target_uninit()

7 关闭lcd:target_display_shutdown()

8 关闭中断:enter_critical_section();

9 完成平台级清除动作:platform_uninit();

10 禁用cache:arch_disable_cache(UCACHE),如果有mmu还要关闭mmu:arch_disable_mmu()

11 设置kernel入口时间戳:bs_set_timestamp(BS_KERNEL_ENTRY);

12 判断是32位还是64位内核,执行不同的跳转操作。对于32bit kernel,直接跳转到kernel入口函数执行。对于64bit kernel,执行scm_elexec_call完成跳转。假设为64位内核,下面继续分析scm_elexec_call函数

 

三 scm_elexec_call

scm_elexec_call定义在bootable/bootloader/lk/platform/msm_shared/scm.c

bootable/bootloader/lk/platform/msm_shared/scm.c Collapse source

void scm_elexec_call(paddr_t kernel_entry, paddr_t dtb_offset)

{

    uint32_t svc_id = SCM_SVC_MILESTONE_32_64_ID;

    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;

    param.el1_elr = kernel_entry;

    /* 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);

    }

    else

    {

        scm_arg.x0 = MAKE_SIP_SCM_CMD(SCM_SVC_MILESTONE_32_64_ID, SCM_SVC_MILESTONE_CMD_ID);

        scm_arg.x1 = MAKE_SCM_ARGS(0x2, SMC_PARAM_TYPE_BUFFER_READ);

        scm_arg.x2 = (uint32_t ) &param;

        scm_arg.x3 = sizeof(el1_system_param);

        scm_call2(&scm_arg, NULL);

    }

    /* Assert if execution ever reaches here */

    dprintf(CRITICAL, "Failed to jump to kernel\n");

    ASSERT(0);

}

在scm_elexec_call中先获取到device tree的物理内存地址param.el1_x0 = dtb_offset, kernel入口的物理内存地址param.el1_elr = kernel_entry,最终通过scm_call或者scm_call2完成跳转到内核的操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值